I love building stuff with my son, and one of our latest projects (admittedly more apt for me than for him as he’s too young to be building these kits), was the Lego buggy 42124. This is a great kit that is fun to build but it is let down by the fact that it is controlled using a smartphone. I don’t like using smartphone remote controls and I definitely don’t want my son looking at a screen at a young age, so I set out to figure out a way to use a hardware remote control.
Turns out it’s quite easy to do. I used Pybricks to add custom code to the Lego hub, then ordered a Lego remote to pair with the buggy.
The code I used can be found below. I set the left red button to “ludicrous mode” which enables the buggy to function at full speed. Otherwise, I set it to run at 50% speed since my son is too young to control it at max speed, especially indoors. This way we can both use it and have some fun while using the appropriate speeds.
Lego Buggy (42124)
from pybricks.pupdevices import Motor, Remote
from pybricks.parameters import Port, Direction, Stop, Button
from pybricks.hubs import TechnicHub
from pybricks.tools import wait
# Initialize the motors.
steer = Motor(Port.B)
front = Motor(Port.A, Direction.COUNTERCLOCKWISE)
# Connect to the remote.
remote = Remote()
# Initialize the hub.
hub = TechnicHub()
# Read the current settings
old_kp, old_ki, old_kd, _, _ = steer.control.pid()
# Set new values
steer.control.pid(kp=old_kp*4, kd=old_kd*0.4)
# Find the steering endpoint on the left and right.
# The middle is in between.
left_end = steer.run_until_stalled(-200, then=Stop.HOLD)
right_end = steer.run_until_stalled(200, then=Stop.HOLD)
# We are now at the right. Reset this angle to be half the difference.
# That puts zero in the middle.
steer.reset_angle((right_end - left_end)/2)
steer.run_target(speed=200, target_angle=0, wait=False)
# Set steering angle for the buggy
steer_angle = (((right_end - left_end)/2)-5)
print('steer angle:',steer_angle)
# Now we can start driving!
while True:
# Check which buttons are pressed.
pressed = remote.buttons.pressed()
# Choose the steer angle based on the right controls.
if Button.LEFT_PLUS in pressed:
steer.run_target(1400, -steer_angle, Stop.HOLD, False)
elif Button.LEFT_MINUS in pressed:
steer.run_target(1400, steer_angle, Stop.HOLD, False)
else:
steer.track_target(0)
# Top speed controls
top_speed = 50
if Button.LEFT in pressed:
top_speed = 100
# Choose the drive speed based on the left controls.
drive_speed = 0
if Button.RIGHT_PLUS in pressed:
drive_speed += top_speed
if Button.RIGHT_MINUS in pressed:
drive_speed -= top_speed
if Button.RIGHT in pressed:
print('Battery voltage:',(hub.battery.voltage())/1000,"V")
wait(100)
# Apply the selected speed.
front.dc(drive_speed)
# Wait.
wait(10)
Lego Top Gear Rally Car (42109)
I also bought the Lego Top Gear Rally Car (42109) and used similar code with a second remote I bought. Now we can race the cars against each other. I can adjust the speed of each through code to adapt it to our different abilities.
Here’s the code I used on this car. I added some things like changing the remote light buttons and naming the remote so that the car would connect to a specific remote out of the two I have, and thus avoid confusion. I also correspondingly changed the hub’s light color.
from pybricks.pupdevices import Motor, Remote
from pybricks.parameters import Port, Direction, Stop, Button, Color
from pybricks.hubs import TechnicHub
from pybricks.tools import wait
# Initialize the motors.
steer = Motor(Port.B)
front = Motor(Port.D, Direction.COUNTERCLOCKWISE)
# Connect to the remote and set the light on the remote
remote = Remote('topgear', timeout=None)
remote.light.on(Color.RED)
# Print the current name of the remote.
print(remote.name())
# Choose a new name.
remote.name('topgear')
# Initialize the hub.
hub = TechnicHub()
hub.light.on(Color.RED)
# Read the current settings
old_kp, old_ki, old_kd, _, _ = steer.control.pid()
# Set new values
steer.control.pid(kp=old_kp*4, kd=old_kd*0.4)
# Set initial top speed value
top_speed = 100
# Find the steering endpoint on the left and right.
# The middle is in between.
left_end = steer.run_until_stalled(-200, then=Stop.HOLD)
right_end = steer.run_until_stalled(200, then=Stop.HOLD)
# We are now at the right. Reset this angle to be half the difference.
# That puts zero in the middle.
steer.reset_angle((right_end - left_end)/2)
steer.run_target(speed=200, target_angle=0, wait=False)
# Set steering angle for the buggy
steer_angle = (((right_end - left_end)/2)-5)
# Now we can start driving!
while True:
# Check which buttons are pressed.
pressed = remote.buttons.pressed()
# Choose the steer angle based on the right controls.
if Button.LEFT_PLUS in pressed:
steer.run_target(1400, -steer_angle, Stop.HOLD, False)
elif Button.LEFT_MINUS in pressed:
steer.run_target(1400, steer_angle, Stop.HOLD, False)
else:
steer.track_target(0)
# Top speed controls
if Button.LEFT in pressed:
top_speed = 75
if Button.RIGHT in pressed:
top_speed = 100
if ((Button.RIGHT in pressed) and (Button.LEFT in pressed)):
top_speed = 40
# Choose the drive speed based on the left controls.
drive_speed = 0
if Button.RIGHT_PLUS in pressed:
drive_speed -= top_speed
if Button.RIGHT_MINUS in pressed:
drive_speed += top_speed
# Print battery voltage
if Button.RIGHT in pressed:
print('Battery voltage:',(hub.battery.voltage())/1000,"V")
wait(100)
# Apply the selected speed.
front.dc(drive_speed)
# Wait.
wait(10)
Lego Go Kart (42109 variant)
from pybricks.pupdevices import Motor, Remote
from pybricks.parameters import Port, Direction, Stop, Button, Color
from pybricks.hubs import TechnicHub
from pybricks.tools import wait
# Initialize the motors.
steer = Motor(Port.B)
front = Motor(Port.D, Direction.COUNTERCLOCKWISE)
# Connect to the remote and set the light on the remote
remote = Remote('topgear', timeout=None)
remote.light.on(Color.GREEN)
# Print the current name of the remote.
print(remote.name())
# Choose a new name.
remote.name('kart')
# Initialize the hub.
hub = TechnicHub()
hub.light.on(Color.GREEN)
# Read the current settings
old_kp, old_ki, old_kd, _, _ = steer.control.pid()
# Set new values
steer.control.pid(kp=old_kp*4, kd=old_kd*0.4)
# Set initial top speed value
top_speed = 100
# Find the steering endpoint on the left and right.
# The middle is in between.
left_end = steer.run_until_stalled(-200, then=Stop.HOLD)
right_end = steer.run_until_stalled(200, then=Stop.HOLD)
# We are now at the right. Reset this angle to be half the difference.
# That puts zero in the middle.
steer.reset_angle((right_end - left_end)/2)
steer.run_target(speed=200, target_angle=0, wait=False)
# Set steering angle for the buggy
steer_angle = (((right_end - left_end)/2)-5)
# Now we can start driving!
while True:
# Check which buttons are pressed.
pressed = remote.buttons.pressed()
# Choose the steer angle based on the right controls.
if Button.LEFT_PLUS in pressed:
steer.run_target(1400, -steer_angle, Stop.HOLD, False)
elif Button.LEFT_MINUS in pressed:
steer.run_target(1400, steer_angle, Stop.HOLD, False)
else:
steer.track_target(0)
# Top speed controls
if Button.LEFT in pressed:
top_speed = 75
if Button.RIGHT in pressed:
top_speed = 100
if ((Button.RIGHT in pressed) and (Button.LEFT in pressed)):
top_speed = 40
# Choose the drive speed based on the left controls.
drive_speed = 0
if Button.RIGHT_PLUS in pressed:
drive_speed -= top_speed
if Button.RIGHT_MINUS in pressed:
drive_speed += top_speed
# Print battery voltage
if Button.RIGHT in pressed:
print('Battery voltage:',(hub.battery.voltage())/1000,"V")
wait(100)
# Apply the selected speed.
front.dc(drive_speed)
# Wait.
wait(10)
Lego 4×4 Extreme Off-Roader (42099)
from pybricks.pupdevices import Motor, Remote
from pybricks.parameters import Port, Direction, Stop, Button
from pybricks.tools import wait
# Initialize the motors.
steer = Motor(Port.C)
front = Motor(Port.A, Direction.COUNTERCLOCKWISE)
rear = Motor(Port.B, Direction.COUNTERCLOCKWISE)
# Lower the acceleration so the car starts and stops realistically.
front.control.limits(acceleration=1000)
rear.control.limits(acceleration=1000)
# Connect to the remote.
remote = Remote()
# Find the steering endpoint on the left and right.
# The middle is in between.
left_end = steer.run_until_stalled(-200, then=Stop.HOLD)
right_end = steer.run_until_stalled(200, then=Stop.HOLD)
# We are now at the right. Reset this angle to be half the difference.
# That puts zero in the middle.
steer.reset_angle((right_end - left_end) / 2)
steer.run_target(speed=200, target_angle=0, wait=False)
# Now we can start driving!
while True:
# Check which buttons are pressed.
pressed = remote.buttons.pressed()
# Choose the steer angle based on the left controls.
steer_angle = 0
if Button.LEFT_PLUS in pressed:
steer_angle -= 75
if Button.LEFT_MINUS in pressed:
steer_angle += 75
# Steer to the selected angle.
steer.run_target(500, steer_angle, wait=False)
# Choose the drive speed based on the right controls.
drive_speed = 0
if Button.RIGHT_PLUS in pressed:
drive_speed += 1000
if Button.RIGHT_MINUS in pressed:
drive_speed -= 1000
# Apply the selected speed.
front.run(drive_speed)
rear.run(drive_speed)
# Wait.
wait(10)
Troubleshooting
If you’re having issues getting the code to work, you can try both editors:
You can also use this code to verify that a connection is being successfully made by your controller with the hub:
from pybricks.hubs import TechnicHub
from pybricks.pupdevices import Remote
from pybricks.parameters import Button, Color
from pybricks.tools import wait
hub = TechnicHub()
# Make the light red while we connect.
hub.light.on(Color.RED)
# Connect to the remote.
my_remote = Remote()
# Make the light green when we are connected.
hub.light.on(Color.GREEN)
while True:
# For any button press, make the light magenta.
# Otherwise make it yellow.
if my_remote.buttons.pressed():
hub.light.on(Color.MAGENTA)
else:
hub.light.on(Color.YELLOW)
wait(10)
Lego 42124 Trike Variant
from pybricks.pupdevices import Motor, Remote
from pybricks.parameters import Port, Direction, Stop, Button
from pybricks.hubs import TechnicHub
from pybricks.tools import wait
# Initialize the motors.
steer = Motor(Port.B)
front = Motor(Port.A, Direction.COUNTERCLOCKWISE)
# Connect to the remote.
remote = Remote()
# Initialize the hub.
hub = TechnicHub()
# Read the current settings
old_kp, old_ki, old_kd, _, _ = steer.control.pid()
# Set new values
steer.control.pid(kp=old_kp*0.5, kd=old_kd*1)
# Find the steering endpoint on the left and right.
# The middle is in between.
left_end = steer.run_until_stalled(-200, then=Stop.HOLD)
right_end = steer.run_until_stalled(200, then=Stop.HOLD)
print('left end:',left_end)
print('right end:', right_end)
# We are now at the right. Reset this angle to be half the difference.
# That puts zero in the middle.
steer.reset_angle((right_end - left_end)/2)
steer.run_target(speed=100, target_angle=0, wait=False)
# Set steering angle for the buggy
steer_angle = (((right_end - left_end)/2)-20)
print('steer angle:',steer_angle)
# Now we can start driving!
while True:
# Check which buttons are pressed.
pressed = remote.buttons.pressed()
# Choose the steer angle based on the right controls.
if Button.LEFT_PLUS in pressed:
steer.run_target(400, -steer_angle, Stop.HOLD, False)
elif Button.LEFT_MINUS in pressed:
steer.run_target(400, steer_angle, Stop.HOLD, False)
else:
current_angle = steer.angle()
deadband = 3 # Define a deadband range of +/- 3 degrees
if current_angle > deadband:
steer.track_target(0)
elif current_angle < -deadband:
steer.track_target(0)
else:
steer.stop()
# Top speed controls
top_speed = 50
if Button.LEFT in pressed:
top_speed = 100
# Choose the drive speed based on the left controls.
drive_speed = 0
if Button.RIGHT_PLUS in pressed:
drive_speed += top_speed
if Button.RIGHT_MINUS in pressed:
drive_speed -= top_speed
if Button.RIGHT in pressed:
print('Battery voltage:',(hub.battery.voltage())/1000,"V")
wait(100)
# Apply the selected speed.
front.dc(drive_speed)
# Wait.
wait(10)
Lego 51515 Robot Inventor
You can also use the same principles to connect to the Lego 51515 Robot Inventor hub. There are many things you can build with that kit, but below you can find the general framework for connecting the Lego remote to the 51515 hub:
from pybricks.hubs import InventorHub
from pybricks.pupdevices import Remote
from pybricks.parameters import Button
from pybricks.tools import wait
# Initialize the hub and the remote
hub = InventorHub()
remote = Remote()
while True:
# Check if a button on the remote is pressed
pressed = remote.buttons.pressed()
if Button.LEFT in pressed:
# Code for when the left button is pressed
pass
elif Button.RIGHT in pressed:
# Code for when the right button is pressed
pass
# Delay to avoid rapid polling
wait(10)
Using a PS4 Controller via BrickController2
BrickController2 is an app that lets you control LEGO creations with game controllers. To use a PS4 controller with BrickController2, follow these steps:
- Pair the PS4 Controller with Your Device:a. Put the PS4 controller in pairing mode by holding down the “Share” and “PS” buttons at the same time until the light bar starts flashing.b. On your device (whether it’s an Android or iOS), open the Bluetooth settings.
c. Look for the PS4 controller in the list of available devices. It might show up as “Wireless Controller” or something similar.
d. Tap on the PS4 controller’s name in the list to pair it with your device. You might be prompted to confirm the pairing.
- Open BrickController2:a. Make sure you’ve set up your LEGO devices in the app.b. In the “Controllers” section, you should see the PS4 controller listed if it’s connected. If not, try disconnecting and reconnecting the PS4 controller via Bluetooth.
- Assign Controls:a. Once the PS4 controller is recognized in BrickController2, you can start assigning its buttons to control specific functions of your LEGO creation. This can include movement directions, rotations, or other actions.
- Play and Control:Once you’ve set up the controls, you can use your PS4 controller to play with and control your LEGO models. Ensure the LEGO devices and the controller are both connected and in range for optimal performance.
Further Reading
- Brickset – reviews of Lego sets
- Rebrickable – alternate builds
- MOCHub – “my own creation”
- RacingBrick on Youtube – fantastic Lego builds channel
Leave a Reply