$search
00001 #!/usr/bin/env python 00002 00003 # SVN $HeadURL: http://alufr-ros-pkg.googlecode.com/svn/trunk/humanoid_stacks/nao_robot/nao_driver/scripts/nao_sensors.py $ 00004 # SVN $Id: nao_sensors.py 2690 2012-05-03 11:54:59Z hornunga@informatik.uni-freiburg.de $ 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)