Kraz3

Python code and building instructions for the LEGO MINDSTORMS EV3 Official Fan Creations (31313).

Kraz3
Image credit: LEGO

This robot is fun companion with a crazy attitude that reacts to it’s little IR Beacon bug friend. You can control it with the custom program, the IR Beacon, or simply set it to follow it’s little friend around the room.


This program requires LEGO® EV3 MicroPython v2.0 downloadable at https://education.lego.com/en-us/support/mindstorms-ev3/python-for-ev3.

Drive Kraz3 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: turn left forward - Top-Right/Blue-Up: turn right forward - Bottom-Left/Red-Down: turn left backward - Bottom-Right/Blue-Down: turn right backward

Kraz3 makes a kung-fu move when you press the Touch Sensor or the IR Beacon button.

Kraz3 reacts in funny ways to different colors.

The code for the Kraz3 class is in kraz3.py as follows:

from pybricks.hubs import EV3Brick
from pybricks.ev3devices import Motor, TouchSensor, ColorSensor
from pybricks.media.ev3dev import SoundFile
from pybricks.parameters import Button, Color, Direction, Port, Stop
from pybricks.tools import wait

from random import randint

from rc_tank_util import RemoteControlledTank


class Kraz3(RemoteControlledTank):
    WHEEL_DIAMETER = 24
    AXLE_TRACK = 100

    def __init__(
            self,
            left_motor_port: Port = Port.C, right_motor_port: Port = Port.B,
            wiggle_motor_port: Port = Port.A,
            polarity: str = 'inversed',
            touch_sensor_port: Port = Port.S1,
            color_sensor_port: Port = Port.S3,
            ir_sensor_port: Port = Port.S4, ir_beacon_channel: int = 1):
        super().__init__(
            wheel_diameter=self.WHEEL_DIAMETER, axle_track=self.AXLE_TRACK,
            left_motor_port=left_motor_port, right_motor_port=right_motor_port,
            polarity=polarity,
            ir_sensor_port=ir_sensor_port, ir_beacon_channel=ir_beacon_channel)

        self.ev3_brick = EV3Brick()

        self.wiggle_motor = Motor(port=wiggle_motor_port,
                                  positive_direction=Direction.CLOCKWISE)

        self.touch_sensor = TouchSensor(port=touch_sensor_port)

        self.color_sensor = ColorSensor(port=color_sensor_port)

    def kungfu_manoeuvre_whenever_touched_or_remote_controlled(self):
        """
        Kung-Fu manoeuvre via Touch Sensor and Remote Control of head and arms
        """
        while True:
            if self.touch_sensor.pressed():
                self.ev3_brick.speaker.play_file(file=SoundFile.KUNG_FU)

                self.wiggle_motor.run_angle(
                    speed=500,
                    rotation_angle=360,
                    then=Stop.HOLD,
                    wait=True)

            elif Button.BEACON in \
                    self.ir_sensor.buttons(channel=self.ir_beacon_channel):
                self.wiggle_motor.run(speed=111)

            else:
                self.wiggle_motor.stop()

            wait(10)

    def keep_reacting_to_colors(self):
        while True:
            detected_color = self.color_sensor.color()

            if detected_color == Color.YELLOW:
                self.ev3_brick.speaker.play_file(file=SoundFile.YELLOW)

                self.wiggle_motor.run_angle(
                    speed=-860,
                    rotation_angle=360,
                    then=Stop.HOLD,
                    wait=True)

                self.ev3_brick.speaker.play_file(file=SoundFile.UH_OH)

                wait(500)

                self.ev3_brick.speaker.play_file(file=SoundFile.SNEEZING)

                wait(500)

            elif detected_color == Color.RED:
                self.ev3_brick.speaker.play_file(file=SoundFile.SHOUTING)

                for _ in range(randint(1, 6)):
                    self.ev3_brick.speaker.play_file(file=SoundFile.SMACK)

                self.ev3_brick.light.on(color=Color.RED)

                self.wiggle_motor.run_angle(
                    speed=170,
                    rotation_angle=360,
                    then=Stop.HOLD,
                    wait=True)

                self.ev3_brick.speaker.play_file(file=SoundFile.LEGO)
                self.ev3_brick.speaker.play_file(file=SoundFile.MINDSTORMS)

                self.ev3_brick.light.off()

            elif detected_color == Color.BROWN:
                self.ev3_brick.speaker.play_file(file=SoundFile.BROWN)

                wait(1000)

                self.wiggle_motor.run_angle(
                    speed=-200,
                    rotation_angle=360,
                    then=Stop.HOLD,
                    wait=True)

                self.ev3_brick.speaker.play_file(file=SoundFile.CRYING)

            elif detected_color == Color.GREEN:
                self.ev3_brick.speaker.play_file(file=SoundFile.GREEN)

                self.wiggle_motor.run_angle(
                    speed=-400,
                    rotation_angle=360,
                    then=Stop.HOLD,
                    wait=True)

                self.ev3_brick.speaker.play_file(file=SoundFile.YES)

                wait(1000)

            elif detected_color == Color.BLUE:
                self.ev3_brick.speaker.play_file(file=SoundFile.BLUE)

                self.ev3_brick.speaker.play_file(file=SoundFile.FANTASTIC)

                self.ev3_brick.speaker.play_file(file=SoundFile.GOOD_JOB)

                self.wiggle_motor.run_angle(
                    speed=750,
                    rotation_angle=360,
                    then=Stop.HOLD,
                    wait=True)

                self.ev3_brick.speaker.play_file(file=SoundFile.MAGIC_WAND)

            wait(10)

