Track3r

Python code and building instructions for the LEGO MINDSTORMS EV3 Main models (31313).

Track3r
Image credit: LEGO

TRACK3R is a crawler-mounted, all-terrain robot with four interchangeable tools. Start by building the body of the robot, then discover the possibilities of the four different TRACK3R tools: the bi-blade blender, the blasting bazooka, the gripping claw, and the hammer.


These programs require LEGO® EV3 MicroPython v2.0 downloadable at https://education.lego.com/en-us/support/mindstorms-ev3/python-for-ev3.

There are 4 Track3r variants with 4 different tools:

  • Track3r with Bi-blade Spinner
  • Track3r with Blasting Bazooka
  • Track3r with Gripping Claw
  • Track3r with Heavy Hammer

The code for the base Track3r class is in track3r_base.py as follows:

#!/usr/bin/env pybricks-micropython


from pybricks.hubs import EV3Brick
from pybricks.ev3devices import Motor
from pybricks.parameters import Direction, Port
from pybricks.tools import wait

from rc_tank_util import RemoteControlledTank


class Track3r(RemoteControlledTank):
    WHEEL_DIAMETER = 26   # milimeters
    AXLE_TRACK = 140      # milimeters

    def __init__(
            self,
            left_track_motor_port: Port = Port.B,
            right_track_motor_port: Port = Port.C,
            medium_motor_port: Port = Port.A,
            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_track_motor_port,
            right_motor_port=right_track_motor_port,
            ir_sensor_port=ir_sensor_port,
            ir_beacon_channel=ir_beacon_channel)

        self.ev3_brick = EV3Brick()

        self.medium_motor = Motor(port=medium_motor_port,
                                  positive_direction=Direction.CLOCKWISE)

    def main(self, speed: float = 1000):
        """
        Driving Track3r around by the IR beacon
        """
        while True:
            self.drive_by_ir_beacon(speed=speed)
            wait(1)


if __name__ == '__main__':
    TRACK3R = Track3r()
    TRACK3R.main(speed=1000)

