diff --git a/.gitignore b/.gitignore index 8958124..b3d0cd4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ *.pyc settings.json - +.DS_Store diff --git a/chapter10/robot.py b/chapter10/robot.py index 46c2812..6997694 100644 --- a/chapter10/robot.py +++ b/chapter10/robot.py @@ -56,12 +56,12 @@ def convert_speed(self, speed): def set_left(self, speed): mode, output_speed = self.convert_speed(speed) - self.left_motor.setSpeed(output_speed) + self.left_motor.setSpeed(int(output_speed)) self.left_motor.run(mode) def set_right(self, speed): mode, output_speed = self.convert_speed(speed) - self.right_motor.setSpeed(output_speed) + self.right_motor.setSpeed(int(output_speed)) self.right_motor.run(mode) def stop_motors(self): diff --git a/chapter10/servo_type_position.py b/chapter10/servo_type_position.py index a475272..43cac13 100644 --- a/chapter10/servo_type_position.py +++ b/chapter10/servo_type_position.py @@ -1,5 +1,6 @@ from Raspi_MotorHAT.Raspi_PWM_Servo_Driver import PWM import atexit +from builtins import input pwm = PWM(0x6f) # This sets the timebase for it all @@ -33,6 +34,6 @@ def stop(): import time while (True): - position = int(raw_input("Type your position in degrees (90 to -90, 0 is middle): ")) + position = int(input("Type your position in degrees (90 to -90, 0 is middle): ")) end_step = convert_degrees_to_pwm(position) pwm.setPWM(0, 0, end_step) diff --git a/chapter11/avoid_behavior.py b/chapter11/avoid_behavior.py index c286f45..d742441 100644 --- a/chapter11/avoid_behavior.py +++ b/chapter11/avoid_behavior.py @@ -1,3 +1,4 @@ +from __future__ import print_function from robot import Robot, NoDistanceRead from time import sleep diff --git a/chapter11/robot.py b/chapter11/robot.py index bfc4bc3..8234f70 100644 --- a/chapter11/robot.py +++ b/chapter11/robot.py @@ -65,14 +65,14 @@ def set_left(self, speed): if not self.drive_enabled: return mode, output_speed = self.convert_speed(speed) - self.left_motor.setSpeed(output_speed) + self.left_motor.setSpeed(int(output_speed)) self.left_motor.run(mode) def set_right(self, speed): if not self.drive_enabled: return mode, output_speed = self.convert_speed(speed) - self.right_motor.setSpeed(output_speed) + self.right_motor.setSpeed(int(output_speed)) self.right_motor.run(mode) def stop_motors(self): diff --git a/chapter11/simple_avoid_behavior.py b/chapter11/simple_avoid_behavior.py index cd6e188..2ecc247 100644 --- a/chapter11/simple_avoid_behavior.py +++ b/chapter11/simple_avoid_behavior.py @@ -1,3 +1,4 @@ +from __future__ import print_function from robot import Robot, NoDistanceRead from time import sleep diff --git a/chapter11/test_hcsr04.py b/chapter11/test_hcsr04.py index 3c566d8..36b2727 100644 --- a/chapter11/test_hcsr04.py +++ b/chapter11/test_hcsr04.py @@ -1,8 +1,9 @@ +from __future__ import print_function import time from gpiozero import DigitalInputDevice, DigitalOutputDevice # Setup devices, an input device and an output device, with pin numbers for the sensors. -print "Prepare GPIO pins" +print("Prepare GPIO pins") # Left sensor left_trigger = DigitalOutputDevice(17) @@ -17,7 +18,7 @@ right_trigger.value = False # wait a little, to iron out spurious responses. -print "Warm up time" +print("Warm up time") time.sleep(0.5) def make_measurement(trig_device, echo_device): @@ -37,7 +38,7 @@ def make_measurement(trig_device, echo_device): pulse_start = time.time() # We ran out of time here. if pulse_start > time_out: - print "timed out - missed pulse start" + print("timed out - missed pulse start") return 100 # Now we wait for the echo_device pin to stop being 1, going from high, to low, the end of the pulse. @@ -45,7 +46,7 @@ def make_measurement(trig_device, echo_device): while echo_device.pin.state == 1: pulse_end = time.time() if pulse_end > time_out: - print "timed out - pulse end too long" + print("timed out - pulse end too long") return 100 # The duration is the time between the start and end of pulse in seconds. @@ -61,6 +62,6 @@ def make_measurement(trig_device, echo_device): # Make our measurements and print them left_distance = make_measurement(left_trigger, left_echo) right_distance = make_measurement(right_trigger, right_echo) - print "Left: ", left_distance, "cm", "Right:", right_distance + print("Left: ", left_distance, "cm", "Right:", right_distance) # Sleep a bit before making another. time.sleep(0.5) diff --git a/chapter12/drive_distance_behavior.py b/chapter12/drive_distance_behavior.py index 1c018ee..a57537b 100644 --- a/chapter12/drive_distance_behavior.py +++ b/chapter12/drive_distance_behavior.py @@ -1,3 +1,4 @@ +from __future__ import print_function from robot import Robot, EncoderCounter from pid_controller import PIController import time diff --git a/chapter12/drive_square_behavior.py b/chapter12/drive_square_behavior.py index 22321c8..77bc15f 100644 --- a/chapter12/drive_square_behavior.py +++ b/chapter12/drive_square_behavior.py @@ -1,3 +1,4 @@ +from __future__ import print_function from robot import Robot, EncoderCounter from pid_controller import PIController import time @@ -52,7 +53,7 @@ def drive_distances(bot, left_distance, right_distance, speed=80): set_secondary(secondary_speed + adjustment) secondary_encoder.set_direction(math.copysign(1, secondary_speed+adjustment)) # Some debug - print "Primary c:{:.2f} ({:.2f} mm)\tSecondary c:{:.2f} ({:.2f} mm) t:{:.2f} e:{:.2f} s:{:.2f} adjustment: {:.2f}".format( + print("Primary c:{:.2f} ({:.2f} mm)\tSecondary c:{:.2f} ({:.2f} mm) t:{:.2f} e:{:.2f} s:{:.2f} adjustment: {:.2f}".format( primary_encoder.pulse_count, primary_encoder.distance_in_mm(), secondary_encoder.pulse_count, @@ -61,11 +62,11 @@ def drive_distances(bot, left_distance, right_distance, speed=80): error, secondary_speed, adjustment - ) + )) # Stop the primary if we need to if abs(primary_encoder.pulse_count) >= abs(primary_distance): - print "primary stop" + print("primary stop") set_primary(0) secondary_speed = 0 @@ -79,11 +80,11 @@ def drive_arc(bot, turn_in_degrees, radius, speed=80): else: left_radius = radius + half_width_ticks right_radius = radius - half_width_ticks - print "Arc left radius {:.2f}, right_radius {:.2f}".format(left_radius, right_radius) + print("Arc left radius {:.2f}, right_radius {:.2f}".format(left_radius, right_radius)) radians = math.radians(abs(turn_in_degrees)) left_distance = int(left_radius * radians) right_distance = int(right_radius * radians) - print "Arc left distance {}, right_distance {}".format(left_distance, right_distance) + print("Arc left distance {}, right_distance {}".format(left_distance, right_distance)) drive_distances(bot, left_distance, right_distance, speed=speed) bot = Robot() diff --git a/chapter12/robot.py b/chapter12/robot.py index b8b7b38..e5b9596 100644 --- a/chapter12/robot.py +++ b/chapter12/robot.py @@ -75,14 +75,14 @@ def set_left(self, speed): if not self.drive_enabled: return mode, output_speed = self.convert_speed(speed) - self.left_motor.setSpeed(output_speed) + self.left_motor.setSpeed(int(output_speed)) self.left_motor.run(mode) def set_right(self, speed): if not self.drive_enabled: return mode, output_speed = self.convert_speed(speed) - self.right_motor.setSpeed(output_speed) + self.right_motor.setSpeed(int(output_speed)) self.right_motor.run(mode) def stop_motors(self): diff --git a/chapter12/straight_line_drive.py b/chapter12/straight_line_drive.py index 6dc5398..15d2b06 100644 --- a/chapter12/straight_line_drive.py +++ b/chapter12/straight_line_drive.py @@ -1,9 +1,10 @@ +from __future__ import print_function from robot import Robot from pid_controller import PIController import time bot = Robot() -stop_at_time = time.time() + 60 +stop_at_time = time.time() + 5 speed = 80 bot.set_left(speed) @@ -19,10 +20,10 @@ # Get the speed adjustment = pid.get_value(error) right_speed = int(speed + adjustment) - print "left", left, \ - "right", right, \ - "right_speed:", right_speed, \ - "error:", error, \ - "adjustment: %.2f" % adjustment + print("left", left, + "right", right, + "right_speed:", right_speed, + "error:", error, + "adjustment: %.2f" % adjustment) # Appy it to the right motor bot.set_right(right_speed) diff --git a/chapter12/test_distance_travelled.py b/chapter12/test_distance_travelled.py index c8134ba..f0a5413 100644 --- a/chapter12/test_distance_travelled.py +++ b/chapter12/test_distance_travelled.py @@ -1,3 +1,4 @@ +from __future__ import print_function from robot import Robot import time import math @@ -16,6 +17,6 @@ def ticks_to_mm(ticks): bot.set_right(90) while time.time() < stop_at_time: - print "Left:", ticks_to_mm(bot.left_encoder.pulse_count), \ - "Right:", ticks_to_mm(bot.right_encoder.pulse_count) + print("Left:", ticks_to_mm(bot.left_encoder.pulse_count), \ + "Right:", ticks_to_mm(bot.right_encoder.pulse_count)) time.sleep(0.05) diff --git a/chapter12/test_encoders.py b/chapter12/test_encoders.py index a9289fc..c3c5ed5 100644 --- a/chapter12/test_encoders.py +++ b/chapter12/test_encoders.py @@ -23,5 +23,5 @@ def when_changed(self): bot.set_right(90) while time.time() < stop_at_time: - print "Left:", left_encoder.pulse_count, "Right:", right_encoder.pulse_count + print("Left:", left_encoder.pulse_count, "Right:", right_encoder.pulse_count) time.sleep(0.05) diff --git a/chapter15/0_starting_point/drive_square_behavior.py b/chapter15/0_starting_point/drive_square_behavior.py index 901c1c3..550f04f 100644 --- a/chapter15/0_starting_point/drive_square_behavior.py +++ b/chapter15/0_starting_point/drive_square_behavior.py @@ -1,98 +1,98 @@ -from robot import Robot, EncoderCounter -from pid_controller import PIController -import time -import math - - -def drive_distances(bot, left_distance, right_distance, speed=80): - # We always want the "primary" to be the longest distance, therefore the faster motor - if abs(left_distance) >= abs(right_distance): - print("Left is primary") - set_primary = bot.set_left - primary_encoder = bot.left_encoder - set_secondary = bot.set_right - secondary_encoder = bot.right_encoder - primary_distance = left_distance - secondary_distance = right_distance - else: - print("right is primary") - set_primary = bot.set_right - primary_encoder = bot.right_encoder - set_secondary = bot.set_left - secondary_encoder = bot.left_encoder - primary_distance = right_distance - secondary_distance = left_distance - primary_to_secondary_ratio = secondary_distance / (primary_distance * 1.0) - secondary_speed = speed * primary_to_secondary_ratio - print("Targets - primary: %d, secondary: %d, ratio: %.2f" % (primary_distance, secondary_distance, primary_to_secondary_ratio)) - - primary_encoder.reset() - secondary_encoder.reset() - - controller = PIController(proportional_constant=5, integral_constant=0.2) - - # Ensure that the encoder knows which way it is going - primary_encoder.set_direction(math.copysign(1, speed)) - secondary_encoder.set_direction(math.copysign(1, secondary_speed)) - - # start the motors, and start the loop - set_primary(speed) - set_secondary(secondary_speed) - while abs(primary_encoder.pulse_count) < abs(primary_distance) or abs(secondary_encoder.pulse_count) < abs(secondary_distance): - # And sleep a bit before calculating - time.sleep(0.05) - - # How far off are we? - secondary_target = primary_encoder.pulse_count * primary_to_secondary_ratio - error = secondary_target - secondary_encoder.pulse_count - - # How fast should the motor move to get there? - adjustment = controller.get_value(error) - - set_secondary(secondary_speed + adjustment) - secondary_encoder.set_direction(math.copysign(1, secondary_speed+adjustment)) - # Some debug - print "Primary c:{:.2f} ({:.2f} mm)\tSecondary c:{:.2f} ({:.2f} mm) t:{:.2f} e:{:.2f} s:{:.2f} adjustment: {:.2f}".format( - primary_encoder.pulse_count, - primary_encoder.distance_in_mm(), - secondary_encoder.pulse_count, - secondary_encoder.distance_in_mm(), - secondary_target, - error, - secondary_speed, - adjustment - ) - - # Stop the primary if we need to - if abs(primary_encoder.pulse_count) >= abs(primary_distance): - print "primary stop" - set_primary(0) - secondary_speed = 0 - -def drive_arc(bot, turn_in_degrees, radius, speed=80): - """ Turn is based on change in heading. """ - # Get the bot width in ticks - half_width_ticks = EncoderCounter.mm_to_ticks(bot.wheel_distance_mm/2.0) - if turn_in_degrees < 0: - left_radius = radius - half_width_ticks - right_radius = radius + half_width_ticks - else: - left_radius = radius + half_width_ticks - right_radius = radius - half_width_ticks - print "Arc left radius {:.2f}, right_radius {:.2f}".format(left_radius, right_radius) - radians = math.radians(abs(turn_in_degrees)) - left_distance = int(left_radius * radians) - right_distance = int(right_radius * radians) - print "Arc left distance {}, right_distance {}".format(left_distance, right_distance) - drive_distances(bot, left_distance, right_distance, speed=speed) - -bot = Robot() - -distance_to_drive = 300 # in mm -distance_in_ticks = EncoderCounter.mm_to_ticks(distance_to_drive) -radius = bot.wheel_distance_mm + 100 # in mm -radius_in_ticks = EncoderCounter.mm_to_ticks(radius) - -for n in range(4): - drive_distances(bot, distance_in_ticks, distance_in_ticks) - drive_arc(bot, 90, radius_in_ticks, speed=50) +from robot import Robot, EncoderCounter +from pid_controller import PIController +import time +import math + + +def drive_distances(bot, left_distance, right_distance, speed=80): + # We always want the "primary" to be the longest distance, therefore the faster motor + if abs(left_distance) >= abs(right_distance): + print("Left is primary") + set_primary = bot.set_left + primary_encoder = bot.left_encoder + set_secondary = bot.set_right + secondary_encoder = bot.right_encoder + primary_distance = left_distance + secondary_distance = right_distance + else: + print("right is primary") + set_primary = bot.set_right + primary_encoder = bot.right_encoder + set_secondary = bot.set_left + secondary_encoder = bot.left_encoder + primary_distance = right_distance + secondary_distance = left_distance + primary_to_secondary_ratio = secondary_distance / (primary_distance * 1.0) + secondary_speed = speed * primary_to_secondary_ratio + print("Targets - primary: %d, secondary: %d, ratio: %.2f" % (primary_distance, secondary_distance, primary_to_secondary_ratio)) + + primary_encoder.reset() + secondary_encoder.reset() + + controller = PIController(proportional_constant=5, integral_constant=0.2) + + # Ensure that the encoder knows which way it is going + primary_encoder.set_direction(math.copysign(1, speed)) + secondary_encoder.set_direction(math.copysign(1, secondary_speed)) + + # start the motors, and start the loop + set_primary(speed) + set_secondary(secondary_speed) + while abs(primary_encoder.pulse_count) < abs(primary_distance) or abs(secondary_encoder.pulse_count) < abs(secondary_distance): + # And sleep a bit before calculating + time.sleep(0.05) + + # How far off are we? + secondary_target = primary_encoder.pulse_count * primary_to_secondary_ratio + error = secondary_target - secondary_encoder.pulse_count + + # How fast should the motor move to get there? + adjustment = controller.get_value(error) + + set_secondary(secondary_speed + adjustment) + secondary_encoder.set_direction(math.copysign(1, secondary_speed+adjustment)) + # Some debug + print("Primary c:{:.2f} ({:.2f} mm)\tSecondary c:{:.2f} ({:.2f} mm) t:{:.2f} e:{:.2f} s:{:.2f} adjustment: {:.2f}".format( + primary_encoder.pulse_count, + primary_encoder.distance_in_mm(), + secondary_encoder.pulse_count, + secondary_encoder.distance_in_mm(), + secondary_target, + error, + secondary_speed, + adjustment + )) + + # Stop the primary if we need to + if abs(primary_encoder.pulse_count) >= abs(primary_distance): + print("primary stop") + set_primary(0) + secondary_speed = 0 + +def drive_arc(bot, turn_in_degrees, radius, speed=80): + """ Turn is based on change in heading. """ + # Get the bot width in ticks + half_width_ticks = EncoderCounter.mm_to_ticks(bot.wheel_distance_mm/2.0) + if turn_in_degrees < 0: + left_radius = radius - half_width_ticks + right_radius = radius + half_width_ticks + else: + left_radius = radius + half_width_ticks + right_radius = radius - half_width_ticks + print("Arc left radius {:.2f}, right_radius {:.2f}".format(left_radius, right_radius)) + radians = math.radians(abs(turn_in_degrees)) + left_distance = int(left_radius * radians) + right_distance = int(right_radius * radians) + print("Arc left distance {}, right_distance {}".format(left_distance, right_distance)) + drive_distances(bot, left_distance, right_distance, speed=speed) + +bot = Robot() + +distance_to_drive = 300 # in mm +distance_in_ticks = EncoderCounter.mm_to_ticks(distance_to_drive) +radius = bot.wheel_distance_mm + 100 # in mm +radius_in_ticks = EncoderCounter.mm_to_ticks(radius) + +for n in range(4): + drive_distances(bot, distance_in_ticks, distance_in_ticks) + drive_arc(bot, 90, radius_in_ticks, speed=50) diff --git a/chapter15/0_starting_point/following_rainbows.py b/chapter15/0_starting_point/following_rainbows.py index d977416..77a6916 100644 --- a/chapter15/0_starting_point/following_rainbows.py +++ b/chapter15/0_starting_point/following_rainbows.py @@ -1,86 +1,86 @@ -from robot import Robot -import colorsys -from time import sleep - -class FollowingRainbows: - # Note - this is the robot ON the line. - def __init__(self, the_robot, forward_speed=40, cornering=0): - self.robot = the_robot - self.forward_speed = forward_speed - self.cornering = cornering - self.left_index = 0 - self.left_brightness = 0 - self.right_index = 0 - self.right_brightness = 0 - self.main_index = 0 - - led_qtr = int(self.robot.leds.count/4) - self.right_indicator = range(0, led_qtr) - self.left_indicator = range(self.robot.leds.count - led_qtr, self.robot.leds.count) - - - def when_left_crosses_line(self): - self.robot.set_left(self.cornering) - self.left_brightness = 1.0 - - def when_right_crosses_line(self): - self.robot.set_right(self.cornering) - self.right_brightness = 1.0 - - def when_left_off_line(self): - self.robot.set_left(self.forward_speed) - - def when_right_off_line(self): - self.robot.set_right(self.forward_speed) - - def hsv_to_rgb(self, h, s, v): - return [int(component*255) for component in colorsys.hsv_to_rgb(h, s, v)] - - def make_display(self): - # main rainbow - half_leds = int(self.robot.leds.count/2) - qtr_leds = int(self.robot.leds.count/4) - for n in range(0, half_leds): - offset = (240/half_leds) * n - ih = (self.main_index + offset) % 360 - ch = self.hsv_to_rgb(ih / 360.0, 1.0, 0.6) - rgb = [int(c*255) for c in ch] - self.robot.leds.set_one(qtr_leds + n, rgb) - self.main_index += 5 - # LEft and right - for n in range(0, qtr_leds): - offset = (60/7.0) * n - lh = (self.left_index + offset) % 360 - ch = self.hsv_to_rgb(lh / 360.0, 1.0, self.left_brightness) - rgb = [int(c*255) for c in ch] - self.robot.leds.set_one(n, rgb) - rh = (self.right_index + offset) % 360 - ch = self.hsv_to_rgb(rh / 360.0, 1.0, self.right_brightness) - rgb = [int(c*255) for c in ch] - self.robot.leds.set_one(self.robot.leds.count-1-n, rgb) - self.left_index += 5 - self.right_index -= 5 - if self.left_brightness >= 0.1: - self.left_brightness -= 0.1 - if self.right_brightness >= 0.1: - self.right_brightness -= 0.1 - self.robot.leds.show() - - def run(self): - # Setup conditions - self.robot.left_line_sensor.when_line = self.when_left_crosses_line - self.robot.left_line_sensor.when_no_line = self.when_left_off_line - self.robot.right_line_sensor.when_line = self.when_right_crosses_line - self.robot.right_line_sensor.when_no_line = self.when_right_off_line - # Start driving - self.robot.set_left(self.forward_speed) - self.robot.set_right(self.forward_speed) - while True: - sleep(0.01) - self.make_display() - - -bot = Robot() -behavior = FollowingRainbows(bot) -behavior.run() - +from robot import Robot +import colorsys +from time import sleep + +class FollowingRainbows: + # Note - this is the robot ON the line. + def __init__(self, the_robot, forward_speed=40, cornering=0): + self.robot = the_robot + self.forward_speed = forward_speed + self.cornering = cornering + self.left_index = 0 + self.left_brightness = 0 + self.right_index = 0 + self.right_brightness = 0 + self.main_index = 0 + + led_qtr = int(self.robot.leds.count/4) + self.right_indicator = list(range(0, led_qtr)) + self.left_indicator = list(range(self.robot.leds.count - led_qtr, self.robot.leds.count)) + + + def when_left_crosses_line(self): + self.robot.set_left(self.cornering) + self.left_brightness = 1.0 + + def when_right_crosses_line(self): + self.robot.set_right(self.cornering) + self.right_brightness = 1.0 + + def when_left_off_line(self): + self.robot.set_left(self.forward_speed) + + def when_right_off_line(self): + self.robot.set_right(self.forward_speed) + + def hsv_to_rgb(self, h, s, v): + return [int(component*255) for component in colorsys.hsv_to_rgb(h, s, v)] + + def make_display(self): + # main rainbow + half_leds = int(self.robot.leds.count/2) + qtr_leds = int(self.robot.leds.count/4) + for n in range(0, half_leds): + offset = (240/half_leds) * n + ih = (self.main_index + offset) % 360 + ch = self.hsv_to_rgb(ih / 360.0, 1.0, 0.6) + rgb = [int(c*255) for c in ch] + self.robot.leds.set_one(qtr_leds + n, rgb) + self.main_index += 5 + # LEft and right + for n in range(0, qtr_leds): + offset = (60/7.0) * n + lh = (self.left_index + offset) % 360 + ch = self.hsv_to_rgb(lh / 360.0, 1.0, self.left_brightness) + rgb = [int(c*255) for c in ch] + self.robot.leds.set_one(n, rgb) + rh = (self.right_index + offset) % 360 + ch = self.hsv_to_rgb(rh / 360.0, 1.0, self.right_brightness) + rgb = [int(c*255) for c in ch] + self.robot.leds.set_one(self.robot.leds.count-1-n, rgb) + self.left_index += 5 + self.right_index -= 5 + if self.left_brightness >= 0.1: + self.left_brightness -= 0.1 + if self.right_brightness >= 0.1: + self.right_brightness -= 0.1 + self.robot.leds.show() + + def run(self): + # Setup conditions + self.robot.left_line_sensor.when_line = self.when_left_crosses_line + self.robot.left_line_sensor.when_no_line = self.when_left_off_line + self.robot.right_line_sensor.when_line = self.when_right_crosses_line + self.robot.right_line_sensor.when_no_line = self.when_right_off_line + # Start driving + self.robot.set_left(self.forward_speed) + self.robot.set_right(self.forward_speed) + while True: + sleep(0.01) + self.make_display() + + +bot = Robot() +behavior = FollowingRainbows(bot) +behavior.run() + diff --git a/chapter15/0_starting_point/line_following_behavior.py b/chapter15/0_starting_point/line_following_behavior.py index 2d3f675..6dc1905 100644 --- a/chapter15/0_starting_point/line_following_behavior.py +++ b/chapter15/0_starting_point/line_following_behavior.py @@ -1,56 +1,56 @@ -from robot import Robot -from time import sleep - -cross_line_color = (255, 0, 0) -off_line_color = (0, 0, 255) - -class LineFollowingBehavior: - # Note - this is the robot ON the line. - def __init__(self, the_robot, forward_speed=30, cornering=-30): - self.robot = the_robot - self.forward_speed = forward_speed - self.cornering = cornering - - led_qtr = int(self.robot.leds.count/4) - self.right_indicator = range(0, led_qtr) - self.left_indicator = range(self.robot.leds.count - led_qtr, self.robot.leds.count) - - self.robot.leds.show() - - def when_left_crosses_line(self): - self.robot.set_left(self.cornering) - self.robot.leds.set_range(self.left_indicator, cross_line_color) - self.robot.leds.show() - - def when_right_crosses_line(self): - self.robot.set_right(self.cornering) - self.robot.leds.set_range(self.right_indicator, cross_line_color) - self.robot.leds.show() - - def when_left_off_line(self): - self.robot.set_left(self.forward_speed) - self.robot.leds.set_range(self.left_indicator, off_line_color) - self.robot.leds.show() - - def when_right_off_line(self): - self.robot.set_right(self.forward_speed) - self.robot.leds.set_range(self.right_indicator, off_line_color) - self.robot.leds.show() - - def run(self): - # Setup conditions - self.robot.left_line_sensor.when_line = self.when_left_crosses_line - self.robot.left_line_sensor.when_no_line = self.when_left_off_line - self.robot.right_line_sensor.when_line = self.when_right_crosses_line - self.robot.right_line_sensor.when_no_line = self.when_right_off_line - # Start driving - self.robot.set_left(self.forward_speed) - self.robot.set_right(self.forward_speed) - while True: - sleep(0.02) - - -bot = Robot() -behavior = LineFollowingBehavior(bot) -behavior.run() - +from robot import Robot +from time import sleep + +cross_line_color = (255, 0, 0) +off_line_color = (0, 0, 255) + +class LineFollowingBehavior: + # Note - this is the robot ON the line. + def __init__(self, the_robot, forward_speed=30, cornering=-30): + self.robot = the_robot + self.forward_speed = forward_speed + self.cornering = cornering + + led_qtr = int(self.robot.leds.count/4) + self.right_indicator = list(range(0, led_qtr)) + self.left_indicator = list(range(self.robot.leds.count - led_qtr, self.robot.leds.count)) + + self.robot.leds.show() + + def when_left_crosses_line(self): + self.robot.set_left(self.cornering) + self.robot.leds.set_range(self.left_indicator, cross_line_color) + self.robot.leds.show() + + def when_right_crosses_line(self): + self.robot.set_right(self.cornering) + self.robot.leds.set_range(self.right_indicator, cross_line_color) + self.robot.leds.show() + + def when_left_off_line(self): + self.robot.set_left(self.forward_speed) + self.robot.leds.set_range(self.left_indicator, off_line_color) + self.robot.leds.show() + + def when_right_off_line(self): + self.robot.set_right(self.forward_speed) + self.robot.leds.set_range(self.right_indicator, off_line_color) + self.robot.leds.show() + + def run(self): + # Setup conditions + self.robot.left_line_sensor.when_line = self.when_left_crosses_line + self.robot.left_line_sensor.when_no_line = self.when_left_off_line + self.robot.right_line_sensor.when_line = self.when_right_crosses_line + self.robot.right_line_sensor.when_no_line = self.when_right_off_line + # Start driving + self.robot.set_left(self.forward_speed) + self.robot.set_right(self.forward_speed) + while True: + sleep(0.02) + + +bot = Robot() +behavior = LineFollowingBehavior(bot) +behavior.run() + diff --git a/chapter15/0_starting_point/straight_line_drive.py b/chapter15/0_starting_point/straight_line_drive.py index f1f1d30..bbb3bba 100644 --- a/chapter15/0_starting_point/straight_line_drive.py +++ b/chapter15/0_starting_point/straight_line_drive.py @@ -1,28 +1,28 @@ -from robot import Robot -from pid_controller import PIController -import time - -bot = Robot() -stop_at_time = time.time() + 60 - -speed = 80 -bot.set_left(speed) -bot.set_right(speed) - -pid = PIController(proportional_constant=4, integral_constant=0.2) -while time.time() < stop_at_time: - time.sleep(0.02) - # Calculate the error - left = bot.left_encoder.pulse_count - right = bot.right_encoder.pulse_count - error = left - right - # Get the speed - adjustment = pid.get_value(error) - right_speed = int(speed + adjustment) - print "left", left, \ - "right", right, \ - "right_speed:", right_speed, \ - "error:", error, \ - "adjustment: %.2f" % adjustment - # Appy it to the right motor - bot.set_right(right_speed) +from robot import Robot +from pid_controller import PIController +import time + +bot = Robot() +stop_at_time = time.time() + 60 + +speed = 80 +bot.set_left(speed) +bot.set_right(speed) + +pid = PIController(proportional_constant=4, integral_constant=0.2) +while time.time() < stop_at_time: + time.sleep(0.02) + # Calculate the error + left = bot.left_encoder.pulse_count + right = bot.right_encoder.pulse_count + error = left - right + # Get the speed + adjustment = pid.get_value(error) + right_speed = int(speed + adjustment) + print("left", left, \ + "right", right, \ + "right_speed:", right_speed, \ + "error:", error, \ + "adjustment: %.2f" % adjustment) + # Appy it to the right motor + bot.set_right(right_speed) diff --git a/chapter15/full_system/drive_square_behavior.py b/chapter15/full_system/drive_square_behavior.py index 901c1c3..550f04f 100644 --- a/chapter15/full_system/drive_square_behavior.py +++ b/chapter15/full_system/drive_square_behavior.py @@ -1,98 +1,98 @@ -from robot import Robot, EncoderCounter -from pid_controller import PIController -import time -import math - - -def drive_distances(bot, left_distance, right_distance, speed=80): - # We always want the "primary" to be the longest distance, therefore the faster motor - if abs(left_distance) >= abs(right_distance): - print("Left is primary") - set_primary = bot.set_left - primary_encoder = bot.left_encoder - set_secondary = bot.set_right - secondary_encoder = bot.right_encoder - primary_distance = left_distance - secondary_distance = right_distance - else: - print("right is primary") - set_primary = bot.set_right - primary_encoder = bot.right_encoder - set_secondary = bot.set_left - secondary_encoder = bot.left_encoder - primary_distance = right_distance - secondary_distance = left_distance - primary_to_secondary_ratio = secondary_distance / (primary_distance * 1.0) - secondary_speed = speed * primary_to_secondary_ratio - print("Targets - primary: %d, secondary: %d, ratio: %.2f" % (primary_distance, secondary_distance, primary_to_secondary_ratio)) - - primary_encoder.reset() - secondary_encoder.reset() - - controller = PIController(proportional_constant=5, integral_constant=0.2) - - # Ensure that the encoder knows which way it is going - primary_encoder.set_direction(math.copysign(1, speed)) - secondary_encoder.set_direction(math.copysign(1, secondary_speed)) - - # start the motors, and start the loop - set_primary(speed) - set_secondary(secondary_speed) - while abs(primary_encoder.pulse_count) < abs(primary_distance) or abs(secondary_encoder.pulse_count) < abs(secondary_distance): - # And sleep a bit before calculating - time.sleep(0.05) - - # How far off are we? - secondary_target = primary_encoder.pulse_count * primary_to_secondary_ratio - error = secondary_target - secondary_encoder.pulse_count - - # How fast should the motor move to get there? - adjustment = controller.get_value(error) - - set_secondary(secondary_speed + adjustment) - secondary_encoder.set_direction(math.copysign(1, secondary_speed+adjustment)) - # Some debug - print "Primary c:{:.2f} ({:.2f} mm)\tSecondary c:{:.2f} ({:.2f} mm) t:{:.2f} e:{:.2f} s:{:.2f} adjustment: {:.2f}".format( - primary_encoder.pulse_count, - primary_encoder.distance_in_mm(), - secondary_encoder.pulse_count, - secondary_encoder.distance_in_mm(), - secondary_target, - error, - secondary_speed, - adjustment - ) - - # Stop the primary if we need to - if abs(primary_encoder.pulse_count) >= abs(primary_distance): - print "primary stop" - set_primary(0) - secondary_speed = 0 - -def drive_arc(bot, turn_in_degrees, radius, speed=80): - """ Turn is based on change in heading. """ - # Get the bot width in ticks - half_width_ticks = EncoderCounter.mm_to_ticks(bot.wheel_distance_mm/2.0) - if turn_in_degrees < 0: - left_radius = radius - half_width_ticks - right_radius = radius + half_width_ticks - else: - left_radius = radius + half_width_ticks - right_radius = radius - half_width_ticks - print "Arc left radius {:.2f}, right_radius {:.2f}".format(left_radius, right_radius) - radians = math.radians(abs(turn_in_degrees)) - left_distance = int(left_radius * radians) - right_distance = int(right_radius * radians) - print "Arc left distance {}, right_distance {}".format(left_distance, right_distance) - drive_distances(bot, left_distance, right_distance, speed=speed) - -bot = Robot() - -distance_to_drive = 300 # in mm -distance_in_ticks = EncoderCounter.mm_to_ticks(distance_to_drive) -radius = bot.wheel_distance_mm + 100 # in mm -radius_in_ticks = EncoderCounter.mm_to_ticks(radius) - -for n in range(4): - drive_distances(bot, distance_in_ticks, distance_in_ticks) - drive_arc(bot, 90, radius_in_ticks, speed=50) +from robot import Robot, EncoderCounter +from pid_controller import PIController +import time +import math + + +def drive_distances(bot, left_distance, right_distance, speed=80): + # We always want the "primary" to be the longest distance, therefore the faster motor + if abs(left_distance) >= abs(right_distance): + print("Left is primary") + set_primary = bot.set_left + primary_encoder = bot.left_encoder + set_secondary = bot.set_right + secondary_encoder = bot.right_encoder + primary_distance = left_distance + secondary_distance = right_distance + else: + print("right is primary") + set_primary = bot.set_right + primary_encoder = bot.right_encoder + set_secondary = bot.set_left + secondary_encoder = bot.left_encoder + primary_distance = right_distance + secondary_distance = left_distance + primary_to_secondary_ratio = secondary_distance / (primary_distance * 1.0) + secondary_speed = speed * primary_to_secondary_ratio + print("Targets - primary: %d, secondary: %d, ratio: %.2f" % (primary_distance, secondary_distance, primary_to_secondary_ratio)) + + primary_encoder.reset() + secondary_encoder.reset() + + controller = PIController(proportional_constant=5, integral_constant=0.2) + + # Ensure that the encoder knows which way it is going + primary_encoder.set_direction(math.copysign(1, speed)) + secondary_encoder.set_direction(math.copysign(1, secondary_speed)) + + # start the motors, and start the loop + set_primary(speed) + set_secondary(secondary_speed) + while abs(primary_encoder.pulse_count) < abs(primary_distance) or abs(secondary_encoder.pulse_count) < abs(secondary_distance): + # And sleep a bit before calculating + time.sleep(0.05) + + # How far off are we? + secondary_target = primary_encoder.pulse_count * primary_to_secondary_ratio + error = secondary_target - secondary_encoder.pulse_count + + # How fast should the motor move to get there? + adjustment = controller.get_value(error) + + set_secondary(secondary_speed + adjustment) + secondary_encoder.set_direction(math.copysign(1, secondary_speed+adjustment)) + # Some debug + print("Primary c:{:.2f} ({:.2f} mm)\tSecondary c:{:.2f} ({:.2f} mm) t:{:.2f} e:{:.2f} s:{:.2f} adjustment: {:.2f}".format( + primary_encoder.pulse_count, + primary_encoder.distance_in_mm(), + secondary_encoder.pulse_count, + secondary_encoder.distance_in_mm(), + secondary_target, + error, + secondary_speed, + adjustment + )) + + # Stop the primary if we need to + if abs(primary_encoder.pulse_count) >= abs(primary_distance): + print("primary stop") + set_primary(0) + secondary_speed = 0 + +def drive_arc(bot, turn_in_degrees, radius, speed=80): + """ Turn is based on change in heading. """ + # Get the bot width in ticks + half_width_ticks = EncoderCounter.mm_to_ticks(bot.wheel_distance_mm/2.0) + if turn_in_degrees < 0: + left_radius = radius - half_width_ticks + right_radius = radius + half_width_ticks + else: + left_radius = radius + half_width_ticks + right_radius = radius - half_width_ticks + print("Arc left radius {:.2f}, right_radius {:.2f}".format(left_radius, right_radius)) + radians = math.radians(abs(turn_in_degrees)) + left_distance = int(left_radius * radians) + right_distance = int(right_radius * radians) + print("Arc left distance {}, right_distance {}".format(left_distance, right_distance)) + drive_distances(bot, left_distance, right_distance, speed=speed) + +bot = Robot() + +distance_to_drive = 300 # in mm +distance_in_ticks = EncoderCounter.mm_to_ticks(distance_to_drive) +radius = bot.wheel_distance_mm + 100 # in mm +radius_in_ticks = EncoderCounter.mm_to_ticks(radius) + +for n in range(4): + drive_distances(bot, distance_in_ticks, distance_in_ticks) + drive_arc(bot, 90, radius_in_ticks, speed=50) diff --git a/chapter15/full_system/line_following_behavior.py b/chapter15/full_system/line_following_behavior.py index 2d3f675..6dc1905 100644 --- a/chapter15/full_system/line_following_behavior.py +++ b/chapter15/full_system/line_following_behavior.py @@ -1,56 +1,56 @@ -from robot import Robot -from time import sleep - -cross_line_color = (255, 0, 0) -off_line_color = (0, 0, 255) - -class LineFollowingBehavior: - # Note - this is the robot ON the line. - def __init__(self, the_robot, forward_speed=30, cornering=-30): - self.robot = the_robot - self.forward_speed = forward_speed - self.cornering = cornering - - led_qtr = int(self.robot.leds.count/4) - self.right_indicator = range(0, led_qtr) - self.left_indicator = range(self.robot.leds.count - led_qtr, self.robot.leds.count) - - self.robot.leds.show() - - def when_left_crosses_line(self): - self.robot.set_left(self.cornering) - self.robot.leds.set_range(self.left_indicator, cross_line_color) - self.robot.leds.show() - - def when_right_crosses_line(self): - self.robot.set_right(self.cornering) - self.robot.leds.set_range(self.right_indicator, cross_line_color) - self.robot.leds.show() - - def when_left_off_line(self): - self.robot.set_left(self.forward_speed) - self.robot.leds.set_range(self.left_indicator, off_line_color) - self.robot.leds.show() - - def when_right_off_line(self): - self.robot.set_right(self.forward_speed) - self.robot.leds.set_range(self.right_indicator, off_line_color) - self.robot.leds.show() - - def run(self): - # Setup conditions - self.robot.left_line_sensor.when_line = self.when_left_crosses_line - self.robot.left_line_sensor.when_no_line = self.when_left_off_line - self.robot.right_line_sensor.when_line = self.when_right_crosses_line - self.robot.right_line_sensor.when_no_line = self.when_right_off_line - # Start driving - self.robot.set_left(self.forward_speed) - self.robot.set_right(self.forward_speed) - while True: - sleep(0.02) - - -bot = Robot() -behavior = LineFollowingBehavior(bot) -behavior.run() - +from robot import Robot +from time import sleep + +cross_line_color = (255, 0, 0) +off_line_color = (0, 0, 255) + +class LineFollowingBehavior: + # Note - this is the robot ON the line. + def __init__(self, the_robot, forward_speed=30, cornering=-30): + self.robot = the_robot + self.forward_speed = forward_speed + self.cornering = cornering + + led_qtr = int(self.robot.leds.count/4) + self.right_indicator = list(range(0, led_qtr)) + self.left_indicator = list(range(self.robot.leds.count - led_qtr, self.robot.leds.count)) + + self.robot.leds.show() + + def when_left_crosses_line(self): + self.robot.set_left(self.cornering) + self.robot.leds.set_range(self.left_indicator, cross_line_color) + self.robot.leds.show() + + def when_right_crosses_line(self): + self.robot.set_right(self.cornering) + self.robot.leds.set_range(self.right_indicator, cross_line_color) + self.robot.leds.show() + + def when_left_off_line(self): + self.robot.set_left(self.forward_speed) + self.robot.leds.set_range(self.left_indicator, off_line_color) + self.robot.leds.show() + + def when_right_off_line(self): + self.robot.set_right(self.forward_speed) + self.robot.leds.set_range(self.right_indicator, off_line_color) + self.robot.leds.show() + + def run(self): + # Setup conditions + self.robot.left_line_sensor.when_line = self.when_left_crosses_line + self.robot.left_line_sensor.when_no_line = self.when_left_off_line + self.robot.right_line_sensor.when_line = self.when_right_crosses_line + self.robot.right_line_sensor.when_no_line = self.when_right_off_line + # Start driving + self.robot.set_left(self.forward_speed) + self.robot.set_right(self.forward_speed) + while True: + sleep(0.02) + + +bot = Robot() +behavior = LineFollowingBehavior(bot) +behavior.run() + diff --git a/chapter15/full_system/manual_drive.py b/chapter15/full_system/manual_drive.py index 478a936..61dfc87 100644 --- a/chapter15/full_system/manual_drive.py +++ b/chapter15/full_system/manual_drive.py @@ -1,52 +1,52 @@ -import time -from robot import Robot -from image_app_core import start_server_process, get_control_instruction, put_output_image -import pi_camera_stream - -class ManualDriveBehavior(object): - def __init__(self, robot): - self.robot = robot - self.timeout = time.time() + 1 - - def process_control(self): - instruction = get_control_instruction() - while instruction: - self.timeout = time.time() + 1 - parts = instruction.split('/') - if parts[0] == "set_left": - self.robot.set_left(int(parts[1])) - elif parts[0] == "set_right": - self.robot.set_right(int(parts[1])) - elif parts[0] == "exit": - print "Stopping" - exit() - instruction = get_control_instruction() - - def make_display(self, frame): - """Create display output, and put it on the queue""" - encoded_bytes = pi_camera_stream.get_encoded_bytes_for_frame(frame) - put_output_image(encoded_bytes) - - def run(self): - # Set pan and tilt to middle, then clear it. - self.robot.set_pan(0) - self.robot.set_tilt(0) - # start camera - camera = pi_camera_stream.setup_camera() - # warm up and servo move time - time.sleep(0.1) - # Servo's will be in place - stop them for now. - self.robot.servos.stop_all() - print("Setup Complete") - # Main loop - for frame in pi_camera_stream.start_stream(camera): - self.make_display(frame) - self.process_control() - # Auto stop - if time.time() > self.timeout: - self.robot.stop_motors() - -print "Setting up" -behavior = ManualDriveBehavior(Robot()) -process = start_server_process('manual_drive.html') -behavior.run() +import time +from robot import Robot +from image_app_core import start_server_process, get_control_instruction, put_output_image +import pi_camera_stream + +class ManualDriveBehavior(object): + def __init__(self, robot): + self.robot = robot + self.timeout = time.time() + 1 + + def process_control(self): + instruction = get_control_instruction() + while instruction: + self.timeout = time.time() + 1 + parts = instruction.split('/') + if parts[0] == "set_left": + self.robot.set_left(int(parts[1])) + elif parts[0] == "set_right": + self.robot.set_right(int(parts[1])) + elif parts[0] == "exit": + print("Stopping") + exit() + instruction = get_control_instruction() + + def make_display(self, frame): + """Create display output, and put it on the queue""" + encoded_bytes = pi_camera_stream.get_encoded_bytes_for_frame(frame) + put_output_image(encoded_bytes) + + def run(self): + # Set pan and tilt to middle, then clear it. + self.robot.set_pan(0) + self.robot.set_tilt(0) + # start camera + camera = pi_camera_stream.setup_camera() + # warm up and servo move time + time.sleep(0.1) + # Servo's will be in place - stop them for now. + self.robot.servos.stop_all() + print("Setup Complete") + # Main loop + for frame in pi_camera_stream.start_stream(camera): + self.make_display(frame) + self.process_control() + # Auto stop + if time.time() > self.timeout: + self.robot.stop_motors() + +print("Setting up") +behavior = ManualDriveBehavior(Robot()) +process = start_server_process('manual_drive.html') +behavior.run() diff --git a/chapter15/full_system/piconzero_example/behavior_path.py b/chapter15/full_system/piconzero_example/behavior_path.py new file mode 100644 index 0000000..a0c03ae --- /dev/null +++ b/chapter15/full_system/piconzero_example/behavior_path.py @@ -0,0 +1,7 @@ +from pz_robot import Robot +from time import sleep + +r = Robot() +r.set_left(80) +r.set_right(80) +sleep(1) diff --git a/chapter15/full_system/piconzero_example/pz_robot.py b/chapter15/full_system/piconzero_example/pz_robot.py new file mode 100644 index 0000000..ef87ec6 --- /dev/null +++ b/chapter15/full_system/piconzero_example/pz_robot.py @@ -0,0 +1,20 @@ +import piconzero as pz + +import atexit + +class Robot(object): + def __init__(self): + pz.init() + atexit.register(self.stop_motors) + + def stop_motors(self): + pz.stop() + + def convert_speed(self, speed): + return (speed * 127) // 100 + + def set_left(self, speed): + pz.setMotor(0, self.convert_speed(speed)) + + def set_right(self, speed): + pz.setMotor(1, self.convert_speed(speed)) diff --git a/chapter15/full_system/straight_line_drive.py b/chapter15/full_system/straight_line_drive.py new file mode 100644 index 0000000..bbb3bba --- /dev/null +++ b/chapter15/full_system/straight_line_drive.py @@ -0,0 +1,28 @@ +from robot import Robot +from pid_controller import PIController +import time + +bot = Robot() +stop_at_time = time.time() + 60 + +speed = 80 +bot.set_left(speed) +bot.set_right(speed) + +pid = PIController(proportional_constant=4, integral_constant=0.2) +while time.time() < stop_at_time: + time.sleep(0.02) + # Calculate the error + left = bot.left_encoder.pulse_count + right = bot.right_encoder.pulse_count + error = left - right + # Get the speed + adjustment = pid.get_value(error) + right_speed = int(speed + adjustment) + print("left", left, \ + "right", right, \ + "right_speed:", right_speed, \ + "error:", error, \ + "adjustment: %.2f" % adjustment) + # Appy it to the right motor + bot.set_right(right_speed) diff --git a/chapter7/robot.py b/chapter7/robot.py index 7bc8616..f53f240 100644 --- a/chapter7/robot.py +++ b/chapter7/robot.py @@ -28,12 +28,12 @@ def convert_speed(self, speed): def set_left(self, speed): mode, output_speed = self.convert_speed(speed) - self.left_motor.setSpeed(output_speed) + self.left_motor.setSpeed(int(output_speed)) self.left_motor.run(mode) def set_right(self, speed): mode, output_speed = self.convert_speed(speed) - self.right_motor.setSpeed(output_speed) + self.right_motor.setSpeed(int(output_speed)) self.right_motor.run(mode) def stop_motors(self): diff --git a/chapter8/robot.py b/chapter8/robot.py index bc5c8b1..7522b6e 100644 --- a/chapter8/robot.py +++ b/chapter8/robot.py @@ -39,12 +39,12 @@ def convert_speed(self, speed): def set_left(self, speed): mode, output_speed = self.convert_speed(speed) - self.left_motor.setSpeed(output_speed) + self.left_motor.setSpeed(int(output_speed)) self.left_motor.run(mode) def set_right(self, speed): mode, output_speed = self.convert_speed(speed) - self.right_motor.setSpeed(output_speed) + self.right_motor.setSpeed(int(output_speed)) self.right_motor.run(mode) def stop_motors(self): diff --git a/chapter9/following_rainbows.py b/chapter9/following_rainbows.py index 187c3cf..77a6916 100644 --- a/chapter9/following_rainbows.py +++ b/chapter9/following_rainbows.py @@ -15,8 +15,8 @@ def __init__(self, the_robot, forward_speed=40, cornering=0): self.main_index = 0 led_qtr = int(self.robot.leds.count/4) - self.right_indicator = range(0, led_qtr) - self.left_indicator = range(self.robot.leds.count - led_qtr, self.robot.leds.count) + self.right_indicator = list(range(0, led_qtr)) + self.left_indicator = list(range(self.robot.leds.count - led_qtr, self.robot.leds.count)) def when_left_crosses_line(self): diff --git a/chapter9/line_following_behavior.py b/chapter9/line_following_behavior.py index 3ed653f..6dc1905 100644 --- a/chapter9/line_following_behavior.py +++ b/chapter9/line_following_behavior.py @@ -12,8 +12,8 @@ def __init__(self, the_robot, forward_speed=30, cornering=-30): self.cornering = cornering led_qtr = int(self.robot.leds.count/4) - self.right_indicator = range(0, led_qtr) - self.left_indicator = range(self.robot.leds.count - led_qtr, self.robot.leds.count) + self.right_indicator = list(range(0, led_qtr)) + self.left_indicator = list(range(self.robot.leds.count - led_qtr, self.robot.leds.count)) self.robot.leds.show() diff --git a/chapter9/robot.py b/chapter9/robot.py index 65c602b..b44dc29 100644 --- a/chapter9/robot.py +++ b/chapter9/robot.py @@ -47,12 +47,12 @@ def convert_speed(self, speed): def set_left(self, speed): mode, output_speed = self.convert_speed(speed) - self.left_motor.setSpeed(output_speed) + self.left_motor.setSpeed(int(output_speed)) self.left_motor.run(mode) def set_right(self, speed): mode, output_speed = self.convert_speed(speed) - self.right_motor.setSpeed(output_speed) + self.right_motor.setSpeed(int(output_speed)) self.right_motor.run(mode) def stop_motors(self):