Kraz3 uses a remote-controlled tank driving utility whose code is in rc_tank_util.py as follows:

from pybricks.ev3devices import Motor, InfraredSensor
from pybricks.robotics import DriveBase
from pybricks.parameters import Button, Direction, Port
from pybricks.tools import wait


class RemoteControlledTank:
    """
    This reusable mixin provides the capability of driving a robot
    with a Driving Base by the IR beacon
    """
    def __init__(
            self,
            wheel_diameter: float, axle_track: float,   # both in milimeters
            left_motor_port: Port = Port.B, right_motor_port: Port = Port.C,
            polarity: str = 'normal',
            ir_sensor_port: Port = Port.S4, ir_beacon_channel: int = 1):
        if polarity == 'normal':
            left_motor = Motor(port=left_motor_port,
                               positive_direction=Direction.CLOCKWISE)
            right_motor = Motor(port=right_motor_port,
                                positive_direction=Direction.CLOCKWISE)
        else:
            left_motor = Motor(port=left_motor_port,
                               positive_direction=Direction.COUNTERCLOCKWISE)
            right_motor = Motor(port=right_motor_port,
                                positive_direction=Direction.COUNTERCLOCKWISE)

        self.driver = DriveBase(left_motor=left_motor,
                                right_motor=right_motor,
                                wheel_diameter=wheel_diameter,
                                axle_track=axle_track)

        self.ir_sensor = InfraredSensor(port=ir_sensor_port)
        self.ir_beacon_channel = ir_beacon_channel

    def drive_by_ir_beacon(
            self,
            speed: float = 1000,    # mm/s
            turn_rate: float = 90   # rotational speed deg/s
            ):
        ir_beacon_button_pressed = \
            set(self.ir_sensor.buttons(channel=self.ir_beacon_channel))

        # forward
        if ir_beacon_button_pressed == {Button.LEFT_UP, Button.RIGHT_UP}:
            self.driver.drive(
                speed=speed,
                turn_rate=0)

        # backward
        elif ir_beacon_button_pressed == {Button.LEFT_DOWN, Button.RIGHT_DOWN}:
            self.driver.drive(
                speed=-speed,
                turn_rate=0)

        # turn left on the spot
        elif ir_beacon_button_pressed == {Button.LEFT_UP, Button.RIGHT_DOWN}:
            self.driver.drive(
                speed=0,
                turn_rate=-turn_rate)

        # turn right on the spot
        elif ir_beacon_button_pressed == {Button.RIGHT_UP, Button.LEFT_DOWN}:
            self.driver.drive(
                speed=0,
                turn_rate=turn_rate)

        # turn left forward
        elif ir_beacon_button_pressed == {Button.LEFT_UP}:
            self.driver.drive(
                speed=speed,
                turn_rate=-turn_rate)

        # turn right forward
        elif ir_beacon_button_pressed == {Button.RIGHT_UP}:
            self.driver.drive(
                speed=speed,
                turn_rate=turn_rate)

        # turn left backward
        elif ir_beacon_button_pressed == {Button.LEFT_DOWN}:
            self.driver.drive(
                speed=-speed,
                turn_rate=turn_rate)

        # turn right backward
        elif ir_beacon_button_pressed == {Button.RIGHT_DOWN}:
            self.driver.drive(
                speed=-speed,
                turn_rate=-turn_rate)

        # otherwise stop
        else:
            self.driver.stop()

    def keep_driving_by_ir_beacon(
            self,
            speed: float = 1000,    # mm/s
            turn_rate: float = 90   # rotational speed deg/s
            ):
        while True:
            self.drive_by_ir_beacon(
                speed=speed,
                turn_rate=turn_rate)
            wait(10)

The code for the main program is in main.py as follows:

#!/usr/bin/env pybricks-micropython


from pybricks.experimental import run_parallel

from kraz3 import Kraz3


kraz3 = Kraz3()

run_parallel(
    kraz3.keep_driving_by_ir_beacon,
    kraz3.kungfu_manoeuvre_whenever_touched_or_remote_controlled,
    kraz3.keep_reacting_to_colors)


This project was submitted by The Lương-Phạm Family.