nao_sensors.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 
00003 # SVN $HeadURL$
00004 # SVN $Id$
00005 
00006 
00007 #
00008 # ROS node to read Nao's sensors and torso odometry through the Aldebaran API.
00009 # This code is currently compatible to NaoQI version 1.6
00010 #
00011 # Copyright 2009 Armin Hornung, University of Freiburg
00012 # http://www.ros.org/wiki/nao
00013 #
00014 # Redistribution and use in source and binary forms, with or without
00015 # modification, are permitted provided that the following conditions are met:
00016 #
00017 #    # Redistributions of source code must retain the above copyright
00018 #       notice, this list of conditions and the following disclaimer.
00019 #    # Redistributions in binary form must reproduce the above copyright
00020 #       notice, this list of conditions and the following disclaimer in the
00021 #       documentation and/or other materials provided with the distribution.
00022 #    # Neither the name of the University of Freiburg nor the names of its
00023 #       contributors may be used to endorse or promote products derived from
00024 #       this software without specific prior written permission.
00025 #
00026 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00027 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00028 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00029 # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00030 # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00031 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00032 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00033 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00034 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00035 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00036 # POSSIBILITY OF SUCH DAMAGE.
00037 #
00038 
00039 
00040 import roslib
00041 roslib.load_manifest('nao_driver')
00042 import rospy
00043 
00044 from sensor_msgs.msg import JointState
00045 
00046 from nao_msgs.msg import TorsoOdometry, TorsoIMU
00047 
00048 from nao_driver import *
00049 
00050 import threading
00051 from threading import Thread
00052 
00053 class NaoSensors(NaoNode, Thread):
00054     def __init__(self):
00055         NaoNode.__init__(self)
00056         Thread.__init__(self)
00057 
00058         # ROS initialization:
00059         rospy.init_node('nao_sensors')
00060 
00061         self.connectNaoQi()
00062 
00063         self.stopThread = False
00064 
00065         self.odomSleep = 1.0/rospy.get_param('~torso_odom_rate', 20.0)
00066 
00067 
00068         self.dataNamesList = ["DCM/Time",
00069                                 "Device/SubDeviceList/InertialSensor/AngleX/Sensor/Value","Device/SubDeviceList/InertialSensor/AngleY/Sensor/Value",
00070                                 "Device/SubDeviceList/InertialSensor/GyrX/Sensor/Value", "Device/SubDeviceList/InertialSensor/GyrY/Sensor/Value",
00071                                 "Device/SubDeviceList/InertialSensor/AccX/Sensor/Value", "Device/SubDeviceList/InertialSensor/AccY/Sensor/Value",
00072                                 "Device/SubDeviceList/InertialSensor/AccZ/Sensor/Value"]
00073 
00074 
00075         tf_prefix_param_name = rospy.search_param('tf_prefix')
00076         if tf_prefix_param_name:
00077             self.tf_prefix = rospy.get_param(tf_prefix_param_name)
00078         else:
00079             self.tf_prefix = ""
00080 
00081         self.base_frameID = rospy.get_param('~base_frame_id', "torso")
00082         if not(self.base_frameID[0] == '/'):
00083             self.base_frameID = self.tf_prefix + '/' + self.base_frameID
00084 
00085         # send cam odom?
00086         self.sendCamOdom = rospy.get_param('~send_cam_odom', False)
00087         # use sensor values or commanded (open-loop) values for joint angles
00088         self.useJointSensors = rospy.get_param('~use_joint_sensors', True) # (set to False in simulation!)
00089         # init. messages:
00090         self.torsoOdom = TorsoOdometry()
00091         self.camOdom = TorsoOdometry()
00092         self.torsoOdom.header.frame_id = rospy.get_param('~odom_frame_id', "odom")
00093         self.camOdom.header.frame_id = rospy.get_param('~odom_frame_id', "odom")
00094         if not(self.torsoOdom.header.frame_id[0] == '/'):
00095             self.torsoOdom.header.frame_id = self.tf_prefix + '/' + self.torsoOdom.header.frame_id
00096         if not(self.camOdom.header.frame_id[0] == '/'):
00097             self.camOdom.header.frame_id = self.tf_prefix + '/' + self.camOdom.header.frame_id
00098         self.torsoIMU = TorsoIMU()
00099         self.torsoIMU.header.frame_id = self.base_frameID
00100         self.jointState = JointState()
00101         self.jointState.name = self.motionProxy.getJointNames('Body')
00102 
00103         # simluated model misses some joints, we need to fill:
00104         if (len(self.jointState.name) == 22):
00105             self.jointState.name.insert(6,"LWristYaw")
00106             self.jointState.name.insert(7,"LHand")
00107             self.jointState.name.append("RWristYaw")
00108             self.jointState.name.append("RHand")
00109 
00110         msg = "Nao joints found: "+ str(self.jointState.name)
00111         rospy.logdebug(msg)
00112 
00113 
00114         if self.sendCamOdom:
00115             self.camOdomPub = rospy.Publisher("camera_odometry", TorsoOdometry)
00116         self.torsoOdomPub = rospy.Publisher("torso_odometry", TorsoOdometry)
00117         self.torsoIMUPub = rospy.Publisher("torso_imu", TorsoIMU)
00118         self.jointStatePub = rospy.Publisher("joint_states", JointState)
00119 
00120         rospy.loginfo("nao_sensors initialized")
00121 
00122     # (re-) connect to NaoQI:
00123     def connectNaoQi(self):
00124         rospy.loginfo("Connecting to NaoQi at %s:%d", self.pip, self.pport)
00125 
00126         self.motionProxy = self.getProxy("ALMotion")
00127         self.memProxy = self.getProxy("ALMemory")
00128         # TODO: check self.memProxy.version() for > 1.6
00129         if self.motionProxy is None or self.memProxy is None:
00130             exit(1)
00131 
00132     def run(self):
00133         """ Odometry thread code - collects and sends out odometry esimate. """
00134         while(not self.stopThread):
00135                 #
00136                 # Build odometry:
00137                 #
00138             timestamp = rospy.Time.now()
00139             try:
00140                 memData = self.memProxy.getListData(self.dataNamesList)
00141                  # odometry data:
00142                 odomData = self.motionProxy.getPosition('Torso', motion.SPACE_WORLD, True)
00143                 # camera data
00144                 #camData = self.motionProxy.getTransform('CameraTop', motion.SPACE_WORLD, True)
00145                 if self.sendCamOdom:
00146                     camData = self.motionProxy.getPosition('CameraTop', motion.SPACE_WORLD, True)
00147                 positionData = self.motionProxy.getAngles('Body', self.useJointSensors)
00148             except RuntimeError, e:
00149                 print "Error accessing ALMemory, exiting...\n"
00150                 print e
00151                 rospy.signal_shutdown("No NaoQI available anymore")
00152 
00153             self.torsoOdom.header.stamp = timestamp
00154             self.camOdom.header.stamp = timestamp
00155             if len(odomData)==2:
00156                 odomData = odomData[1]
00157             elif len(odomData)!=6:
00158                 print "Error getting odom data"
00159                 continue
00160             self.torsoOdom.x = odomData[0]
00161             self.torsoOdom.y = odomData[1]
00162             self.torsoOdom.z = odomData[2]
00163             self.torsoOdom.wx = odomData[3]
00164             self.torsoOdom.wy = odomData[4]
00165             self.torsoOdom.wz = odomData[5]
00166 
00167             if self.sendCamOdom:
00168                 self.camOdom.x = camData[0]
00169                 self.camOdom.y = camData[1]
00170                 self.camOdom.z = camData[2]
00171                 self.camOdom.wx = camData[3]
00172                 self.camOdom.wy = camData[4]
00173                 self.camOdom.wz = camData[5]
00174 
00175             self.torsoOdomPub.publish(self.torsoOdom)
00176             if self.sendCamOdom:
00177                 self.camOdomPub.publish(self.camOdom)
00178 
00179             # Replace 'None' values with 0
00180             # (=> consistent behavior in 1.8 / 1.10 with 1.6)
00181             for i, m in enumerate(memData):
00182                 if m is None:
00183                     memData[i] = 0
00184 
00185             if len(memData) != len(self.dataNamesList):
00186                 print "memData length does not match expected length"
00187                 print memData
00188                 continue
00189 
00190 
00191             # IMU data:
00192             self.torsoIMU.header.stamp = timestamp
00193             self.torsoIMU.angleX = memData[1]
00194             self.torsoIMU.angleY = memData[2]
00195             self.torsoIMU.gyroX = memData[3]
00196             self.torsoIMU.gyroY = memData[4]
00197             self.torsoIMU.accelX = memData[5]
00198             self.torsoIMU.accelY = memData[6]
00199             self.torsoIMU.accelZ = memData[7]
00200 
00201             self.torsoIMUPub.publish(self.torsoIMU)
00202 
00203 
00204             #
00205             # Send JointState:
00206             #
00207             self.jointState.header.stamp = timestamp
00208             self.jointState.header.frame_id = self.base_frameID
00209             self.jointState.position = positionData
00210 
00211             # simulated model misses some joints, we need to fill:
00212             if (len(self.jointState.position) == 22):
00213                 self.jointState.position.insert(6, 0.0)
00214                 self.jointState.position.insert(7, 0.0)
00215                 self.jointState.position.append(0.0)
00216                 self.jointState.position.append(0.0)
00217 
00218             self.jointStatePub.publish(self.jointState)
00219 
00220             rospy.sleep(self.odomSleep)
00221 
00222 if __name__ == '__main__':
00223 
00224     sensors = NaoSensors()
00225     sensors.start()
00226 
00227     rospy.spin()
00228 
00229     rospy.loginfo("Stopping nao_sensors ...")
00230     sensors.stopThread = True
00231     sensors.join()
00232 
00233     rospy.loginfo("nao_sensors stopped.")
00234     exit(0)
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Friends


nao_driver
Author(s): Armin Hornung, Stefan Osswald, Daniel Maier
autogenerated on Tue Oct 15 2013 10:06:23