Package create_node :: Module roomba_sensor_handler
[frames] | no frames]

Source Code for Module create_node.roomba_sensor_handler

  1  # Software License Agreement (BSD License) 
  2  # 
  3  # Copyright (c) 2011, Willow Garage, Inc. 
  4  # All rights reserved. 
  5  # 
  6  # Redistribution and use in source and binary forms, with or without 
  7  # modification, are permitted provided that the following conditions 
  8  # are met: 
  9  # 
 10  #  * Redistributions of source code must retain the above copyright 
 11  #    notice, this list of conditions and the following disclaimer. 
 12  #  * Redistributions in binary form must reproduce the above 
 13  #    copyright notice, this list of conditions and the following 
 14  #    disclaimer in the documentation and/or other materials provided 
 15  #    with the distribution. 
 16  #  * Neither the name of the Willow Garage nor the names of its 
 17  #    contributors may be used to endorse or promote products derived 
 18  #    from this software without specific prior written permission. 
 19  # 
 20  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 21  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 22  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 23  # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 24  # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 25  # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 26  # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 27  # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 28  # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 29  # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
 30  # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 31  # POSSIBILITY OF SUCH DAMAGE. 
 32   
 33  import struct 
 34  import logging 
 35  import time 
 36  import math 
 37   
 38  import rospy 
 39  import create_driver 
 40   
 41  import std_msgs.msg as std_msgs 
 42   
 43  import robot_types 
 44   
45 -class RoombaSensorHandler(object):
46 47 ROOMBA_PULSES_TO_M = 0.000445558279992234 48
49 - def __init__(self, robot):
50 self._robot = robot 51 self._sensor_state_struct = struct.Struct(">12B2hBHhb7HBH5B4h2HB6H2B4hb") 52 self._last_encoder_counts = None
53
54 - def _request_packet(self, packet_id):
55 """Reqeust a sensor packet.""" 56 with self._robot.sci.lock: 57 self._robot.sci.flush_input() 58 self._robot.sci.sensors(packet_id) 59 #kwc: there appears to be a 10-20ms latency between sending the 60 #sensor request and fully reading the packet. Based on 61 #observation, we are preferring the 'before' stamp rather than 62 #after. 63 stamp = time.time() 64 length = create_driver.SENSOR_GROUP_PACKET_LENGTHS[packet_id] 65 return self._robot.sci.read(length), stamp
66
67 - def _deserialize(self, buffer, timestamp):
68 try: 69 (self.bumps_wheeldrops, 70 self.wall, 71 self.cliff_left, self.cliff_front_left, self.cliff_front_right, self.cliff_right, 72 self.virtual_wall, 73 self.motor_overcurrents, 74 self.dirt_detector_left, self.dirt_detector_right, 75 self.remote_opcode, self.buttons, 76 self.distance, self.angle, 77 self.charging_state, 78 self.voltage, self.current, self.temperature, self.charge, self.capacity, 79 self.wall_signal, self.cliff_left_signal, self.cliff_front_left_signal, 80 self.cliff_front_right_signal, self.cliff_right_signal, 81 self.user_digital_inputs, self.user_analog_input, 82 self.charging_sources_available, 83 self.oi_mode, 84 self.song_number, self.song_playing, 85 self.number_of_stream_packets, 86 self.requested_velocity, self.requested_radius, 87 self.requested_right_velocity, self.requested_left_velocity, 88 self.encoder_counts_left, self.encoder_counts_right, 89 self.light_bumper, 90 self.light_bump_left, self.light_bump_front_left, self.light_bump_center_left, 91 self.light_bump_center_right, self.light_bump_front_right, self.light_bump_right, 92 self.ir_opcode_left, self.ir_opcode_right, 93 self.left_motor_current, self.right_motor_current, 94 self.main_brish_current, self.side_brush_current, 95 self.statis, ) = self._sensor_state_struct.unpack(buffer[0:80]) 96 except struct.error, e: 97 raise roslib.message.DeserializationError(e) 98 99 self.wall = bool(self.wall) 100 self.cliff_left = bool(self.cliff_left) 101 self.cliff_front_left = bool(self.cliff_front_left) 102 self.cliff_front_right = bool(self.cliff_front_right) 103 self.cliff_right = bool(self.cliff_right) 104 self.virtual_wall = bool(self.virtual_wall) 105 self.song_playing = bool(self.song_playing) 106 107 # do unit conversions 108 self.header = std_msgs.Header(stamp=rospy.Time.from_seconds(timestamp)) 109 self.requested_velocity = float(self.requested_velocity) / 1000. 110 self.requested_radius = float(self.requested_radius) / 1000. 111 self.requested_right_velocity = float(self.requested_right_velocity) / 1000. 112 self.requested_left_velocity = float(self.requested_left_velocity) / 1000. 113 114 # The distance and angle calculation sent by the robot seems to 115 # be really bad. Re-calculate the values using the raw enconder 116 # counts. 117 if self._last_encoder_counts: 118 count_delta_left = self._normalize_encoder_count( 119 self.encoder_counts_left - self._last_encoder_counts[0], 0xffff) 120 count_delta_right = self._normalize_encoder_count( 121 self.encoder_counts_right - self._last_encoder_counts[1], 0xffff) 122 distance_left = count_delta_left * self.ROOMBA_PULSES_TO_M 123 distance_right = count_delta_right * self.ROOMBA_PULSES_TO_M 124 self.distance = (distance_left + distance_right) / 2.0 125 self.angle = (distance_right - distance_left) / robot_types.ROBOT_TYPES['roomba'].wheel_separation 126 else: 127 self.disance = 0 128 self.angle = 0 129 self._last_encoder_counts = (self.encoder_counts_left, self.encoder_counts_right)
130
131 - def _normalize_encoder_count(self, count_delta, maximal_count):
132 if count_delta >= maximal_count / 2: 133 return count_delta - maximal_count + 1 134 elif count_delta <= -maximal_count / 2: 135 return count_delta + maximal_count + 1 136 return count_delta
137
138 - def _encode_message(self, message):
139 message.header = self.header 140 message.bumps_wheeldrops = self.bumps_wheeldrops 141 message.wall = self.wall 142 message.cliff_left = self.cliff_left 143 message.cliff_front_left = self.cliff_front_left 144 message.cliff_front_right = self.cliff_front_right 145 message.cliff_right = self.cliff_right 146 message.virtual_wall = self.virtual_wall 147 message.motor_overcurrents = self.motor_overcurrents 148 message.dirt_detector_left = self.dirt_detector_left 149 message.dirt_detector_right = self.dirt_detector_right 150 message.remote_opcode = self.remote_opcode 151 message.buttons = self.buttons 152 message.distance = self.distance 153 message.angle = self.angle 154 message.charging_state = self.charging_state 155 message.voltage = self.voltage 156 message.current = self.current 157 message.temperature = self.temperature 158 message.charge = self.charge 159 message.capacity = self.capacity 160 message.wall_signal = self.wall_signal 161 message.cliff_left_signal = self.cliff_left_signal 162 message.cliff_front_left_signal = self.cliff_front_left_signal 163 message.cliff_front_right_signal = self.cliff_front_right_signal 164 message.cliff_right_signal, = self.cliff_right_signal, 165 message.user_digital_inputs = self.user_digital_inputs 166 message.user_analog_input, = self.user_analog_input, 167 message.charging_sources_available = self.charging_sources_available 168 message.oi_mode = self.oi_mode 169 message.song_number = self.song_number 170 message.song_playing = self.song_playing 171 message.number_of_stream_packets, = self.number_of_stream_packets, 172 message.requested_velocity = self.requested_velocity 173 message.requested_radius, = self.requested_radius, 174 message.requested_right_velocity = self.requested_right_velocity 175 message.requested_left_velocity = self.requested_left_velocity 176 return message
177
178 - def get_all(self, sensor_state):
179 buff, timestamp = self._request_packet(100) 180 if buff is not None: 181 self._deserialize(buff, timestamp) 182 self._encode_message(sensor_state)
183