00001
00002 """Phidgets HC Motor Control ROS service for CoroBot
00003
00004 A ROS service to request a specific acceleration and individual
00005 side drive wheels speed.
00006
00007 """
00008
00009 __author__ = 'Bill Mania <bmania@coroware.com>'
00010 __version__ = '1'
00011
00012 import roslib; roslib.load_manifest('PhidgetMotor')
00013 from corobot_srvs.srv import *
00014 from corobot_msgs.msg import *
00015 import rospy
00016 from threading import Timer
00017 from ctypes import *
00018 from Phidgets.Devices.MotorControl import MotorControl
00019 from Phidgets.PhidgetException import PhidgetErrorCodes, PhidgetException
00020 from Phidgets.Events.Events import EncoderPositionUpdateEventArgs
00021
00022 motors_inverted = False
00023
00024 phidget1065 = False
00025 motorControl = 0
00026 motorControlRight = 0
00027 leftWheels = 0
00028 rightWheels = 1
00029 minAcceleration = 0
00030 maxAcceleration = 0
00031 minSpeed = -100
00032 maxSpeed = 100
00033 timer = 0
00034 posdataPub = 0
00035 leftPosition = 0
00036 rightPosition = 0
00037
00038 def stop():
00039 try:
00040 motorControl.setVelocity(leftWheels,0);
00041
00042 if phidget1065 == True:
00043 motorControlRight.setVelocity(rightWheels,0);
00044 else:
00045 motorControl.setVelocity(rightWheels, 0);
00046 except PhidgetException as e:
00047 rospy.logerr("Failed in setVelocity() %i: %s", e.code, e.details)
00048 return(False)
00049 return(True)
00050
00051
00052 def move(request):
00053 """Cause the CoroBot to move or stop moving
00054
00055 Request a common acceleration, wheel directions and wheel speeds
00056
00057 """
00058 global timer
00059 if timer:
00060 timer.cancel();
00061 rospy.logdebug(
00062 "Left: %d:%d, Right: %d:%d, Acceleration: %d",
00063 leftWheels,
00064 request.leftSpeed,
00065 rightWheels,
00066 request.rightSpeed,
00067 request.acceleration
00068 )
00069 if request.acceleration > maxAcceleration:
00070 acceleration = float(maxAcceleration)
00071 elif request.acceleration < minAcceleration:
00072 acceleration = float(minAcceleration)
00073 else:
00074 acceleration = float(request.acceleration)
00075
00076 if request.leftSpeed < minSpeed:
00077 leftSpeed = float(minSpeed)
00078 elif request.leftSpeed > maxSpeed:
00079 leftSpeed = float(maxSpeed)
00080 else:
00081 leftSpeed = float(request.leftSpeed)
00082 if request.rightSpeed < minSpeed:
00083 rightSpeed = float(minSpeed)
00084 elif request.rightSpeed > maxSpeed:
00085 rightSpeed = float(maxSpeed)
00086 else:
00087 rightSpeed = float(request.rightSpeed)
00088
00089
00090 if motors_inverted == True:
00091 temp = rightSpeed
00092 rightSpeed = -leftSpeed
00093 leftSpeed = -temp
00094
00095 rospy.logdebug(
00096 "Left: %d:%d, Right: %d:%d, Acceleration: %d",
00097 leftWheels,
00098 leftSpeed,
00099 rightWheels,
00100 rightSpeed,
00101 acceleration
00102 )
00103
00104 try:
00105 motorControl.setAcceleration(leftWheels, acceleration);
00106
00107 if phidget1065 == True:
00108 motorControlRight.setAcceleration(rightWheels, acceleration);
00109 else:
00110 motorControl.setAcceleration(rightWheels, acceleration);
00111 except PhidgetException as e:
00112 rospy.logerr("Failed in setAcceleration() %i: %s", e.code, e.details)
00113 return(False)
00114
00115 try:
00116 motorControl.setVelocity(leftWheels, leftSpeed);
00117
00118 if phidget1065 == True:
00119 motorControlRight.setVelocity(rightWheels, rightSpeed);
00120 else:
00121 motorControl.setVelocity(rightWheels, rightSpeed);
00122 except PhidgetException as e:
00123 rospy.logerr("Failed in setVelocity() %i: %s", e.code, e.details)
00124 return(False)
00125
00126 if request.secondsDuration != 0:
00127 timer = Timer(request.secondsDuration, stop)
00128 timer.start()
00129 return(True)
00130
00131 def mcAttached(e):
00132 return
00133
00134 def mcDetached(e):
00135 return
00136
00137 def mcError(e):
00138 return
00139
00140 def mcCurrentChanged(e):
00141 return
00142
00143 def mcInputChanged(e):
00144 return
00145
00146 def mcVelocityChanged(e):
00147 return
00148
00149 def leftEncoderUpdated(e):
00150
00151 global leftPosition, rightPosition
00152
00153 leftPosition += e.positionChange
00154 if motorControlRight:
00155 rightPosition = motorControlRight.getEncoderPosition(rightWheels)
00156
00157
00158 msg = PosMsg()
00159 msg.px = leftPosition
00160 msg.py = rightPosition
00161 msg.header.stamp = rospy.Time.now()
00162 posdataPub.publish(msg)
00163
00164 return
00165
00166 def rightEncoderUpdated(e):
00167
00168 global leftPosition, rightPosition
00169
00170 rightPosition += e.positionChange
00171 if motorControl:
00172 leftPosition = motorControl.getEncoderPosition(leftWheels)
00173
00174
00175 msg = PosMsg()
00176 msg.px = leftPosition
00177 msg.py = rightPosition
00178 msg.header.stamp = rospy.Time.now()
00179 posdataPub.publish(msg)
00180
00181 return
00182
00183 def setupMoveService():
00184 """Initialize the PhidgetMotor service
00185
00186 Establish a connection with the Phidget HC Motor Control and
00187 then with the ROS Master as the service PhidgetMotor
00188
00189 """
00190
00191 rospy.init_node(
00192 'PhidgetMotor',
00193 log_level = rospy.DEBUG
00194 )
00195
00196 global motorControl, motorControlRight, minAcceleration, maxAcceleration, timer, motors_inverted, phidget1065, rightWheels, posdataPub
00197 timer = 0
00198 try:
00199 motorControl = MotorControl()
00200 except:
00201 rospy.logerr("Unable to connect to Phidget HC Motor Control")
00202 return
00203
00204 try:
00205 motorControl.setOnAttachHandler(mcAttached)
00206 motorControl.setOnDetachHandler(mcDetached)
00207 motorControl.setOnErrorhandler(mcError)
00208 motorControl.setOnCurrentChangeHandler(mcCurrentChanged)
00209 motorControl.setOnInputChangeHandler(mcInputChanged)
00210 motorControl.setOnVelocityChangeHandler(mcVelocityChanged)
00211 motorControl.openPhidget()
00212
00213
00214 motorControl.waitForAttach(10000)
00215 """use the function getMotorCount() to know how many motors the Phidget board can take
00216
00217 if the result is more than 1, we have a 1064 board and we take care of both motors with one motorControl variable. The corobot_phidgetIK handles the Phidget encoder board that is
00218 separated of the phidget 1064.
00219 if the result is equal to 1, we have two phidget 1065 boards. The one with serial number that is the lowest will be the left will, the other the right weel. The encoder has to be handled
00220 in this file as it is part of the 1065 board.
00221
00222 """
00223 if motorControl.getMotorCount() == 1:
00224 phidget1065 = True
00225 rightWheels = 0
00226 motorControlRight.setOnAttachHandler(mcAttached)
00227 motorControlRight.setOnDetachHandler(mcDetached)
00228 motorControlRight.setOnErrorhandler(mcError)
00229 motorControlRight.setOnCurrentChangeHandler(mcCurrentChanged)
00230 motorControlRight.setOnInputChangeHandler(mcInputChanged)
00231 motorControlRight.setOnVelocityChangeHandler(mcVelocityChanged)
00232
00233 if motorControl.getSerialNum() > motorControlRight.getSerialNum():
00234 """ As a rule, we need the serial number of the left board to be lower than for the right board. This is for consistancy for all the robots
00235 """
00236 motorControlTemp = motorControl
00237 motorControl = motorControlRight
00238 motorControlRight = motorControlTemp
00239
00240
00241 motorControl.setOnPositionUpdateHandler(leftEncoderUpdated)
00242 motorControlRight.setOnPositionUpdateHandler(rightEncoderUpdated)
00243
00244
00245 motorControlRight.waitForAttach(10000)
00246 except PhidgetException as e:
00247 rospy.logerr("Unable to register the handlers: %i: %s", e.code, e.details)
00248 return
00249 except:
00250 rospy.logerr("Unable to register the handlers")
00251 return
00252
00253
00254 if motorControl.isAttached():
00255 rospy.loginfo(
00256 "Device: %s, Serial: %d, Version: %d",
00257 motorControl.getDeviceName(),
00258 motorControl.getSerialNum(),
00259 motorControl.getDeviceVersion()
00260 )
00261 if phidget1065 == True:
00262 if motorControlRight.isAttached():
00263 rospy.loginfo(
00264 "Device: %s, Serial: %d, Version: %d",
00265 motorControlRight.getDeviceName(),
00266 motorControlRight.getSerialNum(),
00267 motorControlRight.getDeviceVersion()
00268 )
00269
00270 minAcceleration = motorControl.getAccelerationMin(leftWheels)
00271 maxAcceleration = motorControl.getAccelerationMax(leftWheels)
00272
00273 motors_inverted = rospy.get_param('~motors_inverted', False)
00274
00275 phidgetMotorTopic = rospy.Subscriber("PhidgetMotor", MotorCommand ,move)
00276 phidgetMotorService = rospy.Service('PhidgetMotor',Move, move)
00277 if phidget1065 == True:
00278 posdataPub = rospy.Publisher("position_data", PosMsg)
00279 rospy.spin()
00280
00281 if __name__ == "__main__":
00282 setupMoveService()
00283
00284 try:
00285 motorControl.closePhidget()
00286 if phidget1065 == True:
00287 motorControlRight.closePhidget()
00288 except:
00289 pass