This project involves building a remote-controlled vehicle using Lego components and the M5Stack Atom Motion module for motor control. The vehicle is operated via a joystick, with communication handled through the socket protocol, enabling real-time data exchange between the controller and the vehicle.
The idea came from a desire to combine creativity with embedded systems in a hands-on, modular way. Lego offered the perfect platform for rapid prototyping and physical flexibility, while the M5Stack ecosystem provided a compact and powerful solution for motor control and wireless communication.
Key Features- Modular structure using Lego, allowing for easy customization and reconfiguration.
- Wireless control via socket protocol, ensuring efficient and responsive communication.
- Motor management through the M5Stack Atom Motion, providing accurate and smooth movement.
The motivation behind this project was to explore how embedded systems can be applied in a playful yet technically rich environment. It’s a way to learn and demonstrate concepts like I2C communication, socket networking, and servo control.
How dos it work?The system architecture is divided into two main parts:
- Joystick Controller: Built around the Atom Lite, it reads user input via I2C and transmits commands to the Atom Motion using a socket connection.
- Vehicle Unit: The Atom Motion receives these commands and controls two servos—one with a 180-degree range for steering, and another with a 360-degree range for continuous rotation, enabling movement.
The Atom-Lite is a compact 24×24 mm development board from the M5Stack series, ideal for embedded smart hardware projects. Powered by the ESP32-PICO-D4, it features Wi-Fi. It supports fast programming via USB Type-C.
SetupTo work the Lego Remote-Control Vehicle, both Atom Lite modules need to be configured with the firmware and MicroPython code. One module is connected to the joystick, while the other works with the Atom Motion to control the vehicle.
Download the firmware: https://micropython.org/download/esp32/ and followed by:
# Install esptool
virtualenv venv
source venv/bin/activate
pip install esptool
# Erase device
esptool.py --port /dev/ttyUSB0 erase_flash
# Install firmware
esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 750000 write_flash -z 0x1000 esp32-20210902-v1.17.bin
This code sets up a joystick-controlled remote system using an Atom Lite device. It reads joystick input via I2C, connects to a Wi-Fi network, and sends the data to another device (Atom Motion with an Atom Lite) using UDP socket communication.
import machine
import struct
import network
import socket
import neopixel
import time
# setup led
np = neopixel.NeoPixel(machine.Pin(27), 1)
# setup joystick
sda_pin = machine.Pin(26)
scl_pin = machine.Pin(32)
i2c = machine.I2C(0, sda=sda_pin, scl=scl_pin, freq=400000)
devices = i2c.scan()
device = [i for i in devices if hex(i) == '0x52'][0]
# create access-point
def ap_connect():
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
print('connecting to network...')
wlan.connect('ATOM-MOTION')
while not wlan.isconnected():
pass
print('network config', wlan.ifconfig())
ap_connect()
# create client socket
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# green led
np[0] = (0,255,0)
np.write()
while True:
client.sendto(i2c.readfrom(device, 3), ('192.168.4.1', 12000))
time.sleep(1)
This code sets up the Atom Motion with server socket and access point, allowing the joystick to connect and transmit data. It includes functions to control speed and steering angle for vehicle navigation.
import machine
import struct
import network
import socket
import neopixel
import utime
# setup led
np = neopixel.NeoPixel(machine.Pin(27), 1)
# setup servo and motor
sda_pin = machine.Pin(25)
scl_pin = machine.Pin(21)
i2c = machine.I2C(0, sda=sda_pin, scl=scl_pin, freq=400000)
devices = i2c.scan()
device = [i for i in devices if hex(i) == "0x38"][0]
def set_speed(speed):
buf = bytearray(1)
struct.pack_into("b", buf, 0, speed)
i2c.writeto_mem(device, 0, buf)
def set_angle(angle):
buf = bytearray(1)
struct.pack_into("b", buf, 0, angle)
i2c.writeto_mem(device, 2, buf)
def set_direction(x):
if x > 200:
set_angle(65)
elif x < 50:
set_angle(115)
else:
set_angle(90)
def set_run(x):
if x > 200:
set_speed(127)
elif x < 50:
set_speed(0)
else:
set_speed(86)
# create access-point
ap = network.WLAN(network.AP_IF)
ap.config(essid="ATOM-MOTION")
ap.config(max_clients=10)
ap.active(True)
# create server socket
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(("", 12000))
while True:
try:
np[0] = (0, 255, 0)
np.write()
direction, address_client = server.recvfrom(2048)
out = struct.unpack("BBB", direction)
set_direction(out[0])
set_run(out[1])
print(out)
except:
pass
utime.sleep_ms(500)
I used the Thonny IDE to programming and upload the code in the ESP32 boards. Now, the Lego vehicle in action!
Comments