Python UART
The ESP32 driver board exposes a USB-serial interface (via CP2102 or CH340 chip) for direct wired control. Serial commands use the same JSON protocol as WiFi and ESP-NOW.
Connection Setup
Section titled “Connection Setup”Hardware
Section titled “Hardware”Connect the ESP32 board to your computer via USB-C. The serial port appears as:
| OS | Typical Port |
|---|---|
| Linux | /dev/ttyUSB0 or /dev/ttyACM0 |
| macOS | /dev/cu.usbserial-* or /dev/cu.SLAB_USBtoUART |
| Windows | COM3, COM4, etc. |
Serial Parameters
Section titled “Serial Parameters”| Setting | Value |
|---|---|
| Baud rate | 115200 |
| Data bits | 8 |
| Parity | None |
| Stop bits | 1 |
| Flow control | None |
Python Setup
Section titled “Python Setup”Install pyserial:
pip install pyserialBasic Usage
Section titled “Basic Usage”import serialimport jsonimport time
# Open serial connectionser = serial.Serial("/dev/ttyUSB0", 115200, timeout=1)time.sleep(2) # Wait for ESP32 boot
def send_command(cmd: dict) -> str: """Send a JSON command and read the response.""" payload = json.dumps(cmd) + "\n" ser.write(payload.encode()) time.sleep(0.1) response = ser.read(ser.in_waiting).decode(errors="ignore") return response
# Move to home positionprint(send_command({"T": 100}))
# Get current positionprint(send_command({"T": 105}))
# Move to specific XYZprint(send_command({"T": 104, "x": 200, "y": 50, "z": 150, "t": 1.57, "spd": 0.25}))
# Close gripperprint(send_command({"T": 106, "cmd": 3.14, "spd": 0, "acc": 0}))
ser.close()Reading Responses
Section titled “Reading Responses”The arm sends JSON responses back over serial. For position feedback:
response = send_command({"T": 105})data = json.loads(response)print(f"Position: x={data['x']}, y={data['y']}, z={data['z']}")print(f"Torques: base={data['torB']}, shoulder={data['torS']}, elbow={data['torE']}")Continuous Control Loop
Section titled “Continuous Control Loop”For real-time control applications (e.g., joystick input, sensor-based reactions):
import serialimport jsonimport time
ser = serial.Serial("/dev/ttyUSB0", 115200, timeout=0.1)time.sleep(2)
try: while True: # Read current position ser.write(b'{"T":105}\n') time.sleep(0.05) response = ser.read(ser.in_waiting).decode(errors="ignore")
# Process and send next command cmd = {"T": 104, "x": 200, "y": 0, "z": 200, "t": 1.57, "spd": 0.5} ser.write((json.dumps(cmd) + "\n").encode())
time.sleep(0.05) # 20 Hz update rateexcept KeyboardInterrupt: # Emergency stop on exit ser.write(b'{"T":0}\n') ser.close()Debug Output Control
Section titled “Debug Output Control”Control how much the firmware prints to serial:
{"T":605,"cmd":0}| Value | Behavior |
|---|---|
| 0 | Suppress debug output |
| 1 | Print debug info (default) |
| 2 | Flow feedback mode |
Error Handling
Section titled “Error Handling”import serialimport json
def connect(port: str, retries: int = 3) -> serial.Serial: for attempt in range(retries): try: ser = serial.Serial(port, 115200, timeout=1) time.sleep(2) # Test connection ser.write(b'{"T":105}\n') time.sleep(0.2) if ser.in_waiting > 0: return ser except serial.SerialException: if attempt < retries - 1: time.sleep(1) raise ConnectionError(f"Cannot connect to {port}")Serial control reference from the Waveshare Python UART guide and firmware source.