Skip to content

youssefalboraei/sts3215-micropython

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

STS3215 MicroPython Library

MicroPython License: MIT

A MicroPython library for controlling STS3215 serial bus servos on Raspberry Pi Pico. Provides both high-level Servo class for ease of use and low-level register access for advanced control.

Features

  • 🎯 High-level API - Clean Servo class with intuitive methods
  • Synchronised movement - Move multiple servos simultaneously
  • 🔧 Fully configurable - Custom UART pins, baudrate, and timing
  • 📊 Status monitoring - Temperature, voltage, position, and movement detection
  • 🛡️ Safety features - Torque control, angle limits, automatic value clamping

Installation

Choose one of these installs:

Pico W (WiFi, no host tools)

# In the MicroPython REPL
import mip
mip.install("github:youssefalboraei/sts3215-micropython")

USB copy (no WiFi)

# Clone or download this repository
git clone https://github.com/youssefalboraei/sts3215-micropython.git

# Install mpremote (host tool for USB copy)
python3 -m pip install mpremote

# Copy the sts3215 folder to your Pico
mpremote fs cp -r sts3215 :

No mpremote? Use Thonny (or another uploader) to copy sts3215/ onto the Pico.

Requirements

  • Hardware: Raspberry Pi Pico (or Pico W)
  • Firmware: MicroPython 1.20 or later
  • Servos: STS3215 serial bus servos (Feetech/Waveshare compatible)
  • Host tools (optional): mpremote for USB copy/launch (python3 -m pip install mpremote)

No external Python dependencies on the Pico - uses only built-in MicroPython modules (machine, time).

Quick Start

from sts3215 import ServoController, Servo

# Initialize controller with your UART pins
controller = ServoController(tx_pin=0, rx_pin=1)

# Create servo instance
servo = Servo(controller, servo_id=1)

# Check connection
if servo.ping():
    print("Servo connected!")
    
    # Enable torque and move
    servo.enable()
    servo.move_to(2048, time_ms=500)  # Move to centre
    servo.wait_until_idle()
    
    # Check status
    print(servo.status())

API Reference

ServoController

Low-level communication layer. Configure once and share with multiple Servo instances.

controller = ServoController(
    tx_pin=0,           # GPIO pin for UART TX
    rx_pin=1,           # GPIO pin for UART RX
    uart_id=0,          # UART peripheral (0 or 1)
    baudrate=1_000_000, # Communication speed
    timeout=50,         # UART timeout in ms
    read_wait=100,      # Wait before reading response
)

Servo Class

High-level interface for individual servos.

servo = Servo(controller, servo_id=1)

# Movement
servo.move_to(position, time_ms=400, speed=2000)
servo.center(time_ms=500)
servo.wait_until_idle(timeout_ms=5000)

# Status
servo.get_position()      # Returns 0-4095
servo.is_moving()         # Returns True/False
servo.get_temperature()   # Returns °C
servo.get_voltage()       # Returns volts
servo.status()            # Returns complete status dict

# Torque
servo.enable()            # Enable torque
servo.disable()           # Disable torque
servo.set_torque(True)    # Explicit control

# Limits
servo.set_limits(cw=1000, ccw=3000)
servo.set_full_range()
servo.get_limits()        # Returns (cw, ccw)

Synchronised Movement

Move multiple servos together for coordinated motion:

from sts3215 import ServoController, Servo, sync_write_pos

controller = ServoController(tx_pin=0, rx_pin=1)

# Move servos 1, 2, 3 simultaneously
sync_write_pos(controller, [1, 2, 3], [1024, 2048, 3072], time_ms=500)

Wiring

Pico Pin Servo Wire Description
GPIO 0 TX (Yellow) Data out
GPIO 1 RX (White) Data in
VSYS VCC (Red) 6-8.4V power
GND GND (Black) Ground