Track3r 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


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,
            ir_sensor_port: Port = Port.S4, ir_beacon_channel: int = 1):
        self.drive_base = \
            DriveBase(
                left_motor=Motor(port=left_motor_port,
                                 positive_direction=Direction.CLOCKWISE),
                right_motor=Motor(port=right_motor_port,
                                  positive_direction=Direction.CLOCKWISE),
                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.drive_base.drive(
                speed=speed,
                turn_rate=0)

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

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

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

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

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

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

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

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

The code for the Track3rWithBiBladeSpinner is in track3r_with_biblade_spinner.py as follows:

#!/usr/bin/env pybricks-micropython


from pybricks.parameters import Button
from pybricks.tools import wait

from track3r_base import Track3r


class Track3rWithBiBladeSpinner(Track3r):
    """
    Track3r spins its blade when the Beacon button is pressed
    (inspiration from LEGO Mindstorms EV3 Home Edition: Track3r: Tutorial #5)
    """
    def spin_blade_by_ir_beacon(self, speed: float = 1000):
        if Button.BEACON in \
                self.ir_sensor.buttons(channel=self.ir_beacon_channel):
            self.medium_motor.run(speed=speed)

        else:
            self.medium_motor.stop()

    def main(self, speed: float = 1000):
        while True:
            self.drive_by_ir_beacon(speed=speed)
            self.spin_blade_by_ir_beacon(speed=speed)
            wait(1)


if __name__ == '__main__':
    TRACK3R = Track3rWithBiBladeSpinner()
    TRACK3R.main(speed=1000)

The code for the Track3rWithBlastingBazooka is in track3r_with_blasting_bazooka.py as follows:

#!/usr/bin/env pybricks-micropython


from pybricks.media.ev3dev import ImageFile, SoundFile
from pybricks.parameters import Button, Stop
from pybricks.tools import wait

from track3r_base import Track3r


class Track3rWithBlastingBazooka(Track3r):
    """
    Track3r blasts his bazooka when the Beacon button is pressed
    (inspiration from LEGO Mindstorms EV3 Home Edition: Track3r: Tutorial #2)
    """
    def blast_bazooka_by_ir_beacon(self, speed: float = 1000):
        if Button.BEACON in \
                self.ir_sensor.buttons(channel=self.ir_beacon_channel):
            self.medium_motor.run_angle(
                speed=speed,
                rotation_angle=3 * 360,   # about 3 rotations for 1 shot
                then=Stop.HOLD,
                wait=True)

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

            while Button.BEACON in \
                    self.ir_sensor.buttons(channel=self.ir_beacon_channel):
                pass

    def main(self, speed: float = 1000):
        self.ev3_brick.screen.load_image(ImageFile.PINCHED_MIDDLE)

        while True:
            self.drive_by_ir_beacon(speed=speed)
            self.blast_bazooka_by_ir_beacon(speed=speed)
            wait(1)


if __name__ == '__main__':
    TRACK3R = Track3rWithBlastingBazooka()
    TRACK3R.main(speed=1000)

The code for the Track3rWithGrippingClaw is in track3r_with_gripping_claw.py as follows:

#!/usr/bin/env pybricks-micropython


from pybricks.media.ev3dev import SoundFile
from pybricks.parameters import Button
from pybricks.tools import wait

from track3r_base import Track3r


class Track3rWithGrippingClaw(Track3r):
    """
    Track3r grips or releases its claw when the Beacon button is pressed
    (inspiration from LEGO Mindstorms EV3 Home Edition: Track3r: Tutorial #3)
    """
    is_gripping = False

    def grip_or_release_claw_by_ir_beacon(self, speed: float = 1000):
        if Button.BEACON in \
                self.ir_sensor.buttons(channel=self.ir_beacon_channel):
            if self.is_gripping:
                self.medium_motor.run(speed=-speed)
                self.ev3_brick.speaker.play_file(file=SoundFile.AIR_RELEASE)
                self.is_gripping = False

            else:
                self.medium_motor.run(speed=speed)
                self.ev3_brick.speaker.play_file(file=SoundFile.AIRBRAKE)
                self.is_gripping = True

            while Button.BEACON in \
                    self.ir_sensor.buttons(channel=self.ir_beacon_channel):
                pass

    def main(self, speed: float = 1000):
        while True:
            self.drive_by_ir_beacon(speed=speed)
            self.grip_or_release_claw_by_ir_beacon(speed=speed)
            wait(1)


if __name__ == '__main__':
    TRACK3R = Track3rWithGrippingClaw()
    TRACK3R.main(speed=1000)

The code for the Track3rWithHeavyHammer is in track3r_with_heavy_hammer.py as follows:

#!/usr/bin/env pybricks-micropython


from pybricks.media.ev3dev import ImageFile, SoundFile
from pybricks.parameters import Button, Stop
from pybricks.tools import wait

from track3r_base import Track3r


class Track3rWithHeavyHammer(Track3r):
    """
    Track3r hammers down when the Beacon button is pressed
    (inspiration from LEGO Mindstorms EV3 Home Edition: Track3r: Tutorial #4)
    """
    def hammer_by_ir_beacon(self, speed: float = 1000):
        if Button.BEACON in \
                self.ir_sensor.buttons(channel=self.ir_beacon_channel):
            self.ev3_brick.screen.load_image(ImageFile.ANGRY)

            self.medium_motor.run_time(
                speed=speed,
                time=1000,
                then=Stop.COAST,
                wait=True)

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

            self.medium_motor.run_time(
                speed=-speed,
                time=1000,
                then=Stop.COAST,
                wait=True)

    def main(self, speed: float = 1000):
        self.medium_motor.run_time(
            speed=-200,
            time=1000,
            then=Stop.COAST,
            wait=True)

        while True:
            self.drive_by_ir_beacon(speed=speed)
            self.hammer_by_ir_beacon(speed=speed)
            wait(1)


if __name__ == '__main__':
    TRACK3R = Track3rWithHeavyHammer()
    TRACK3R.main(speed=1000)


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