wheeled_robin_driver.py
Go to the documentation of this file.
00001 
00002 #!/usr/bin/python
00003 
00004 # The MIT License
00005 #
00006 # Copyright (c) 2013 Johannes Mayr
00007 #
00008 # Permission is hereby granted, free of charge, to any person obtaining a copy
00009 # of this software and associated documentation files (the "Software"), to deal
00010 # in the Software without restriction, including without limitation the rights
00011 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00012 # copies of the Software, and to permit persons to whom the Software is
00013 # furnished to do so, subject to the following conditions:
00014 #
00015 # The above copyright notice and this permission notice shall be included in
00016 # all copies or substantial portions of the Software.
00017 #
00018 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00019 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00020 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00021 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00022 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00023 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00024 # THE SOFTWARE.
00025 
00026 from __future__ import with_statement
00027 
00028 """
00029 wheeled_robin serial control Interface (WSCI) is based on Roomba SCI and Create OI and implements a
00030 subset of the opcodes specified there.
00031 
00032 wheeled_robin_driver.py uses the SerialCommandInterface of create_driver from ROS.
00033 The Wheeled_Robin class is adopted from the Roomba class in create_driver.
00034 """
00035 __author__ = "joh.mayr@jku.at (Johannes Mayr)"
00036 
00037 import struct
00038 import time
00039 from create_driver import SerialCommandInterface, DriverError
00040 
00041 WHEELED_ROBIN_OPCODES = dict(
00042     start = 128,
00043     safe = 131,
00044     full = 132,
00045     drive = 137,
00046     leds = 139,
00047     sensors = 142,
00048     direct_drive = 145,
00049     digital_outputs = 147,
00050     stream = 148,
00051     query_list = 149,
00052     pause_resume_stream = 150,
00053     control_params = 255,
00054     )
00055 
00056 WHEELED_ROBIN_MODES = (
00057     'off',
00058     'passive',
00059     'safe',
00060     'full')
00061 
00062 SENSOR_GROUP_PACKET_LENGTHS = {
00063     0: 29,
00064     1: 17,
00065     7: 2,
00066     8: 2,
00067     9: 2,
00068     10: 2,
00069     11: 2,
00070     12: 2,
00071     13: 2,
00072     14: 2,
00073     15: 1,
00074     16: 2,
00075     17: 2,
00076     18: 2,
00077     19: 2,
00078     20: 2,
00079     21: 2,
00080     22: 1,
00081     }
00082 
00083 # drive constants.
00084 VELOCITY_X_MAX = 500 # mm/s
00085 VELOCITY_X_SLOW = int(VELOCITY_X_MAX * 0.33)
00086 VELOCITY_X_FAST = int(VELOCITY_X_MAX * 0.66)
00087 
00088 VELOCITY_G_MAX = 500 # mm/s
00089 VELOCITY_G_SLOW = int(VELOCITY_G_MAX * 0.33)
00090 VELOCITY_G_FAST = int(VELOCITY_G_MAX * 0.66)
00091 
00092 MAX_WHEEL_SPEED = 500
00093 WHEEL_SEPARATION = 260 # mm
00094 
00095 SERIAL_TIMEOUT = 2 # Number of seconds to wait for reads. 2 is generous.
00096 START_DELAY = 5 # Time it takes the wheeled_robin to boot.
00097 
00098 assert struct.calcsize('H') == 2, 'Expecting 2-byte shorts.'
00099 
00100 class WheeledRobin(object):
00101 
00102   """Represents a wheeled_robin robot."""
00103 
00104   def __init__(self):
00105     self.tty = None
00106     self.sci = None
00107     self.safe = True
00108 
00109   def start(self, tty='/dev/ttyUSB0'): 
00110     self.tty = tty
00111     self.sci = SerialCommandInterface(tty, 38400)# The real baudrate has do be defined with setserial (spd_cust and divisor)
00112     self.sci.add_opcodes(WHEELED_ROBIN_OPCODES)
00113 
00114   def passive(self):
00115     """Put the robot in passive mode."""
00116     self.sci.start()
00117     time.sleep(0.5)
00118 
00119   def control(self):
00120     """Start the robot's SCI interface and place it in safe mode."""
00121     self.passive()
00122     if not self.safe:
00123       self.sci.full()
00124     else:
00125       self.sci.safe()
00126 # self.sci.control() # Also puts the Roomba in to safe mode. #is deprecated
00127     time.sleep(0.5)
00128 
00129   def direct_drive(self, velocity_left, velocity_right):
00130     # Mask integers to 2 bytes.
00131     vl = int(velocity_left) & 0xffff
00132     vr = int(velocity_right) & 0xffff
00133     self.sci.direct_drive(*struct.unpack('4B', struct.pack('>2H', vr, vl)))
00134     
00135   def drive(self, velocity_x, velocity_g):
00136     """controls wheeled_robins's drive wheels.
00137 
00138     NOTE(Johannes Mayr): This commands differs slightly from the SCI and the OI
00139     as the second argument is not the radius. Instead the angular velocity around 
00140     z is used as second argument.
00141 
00142     The wheeled_robin takes four data bytes, interpreted as two 16-bit signed values
00143     using two's complement. The first two bytes specify the average linear velocity
00144     of the drive wheels in millimeters per second (mm/s), with the high byte
00145     being sent first. The next two bytes specify the average angular velocity  in millirad per second (mrad/s) at
00146     which wheeled_robin will turn. 
00147 
00148     Also see drive_straight and turn_in_place convenience methods.
00149     """
00150     # Mask integers to 2 bytes.
00151     velocity_x = int(velocity_x) & 0xffff
00152     velocity_g = int(velocity_g) & 0xffff
00153 
00154     # Pack as shorts to get 2 x 2 byte integers. Unpack as 4 bytes to send.
00155     # TODO(damonkohler): The 4 unpacked bytes will just be repacked later,
00156     # that seems dumb to me.
00157     bytes = struct.unpack('4B', struct.pack('>2H', velocity_x, velocity_g))
00158     self.sci.drive(*bytes)
00159 
00160   def stop(self):
00161     """Set velocities to 0 to stop movement."""
00162     self.drive(0, 0)
00163 
00164   def slow_stop(self, velocity):
00165     """Slowly reduce the velocities to 0 to stop movement."""
00166     velocities = xrange(velocity, VELOCITY_X_SLOW, -25)
00167     if velocity < 0:
00168       velocities = xrange(velocity, -VELOCITY_X_SLOW, 25)
00169     for v in velocities:
00170       self.drive(v, 0)
00171       time.sleep(0.05)
00172     self.stop()
00173 
00174   def drive_straight(self, velocity):
00175     """drive in a straight line."""
00176     self.drive(velocity, 0)
00177 
00178   def turn_in_place(self, velocity):
00179     """Turn in place either clockwise or counter-clockwise."""
00180     self.drive(0, velocity)  
00181     
00182   def set_digital_outputs(self, value):
00183     """Enable or disable digital outputs."""
00184     self.sci.digital_outputs(value)


wheeled_robin_driver
Author(s): Johannes Mayr , Klemens Springer
autogenerated on Fri Aug 28 2015 13:38:53