⚠️ Note: STS3215 servos use half-duplex serial. TX and RX may be combined on a single data wire in some setups.

Examples

Robot Arm

from sts3215 import ServoController, Servo, sync_write_pos

controller = ServoController(tx_pin=0, rx_pin=1)

class RobotArm:
    def __init__(self):
        self.shoulder = Servo(controller, 1)
        self.elbow = Servo(controller, 2)
        self.gripper = Servo(controller, 3)
    
    def home(self):
        """Move all joints to centre position."""
        sync_write_pos(controller, [1, 2, 3], [2048, 2048, 2048], time_ms=1000)
        self.shoulder.wait_until_idle()
    
    def enable_all(self):
        for servo in [self.shoulder, self.elbow, self.gripper]:
            servo.enable()
    
    def disable_all(self):
        for servo in [self.shoulder, self.elbow, self.gripper]:
            servo.disable()

arm = RobotArm()
arm.enable_all()
arm.home()

Temperature Monitoring

def monitor_temperature(servos, max_temp=70):
    """Disable overheating servos."""
    for servo in servos:
        temp = servo.get_temperature()
        if temp and temp > max_temp:
            print(f"Servo {servo.id} overheating: {temp}°C")
            servo.disable()

Scanning for Servos

def scan_servos(controller, id_range=range(1, 20)):
    """Find all connected servos."""
    found = []
    for sid in id_range:
        if controller.ping(sid):
            found.append(sid)
            print(f"Found servo ID {sid}")
    return found

Running on Pico (USB, No Internet)

These commands could be used to run your files on Pico from terminal. Replace /dev/tty.usbmodemXXXX with your Pico port.

# Find the Pico port
mpremote connect list
# or on macOS
ls /dev/tty.usbmodem*

# Copy the library and example to the Pico (persistent)
mpremote connect /dev/tty.usbmodemXXXX fs cp -r sts3215 :
mpremote connect /dev/tty.usbmodemXXXX fs cp examples/robot_finger.py :main.py

# Run (boots and runs main.py)
mpremote connect /dev/tty.usbmodemXXXX reset

# Run without copying (one-off)
mpremote connect /dev/tty.usbmodemXXXX run examples/robot_finger.py

# Live dev without copying (mount local files)
mpremote connect /dev/tty.usbmodemXXXX mount . run examples/robot_finger.py

# Stop a running script
mpremote connect /dev/tty.usbmodemXXXX repl
# press Ctrl-C to interrupt

# Remove auto-run on boot
mpremote connect /dev/tty.usbmodemXXXX fs rm :main.py

Register Reference

Address Name Size Description
0x2A Goal 6B Position + time + speed
0x38 Position 2B Current position (0-4095)
0x3E Voltage 1B Input voltage (×0.1V)
0x3F Temperature 1B Temperature (°C)
0x34 Torque 1B 1=enabled, 0=disabled
0x06 CW Limit 2B Clockwise angle limit
0x08 CCW Limit 2B Counter-clockwise limit

For direct register access:

# Read register
value = controller.read_reg_value(servo_id=1, addr=0x38, nbytes=2)

# Write register
controller.write_reg(servo_id=1, addr=0x34, value=1, nbytes=1)

Troubleshooting

No response from servo

  1. Check wiring connections
  2. Verify servo ID with scan_servos()
  3. Ensure adequate power supply (6-8.4V)
  4. Try controller.ping(servo_id)

Erratic movement

  1. Check for loose connections
  2. Add time.sleep_ms(50) between rapid commands
  3. Reduce speed parameter

Wrong positions

  1. Register addresses may differ between servo models
  2. Use controller.read_reg_value() to scan registers
  3. Modify constants in sts3215/constants.py if needed

License

MIT License - see LICENSE for details.

Contributing

Contributions welcome! Please read CONTRIBUTING.md first.

About

A MicroPython library for controlling STS3215 serial bus servos on Raspberry Pi Pico.

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages