nao_walker.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 
00003 #
00004 # ROS node to control Nao's walking engine (omniwalk and footsteps)
00005 # This code is currently compatible to NaoQI version 1.6 or newer (latest
00006 # tested: 1.12)
00007 #
00008 # Copyright 2009-2011 Armin Hornung & Stefan Osswald, University of Freiburg
00009 # http://www.ros.org/wiki/nao
00010 #
00011 # Redistribution and use in source and binary forms, with or without
00012 # modification, are permitted provided that the following conditions are met:
00013 #
00014 #    # Redistributions of source code must retain the above copyright
00015 #       notice, this list of conditions and the following disclaimer.
00016 #    # Redistributions in binary form must reproduce the above copyright
00017 #       notice, this list of conditions and the following disclaimer in the
00018 #       documentation and/or other materials provided with the distribution.
00019 #    # Neither the name of the University of Freiburg nor the names of its
00020 #       contributors may be used to endorse or promote products derived from
00021 #       this software without specific prior written permission.
00022 #
00023 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00024 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00025 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00026 # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00027 # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00028 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00029 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00030 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00031 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00032 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00033 # POSSIBILITY OF SUCH DAMAGE.
00034 #
00035 
00036 import roslib
00037 roslib.load_manifest('nao_driver')
00038 import rospy
00039 
00040 import logging
00041 logging.basicConfig()
00042 
00043 from nao_driver import *
00044 
00045 import math
00046 from math import fabs
00047 
00048 from std_msgs.msg import String
00049 from geometry_msgs.msg import Twist
00050 from geometry_msgs.msg import Pose2D
00051 from sensor_msgs.msg import JointState
00052 from std_msgs.msg import Bool
00053 import std_msgs.msg
00054 
00055 from std_srvs.srv import Empty, EmptyResponse
00056 from nao_msgs.srv import CmdPoseService, CmdVelService, CmdPoseServiceResponse, CmdVelServiceResponse
00057 from humanoid_nav_msgs.msg import StepTarget
00058 from humanoid_nav_msgs.srv import StepTargetService, StepTargetServiceResponse
00059 
00060 import nao_msgs.srv
00061 
00062 from start_walk_pose import startWalkPose
00063 
00064 class NaoWalker(NaoNode):
00065     def __init__(self):
00066         NaoNode.__init__(self)
00067 
00068         # ROS initialization:
00069         rospy.init_node('nao_walker')
00070 
00071         self.connectNaoQi()
00072 
00073         # head scan is not active
00074         self.scan_active = False
00075         # walking pattern params:
00076         self.stepFrequency = rospy.get_param('~step_frequency', 0.5)
00077 
00078         self.useStartWalkPose = rospy.get_param('~use_walk_pose', False)
00079         self.needsStartWalkPose = True
00080 
00081         # other params
00082         self.maxHeadSpeed = rospy.get_param('~max_head_speed', 0.2)
00083         # initial stiffness (defaults to 0 so it doesn't strain the robot when no teleoperation is running)
00084         # set to 1.0 if you want to control the robot immediately
00085         initStiffness = rospy.get_param('~init_stiffness', 0.0)
00086 
00087         self.for_iros2011 = rospy.get_param('~for_iros2011', False)
00088         rospy.loginfo("for_iros2011 = %d" % self.for_iros2011)
00089         if self.for_iros2011:
00090             self.doubleScan = rospy.get_param('~double_scan', False)
00091             self.doubleScanFrom = rospy.get_param('~double_scan_from', 0.0)
00092             self.doubleScanTo = rospy.get_param('~double_scan_to', -30.0)
00093             self.scanInfoPub = rospy.Publisher("scan_info", Bool, latch=True)
00094             scanInfo = Bool(False)
00095             self.scanInfoPub.publish(scanInfo)
00096 
00097         self.useFootGaitConfig = rospy.get_param('~use_foot_gait_config', False)
00098         rospy.loginfo("useFootGaitConfig = %d" % self.useFootGaitConfig)
00099         if self.useFootGaitConfig:
00100             self.footGaitConfig = rospy.get_param('~foot_gait_config', self.motionProxy.getFootGaitConfig("Default"))
00101         else:
00102             self.footGaitConfig = self.motionProxy.getFootGaitConfig("Default")
00103 
00104         # TODO: parameterize
00105         if initStiffness > 0.0 and initStiffness <= 1.0:
00106             self.motionProxy.stiffnessInterpolation('Body', initStiffness, 0.5)
00107 
00108         try:
00109             enableFootContactProtection = rospy.get_param('~enable_foot_contact_protection')
00110             self.motionProxy.setMotionConfig([["ENABLE_FOOT_CONTACT_PROTECTION", enableFootContactProtection]])
00111             if enableFootContactProtection:
00112                 rospy.loginfo("Enabled foot contact protection")
00113             else:
00114                 rospy.loginfo("Disabled foot contact protection")
00115         except KeyError:
00116             # do not change foot contact protection
00117             pass
00118 
00119         # last: ROS subscriptions (after all vars are initialized)
00120         rospy.Subscriber("cmd_vel", Twist, self.handleCmdVel, queue_size=1)
00121         rospy.Subscriber("cmd_pose", Pose2D, self.handleTargetPose, queue_size=1)
00122         rospy.Subscriber("cmd_step", StepTarget, self.handleStep, queue_size=50)
00123         rospy.Subscriber("speech", String, self.handleSpeech)
00124         rospy.Subscriber("start_scan", std_msgs.msg.Empty, self.handleStartScan, queue_size=1)
00125 
00126         # ROS services (blocking functions)
00127         self.cmdPoseSrv = rospy.Service("cmd_pose_srv", CmdPoseService, self.handleTargetPoseService)
00128         self.cmdVelSrv = rospy.Service("cmd_vel_srv", CmdVelService, self.handleCmdVelService)
00129         self.stepToSrv = rospy.Service("cmd_step_srv", StepTargetService, self.handleStepSrv)
00130         self.headScanSrv = rospy.Service("head_scan_srv", Empty, self.handleHeadScanSrv)
00131         self.stopWalkSrv = rospy.Service("stop_walk_srv", Empty, self.handleStopWalkSrv)
00132         self.needsStartWalkPoseSrv = rospy.Service("needs_start_walk_pose_srv", Empty, self.handleNeedsStartWalkPoseSrv)
00133         self.readFootGaitConfigSrv = rospy.Service("read_foot_gait_config_srv", Empty, self.handleReadFootGaitConfigSrv)
00134 
00135         self.say("Walker online")
00136 
00137         rospy.loginfo("nao_walker initialized")
00138 
00139     def connectNaoQi(self):
00140         '''(re-) connect to NaoQI'''
00141         rospy.loginfo("Connecting to NaoQi at %s:%d", self.pip, self.pport)
00142 
00143         self.motionProxy = self.getProxy("ALMotion")
00144         if self.motionProxy is None:
00145             exit(1)
00146 
00147         self.ttsProxy = self.getProxy("ALTextToSpeech", warn=False)
00148         if self.ttsProxy is None:
00149             rospy.logwarn("No Proxy to TTS available, disabling speech output.")
00150 
00151 
00152     def stopWalk(self):
00153         """ Stops the current walking bahavior and blocks until the clearing is complete. """
00154         try:
00155             self.motionProxy.setWalkTargetVelocity(0.0, 0.0, 0.0, self.stepFrequency)
00156             self.motionProxy.waitUntilWalkIsFinished()
00157 
00158 
00159         except RuntimeError,e:
00160             print "An error has been caught"
00161             print e
00162             return False
00163 
00164         return True
00165 
00166 
00167     def handleSpeech(self,data):
00168         self.say(data.data)
00169 
00170     def say(self, text):
00171         if (not self.ttsProxy is None):
00172             try:
00173                 # self.ttsProxy.say() sometimes causes deadlocks
00174                 # see http://users.aldebaran-robotics.com/index.php?option=com_kunena&Itemid=14&func=view&catid=68&id=3857&limit=6&limitstart=6#6251
00175                 print("say %s ..." % str(text))
00176                 ttsid = self.ttsProxy.post.say(str(text))
00177                 #self.ttsProxy.wait(ttsid, 0)
00178                 print("...done")
00179             except RuntimeError,e:
00180                 rospy.logerr("Exception caught:\n%s", e)
00181 
00182     def handleCmdVel(self, data):
00183         rospy.logdebug("Walk cmd_vel: %f %f %f, frequency %f", data.linear.x, data.linear.y, data.angular.z, self.stepFrequency)
00184         if data.linear.x != 0 or data.linear.y != 0 or data.angular.z != 0:
00185             self.gotoStartWalkPose()
00186         try:
00187             eps = 1e-3 # maybe 0,0,0 is a special command in motionProxy...
00188             if abs(data.linear.x)<eps and abs(data.linear.y)<eps and abs(data.angular.z)<eps:
00189                 self.motionProxy.setWalkTargetVelocity(0,0,0,0.5)
00190             else:
00191                 self.motionProxy.setWalkTargetVelocity(data.linear.x, data.linear.y, data.angular.z, self.stepFrequency, self.footGaitConfig)
00192         except RuntimeError,e:
00193             # We have to assume there's no NaoQI running anymore => exit!
00194             rospy.logerr("Exception caught in handleCmdVel:\n%s", e)
00195             rospy.signal_shutdown("No NaoQI available anymore")
00196 
00197 
00198 
00199     def handleCmdVelService(self, req):
00200         self.handleCmdVel(req.twist)
00201         return CmdVelServiceResponse()
00202 
00203     def handleTargetPose(self, data, post=True):
00204         """handles cmd_pose requests, walks to (x,y,theta) in robot coordinate system"""
00205         if self.scan_active:
00206             return False
00207 
00208         rospy.logdebug("Walk target_pose: %f %f %f", data.x,
00209                 data.y, data.theta)
00210 
00211         self.gotoStartWalkPose()
00212 
00213         try:
00214             if post:
00215                 self.motionProxy.post.walkTo(data.x, data.y, data.theta, self.footGaitConfig)
00216             else:
00217                 self.motionProxy.walkTo(data.x, data.y, data.theta, self.footGaitConfig)
00218             return True
00219         except RuntimeError,e:
00220             rospy.logerr("Exception caught in handleTargetPose:\n%s", e)
00221             return False
00222 
00223 
00224     def handleStep(self, data):
00225         rospy.logdebug("Step leg: %d; target: %f %f %f", data.leg, data.pose.x,
00226                 data.pose.y, data.pose.theta)
00227         try:
00228             if data.leg == StepTarget.right:
00229                 leg = "RLeg"
00230             elif data.leg == StepTarget.left:
00231                 leg = "LLeg"
00232             else:
00233                 rospy.logerr("Received a wrong leg constant: %d, ignoring step command", data.leg)
00234                 return
00235             self.motionProxy.stepTo(leg, data.pose.x, data.pose.y, data.pose.theta)
00236             return True
00237         except RuntimeError, e:
00238             rospy.logerr("Exception caught in handleStep:\n%s", e)
00239             return False
00240 
00241     def handleStepSrv(self, req):
00242         if self.handleStep(req.step):
00243             return StepTargetServiceResponse()
00244         else:
00245             return None
00246 
00247     def handleTargetPoseService(self, req):
00248         """ do NOT use post"""
00249         if self.handleTargetPose(req.pose, False):
00250             return CmdPoseServiceResponse()
00251         else:
00252             return None
00253 
00254     def handleHeadScanSrv(self, req):
00255         if self.perform_laser_scan():
00256             return EmptyResponse()
00257         else:
00258             return None
00259 
00260     def handleStartScan(self, msg):
00261         self.perform_laser_scan()
00262 
00263     def handleStopWalkSrv(self, req):
00264         if self.stopWalk():
00265             return EmptyResponse()
00266         else:
00267             return None
00268 
00269     def gotoStartWalkPose(self):
00270         if self.useStartWalkPose and self.needsStartWalkPose:
00271             startWalkPose(self.motionProxy)
00272             self.needsStartWalkPose = False
00273 
00274     def handleNeedsStartWalkPoseSrv(self, data):
00275         self.needsStartWalkPose = True
00276         return EmptyResponse()
00277 
00278     def handleReadFootGaitConfigSrv(self, data):
00279         self.useFootGaitConfig = rospy.get_param('~use_foot_gait_config', False)
00280         rospy.loginfo("useFootGaitConfig = %d" % self.useFootGaitConfig)
00281         if self.useFootGaitConfig:
00282             self.footGaitConfig = rospy.get_param('~foot_gait_config', self.motionProxy.getFootGaitConfig("Default"))
00283         else:
00284             self.footGaitConfig = self.motionProxy.getFootGaitConfig("Default")
00285         return EmptyResponse()
00286 
00287     def perform_laser_scan(self):
00288         if self.scan_active:
00289             print "ignoring button press because I'm already scanning"
00290             return False
00291         self.scan_active = True
00292         self.stopWalk()
00293         if self.for_iros2011:
00294             from iros2011_scan import head_scan
00295             head_scan(self.motionProxy,self.ttsProxy, 28.0, -36.0, 1.0, 10.0, True)
00296             if self.doubleScan:
00297                 head_scan(self.motionProxy, self.ttsProxy, self.doubleScanFrom, self.doubleScanTo, 1.0, 10.0, False)
00298                 self.motionProxy.angleInterpolation('HeadPitch', 0.0, 2.5, True)
00299         else:
00300             # todo: remove sleeps
00301             #from headscan import head_scan
00302             from headscanTop import head_scan
00303             if (not self.ttsProxy is None):
00304                 self.say("Starting scan")
00305             else:
00306                 rospy.loginfo("Starting scan")
00307             # max angle, min angle (pitch), scan freq, resolution, use squat
00308             rospy.sleep(2)
00309             #head_scan(self.motionProxy,26.0,-5.0,10.0,0.5,True)
00310             head_scan(self.motionProxy,28.0, -35.0, 1.0, 10.0, True)
00311             if (not self.ttsProxy is None):
00312                 self.say("Scan complete")
00313             else:
00314                 rospy.loginfo("Scan complete")
00315         self.scan_active = False
00316         self.needsStartWalkPose = True
00317         return True
00318 
00319 
00320 if __name__ == '__main__':
00321     walker = NaoWalker()
00322     rospy.loginfo("nao_walker running...")
00323     rospy.spin()
00324     rospy.loginfo("nao_walker stopping...")
00325     walker.stopWalk()
00326 
00327     rospy.loginfo("nao_walker stopped.")
00328     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