Python SDK for Henschel Robotics HDrive servo motors over EtherCAT
Project description
HDrive EtherCAT Python SDK
Control Henschel Robotics HDrive servo motors over EtherCAT from Python. No PLC required.
Web Interface
The SDK includes a full-featured browser-based GUI for motor control, monitoring, and testing.
pip install hdrive-etc
sudo hdrive-web
Then open http://localhost:8081 in your browser.
The web GUI provides:
- Real-time telemetry — live position, velocity, torque, temperature, and supply voltage
- Motor control — switch modes (torque / velocity / position), set targets, enable / disable
- Parameter tuning — adjust control bandwidth, damping, and inertia
- SDO browser — read and write any drive object
- Bus discovery — scan the EtherCAT bus and configure PDO mapping
- Built-in tests — step response, Bode plot (frequency response), inertia identification, and network latency
- Calibration — trigger encoder calibration from the browser
| Control | Step Response | EtherCAT Config |
|---|---|---|
Full guide with all screenshots:
docs/web-interface.md
sudo hdrive-web --adapter "\Device\NPF_{...}" --slave 0 --port 8081
sudo hdrive-web --list-adapters
Raspberry Pi / Linux: The web GUI saves its configuration (adapter, slave, PDO mapping) to
ethercat_config.json. When installed via pip, the default file is inside the package directory. Copy it to your working directory for easy editing:cp $(python3 -c "import hdrive_etc, os; print(os.path.join(os.path.dirname(hdrive_etc.__file__), '..', 'ethercat_config.json'))") . hdrive-web --pdo-config ./ethercat_config.json
Features
- Simple API —
motor.set_torque(200)and you're done - Web interface — built-in browser GUI for control, tuning, and testing
- Real-time EtherCAT — 5 ms processdata cycle via PySOEM
- CiA 402 state machine — automatic enable/disable transitions
- Thread-safe — send commands from any thread
- Context manager — automatic connect/disconnect with
withstatement - SDO read/write — read and write drive configuration objects
- Auto-recovery — background thread monitors slave health
Installation
pip install hdrive-etc
Or install from source:
git clone https://github.com/henschel-robotics/python-hdrive-etc.git
cd python-hdrive-etc
pip install .
For development (editable install):
pip install -e ".[dev]"
Quickstart
1. Configure the bus (one-time setup)
Start the web interface and use it to select your adapter, scan the bus, configure PDO assignments, and save:
sudo hdrive-web # Linux / Raspberry Pi
Open http://localhost:8081, go to the EtherCAT Config tab, click Scan Bus, then Save PDO Config. This writes ethercat_config.json with your adapter and PDO mapping.
2. Use the motor in your script
from hdrive_etc import HDriveETC, Mode
import time
# slave_index = position of the HDrive on the bus (check "Scan Bus" in the web GUI)
with HDriveETC(slave_index=0, pdo_config_path="ethercat_config.json") as motor:
motor.set_mode(Mode.TORQUE)
motor.set_torque(200) # 200 mNm
time.sleep(1)
print(f"Position: {motor.get_position()}")
print(f"Velocity: {motor.get_velocity():.1f} RPM")
motor.stop()
# Motor is automatically stopped and disconnected when leaving the 'with' block
API Reference
Connect
from hdrive_etc import HDriveETC
# Recommended: use ethercat_config.json from the web interface
with HDriveETC(slave_index=0, pdo_config_path="ethercat_config.json") as motor:
motor.set_torque(200)
# Motor is stopped and connection is closed automatically.
# Alternative: specify adapter directly (slave_index is always required)
with HDriveETC(adapter=r"\Device\NPF_{...}", slave_index=0) as motor:
motor.set_torque(200)
Torque Control
from hdrive_etc import Mode
# Set torque in milli-Newton-metres
motor.set_mode(Mode.TORQUE)
motor.set_torque(200) # 200 mNm
Velocity Control
# Set velocity
motor.set_mode(Mode.VELOCITY)
motor.set_velocity(300)
Position Control
# Set target position in encoder increments
motor.set_mode(Mode.POSITION)
motor.set_position(10000)
Stop
# Stop the motor (sets mode to 0)
motor.stop()
Read / Write SDO Objects
# Read a drive object (e.g. modes of operation display)
value = motor.read_sdo(0x6061, 0x00, 'b')
print(f"Current mode: {value}")
# Write a drive object
motor.write_sdo(0x6640, 0x01, 100) # Set torque bandwidth
Telemetry
# Get motor status snapshot
status = motor.get_status()
print(f"Position: {status['position']}")
print(f"Velocity: {status['velocity']}")
print(f"Torque: {status['torque']}")
# Individual readings
pos = motor.get_position() # encoder increments
vel = motor.get_velocity() # RPM
torque = motor.get_torque() # actual torque
state = motor.get_state_name() # CiA 402 state name
# Communication health
stats = motor.get_comm_stats()
print(f"Success rate: {stats['success_rate']:.1f}%")
print(f"Cycle time: {stats['cycle_time_actual_ms']:.2f} ms")
Error Handling
# Read error code from drive
error_code = motor.get_error_code()
print(motor.get_error_message(error_code))
# Clear error
motor.clear_error()
Control Tuning
# Configure control parameters
motor.configure_control_parameters(
rotor_inertia=1000,
damping=500,
torque_bw=100,
velocity_bw=200,
position_bw=300,
)
Control Modes
| Constant | Value | Description |
|---|---|---|
Mode.TORQUE |
4 | Cyclic synchronous torque (CST) |
Mode.VELOCITY |
-3 | Cyclic synchronous velocity / stepper |
Mode.POSITION |
8 | Cyclic synchronous position (CSP) |
Mode.PROFILE_POSITION |
1 | Profile position mode |
Mode.PROFILE_VELOCITY |
3 | Profile velocity mode |
Mode.CALIBRATION |
-99 | Manufacturer calibration mode |
Mode.STOP |
0 | Motor disabled |
CiA 402 States
The motor automatically transitions through these states on connect:
| State | Description |
|---|---|
not_ready |
Drive is initializing |
switch_on_disabled |
Drive is disabled |
ready_to_switch_on |
Drive is ready |
switched_on |
Drive is powered |
operation_enabled |
Drive accepts motion commands |
fault |
Drive is in fault state |
Examples
See the examples/ folder:
basic_control.py— Connect, apply torque, print telemetryvelocity_mode.py— Constant speed control with direction reversaltorque_mode.py— Torque ramp up/downposition_mode.py— Move to a sequence of positionsread_sdo.py— Read configuration objects via SDO
Requirements
- Python 3.8+
- PySOEM >= 1.1.0
- Npcap or WinPcap (Windows only)
- Important: During Npcap installation, check "Install Npcap in WinPcap API-compatible Mode"
- EtherCAT-compatible network adapter
- HDrive servo motor with EtherCAT interface
- For USB-to-Ethernet adapters, use one based on the ASIX AX88772 chipset (recommended for reliable real-time EtherCAT communication) e.g. TU2-ET100
License
MIT — see LICENSE for details.
Third-party notice: This package depends on PySOEM (MIT), which wraps SOEM (GPLv3 / Commercial). Users are responsible for complying with SOEM's license terms. For commercial use of SOEM, contact RT-Labs (sales@rt-labs.com).
Support
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file hdrive_etc-0.2.2.tar.gz.
File metadata
- Download URL: hdrive_etc-0.2.2.tar.gz
- Upload date:
- Size: 1.4 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a4e3b5f7cb579df6aa56294238fe91ccd2916e590595be7323f9759cd1a24e7b
|
|
| MD5 |
5219ebb727575d6dade2629ccb0f5cf8
|
|
| BLAKE2b-256 |
de2aba30ac5f0c4d1982f626d934057ebc8b0d75c8025f6310d70150881549df
|
File details
Details for the file hdrive_etc-0.2.2-py3-none-any.whl.
File metadata
- Download URL: hdrive_etc-0.2.2-py3-none-any.whl
- Upload date:
- Size: 1.4 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d7498d96827a1b0c89a752c269b6632108cbc788eee6df2bef7251e7f2646700
|
|
| MD5 |
72f81516623b423a3cef509f669642c5
|
|
| BLAKE2b-256 |
2b41ea0a999e1edf6116703f3c784c530d3500a90e28755bb4ddc21ca5349cca
|