vassar-feetech-servo-sdk


Namevassar-feetech-servo-sdk JSON
Version 1.4.0 PyPI version JSON
download
home_pageNone
SummaryVassar Robotics' Python SDK for Feetech servo control
upload_time2025-08-20 18:25:32
maintainerNone
docs_urlNone
authorNone
requires_python>=3.7
licenseMIT
keywords robotics servo feetech serial hardware sts hls control
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Vassar Feetech Servo SDK

[![PyPI version](https://badge.fury.io/py/vassar-feetech-servo-sdk.svg)](https://badge.fury.io/py/vassar-feetech-servo-sdk)
[![Stability: Stable](https://img.shields.io/badge/stability-stable-green.svg)](https://github.com/vassar-robotics/feetech-servo-sdk)

A comprehensive Python SDK for controlling Feetech servos (STS/HLS series).

## Features

- 🔌 **Auto-detection** of serial ports
- 🎯 **Support for STS and HLS servos** (HLS includes torque control)
- 📖 **Read positions** from single or multiple servos  
- âš¡ **Read voltage** from servos for monitoring power status
- 🎯 **Set middle position** - Calibrate servos to position 2048
- 💪 **Write torque targets** - HLS servos only with automatic mode switching
- 🔧 **Set operating modes** - Configure servo behavior (position/speed/torque/PWM)

## Installation

### From PyPI

```bash
pip install vassar-feetech-servo-sdk
```

### From Source

```bash
git clone https://github.com/vassar-robotics/feetech-servo-sdk.git
cd feetech-servo-sdk
pip install -e .
```

## Dependencies

- Python >= 3.7
- pyserial >= 3.5

Note: The `scservo_sdk` is bundled with this package, so no separate installation is needed.

## Quick Start

```python
from vassar_feetech_servo_sdk import ServoController

# Initialize controller with your servo configuration
servo_ids = [1, 2, 3, 4, 5, 6]
controller = ServoController(servo_ids=servo_ids, servo_type="sts")  # or "hls"
controller.connect()

# Read all configured servos
positions = controller.read_all_positions()
for motor_id, pos in positions.items():
    print(f"Motor {motor_id}: {pos} ({pos/4095*100:.1f}%)")

# Set servos to middle position
success = controller.set_middle_position()
if success:
    print("All servos calibrated to middle position!")

controller.disconnect()

# Using context manager
with ServoController([1, 2, 3], "sts") as controller:
    positions = controller.read_all_positions()
    print(positions)
```

### Changing Servo IDs

```python
from vassar_feetech_servo_sdk import ServoController

# Connect to a servo with current ID 1
controller = ServoController(servo_ids=[1], servo_type="sts")
controller.connect()

# Change its ID from 1 to 10
success = controller.set_motor_id(
    current_id=1,
    new_id=10,
    confirm=True  # Will ask for user confirmation
)

if success:
    print("ID changed! Power cycle the servo to apply.")
    
controller.disconnect()

# After power cycling, connect with new ID
controller = ServoController(servo_ids=[10], servo_type="sts")
controller.connect()
```

### Position Control

```python
from vassar_feetech_servo_sdk import ServoController

# Connect to servos (STS or HLS)
controller = ServoController(servo_ids=[1, 2, 3], servo_type="hls")
controller.connect()

# Write position values (automatically switches to position mode)
positions = {
    1: 1024,   # ~90° (position 0-4095)
    2: 2048,   # ~180° (middle position)
    3: 3072    # ~270°
}

results = controller.write_position(positions)  # Uses default speed=100
print(f"Position write results: {results}")

# Position control with speed and acceleration
results = controller.write_position(
    positions, 
    speed=60,        # 60 * 0.732 = ~44 RPM
    acceleration=50  # 50 * 8.7 = 435°/s²
)

# For HLS servos only: Position control with torque limit
if controller.servo_type == "hls":
    positions_with_limit = {1: 2048, 2: 2048}
    torque_limits = {1: 0.5, 2: 0.8}  # 50% and 80% torque limit
    
    results = controller.write_position(positions_with_limit, torque_limits, speed=40)
    print(f"Position write with torque limit: {results}")

controller.disconnect()
```

### Voltage Reading

```python
from vassar_feetech_servo_sdk import ServoController

# Connect to servos
with ServoController([1, 2, 3, 4, 5, 6], "sts") as controller:
    # Read voltage from single servo
    voltage = controller.read_voltage(1)
    print(f"Servo 1 voltage: {voltage:.1f}V")
    
    # Read voltages from all servos
    voltages = controller.read_voltages()
    for motor_id, v in sorted(voltages.items()):
        print(f"Servo {motor_id}: {v:.1f}V")
    
    # Detect leader/follower arms based on voltage
    if voltages[1] < 9.0:
        print("Servo 1 is on the leader arm (< 9V)")
    else:
        print("Servo 1 is on the follower arm (> 9V)")
```

### Torque Control (HLS Only)

```python
from vassar_feetech_servo_sdk import ServoController

# Connect to HLS servos
controller = ServoController(servo_ids=[1, 2, 3], servo_type="hls")
controller.connect()

# Write torque values (automatically switches to torque mode)
torque_values = {
    1: 0.04,   # 4% forward torque
    2: -0.06,  # 6% reverse torque  
    3: 0       # No torque
}

results = controller.write_torque(torque_values)
print(f"Torque write results: {results}")

# You can also manually set operating modes
controller.set_operating_mode(1, 0)  # Position mode
controller.set_operating_mode(2, 1)  # Speed mode
controller.set_operating_mode(3, 2)  # Torque mode

controller.disconnect()
```

### Advanced Usage

```python
# Initialize with specific configuration
controller = ServoController(
    servo_ids=[1, 2, 3, 4, 5, 6],
    servo_type="hls",  # 'sts' or 'hls'
    port="/dev/ttyUSB0",
    baudrate=1000000
)

# Error handling
from vassar_feetech_servo_sdk import ServoReaderError, PortNotFoundError

try:
    controller = ServoController([1, 2, 3], "sts")
    controller.connect()
    positions = controller.read_all_positions()
except PortNotFoundError:
    print("No servo port found!")
except ServoReaderError as e:
    print(f"Error: {e}")
```

## API Reference

### ServoController Class

#### Constructor

```python
ServoController(servo_ids, servo_type="sts", port=None, baudrate=1000000)
```

- `servo_ids`: List of servo IDs to control (e.g., [1, 2, 3, 4, 5, 6])
- `servo_type`: Type of servo - 'sts' or 'hls' (default: 'sts')
- `port`: Serial port path (auto-detect if None)
- `baudrate`: Communication speed (default: 1000000)

#### Methods

- `connect()`: Establish connection to servos
- `disconnect()`: Close connection
- `read_position(motor_id)`: Read single motor position
- `read_positions(motor_ids=None)`: Read multiple motor positions
- `read_all_positions()`: Read all configured servo positions
- `read_voltage(motor_id)`: Read voltage from single servo (returns float in volts)
- `read_voltages(motor_ids=None)`: Read voltages from multiple servos (returns dict of voltages)
- `set_middle_position(motor_ids=None)`: Calibrate servos to middle position (2048)
- `set_motor_id(current_id, new_id, confirm=True)`: Change a servo's ID (requires power cycle)
- `set_operating_mode(motor_id, mode)`: Set servo operating mode (0-3)
- `write_position(position_dict, torque_limit_dict=None, speed=100, acceleration=0)`: Write position values to servos (auto-switches to position mode)
- `write_torque(torque_dict)`: Write torque values to HLS servos (auto-switches to torque mode)
- `disable_all_servos()`: Disable torque on all servos (called automatically on cleanup)

**Note**: The controller automatically disables all servos when the object is destroyed or when using context manager (with statement).

### Utility Functions

- `find_servo_port()`: Auto-detect servo serial port

## Servo Types

- **STS**: Standard Feetech servos (default) - position and speed control
  - Middle position calibration uses torque=128 method
- **HLS**: High-end servos with additional torque control capabilities
  - Middle position calibration uses offset calibration (`reOfsCal`) method

## Troubleshooting

### Port Not Found

If auto-detection fails, specify the port manually:

```python
# Linux
controller = ServoController(servo_ids=[1,2,3], port="/dev/ttyUSB0")

# macOS
controller = ServoController(servo_ids=[1,2,3], port="/dev/tty.usbserial-XXXXX")

# Windows
controller = ServoController(servo_ids=[1,2,3], port="COM3")
```

### Permission Denied (Linux)

Option 1: Add your user to the dialout group (recommended):

```bash
sudo usermod -a -G dialout $USER
# Log out and back in for changes to take effect
```

Option 2: Grant permissions to the serial port (temporary):

```bash
sudo chmod 666 /dev/ttyUSB0
# Replace /dev/ttyUSB0 with your actual serial port
```

### Connection Failed

1. Check servo power supply
2. Verify baudrate matches servo configuration (default: 1000000)
3. Ensure proper wiring (TX/RX not swapped)

## Examples

The package includes several example scripts in the `examples/` directory:

- `basic_usage.py` - Simple example showing how to connect and read servo positions
- `continuous_reading.py` - Real-time monitoring with custom callbacks
- `servo_types.py` - Demonstrates differences between STS and HLS servos
- `set_middle_position.py` - Shows how to calibrate servos to middle position
- `position_control.py` - Comprehensive position control examples
- `torque_control.py` - HLS torque control examples
- `change_servo_id.py` - How to change servo IDs
- `read_voltage.py` - Reading voltage from servos
- `teleoperation.py` - Leader-follower arm control with voltage-based auto-detection

## Testing

Run the test suite:

```bash
./run_tests.sh  # Installs dev dependencies and runs tests with coverage
# or
pip install -r requirements-dev.txt
python -m pytest tests/ -v
```

## Acknowledgments

Built on top of the excellent `scservo_sdk` library for Feetech servo communication.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "vassar-feetech-servo-sdk",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": "Vassar Robotics <hello@vassarrobotics.com>",
    "keywords": "robotics, servo, feetech, serial, hardware, sts, hls, control",
    "author": null,
    "author_email": "Vassar Robotics <hello@vassarrobotics.com>",
    "download_url": "https://files.pythonhosted.org/packages/61/bc/f6df1bf5abf95ab471bfc892a2669d84a61ba47801eb222c6afab38d4c0a/vassar_feetech_servo_sdk-1.4.0.tar.gz",
    "platform": null,
    "description": "# Vassar Feetech Servo SDK\n\n[![PyPI version](https://badge.fury.io/py/vassar-feetech-servo-sdk.svg)](https://badge.fury.io/py/vassar-feetech-servo-sdk)\n[![Stability: Stable](https://img.shields.io/badge/stability-stable-green.svg)](https://github.com/vassar-robotics/feetech-servo-sdk)\n\nA comprehensive Python SDK for controlling Feetech servos (STS/HLS series).\n\n## Features\n\n- \ud83d\udd0c **Auto-detection** of serial ports\n- \ud83c\udfaf **Support for STS and HLS servos** (HLS includes torque control)\n- \ud83d\udcd6 **Read positions** from single or multiple servos  \n- \u26a1 **Read voltage** from servos for monitoring power status\n- \ud83c\udfaf **Set middle position** - Calibrate servos to position 2048\n- \ud83d\udcaa **Write torque targets** - HLS servos only with automatic mode switching\n- \ud83d\udd27 **Set operating modes** - Configure servo behavior (position/speed/torque/PWM)\n\n## Installation\n\n### From PyPI\n\n```bash\npip install vassar-feetech-servo-sdk\n```\n\n### From Source\n\n```bash\ngit clone https://github.com/vassar-robotics/feetech-servo-sdk.git\ncd feetech-servo-sdk\npip install -e .\n```\n\n## Dependencies\n\n- Python >= 3.7\n- pyserial >= 3.5\n\nNote: The `scservo_sdk` is bundled with this package, so no separate installation is needed.\n\n## Quick Start\n\n```python\nfrom vassar_feetech_servo_sdk import ServoController\n\n# Initialize controller with your servo configuration\nservo_ids = [1, 2, 3, 4, 5, 6]\ncontroller = ServoController(servo_ids=servo_ids, servo_type=\"sts\")  # or \"hls\"\ncontroller.connect()\n\n# Read all configured servos\npositions = controller.read_all_positions()\nfor motor_id, pos in positions.items():\n    print(f\"Motor {motor_id}: {pos} ({pos/4095*100:.1f}%)\")\n\n# Set servos to middle position\nsuccess = controller.set_middle_position()\nif success:\n    print(\"All servos calibrated to middle position!\")\n\ncontroller.disconnect()\n\n# Using context manager\nwith ServoController([1, 2, 3], \"sts\") as controller:\n    positions = controller.read_all_positions()\n    print(positions)\n```\n\n### Changing Servo IDs\n\n```python\nfrom vassar_feetech_servo_sdk import ServoController\n\n# Connect to a servo with current ID 1\ncontroller = ServoController(servo_ids=[1], servo_type=\"sts\")\ncontroller.connect()\n\n# Change its ID from 1 to 10\nsuccess = controller.set_motor_id(\n    current_id=1,\n    new_id=10,\n    confirm=True  # Will ask for user confirmation\n)\n\nif success:\n    print(\"ID changed! Power cycle the servo to apply.\")\n    \ncontroller.disconnect()\n\n# After power cycling, connect with new ID\ncontroller = ServoController(servo_ids=[10], servo_type=\"sts\")\ncontroller.connect()\n```\n\n### Position Control\n\n```python\nfrom vassar_feetech_servo_sdk import ServoController\n\n# Connect to servos (STS or HLS)\ncontroller = ServoController(servo_ids=[1, 2, 3], servo_type=\"hls\")\ncontroller.connect()\n\n# Write position values (automatically switches to position mode)\npositions = {\n    1: 1024,   # ~90\u00b0 (position 0-4095)\n    2: 2048,   # ~180\u00b0 (middle position)\n    3: 3072    # ~270\u00b0\n}\n\nresults = controller.write_position(positions)  # Uses default speed=100\nprint(f\"Position write results: {results}\")\n\n# Position control with speed and acceleration\nresults = controller.write_position(\n    positions, \n    speed=60,        # 60 * 0.732 = ~44 RPM\n    acceleration=50  # 50 * 8.7 = 435\u00b0/s\u00b2\n)\n\n# For HLS servos only: Position control with torque limit\nif controller.servo_type == \"hls\":\n    positions_with_limit = {1: 2048, 2: 2048}\n    torque_limits = {1: 0.5, 2: 0.8}  # 50% and 80% torque limit\n    \n    results = controller.write_position(positions_with_limit, torque_limits, speed=40)\n    print(f\"Position write with torque limit: {results}\")\n\ncontroller.disconnect()\n```\n\n### Voltage Reading\n\n```python\nfrom vassar_feetech_servo_sdk import ServoController\n\n# Connect to servos\nwith ServoController([1, 2, 3, 4, 5, 6], \"sts\") as controller:\n    # Read voltage from single servo\n    voltage = controller.read_voltage(1)\n    print(f\"Servo 1 voltage: {voltage:.1f}V\")\n    \n    # Read voltages from all servos\n    voltages = controller.read_voltages()\n    for motor_id, v in sorted(voltages.items()):\n        print(f\"Servo {motor_id}: {v:.1f}V\")\n    \n    # Detect leader/follower arms based on voltage\n    if voltages[1] < 9.0:\n        print(\"Servo 1 is on the leader arm (< 9V)\")\n    else:\n        print(\"Servo 1 is on the follower arm (> 9V)\")\n```\n\n### Torque Control (HLS Only)\n\n```python\nfrom vassar_feetech_servo_sdk import ServoController\n\n# Connect to HLS servos\ncontroller = ServoController(servo_ids=[1, 2, 3], servo_type=\"hls\")\ncontroller.connect()\n\n# Write torque values (automatically switches to torque mode)\ntorque_values = {\n    1: 0.04,   # 4% forward torque\n    2: -0.06,  # 6% reverse torque  \n    3: 0       # No torque\n}\n\nresults = controller.write_torque(torque_values)\nprint(f\"Torque write results: {results}\")\n\n# You can also manually set operating modes\ncontroller.set_operating_mode(1, 0)  # Position mode\ncontroller.set_operating_mode(2, 1)  # Speed mode\ncontroller.set_operating_mode(3, 2)  # Torque mode\n\ncontroller.disconnect()\n```\n\n### Advanced Usage\n\n```python\n# Initialize with specific configuration\ncontroller = ServoController(\n    servo_ids=[1, 2, 3, 4, 5, 6],\n    servo_type=\"hls\",  # 'sts' or 'hls'\n    port=\"/dev/ttyUSB0\",\n    baudrate=1000000\n)\n\n# Error handling\nfrom vassar_feetech_servo_sdk import ServoReaderError, PortNotFoundError\n\ntry:\n    controller = ServoController([1, 2, 3], \"sts\")\n    controller.connect()\n    positions = controller.read_all_positions()\nexcept PortNotFoundError:\n    print(\"No servo port found!\")\nexcept ServoReaderError as e:\n    print(f\"Error: {e}\")\n```\n\n## API Reference\n\n### ServoController Class\n\n#### Constructor\n\n```python\nServoController(servo_ids, servo_type=\"sts\", port=None, baudrate=1000000)\n```\n\n- `servo_ids`: List of servo IDs to control (e.g., [1, 2, 3, 4, 5, 6])\n- `servo_type`: Type of servo - 'sts' or 'hls' (default: 'sts')\n- `port`: Serial port path (auto-detect if None)\n- `baudrate`: Communication speed (default: 1000000)\n\n#### Methods\n\n- `connect()`: Establish connection to servos\n- `disconnect()`: Close connection\n- `read_position(motor_id)`: Read single motor position\n- `read_positions(motor_ids=None)`: Read multiple motor positions\n- `read_all_positions()`: Read all configured servo positions\n- `read_voltage(motor_id)`: Read voltage from single servo (returns float in volts)\n- `read_voltages(motor_ids=None)`: Read voltages from multiple servos (returns dict of voltages)\n- `set_middle_position(motor_ids=None)`: Calibrate servos to middle position (2048)\n- `set_motor_id(current_id, new_id, confirm=True)`: Change a servo's ID (requires power cycle)\n- `set_operating_mode(motor_id, mode)`: Set servo operating mode (0-3)\n- `write_position(position_dict, torque_limit_dict=None, speed=100, acceleration=0)`: Write position values to servos (auto-switches to position mode)\n- `write_torque(torque_dict)`: Write torque values to HLS servos (auto-switches to torque mode)\n- `disable_all_servos()`: Disable torque on all servos (called automatically on cleanup)\n\n**Note**: The controller automatically disables all servos when the object is destroyed or when using context manager (with statement).\n\n### Utility Functions\n\n- `find_servo_port()`: Auto-detect servo serial port\n\n## Servo Types\n\n- **STS**: Standard Feetech servos (default) - position and speed control\n  - Middle position calibration uses torque=128 method\n- **HLS**: High-end servos with additional torque control capabilities\n  - Middle position calibration uses offset calibration (`reOfsCal`) method\n\n## Troubleshooting\n\n### Port Not Found\n\nIf auto-detection fails, specify the port manually:\n\n```python\n# Linux\ncontroller = ServoController(servo_ids=[1,2,3], port=\"/dev/ttyUSB0\")\n\n# macOS\ncontroller = ServoController(servo_ids=[1,2,3], port=\"/dev/tty.usbserial-XXXXX\")\n\n# Windows\ncontroller = ServoController(servo_ids=[1,2,3], port=\"COM3\")\n```\n\n### Permission Denied (Linux)\n\nOption 1: Add your user to the dialout group (recommended):\n\n```bash\nsudo usermod -a -G dialout $USER\n# Log out and back in for changes to take effect\n```\n\nOption 2: Grant permissions to the serial port (temporary):\n\n```bash\nsudo chmod 666 /dev/ttyUSB0\n# Replace /dev/ttyUSB0 with your actual serial port\n```\n\n### Connection Failed\n\n1. Check servo power supply\n2. Verify baudrate matches servo configuration (default: 1000000)\n3. Ensure proper wiring (TX/RX not swapped)\n\n## Examples\n\nThe package includes several example scripts in the `examples/` directory:\n\n- `basic_usage.py` - Simple example showing how to connect and read servo positions\n- `continuous_reading.py` - Real-time monitoring with custom callbacks\n- `servo_types.py` - Demonstrates differences between STS and HLS servos\n- `set_middle_position.py` - Shows how to calibrate servos to middle position\n- `position_control.py` - Comprehensive position control examples\n- `torque_control.py` - HLS torque control examples\n- `change_servo_id.py` - How to change servo IDs\n- `read_voltage.py` - Reading voltage from servos\n- `teleoperation.py` - Leader-follower arm control with voltage-based auto-detection\n\n## Testing\n\nRun the test suite:\n\n```bash\n./run_tests.sh  # Installs dev dependencies and runs tests with coverage\n# or\npip install -r requirements-dev.txt\npython -m pytest tests/ -v\n```\n\n## Acknowledgments\n\nBuilt on top of the excellent `scservo_sdk` library for Feetech servo communication.\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Vassar Robotics' Python SDK for Feetech servo control",
    "version": "1.4.0",
    "project_urls": {
        "Homepage": "https://github.com/vassar-robotics/feetech-servo-sdk",
        "Issues": "https://github.com/vassar-robotics/feetech-servo-sdk/issues",
        "Repository": "https://github.com/vassar-robotics/feetech-servo-sdk"
    },
    "split_keywords": [
        "robotics",
        " servo",
        " feetech",
        " serial",
        " hardware",
        " sts",
        " hls",
        " control"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "f1b8e6c0cb0b73dc93534c4113384f3a9b360e56daf3afdcefe4342263e90070",
                "md5": "bec2ff61ee9ae52f0a3c4126910e6a58",
                "sha256": "111d255847a4ed2029df77aced913efd95d9649b49c3ac6901d62d9d07d93871"
            },
            "downloads": -1,
            "filename": "vassar_feetech_servo_sdk-1.4.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "bec2ff61ee9ae52f0a3c4126910e6a58",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7",
            "size": 32708,
            "upload_time": "2025-08-20T18:25:30",
            "upload_time_iso_8601": "2025-08-20T18:25:30.534288Z",
            "url": "https://files.pythonhosted.org/packages/f1/b8/e6c0cb0b73dc93534c4113384f3a9b360e56daf3afdcefe4342263e90070/vassar_feetech_servo_sdk-1.4.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "61bcf6df1bf5abf95ab471bfc892a2669d84a61ba47801eb222c6afab38d4c0a",
                "md5": "fa40b30db1fe0535033a53bf4e86b5e7",
                "sha256": "9f4778ba64c433846b55ce43b85ff458fb40233f62b9cbe6507ef9ebb5deedbd"
            },
            "downloads": -1,
            "filename": "vassar_feetech_servo_sdk-1.4.0.tar.gz",
            "has_sig": false,
            "md5_digest": "fa40b30db1fe0535033a53bf4e86b5e7",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 30529,
            "upload_time": "2025-08-20T18:25:32",
            "upload_time_iso_8601": "2025-08-20T18:25:32.634280Z",
            "url": "https://files.pythonhosted.org/packages/61/bc/f6df1bf5abf95ab471bfc892a2669d84a61ba47801eb222c6afab38d4c0a/vassar_feetech_servo_sdk-1.4.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-08-20 18:25:32",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "vassar-robotics",
    "github_project": "feetech-servo-sdk",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "vassar-feetech-servo-sdk"
}
        
Elapsed time: 1.04714s