diff --git a/robots/ROBODOZ3R/README.md b/robots/ROBODOZ3R/README.md new file mode 100644 index 0000000..3ca24f4 --- /dev/null +++ b/robots/ROBODOZ3R/README.md @@ -0,0 +1,27 @@ +# ROBODOZ3R + +> Designed by Mark Crosbie. +> +> This robot bulldozer can be controlled using the IR Beacon or it can drive on it’s own, avoiding obstacles while clearing and pushing things with its bulldozer bucket. + +The build instructions may be found at the official LEGO MINDSTROMS site [here](https://www.lego.com/cdn/cs/set/assets/bltfef825595f55768c/ROBODOZ3R.pdf) + +Control ROBODOZ3R as follows: + +- ROBODOZ3R starts with the User-Controlled Mode. You can switch between the User-Controlled Mode and the Autonomous Mode by pressing the Touch Sensor. + +- User-Controlled Mode: + + - Drive ROBODOZ3R around according to instructions from Channel 1 of the IR Remote Control: + - 2 Top/Up Buttons together: drive forward + - 2 Bottom/Down Buttons together: drive backward + - Top-Left/Red-Up and Bottom-Right/Blue-Down together: turn left on the spot + - Top-Right/Blue-Up and Bottom-Left/Red-Down together: turn right on the spot + - Top-Left/Red-Up: turn left forward + - Top-Right/Blue-Up: turn right forward + - Bottom-Left/Red-Down: turn left backward + - Bottom-Right/Blue-Down: turn right backward + + - Use Channel 4 of the IR Remote Control to make ROBODOZ3R raise the shovel by pressing either Up button, or lower the shovel by pressing either Down button + +- Autonomous Mode: ROBODOZ3R drives around on his own to clean up small things but avoids big obstacles by reversing and turning diff --git a/robots/ROBODOZ3R/media/Airbrake.wav b/robots/ROBODOZ3R/media/Airbrake.wav new file mode 100644 index 0000000..9558ef2 Binary files /dev/null and b/robots/ROBODOZ3R/media/Airbrake.wav differ diff --git a/robots/ROBODOZ3R/media/Motor idle.wav b/robots/ROBODOZ3R/media/Motor idle.wav new file mode 100644 index 0000000..26c21f5 Binary files /dev/null and b/robots/ROBODOZ3R/media/Motor idle.wav differ diff --git a/robots/ROBODOZ3R/media/Motor start.wav b/robots/ROBODOZ3R/media/Motor start.wav new file mode 100644 index 0000000..d9df5a5 Binary files /dev/null and b/robots/ROBODOZ3R/media/Motor start.wav differ diff --git a/robots/ROBODOZ3R/media/Motor stop.wav b/robots/ROBODOZ3R/media/Motor stop.wav new file mode 100644 index 0000000..2021cb4 Binary files /dev/null and b/robots/ROBODOZ3R/media/Motor stop.wav differ diff --git a/robots/ROBODOZ3R/media/Start up.wav b/robots/ROBODOZ3R/media/Start up.wav new file mode 100644 index 0000000..1964566 Binary files /dev/null and b/robots/ROBODOZ3R/media/Start up.wav differ diff --git a/robots/ROBODOZ3R/rc_tank_util.py b/robots/ROBODOZ3R/rc_tank_util.py new file mode 100644 index 0000000..68a83d1 --- /dev/null +++ b/robots/ROBODOZ3R/rc_tank_util.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python3 + + +from ev3dev.ev3 import \ + Motor, LargeMotor, OUTPUT_B, OUTPUT_C, \ + InfraredSensor, RemoteControl, INPUT_4 + + +class RemoteControlledTank: + """ + This reusable mixin provides the capability of driving a robot + with a Driving Base by the IR beacon + """ + def __init__( + self, + left_motor_port: str = OUTPUT_B, right_motor_port: str = OUTPUT_C, + polarity: str = Motor.POLARITY_NORMAL, + ir_sensor_port: str = INPUT_4, ir_beacon_channel: int = 1): + self.left_motor = LargeMotor(address=left_motor_port) + self.right_motor = LargeMotor(address=right_motor_port) + + self.left_motor.polarity = self.right_motor.polarity = polarity + + self.ir_sensor = InfraredSensor(address=ir_sensor_port) + self.tank_drive_remote_control = \ + RemoteControl( + sensor=self.ir_sensor, + channel=ir_beacon_channel) + + def drive_by_ir_beacon(self, speed: float = 1000): + # forward + if self.tank_drive_remote_control.red_up and \ + self.tank_drive_remote_control.blue_up: + self.left_motor.run_forever(speed_sp=speed) + self.right_motor.run_forever(speed_sp=speed) + + # backward + elif self.tank_drive_remote_control.red_down and \ + self.tank_drive_remote_control.blue_down: + self.left_motor.run_forever(speed_sp=-speed) + self.right_motor.run_forever(speed_sp=-speed) + + # turn left on the spot + elif self.tank_drive_remote_control.red_up and \ + self.tank_drive_remote_control.blue_down: + self.left_motor.run_forever(speed_sp=-speed) + self.right_motor.run_forever(speed_sp=speed) + + # turn right on the spot + elif self.tank_drive_remote_control.red_down and \ + self.tank_drive_remote_control.blue_up: + self.left_motor.run_forever(speed_sp=speed) + self.right_motor.run_forever(speed_sp=-speed) + + # turn left forward + elif self.tank_drive_remote_control.red_up: + self.right_motor.run_forever(speed_sp=speed) + + # turn right forward + elif self.tank_drive_remote_control.blue_up: + self.left_motor.run_forever(speed_sp=speed) + + # turn left backward + elif self.tank_drive_remote_control.red_down: + self.right_motor.run_forever(speed_sp=-speed) + + # turn right backward + elif self.tank_drive_remote_control.blue_down: + self.left_motor.run_forever(speed_sp=-speed) + + # otherwise stop + else: + self.left_motor.stop(stop_action=Motor.STOP_ACTION_COAST) + self.right_motor.stop(stop_action=Motor.STOP_ACTION_COAST) diff --git a/robots/ROBODOZ3R/robodoz3r.py b/robots/ROBODOZ3R/robodoz3r.py new file mode 100644 index 0000000..901d684 --- /dev/null +++ b/robots/ROBODOZ3R/robodoz3r.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python3 + + +from ev3dev.ev3 import ( + Motor, MediumMotor, OUTPUT_A, OUTPUT_B, OUTPUT_C, + TouchSensor, RemoteControl, INPUT_1, INPUT_4, + Screen, Sound +) + +from time import sleep, time + +from rc_tank_util import RemoteControlledTank + + +class RoboDoz3r(RemoteControlledTank): + def __init__( + self, + left_motor_port: str = OUTPUT_C, right_motor_port: str = OUTPUT_B, + shovel_motor_port: str = OUTPUT_A, + touch_sensor_port: str = INPUT_1, + ir_sensor_port: str = INPUT_4, + tank_drive_ir_beacon_channel: int = 1, + shovel_control_ir_beacon_channel: int = 4): + super().__init__( + left_motor_port=left_motor_port, right_motor_port=right_motor_port, + polarity=Motor.POLARITY_INVERSED, + ir_sensor_port=ir_sensor_port, + ir_beacon_channel=tank_drive_ir_beacon_channel) + + self.shovel_motor = MediumMotor(address=shovel_motor_port) + + self.touch_sensor = TouchSensor(address=touch_sensor_port) + + self.shovel_control_remote_control = \ + RemoteControl( + sensor=self.ir_sensor, + channel=shovel_control_ir_beacon_channel) + + self.screen = Screen() + self.speaker = Sound() + + def raise_or_lower_shovel_by_ir_beacon(self): + """ + If the channel 4 is selected on the IR remote + then you can control raising and lowering the shovel on the RoboDoz3r. + + Raise the shovel by pressing either Up button, + or lower the shovel by pressing either Down button. + """ + # raise the shovel + if self.shovel_control_remote_control.red_up or \ + self.shovel_control_remote_control.blue_up: + self.shovel_motor.run_forever(speed_sp=100) + + # lower the shovel + elif self.shovel_control_remote_control.red_down or \ + self.shovel_control_remote_control.blue_down: + self.shovel_motor.run_forever(speed_sp=-100) + + else: + self.shovel_motor.stop(stop_action=Motor.STOP_ACTION_HOLD) + + def main(self, driving_speed: float = 1000): + """ + This is the main control program for the RoboDoz3r + """ + self.screen.draw.text( + xy=(2, 2), + text='ROBODOZ3R', + fill=None, + font=None, + anchor=None, + spacing=4, + align='left', + direction=None, + features=None, + language=None, + stroke_width=0, + stroke_fill=None) + self.screen.update() + + self.speaker.play(wav_file='media/Motor start.wav').wait() + + # Engine Idle: + # Let the engine sound idle for 2 seconds + motor_idle_start_time = time() + while time() - motor_idle_start_time <= 2: + self.speaker.play( + wav_file='media/Motor idle.wav').wait() + + while True: + # Driving Mode: + # Manual mode where the movement of the RoboDoz3r is controlled + # by the IR remote + while not self.touch_sensor.is_pressed: + self.raise_or_lower_shovel_by_ir_beacon() + self.drive_by_ir_beacon(speed=driving_speed) + sleep(0.01) + + self.speaker.play(wav_file='media/Airbrake.wav').wait() + + # Auto Mode: + # In autonomous mode the RoboDoz3r uses the IR sensor + # in proximity mode to detect nearby obstacles in its path + while not self.touch_sensor.is_pressed: + if self.ir_sensor.proximity < 50: + self.left_motor.stop(stop_action=Motor.STOP_ACTION_HOLD) + self.right_motor.stop(stop_action=Motor.STOP_ACTION_HOLD) + + sleep(1) + + self.left_motor.run_timed( + speed_sp=-300, + time_sp=1000, + stop_action=Motor.STOP_ACTION_HOLD) + self.right_motor.run_timed( + speed_sp=-300, + time_sp=1000, + stop_action=Motor.STOP_ACTION_HOLD) + self.left_motor.wait_while(Motor.STATE_RUNNING) + self.right_motor.wait_while(Motor.STATE_RUNNING) + + self.left_motor.run_timed( + speed_sp=500, + time_sp=1000, + stop_action=Motor.STOP_ACTION_HOLD) + self.right_motor.run_timed( + speed_sp=-500, + time_sp=1000, + stop_action=Motor.STOP_ACTION_HOLD) + self.left_motor.wait_while(Motor.STATE_RUNNING) + self.right_motor.wait_while(Motor.STATE_RUNNING) + + else: + self.left_motor.run_forever(speed_sp=500) + self.right_motor.run_forever(speed_sp=500) + + sleep(0.01) + + self.speaker.play(wav_file='media/Airbrake.wav').wait() + + +if __name__ == '__main__': + ROBODOZ3R = RoboDoz3r() + ROBODOZ3R.main()