CI License: Apache 2.0 Hex version badge REUSE status

Elixir driver for Feetech TTL-based serial bus servos (STS/SCS series).

Features

  • Full protocol support for STS3215 and compatible servos
  • Position, velocity, and step operating modes
  • Synchronised multi-servo control via sync_read/sync_write
  • Buffered writes with action trigger for coordinated movement
  • Converted (radians) and raw (steps) APIs
  • Mix tasks for servo configuration and debugging

Installation

Add feetech to your list of dependencies in mix.exs:

def deps do
  [
    {:feetech, "~> 0.2.2"}
  ]
end

Hardware Requirements

  • Feetech STS or SCS series servo (e.g., STS3215)
  • Feetech URT-1 USB UART adapter (or compatible TTL serial adapter)
  • 6-7.4V power supply for servos

Quick Start

Controlling a Single Servo

# Connect to the servo bus
{:ok, pid} = Feetech.start_link(port: "/dev/ttyUSB0")

# Check servo is responding
{:ok, status} = Feetech.ping(pid, 1)

# Read current position in radians
{:ok, position} = Feetech.read(pid, 1, :present_position)

# Enable torque and move to 90 degrees (π/2 radians)
Feetech.write(pid, 1, :torque_enable, true)
Feetech.write(pid, 1, :goal_position, :math.pi() / 2)

# Read servo status
{:ok, voltage} = Feetech.read(pid, 1, :present_voltage)
{:ok, temperature} = Feetech.read(pid, 1, :present_temperature)
{:ok, load} = Feetech.read(pid, 1, :present_load)

# Disable torque when done
Feetech.write(pid, 1, :torque_enable, false)

Controlling Multiple Servos

{:ok, pid} = Feetech.start_link(port: "/dev/ttyUSB0")

# Write positions to multiple servos simultaneously
Feetech.sync_write(pid, :goal_position, [
  {1, 0.0},           # Servo 1 to 0 degrees
  {2, :math.pi() / 2}, # Servo 2 to 90 degrees
  {3, :math.pi()}      # Servo 3 to 180 degrees
])

# Read positions from multiple servos
{:ok, positions} = Feetech.sync_read(pid, [1, 2, 3], :present_position)

Synchronised Movement

For perfectly coordinated multi-servo motion, use buffered writes:

# Buffer commands (servos don't move yet)
Feetech.reg_write(pid, 1, :goal_position, :math.pi() / 4)
Feetech.reg_write(pid, 2, :goal_position, :math.pi() / 2)
Feetech.reg_write(pid, 3, :goal_position, 3 * :math.pi() / 4)

# Execute all buffered commands simultaneously
Feetech.action(pid)

Operating Modes

Servos support multiple operating modes:

# Unlock EEPROM to change mode
Feetech.write(pid, 1, :lock, false)

# Position mode (default) - servo holds position
Feetech.write(pid, 1, :mode, :position)

# Velocity mode - continuous rotation
Feetech.write(pid, 1, :mode, :velocity)
Feetech.write(pid, 1, :torque_enable, true)
Feetech.write_raw(pid, 1, :goal_speed, 500)  # Set rotation speed

# Step mode - multi-turn positioning
Feetech.write(pid, 1, :mode, :step)

# Lock EEPROM when done
Feetech.write(pid, 1, :lock, true)

Raw vs Converted Values

The driver supports both converted (user-friendly) and raw (register) values:

# Converted: position in radians, voltage in volts
{:ok, radians} = Feetech.read(pid, 1, :present_position)
{:ok, volts} = Feetech.read(pid, 1, :present_voltage)

# Raw: position in steps (0-4095), voltage in 0.1V units
{:ok, steps} = Feetech.read_raw(pid, 1, :present_position)
{:ok, decivolts} = Feetech.read_raw(pid, 1, :present_voltage)

Mix Tasks

Scan for Servos

# Scan for all connected servos
mix feetech.scan /dev/ttyUSB0

# Scan with verbose output
mix feetech.scan /dev/ttyUSB0 --verbose

# Scan specific ID range
mix feetech.scan /dev/ttyUSB0 --start-id 1 --end-id 10

Set Servo ID

# Change servo ID from 1 to 5
mix feetech.set_id /dev/ttyUSB0 5

# Change servo with current ID 3 to ID 7
mix feetech.set_id /dev/ttyUSB0 7 --current-id 3

# Use broadcast (only one servo connected)
mix feetech.set_id /dev/ttyUSB0 1 --broadcast

Debug Communication

# Low-level protocol debugging
mix feetech.debug /dev/ttyUSB0

# Try different baud rates
mix feetech.debug /dev/ttyUSB0 --baud-rate 115200

Available Registers

EEPROM (Persistent)

RegisterTypeDescription
:idintegerServo ID (1-253)
:baud_rateintegerCommunication baud rate
:modeatomOperating mode (:position, :velocity, :step)
:min_angle_limitfloatMinimum position limit (radians)
:max_angle_limitfloatMaximum position limit (radians)
:max_temperatureintegerTemperature limit (°C)
:max_torquefloatMaximum torque (0.0-1.0)
:position_p_gainintegerPosition P gain
:position_i_gainintegerPosition I gain
:position_d_gainintegerPosition D gain

SRAM (Volatile)

RegisterTypeDescription
:torque_enablebooleanEnable/disable torque
:goal_positionfloatTarget position (radians)
:goal_speedfloatTarget speed
:goal_timeintegerMovement time
:accelerationintegerAcceleration profile
:lockbooleanEEPROM write lock

Feedback (Read-only)

RegisterTypeDescription
:present_positionfloatCurrent position (radians)
:present_speedfloatCurrent speed
:present_loadfloatCurrent load (%)
:present_voltagefloatSupply voltage (V)
:present_temperatureintegerTemperature (°C)
:movingbooleanMovement in progress

Configuration Options

Feetech.start_link(
  port: "/dev/ttyUSB0",        # Serial port (required)
  baud_rate: 1_000_000,        # Baud rate (default: 1M)
  control_table: Feetech.ControlTable.STS3215,  # Servo type (default)
  timeout: 100,                # Response timeout in ms
  name: MyServo                # Optional GenServer name
)

Documentation

Full documentation is available at HexDocs.

Licence

Apache 2.0.