In this post, we will present the code of Wheel Component.
One of the interesting problems when we try to control a wheel is the fact that the left wheel and right wheel are mirror symmetric. It means that we cannot use the same code to control the two wheels at the same time.
For example, let us assume that we have a Motor class and it has two methods: (1)spin_clockwisely and (2)spin_anti_clockwisely. If the Motor is used in the right wheel then spin_clockwisely function will make the robot move forward while the spin_anti_clockwisely function will make the robot move backward. It is easy to see if the Motor is used in the left wheel then the effect is opposite, meaning that the spin_clockwisely function will make the robot move backward and the spin_anti_clockwisely function will make the robot forward.
In our design, we do not want the Motor class to handle the mirror symmetry problem because the motor does not know if it is used in a wheel and our Component class is specifically designed to represent a physical device. Therefore, we will create a WheelComponent to control the motor used in a wheel.
class WheelComponent(Component): """ Represent a single wheel. """ def __init__(self, name=None, mirror=False, pin_signal=None, repeat=10, pulse=None, width=None): """ Args: name: the name of the component. mirror: Bool. The left wheel and right wheel is a mirro image of each other. Therefore, with the same configuration and the same operaton the effect is opposite. For example, let assume we are in a scenario where when we increase the pulse, the motor spins faster clockwisely. If this motor is used for right wheel, when the pulse is increased, the robot will be speed up; while if it is used for right wheel, the robot will be slowed down. This is a mirror effect. The mirror parameter is used to handle the mirror effet so we can have a unified interface to control both the left and right wheel. pin_signal: the pin number for sending the pulse to the motor. pulse: the pulse that is send to the motor. If the pulse is None,it will be set to the reference pulse of the underlying motor class, which make the motor still. The default value of pulse is None. repeat: the number pulse sent to the motor in a cycle. width: In the communication protocol, the signal consists of two parts: (1)pulse and (2)silence. The width specifies the length of the slient period. If the width is None, it will be set to the width value of the underlaying motor class. """ assert name is not None assert pin_signal is not None self._name = name self._pin_signal = pin_signal self._motor = WheelMotor(pin_signal=self._pin_signal) self._reference_pulse = self._motor.reference_pulse self._max_deviation = self._motor.max_pulse_deviation self._max_pulse = self._reference_pulse + self._max_deviation self._min_pulse = self._reference_pulse - self._max_deviation self._pulse = pulse if pulse is not None else self._reference_pulse self._width = width if width is not None else self._motor.width self._repeat = repeat self._mirror = mirror def run(self): self._motor.generate_pulse(repeat=self._repeat,pulse=self._pulse, width=0.020) def send_msg(self,Q): pass @property def pulse(self): return self._pulse @pulse.setter def pulse(self, val): self._pulse = min(val, self._width) @property def repeat(self): return self._repeat @repeat.setter def repeat(self,val): self._repeat = min(val, 50) def increase_speed(self, scale): scale = min(scale, 1.) scale = max(scale, -1.) increment = scale * self._max_deviation if self._mirror: increment = -1 * increment new_pulse = self.pulse + increment new_pulse = min(self._max_pulse, new_pulse) new_pulse = max(self._min_pulse, new_pulse) self._pulse = new_pulse def stop(self): self._pulse = self._reference_pulse
Note that in the __init__ function ,we have a parameter called mirror and it is used in the increase_speed method. This parameter indicates if we want to use the mirror effect of an operation. In case of increasing the speed of the rotation, it flips the sign of the incremental amount of pulse. In this way, we have a unified interface to control both the left and right wheel.
To use the component, we need to wrap it in a ContinuousComponentWrapper as we did before. Here is a sample code that shows how we can increase the speed of the wheel.
pin_signal_left = 13 pin_signal_right = 15 left_wheel_component = WheelComponent(name='left_wheel', mirror=False, pin_signal=pin_signal_left, repeat=20, pulse=None, width=None) right_wheel_component = WheelComponent(name='right_wheel', mirror=True, pin_signal=pin_signal_right, repeat=20, pulse=None, width=None) cmd_Q_left_wheel = mp.Queue() output_Q_left_wheel = mp.Queue() cmd_Q_right_wheel = mp.Queue() output_Q_right_wheel = mp.Queue() left_wheel = ContinuousComponentWrapper(component=left_wheel_component,cmd_Q=cmd_Q_left_wheel,output_Q=output_Q_left_wheel) right_wheel = ContinuousComponentWrapper(component=right_wheel_component,cmd_Q=cmd_Q_right_wheel,output_Q=output_Q_right_wheel) left_wheel.start() right_wheel.start() scale = 0. while True: print('scale: {}'.format(scale)) time.sleep(3) cmd_Q_left_wheel.put(('increase_speed',(0.1,), {})) cmd_Q_right_wheel.put(('increase_speed', (0.1,), {})) scale += 0.1
No comments:
Post a Comment