Python SDK - Revo2 Dexterous Hand
System Requirements
- Linux: Ubuntu 20.04/22.04 LTS (x86_64/aarch64), glibc ≥ 2.31
- macOS: 10.15+
- Windows: 10/11
- Python: 3.8 ~ 3.12 (Conda recommended)
Quick Start
Clone Repository
shell
# Using HTTPS
git clone https://github.com/BrainCoTech/stark-serialport-example.git
# Or using SSH
git clone git@github.com:BrainCoTech/stark-serialport-example.gitInstallation and Configuration
shell
# Navigate to Python directory
cd stark-serialport-example/python
# Activate Conda environment (recommended)
conda activate py310
# Install SDK dependencies
pip install -r requirements.txt --index-url https://pypi.org/simple/
# If unable to install via PyPI, manually download and install the .whl file
# Download from: https://pypi.org/project/bc-stark-sdk/#files
pip install --force-reinstall '/path/to/bc_stark_sdk-x.x.x-cp38-abi3-manylinux_2_31_x86_64.whl'
# Configure serial port device permissions
# In Linux systems, serial devices (e.g., /dev/ttyUSB0) typically belong to the dialout user group
# Add current user to dialout group
sudo usermod -aG dialout $USER
# Note: You need to log out and log back in for this to take effect
# Run examples
cd revo2
python revo2_ctrl.py # Single hand control
python revo2_touch.py # Tactile sensor (tactile version)
python revo2_ctrl_multi.py # Multi-hand control
python revo2_action_seq.py # Action sequence
python revo2_cfg.py # Device configuration
python revo2_dfu.py # Firmware upgrade
# CANFD communication protocol
cd revo2_canfd
python zqwl_canfd.py # Read device information and control device
python zqwl_canfd_dfu.py # Firmware OTA
# EtherCAT communication protocol
cd revo2_ethercat
python ec_sdo.py # SDO read/configure
python ec_pdo.py # PDO read joint status and control device
python ec_dfu.py # Firmware OTAshell
# Installation steps same as Ubuntu
# Note: macOS serial device names are typically /dev/tty.usbserial-xxx
# macOS does not support CANFD communication protocolshell
# If USB driver is not recognized, check serial port name in Device Manager
# Serial driver download: https://app.brainco.cn/universal/stark-serialport-prebuild/driver/CH340-drivers.zip
# Other installation steps same as Ubuntu
# Note: Windows serial device names are typically COM3, COM4, etc.
# Windows does not support EtherCAT communication protocolSample Code
SDK provides rich sample code covering different communication protocols and application scenarios.
Modbus-RTU Protocol
Single Hand/Dual Hand Control
- Single Hand Control Example
- Dual Hand Control (Dual Serial Port) - Use two serial ports to connect left and right hands separately
- Dual Hand Control (Single Serial Port) - Use a single serial port to connect left and right hands, default left hand ID=126, right hand ID=127
Tactile Sensor
Action Sequence (Gestures)
Firmware Upgrade
CANFD Protocol
Single Hand/Dual Hand Control
- Custom CANFD Device - C++ Example
- ZLG USBCANFD Device - C++ Example
- ZQWL USBCANFD Device (Windows) - C++ Example
- ZQWL USBCANFD Device - Python Example
Firmware Upgrade
- ZLG USBCANFD Device OTA - C++ Example
- ZQWL USBCANFD Device OTA - Python Example
EtherCAT Protocol
Command Line Tools
shell
# Check EtherCAT version
# Recommended: igH EtherCAT Master 1.6.x (latest stable version)
❯ ethercat version
IgH EtherCAT master 1.6.6 1.6.6-5-g64899015
# Note: If your EtherCAT version is 1.5.x, please contact technical support
# SDK is compiled for 1.6.x by default, 1.5.x may have compatibility issues
❯ ethercat version
IgH EtherCAT master 1.5.3 1.5.3
# Check master status
❯ systemctl status ethercat
# Check device
❯ ethercat slave
0 0:0 PREOP + BrainCo-Revo2Slave
# SDO - Read firmware version
❯ ethercat upload -t string -p 0 0x8000 0x11 # Wrist FW version
0.0.4
❯ ethercat upload -t string -p 0 0x8000 0x13 # CTRL FW version
0.0.4
# PDO - Read joint position
❯ ethercat upload -t raw -p 0 0x6000 0x01 | xxd -r -p | od -An -t u2 --endian=little -w2
# Set permissions for Python program
sudo setcap cap_sys_nice,cap_net_raw=eip /path/to/miniconda3/envs/py310/bin/python3.10About EtherCAT Version
- Recommended Version: igH EtherCAT Master 1.6.x (latest stable)
- SDK Compatibility: SDK is compiled for 1.6.x by default
- Version 1.5.x: If you're using 1.5.x, please contact technical support for compatible version
- Pure C++ Implementation: Recommended Pure C++ EtherCAT Examples (SDK-independent, uses EtherCAT library directly)
PDO Communication
SDO Communication
Firmware Upgrade
API Reference
Connection Management
Modbus-RTU Connection
py
import libstark
from libstark import Baudrate, DeviceContext, DetectedDevice
# ================================
# Recommended: Auto-Detect and Initialize (Supports All Protocols)
# ================================
async def auto_detect_and_connect(scan_all: bool = False, port: str = None, protocol: str = None):
"""
Auto-detect Stark devices across all protocols (Recommended)
This is the recommended way to connect to devices. It automatically:
- Scans for devices across CANFD, CAN 2.0, and Modbus protocols
- Initializes the appropriate transport (ZQWL CAN/CANFD or Modbus)
- Sets hardware type from detected device info
Args:
scan_all: If True, scan for all devices. If False, stop at first found.
port: Optional port name to scan. If None, scans all available ports.
protocol: Optional protocol to use ("CanFd", "Can", "Modbus"). If None, tries all.
Returns:
tuple: (DeviceContext, DetectedDevice) or (None, None) if not found
Scan Priority Order:
1. ZQWL CANFD (Revo2: IDs 0x7E, 0x7F)
2. ZQWL CAN 2.0 (Revo1/Revo2: IDs 1, 2)
3. Modbus/RS485 (IDs 0x7E, 0x7F, 1, 2, 10)
Example:
# Simple auto-detect (recommended)
ctx, device = await auto_detect_and_connect()
if ctx:
slave_id = device.slave_id
info = await ctx.get_device_info(slave_id)
print(f"Connected: {info.serial_number}")
# ... use ctx ...
await libstark.close_device_handler(ctx)
# Scan all devices
ctx, device = await auto_detect_and_connect(scan_all=True)
# Scan specific protocol
ctx, device = await auto_detect_and_connect(protocol="CanFd")
"""
try:
devices = await libstark.auto_detect(scan_all, port, protocol)
if not devices:
print("No devices found")
return None, None
device = devices[0]
print(f"Detected: {device.protocol_type.name} on {device.port_name}, ID: {device.slave_id}")
ctx = await libstark.init_from_detected(device)
print(f"Connected successfully")
return ctx, device
except Exception as e:
print(f"Auto-detect failed: {e}")
return None, None
async def auto_detect_all_devices(port: str = None, protocol: str = None):
"""
Scan and list all available Stark devices
Args:
port: Optional port name to scan
protocol: Optional protocol filter ("CanFd", "Can", "Modbus")
Returns:
List[DetectedDevice]: List of detected devices
Example:
devices = await auto_detect_all_devices()
for dev in devices:
print(f"Found: {dev.protocol_type.name} @ {dev.port_name}, ID: {dev.slave_id}")
if dev.serial_number:
print(f" SN: {dev.serial_number}, FW: {dev.firmware_version}")
"""
try:
devices = await libstark.auto_detect(scan_all=True, port=port, protocol=protocol)
print(f"Found {len(devices)} device(s)")
return devices
except Exception as e:
print(f"Scan failed: {e}")
return []
# ================================
# Modbus Serial Connection (for Revo1/Revo2)
# ================================
async def connect_modbus(port_name: str = "/dev/ttyUSB0", baudrate: Baudrate = Baudrate.Baud115200) -> DeviceContext:
"""
Connect to device via Modbus protocol
Args:
port_name: Serial port name
- Linux: "/dev/ttyUSB0", "/dev/ttyACM0"
- Windows: "COM3", "COM4"
- macOS: "/dev/tty.usbserial-xxx"
baudrate: Serial port baud rate
- Revo1 default: Baudrate.Baud115200
- Revo2 default: Baudrate.Baud460800
- Other options: Baud57600, Baud1Mbps, Baud2Mbps, Baud5Mbps
Returns:
DeviceContext: Device connection object
Example:
device = await connect_modbus("/dev/ttyUSB0", Baudrate.Baud460800)
device_info = await device.get_device_info(slave_id=1)
print(f"Connected device: {device_info.sku_type}")
"""
try:
device = await libstark.modbus_open(port_name, baudrate)
print(f"Modbus connection successful: {port_name} @ {baudrate.name}")
return device
except Exception as e:
print(f"Modbus connection failed: {e}")
raise
# ================================
# Device Connection Utilities
# ================================
def list_available_ports():
"""
List available serial ports on the system
Returns:
list: List of available serial ports
Example:
ports = list_available_ports()
print("Available ports:")
for port in ports:
print(f" {port}")
"""
try:
ports = libstark.list_available_ports()
print(f"Found {len(ports)} available ports")
return ports
except Exception as e:
print(f"Failed to get port list: {e}")
return []
def list_zqwl_devices():
"""
List all ZQWL USB CAN/CANFD devices
Returns:
List[ZqwlDeviceInfo]: List of ZQWL devices with:
- port_name: Serial port name
- vid/pid: USB VID/PID
- supports_canfd: Whether CANFD is supported
- channel_count: Number of channels
Example:
devices = list_zqwl_devices()
for dev in devices:
print(f"ZQWL: {dev.port_name}, CANFD: {dev.supports_canfd}")
"""
try:
devices = libstark.list_zqwl_devices()
print(f"Found {len(devices)} ZQWL device(s)")
return devices
except Exception as e:
print(f"Failed to list ZQWL devices: {e}")
return []
# ================================
# Legacy Auto-Detect (Modbus Only)
# ================================
async def auto_detect_device(port_name: str = None, quick: bool = True):
"""
Auto-detect device protocol and connection parameters
@deprecated Use auto_detect_and_connect() instead for multi-protocol support.
Args:
port_name: Specify port name, None for auto-search
quick: Whether to use quick detection
Returns:
tuple: (protocol, port_name, baudrate, slave_id) or None
Important:
- **ONLY supports Modbus-RTU protocol detection**
- For CAN/CANFD support, use auto_detect_and_connect() instead
"""
try:
(protocol, port_name, baudrate, slave_id) = await libstark.auto_detect_device(port_name, quick)
print(f"Detected: {protocol}, {port_name}, {baudrate}, {slave_id}")
return (protocol, port_name, baudrate, slave_id)
except Exception as e:
print(f"Device auto-detection failed: {e}")
return None
async def auto_detect_modbus_revo1(port_name: str = None, quick: bool = True):
"""
Auto-detect Revo1 device Modbus-RTU connection parameters
@deprecated Use auto_detect_and_connect() instead.
"""
try:
(protocol, port_name, baudrate, slave_id) = await libstark.auto_detect_modbus_revo1(port_name, quick)
print(f"Detected Revo1: {protocol}, {port_name}, {baudrate}, {slave_id}")
return (protocol, port_name, baudrate, slave_id)
except Exception as e:
print(f"Revo1 device auto-detection failed: {e}")
return None
async def auto_detect_modbus_revo2(port_name: str = None, quick: bool = True):
"""
Auto-detect Revo2 device Modbus-RTU connection parameters
@deprecated Use auto_detect_and_connect() instead.
"""
try:
(protocol, port_name, baudrate, slave_id) = await libstark.auto_detect_modbus_revo2(port_name, quick)
print(f"Detected Revo2: {protocol}, {port_name}, {baudrate}, {slave_id}")
return (protocol, port_name, baudrate, slave_id)
except Exception as e:
print(f"Revo2 device auto-detection failed: {e}")
return None
# ================================
# Close Connection
# ================================
async def close_device(device: DeviceContext):
"""
Close device connection (recommended for all protocols)
This function handles cleanup for any protocol type:
- For CAN/CANFD: Closes ZQWL adapter automatically
- For Modbus: Closes serial port
Args:
device: Device connection object
Example:
await libstark.close_device_handler(device)
print("Device connection closed")
"""
await libstark.close_device_handler(device)
def close_modbus(device: DeviceContext):
"""
Close Modbus connection (legacy)
@deprecated Use close_device() instead for unified cleanup.
"""
libstark.modbus_close(device)CANFD Connection
py
import libstark
from libstark import DeviceContext, StarkProtocolType
# ================================
# CANFD Connection (for Revo2, DIP switch below wrist, switch to CANFD side)
# ================================
# ================================
# Recommended: Use auto_detect + init_from_detected
# ================================
async def connect_canfd_auto():
"""
Connect to CANFD device using auto-detection (Recommended)
This is the simplest way to connect to a CANFD device.
The SDK automatically:
- Detects ZQWL CANFD adapter
- Initializes the adapter with correct baudrates
- Sets up the device handler
Returns:
tuple: (DeviceContext, slave_id) or (None, None) if not found
Example:
ctx, slave_id = await connect_canfd_auto()
if ctx:
info = await ctx.get_device_info(slave_id)
print(f"Connected: {info.serial_number}")
# ... use ctx ...
await libstark.close_device_handler(ctx)
"""
try:
# Auto-detect CANFD devices only
devices = await libstark.auto_detect(scan_all=False, protocol="CanFd")
if not devices:
print("No CANFD devices found")
return None, None
device = devices[0]
print(f"Found CANFD device on {device.port_name}, ID: {device.slave_id}")
# Initialize from detected device (handles ZQWL setup automatically)
ctx = await libstark.init_from_detected(device)
return ctx, device.slave_id
except Exception as e:
print(f"CANFD connection failed: {e}")
return None, None
# ================================
# Manual ZQWL CANFD Initialization
# ================================
def list_zqwl_devices():
"""
List all ZQWL USB CAN/CANFD devices
Returns:
List[ZqwlDeviceInfo]: List of devices with:
- port_name: Serial port name
- vid/pid: USB VID/PID
- supports_canfd: Whether CANFD is supported
- channel_count: Number of channels
Example:
devices = list_zqwl_devices()
for dev in devices:
print(f"Port: {dev.port_name}, CANFD: {dev.supports_canfd}")
"""
return libstark.list_zqwl_devices()
def init_zqwl_canfd(port_name: str, arb_baudrate: int = 1000000, data_baudrate: int = 5000000):
"""
Initialize ZQWL CANFD device manually
Args:
port_name: Serial port name (e.g., "/dev/cu.usbmodem*" on macOS, "COM3" on Windows)
arb_baudrate: Arbitration baudrate in bps (default 1Mbps)
data_baudrate: Data baudrate in bps (default 5Mbps)
Note:
- This is a low-level API
- Recommend using auto_detect + init_from_detected instead
- Call close_zqwl() when done
Example:
# Manual initialization
libstark.init_zqwl_canfd("/dev/cu.usbmodem12345", 1000000, 5000000)
ctx = libstark.init_device_handler(StarkProtocolType.CanFd, master_id=0)
# ... use ctx ...
libstark.close_zqwl()
"""
libstark.init_zqwl_canfd(port_name, arb_baudrate, data_baudrate)
def init_zqwl_can(port_name: str, arb_baudrate: int = 1000000):
"""
Initialize ZQWL CAN 2.0 device manually
Args:
port_name: Serial port name
arb_baudrate: Arbitration baudrate in bps (default 1Mbps)
Note:
- For Revo1 devices using CAN 2.0 protocol
- This is a low-level API
- Recommend using auto_detect + init_from_detected instead
Example:
libstark.init_zqwl_can("/dev/cu.usbmodem12345", 1000000)
ctx = libstark.init_device_handler(StarkProtocolType.Can, master_id=0)
"""
libstark.init_zqwl_can(port_name, arb_baudrate)
def close_zqwl():
"""
Close ZQWL CAN/CANFD device
Note:
- If using init_from_detected(), use close_device_handler() instead
- close_device_handler() automatically handles ZQWL cleanup
"""
libstark.close_zqwl()
def connect_canfd_manual(master_id: int = 0) -> DeviceContext:
"""
Create CANFD device handler manually
Args:
master_id: CANFD master ID (usually 0)
Returns:
DeviceContext: Device connection object
Note:
- Must call init_zqwl_canfd() first
- Or set custom CAN callbacks for non-ZQWL adapters
Example:
# For ZQWL adapter
libstark.init_zqwl_canfd(port_name, 1000000, 5000000)
ctx = connect_canfd_manual(master_id=0)
# For custom adapter (ZLG, etc.)
libstark.set_can_tx_callback(my_send_func)
libstark.set_can_rx_callback(my_recv_func)
ctx = connect_canfd_manual(master_id=0)
"""
return libstark.init_device_handler(StarkProtocolType.CanFd, master_id)
# ================================
# Custom CAN Adapter Callbacks (for ZLG, etc.)
# ================================
def setup_custom_can_callbacks(tx_callback, rx_callback):
"""
Set custom CAN/CANFD communication callbacks
Use this for non-ZQWL adapters (e.g., ZLG USBCANFD)
Args:
tx_callback: Function to send CAN frames
Signature: (slave_id: int, can_id: int, data: bytes) -> int
Returns 0 on success, non-zero on failure
rx_callback: Function to receive CAN frames
Signature: (slave_id: int, expected_can_id: int, expected_frames: int)
-> tuple[int, bytes, int] # (can_id, data, data_len)
Returns received CAN ID, data, and data length
Example:
def my_can_send(slave_id, can_id, data):
# Send via your CAN adapter
zlg_adapter.send(can_id, data)
return 0
def my_can_recv(slave_id, expected_can_id, expected_frames):
# Receive from your CAN adapter
can_id, data = zlg_adapter.recv(timeout=100)
return can_id, data, len(data)
setup_custom_can_callbacks(my_can_send, my_can_recv)
ctx = libstark.init_device_handler(StarkProtocolType.CanFd, 0)
"""
libstark.set_can_tx_callback(tx_callback)
libstark.set_can_rx_callback(rx_callback)EtherCAT Connection
py
import libstark
from libstark import DeviceContext, StarkProtocolType, EtherCATFoeType
# ================================
# EtherCAT Connection (Industrial Real-time Control)
# ================================
# Initialize EtherCAT device handler
ctx = libstark.init_device_handler(StarkProtocolType.EtherCAT, master_id=0)
# Reserve the EtherCAT master for exclusive use
await ctx.ec_reserve_master()
# Configure SDO for slave device
await ctx.ec_setup_sdo(slave_id=1)
# Start cyclic PDO loop
await ctx.ec_start_loop(
slave_positions=[1], # List of slave positions
dc_assign_activate=0x0300, # DC flags (0x0000 = DC disabled)
sync0_cycle_time=1000000, # SYNC0 cycle time in ns (1ms)
sync0_shift_time=0, # SYNC0 phase shift in ns
sync1_cycle_time=0, # SYNC1 cycle time in ns
sync1_shift_time=0 # SYNC1 phase shift in ns
)
# ... control operations ...
# Stop cyclic loop
await ctx.ec_stop_loop()
# Close connection
await libstark.close_device_handler(ctx)
# ================================
# EtherCAT DFU (Firmware Upgrade)
# ================================
# Upgrade wrist firmware via FoE protocol
await ctx.ec_start_dfu(
slave_pos=1,
dfu_type=EtherCATFoeType.Wrist,
file_path="revo2_ec_wrist_v1.0.0.bin"
)
# Upgrade control board firmware
await ctx.ec_start_dfu(
slave_pos=1,
dfu_type=EtherCATFoeType.Control,
file_path="revo2_ec_ctrl_v1.0.0.bin"
)
# ================================
# Notes
# ================================
# - EtherCAT is only supported on Linux with IgH EtherCAT Master
# - Requires root privileges or proper udev rules
# - Only applicable to Revo2 EtherCAT version devices
# - Provides deterministic real-time communicationDevice Information and Settings
Device Information
py
import libstark
from libstark import DeviceContext, DeviceInfo, StarkHardwareType
# ================================
# Device Information Interface
# ================================
async def get_device_info(ctx: DeviceContext, slave_id: int) -> DeviceInfo:
"""
Get device information
IMPORTANT: This method should be called after connecting to the device.
It automatically sets the hardware type internally, which is required
for touch-related APIs to work correctly.
Args:
ctx: Device context object
slave_id: Device slave ID
Returns:
DeviceInfo: Device information object containing:
- sku_type: SkuType - Device SKU type (left/right hand)
- hardware_type: StarkHardwareType - Hardware type
- serial_number: str - Serial number
- firmware_version: str - Firmware version
- description: str - Device description
Example:
device_info = await ctx.get_device_info(slave_id=1)
print(f"SKU Type: {device_info.sku_type}")
print(f"Hardware Type: {device_info.hardware_type}")
print(f"Serial Number: {device_info.serial_number}")
print(f"Firmware Version: {device_info.firmware_version}")
# Check device capabilities using DeviceInfo methods
if device_info.is_touch():
print("This device has touch sensors")
if device_info.uses_revo1_motor_api():
print("Uses Revo1 Motor API")
elif device_info.uses_revo2_motor_api():
print("Uses Revo2 Motor API")
"""
return await ctx.get_device_info(slave_id)
# ================================
# Device Type Helper Methods
# ================================
def check_device_capabilities(ctx: DeviceContext, slave_id: int):
"""
Check device capabilities using DeviceContext helper methods
These methods check the hardware type that was set when get_device_info()
was called, or when using init_from_detected().
Example:
# Check if device has touch sensors
if ctx.is_touch_hand(slave_id):
print("Device has touch sensors")
# Check touch sensor type
if ctx.uses_pressure_touch_api(slave_id):
print("Uses Pressure/Modulus touch sensors")
# Use get_modulus_touch_summary() or get_modulus_touch_data()
else:
print("Uses Capacitive touch sensors")
# Use get_touch_sensor_status()
# Check motor API version
if ctx.uses_revo1_motor_api(slave_id):
print("Uses Revo1 Motor API (5 fingers)")
# Revo1 Basic/Touch
elif ctx.uses_revo2_motor_api(slave_id):
print("Uses Revo2 Motor API (6 joints)")
# Revo1 Advanced/AdvancedTouch and all Revo2
"""
# Touch sensor check
is_touch = ctx.is_touch_hand(slave_id)
uses_pressure = ctx.uses_pressure_touch_api(slave_id)
# Motor API check
uses_revo1_motor = ctx.uses_revo1_motor_api(slave_id)
uses_revo2_motor = ctx.uses_revo2_motor_api(slave_id)
return {
"is_touch": is_touch,
"uses_pressure_touch": uses_pressure,
"uses_revo1_motor_api": uses_revo1_motor,
"uses_revo2_motor_api": uses_revo2_motor
}
async def get_device_serial_number(ctx: DeviceContext, slave_id: int):
"""
Get device serial number
Args:
ctx: Device context object
slave_id: Device slave ID
Returns:
str: Device serial number
Example:
sn = await ctx.get_device_sn(slave_id=1)
print(f"Serial Number: {sn}")
"""
return await ctx.get_device_sn(slave_id)
async def get_firmware_version(ctx: DeviceContext, slave_id: int):
"""
Get firmware version
Args:
ctx: Device context object
slave_id: Device slave ID
Returns:
str: Firmware version
Example:
version = await ctx.get_device_fw_version(slave_id=1)
print(f"Firmware Version: {version}")
"""
return await ctx.get_device_fw_version(slave_id)
async def get_sku_type(ctx: DeviceContext, slave_id: int):
"""
Get device SKU type (hand side: left/right)
Args:
ctx: Device context object
slave_id: Device slave ID
Returns:
SkuType: Device SKU type enumeration
Example:
sku = await ctx.get_sku_type(slave_id=1)
print(f"SKU Type: {sku}")
"""
return await ctx.get_sku_type(slave_id)
# ================================
# Device Settings Interface
# ================================
async def get_finger_unit_mode(ctx: DeviceContext, slave_id: int):
"""
Get finger control unit mode (Revo2 only)
Args:
ctx: Device context object
slave_id: Device slave ID
Returns:
FingerUnitMode: Unit mode enumeration
- Normalized: Normalized mode (0-1000)
- Physical: Physical mode (actual units like degrees, mA)
Example:
mode = await ctx.get_finger_unit_mode(slave_id=1)
print(f"Unit mode: {mode}")
"""
return await ctx.get_finger_unit_mode(slave_id)
async def set_finger_unit_mode(ctx: DeviceContext, slave_id: int, mode):
"""
Set finger control unit mode (Revo2 only)
Args:
ctx: Device context object
slave_id: Device slave ID
mode: libstark.FingerUnitMode enumeration value
Example:
# Set to normalized mode (0-1000)
await ctx.set_finger_unit_mode(slave_id=1, mode=libstark.FingerUnitMode.Normalized)
# Set to physical mode (degrees, mA, etc.)
await ctx.set_finger_unit_mode(slave_id=1, mode=libstark.FingerUnitMode.Physical)
"""
await ctx.set_finger_unit_mode(slave_id, mode)
async def get_finger_settings(ctx: DeviceContext, slave_id: int, finger_id):
"""
Get single finger settings (Revo2 only)
Args:
ctx: Device context object
slave_id: Device slave ID
finger_id: libstark.FingerId enumeration value
Returns:
MotorSettings: Motor settings object containing:
- min_position: int - Minimum position
- max_position: int - Maximum position
- max_speed: int - Maximum speed
- max_current: int - Maximum current
- description: str - Settings description
Example:
settings = await ctx.get_finger_settings(slave_id=1, finger_id=libstark.FingerId.Index)
print(f"Min position: {settings.min_position}")
print(f"Max position: {settings.max_position}")
print(f"Max speed: {settings.max_speed}")
print(f"Max current: {settings.max_current}")
"""
return await ctx.get_finger_settings(slave_id, finger_id)
async def set_finger_settings(ctx: DeviceContext, slave_id: int, finger_id, settings):
"""
Set single finger settings (Revo2 only)
Args:
ctx: Device context object
slave_id: Device slave ID
finger_id: libstark.FingerId enumeration value
settings: MotorSettings object
Example:
# Get current settings
settings = await ctx.get_finger_settings(slave_id=1, finger_id=libstark.FingerId.Index)
# Modify settings
settings.max_speed = 130
settings.max_current = 1000
# Apply new settings
await ctx.set_finger_settings(slave_id=1, finger_id=libstark.FingerId.Index, settings=settings)
"""
await ctx.set_finger_settings(slave_id, finger_id, settings)
async def get_all_finger_settings(ctx: DeviceContext, slave_id: int):
"""
Get all finger settings (Revo2 only)
Args:
ctx: Device context object
slave_id: Device slave ID
Returns:
List[MotorSettings]: List of motor settings for all fingers
Example:
all_settings = await ctx.get_all_finger_settings(slave_id=1)
for i, settings in enumerate(all_settings):
print(f"Finger {i}: {settings.description}")
"""
return await ctx.get_all_finger_settings(slave_id)
async def get_finger_protected_current(ctx: DeviceContext, slave_id: int, finger_id):
"""
Get single finger protection current (Revo2 only)
Args:
ctx: Device context object
slave_id: Device slave ID
finger_id: libstark.FingerId enumeration value
Returns:
int: Protection current value
Example:
current = await ctx.get_finger_protected_current(slave_id=1, finger_id=libstark.FingerId.Thumb)
print(f"Protection current: {current}")
"""
return await ctx.get_finger_protected_current(slave_id, finger_id)
async def set_finger_protected_current(ctx: DeviceContext, slave_id: int, finger_id, current: int):
"""
Set single finger protection current (Revo2 only)
Args:
ctx: Device context object
slave_id: Device slave ID
finger_id: libstark.FingerId enumeration value
current: Protection current value
Example:
await ctx.set_finger_protected_current(slave_id=1, finger_id=libstark.FingerId.Thumb, current=500)
"""
await ctx.set_finger_protected_current(slave_id, finger_id, current)
async def get_finger_protected_currents(ctx: DeviceContext, slave_id: int):
"""
Get all finger protection currents (Revo2 only)
Args:
ctx: Device context object
slave_id: Device slave ID
Returns:
List[int]: List of protection current values for all fingers
Example:
currents = await ctx.get_finger_protected_currents(slave_id=1)
print(f"Protection currents: {currents}")
"""
return await ctx.get_finger_protected_currents(slave_id)
async def set_finger_protected_currents(ctx: DeviceContext, slave_id: int, currents):
"""
Set all finger protection currents (Revo2 only)
Args:
ctx: Device context object
slave_id: Device slave ID
currents: List of protection current values
Example:
await ctx.set_finger_protected_currents(slave_id=1, protected_currents=[600] * 6)
"""
await ctx.set_finger_protected_currents(slave_id, currents)
# ================================
# LED, Buzzer, Vibration Control
# ================================
async def get_led_enabled(ctx: DeviceContext, slave_id: int):
"""Get LED enabled status"""
return await ctx.get_led_enabled(slave_id)
async def set_led_enabled(ctx: DeviceContext, slave_id: int, enabled: bool):
"""
Enable or disable LED
Example:
await ctx.set_led_enabled(slave_id=1, enabled=True)
"""
await ctx.set_led_enabled(slave_id, enabled)
async def get_buzzer_enabled(ctx: DeviceContext, slave_id: int):
"""Get buzzer enabled status"""
return await ctx.get_buzzer_enabled(slave_id)
async def set_buzzer_enabled(ctx: DeviceContext, slave_id: int, enabled: bool):
"""
Enable or disable buzzer
Example:
await ctx.set_buzzer_enabled(slave_id=1, enabled=False)
"""
await ctx.set_buzzer_enabled(slave_id, enabled)
async def get_vibration_enabled(ctx: DeviceContext, slave_id: int):
"""Get vibration enabled status"""
return await ctx.get_vibration_enabled(slave_id)
async def set_vibration_enabled(ctx: DeviceContext, slave_id: int, enabled: bool):
"""
Enable or disable vibration motor
Example:
await ctx.set_vibration_enabled(slave_id=1, enabled=True)
"""
await ctx.set_vibration_enabled(slave_id, enabled)Motion Control
Joint Control (Position/Velocity/Current)
py
import libstark
from libstark import DeviceContext, FingerId
from typing import Sequence
# ================================
# Finger Control Interface
# ================================
# Finger ID Enumeration
# libstark.FingerId.Thumb - Thumb
# libstark.FingerId.ThumbAux - Thumb Auxiliary (Revo2 only)
# libstark.FingerId.Index - Index finger
# libstark.FingerId.Middle - Middle finger
# libstark.FingerId.Ring - Ring finger
# libstark.FingerId.Pinky - Pinky finger
# ================================
# Position Control
# ================================
async def set_finger_position(ctx: DeviceContext, slave_id: int, finger_id: FingerId, position: int):
"""
Set single finger position
Args:
ctx: Device context object
slave_id: Device slave ID
finger_id: libstark.FingerId enumeration value
position: Target position value (0~1000, unified range for all devices)
0 = fully open, 1000 = fully closed
Example:
# Set thumb position to 50%
await ctx.set_finger_position(slave_id=1, finger_id=libstark.FingerId.Thumb, position=500)
# Set index finger to fully closed
await ctx.set_finger_position(slave_id=1, finger_id=libstark.FingerId.Index, position=1000)
"""
await ctx.set_finger_position(slave_id, finger_id, position)
async def set_finger_positions(ctx: DeviceContext, slave_id: int, positions: Sequence[int]):
"""
Set all finger positions
Args:
ctx: Device context object
slave_id: Device slave ID
positions: Position value list (length 6) in order [Thumb, ThumbAux, Index, Middle, Ring, Pinky]
Range: 0~1000 (unified for all devices)
Example:
# Set all fingers to specific positions
positions = [600, 600, 1000, 1000, 1000, 1000] # Thumb half-open, others closed
await ctx.set_finger_positions(slave_id=1, positions=positions)
# Fully open all fingers
await ctx.set_finger_positions(slave_id=1, positions=[0] * 6)
"""
await ctx.set_finger_positions(slave_id, positions)
async def set_finger_position_with_millis(ctx: DeviceContext, slave_id: int, finger_id: FingerId,
position: int, milliseconds: int):
"""
Set single finger position with specified duration (Revo2 only)
Args:
ctx: Device context object
slave_id: Device slave ID
finger_id: libstark.FingerId enumeration value
position: Target position value (0~1000)
milliseconds: Duration to reach target (1~2000 milliseconds)
Example:
# Move thumb to position 500 in 2 seconds
await ctx.set_finger_position_with_millis(
slave_id=1,
finger_id=libstark.FingerId.Thumb,
position=500,
milliseconds=2000
)
"""
await ctx.set_finger_position_with_millis(slave_id, finger_id, position, milliseconds)
async def set_finger_position_with_speed(ctx: DeviceContext, slave_id: int, finger_id: FingerId,
position: int, speed: int):
"""
Set single finger position with specified speed (Revo2 only)
Args:
ctx: Device context object
slave_id: Device slave ID
finger_id: libstark.FingerId enumeration value
position: Target position value (0~1000)
speed: Movement speed value (1~1000)
Example:
# Move thumb to position 500 at speed 300
await ctx.set_finger_position_with_speed(
slave_id=1,
finger_id=libstark.FingerId.Thumb,
position=500,
speed=300
)
"""
await ctx.set_finger_position_with_speed(slave_id, finger_id, position, speed)
async def set_finger_positions_and_durations(ctx: DeviceContext, slave_id: int,
positions: Sequence[int],
durations: Sequence[int]):
"""
Set all finger positions with individual durations (Revo2 only)
Args:
ctx: Device context object
slave_id: Device slave ID
positions: Position value list (length 6, range 0~1000)
durations: Duration list (length 6, range 1~2000 milliseconds)
Example:
positions = [1000, 1000, 1000, 1000, 1000, 1000]
durations = [2000, 2000, 1500, 1500, 1500, 1500] # Different durations per finger
await ctx.set_finger_positions_and_durations(slave_id=1, positions=positions, durations=durations)
"""
await ctx.set_finger_positions_and_durations(slave_id, positions, durations)
async def set_finger_positions_and_speeds(ctx: DeviceContext, slave_id: int,
positions: Sequence[int],
speeds: Sequence[int]):
"""
Set all finger positions with individual speeds (Revo2 only)
Args:
ctx: Device context object
slave_id: Device slave ID
positions: Position value list (length 6, range 0~1000)
speeds: Speed value list (length 6, range 1~1000)
Example:
positions = [1000, 1000, 1000, 1000, 1000, 1000]
speeds = [300, 300, 400, 400, 400, 400] # Different speeds per finger
await ctx.set_finger_positions_and_speeds(slave_id=1, positions=positions, speeds=speeds)
"""
await ctx.set_finger_positions_and_speeds(slave_id, positions, speeds)
# ================================
# Speed Control
# ================================
async def set_finger_speed(ctx: DeviceContext, slave_id: int, finger_id: FingerId, speed: int):
"""
Set single finger speed
Args:
ctx: Device context object
slave_id: Device slave ID
finger_id: libstark.FingerId enumeration value
speed: Target speed value (-1000~+1000, unified range for all devices)
Positive: closing direction, Negative: opening direction, 0: stop
Example:
# Close thumb at speed 500
await ctx.set_finger_speed(slave_id=1, finger_id=libstark.FingerId.Thumb, speed=500)
# Open index finger at speed 300
await ctx.set_finger_speed(slave_id=1, finger_id=libstark.FingerId.Index, speed=-300)
"""
await ctx.set_finger_speed(slave_id, finger_id, speed)
async def set_finger_speeds(ctx: DeviceContext, slave_id: int, speeds: Sequence[int]):
"""
Set all finger speeds
Args:
ctx: Device context object
slave_id: Device slave ID
speeds: Speed value list (length 6, range -1000~+1000)
Example:
# Close all fingers at speed 500
await ctx.set_finger_speeds(slave_id=1, speeds=[500] * 6)
# Open all fingers at speed 300
await ctx.set_finger_speeds(slave_id=1, speeds=[-300] * 6)
"""
await ctx.set_finger_speeds(slave_id, speeds)
# ================================
# Current Control
# ================================
async def set_finger_current(ctx: DeviceContext, slave_id: int, finger_id: FingerId, current: int):
"""
Set single finger current
Args:
ctx: Device context object
slave_id: Device slave ID
finger_id: libstark.FingerId enumeration value
current: Target current value (-1000~+1000, unified range for all devices)
Positive: closing direction, Negative: opening direction
Example:
# Apply closing current 400 to thumb
await ctx.set_finger_current(slave_id=1, finger_id=libstark.FingerId.Thumb, current=400)
# Apply opening current 300 to index finger
await ctx.set_finger_current(slave_id=1, finger_id=libstark.FingerId.Index, current=-300)
"""
await ctx.set_finger_current(slave_id, finger_id, current)
async def set_finger_currents(ctx: DeviceContext, slave_id: int, currents: Sequence[int]):
"""
Set all finger currents
Args:
ctx: Device context object
slave_id: Device slave ID
currents: Current value list (length 6, range -1000~+1000)
Example:
# Apply closing current to all fingers
await ctx.set_finger_currents(slave_id=1, currents=[400] * 6)
# Apply opening current to all fingers
await ctx.set_finger_currents(slave_id=1, currents=[-300] * 6)
"""
await ctx.set_finger_currents(slave_id, currents)
# ================================
# PWM Control (Revo2 only)
# ================================
async def set_finger_pwm(ctx: DeviceContext, slave_id: int, finger_id: FingerId, pwm: int):
"""
Set single finger PWM (Revo2 only)
Args:
ctx: Device context object
slave_id: Device slave ID
finger_id: libstark.FingerId enumeration value
pwm: Target PWM value (-1000~+1000)
Positive: closing direction, Negative: opening direction
Example:
# Apply closing PWM 700 to thumb
await ctx.set_finger_pwm(slave_id=1, finger_id=libstark.FingerId.Thumb, pwm=700)
# Apply opening PWM 500 to index finger
await ctx.set_finger_pwm(slave_id=1, finger_id=libstark.FingerId.Index, pwm=-500)
"""
await ctx.set_finger_pwm(slave_id, finger_id, pwm)
async def set_finger_pwms(ctx: DeviceContext, slave_id: int, pwms: Sequence[int]):
"""
Set all finger PWMs (Revo2 only)
Args:
ctx: Device context object
slave_id: Device slave ID
pwms: PWM value list (length 6, range -1000~+1000)
Example:
# Apply closing PWM to all fingers
await ctx.set_finger_pwms(slave_id=1, pwms=[700] * 6)
# Apply opening PWM to all fingers
await ctx.set_finger_pwms(slave_id=1, pwms=[-500] * 6)
"""
await ctx.set_finger_pwms(slave_id, pwms)Motor Status
py
import libstark
from libstark import DeviceContext, MotorStatusData
# ================================
# Motor Status Interface
# ================================
async def get_motor_status(ctx: DeviceContext, slave_id: int) -> MotorStatusData:
"""
Get motor status information
Args:
ctx: Device context object
slave_id: Device slave ID
Returns:
MotorStatusData: Motor status object containing:
- positions: List[int] - Finger positions (0~1000)
- speeds: List[int] - Finger speeds (-1000~+1000)
- currents: List[int] - Finger currents (-1000~+1000)
- states: List[MotorState] - Finger states
- description: str - Status description
Example:
# Get motor status
status = await ctx.get_motor_status(slave_id=1)
# Check overall status
print(f"Is idle: {status.is_idle()}")
print(f"Is opened: {status.is_opened()}")
# For is_closed(), need to know if device uses Revo1 Motor API
uses_revo1 = ctx.uses_revo1_motor_api(slave_id)
print(f"Is closed: {status.is_closed(uses_revo1)}")
# Access individual finger data
print(f"Positions: {list(status.positions)}")
print(f"Speeds: {list(status.speeds)}")
print(f"Currents: {list(status.currents)}")
print(f"States: {list(status.states)}")
# Get formatted description
print(f"Status: {status.description}")
"""
status = await ctx.get_motor_status(slave_id)
return status
# ================================
# Motor Status Helper Functions
# ================================
def check_motor_idle(status: MotorStatusData) -> bool:
"""
Check if all motors are idle (not moving)
Args:
status: MotorStatusData object
Returns:
bool: True if all motors are idle
Example:
status = await ctx.get_motor_status(slave_id=1)
if status.is_idle():
print("All motors are idle, ready for next command")
"""
return status.is_idle()
def check_motors_opened(status: MotorStatusData) -> bool:
"""
Check if all fingers are in open position
Args:
status: MotorStatusData object
Returns:
bool: True if all fingers are opened
Example:
status = await ctx.get_motor_status(slave_id=1)
if status.is_opened():
print("Hand is fully opened")
"""
return status.is_opened()
def check_motors_closed(ctx: DeviceContext, status: MotorStatusData, slave_id: int) -> bool:
"""
Check if all fingers are in closed position
Args:
ctx: Device context object
status: MotorStatusData object
slave_id: Device slave ID
Returns:
bool: True if all fingers are closed
Note:
Revo1 and Revo2 have different closed position thresholds,
so we need to check which motor API the device uses.
Example:
status = await ctx.get_motor_status(slave_id=1)
if check_motors_closed(ctx, status, slave_id=1):
print("Hand is fully closed")
"""
uses_revo1 = ctx.uses_revo1_motor_api(slave_id)
return status.is_closed(uses_revo1)
# ================================
# Complete Example: Automatic Control Based on Status
# ================================
async def automatic_control_example(ctx: DeviceContext, slave_id: int):
"""
Example of automatic control based on motor status
This example demonstrates how to:
- Get motor status periodically
- Make control decisions based on status
- Execute appropriate actions
Args:
ctx: Device context object
slave_id: Device slave ID
"""
import asyncio
uses_revo1 = ctx.uses_revo1_motor_api(slave_id)
while True:
# Get current motor status
status = await ctx.get_motor_status(slave_id)
# Log status information
print(f"Motor status: {status.description}")
print(f"Is idle: {status.is_idle()}, Is opened: {status.is_opened()}, Is closed: {status.is_closed(uses_revo1)}")
# Execute control based on status
if status.is_idle():
if status.is_opened():
# When hand is open and idle, close it
print("Closing hand...")
await ctx.set_finger_positions(slave_id, [600, 600, 1000, 1000, 1000, 1000])
elif status.is_closed(uses_revo1):
# When hand is closed and idle, open it
print("Opening hand...")
await ctx.set_finger_positions(slave_id, [0] * 6)
# Wait before next status check
await asyncio.sleep(1.0)Sensors
Tactile Information
py
# ================================
# Touch Sensor API (Revo2 Touch - Capacitive)
# ================================
from typing import List
import libstark
from libstark import DeviceContext, TouchFingerItem
"""
Touch Sensor API for Revo2 Touch version (Capacitive sensors).
Revo2 Touch has simplified touch data compared to Revo1:
- Single normal force value per finger
- Single tangential force and direction per finger
- Self-capacitance proximity value
Check device type before use:
info = await ctx.get_device_info(slave_id=1)
if info.uses_revo2_touch_api() and not ctx.uses_pressure_touch_api(slave_id):
print("Revo2 Touch - Capacitive sensors")
Touch sensor workflow:
1. Check if device supports touch functionality
2. Enable and initialize touch sensors
3. Get touch data
4. Process touch data and implement control logic
5. Calibrate and reset touch sensors as needed
"""
# ================================
# Basic Touch Sensor API
# ================================
async def get_touch_sensor_enabled(ctx: DeviceContext, slave_id: int) -> int:
"""
Get touch sensor enabled status
Args:
ctx: Device context object
slave_id: Device slave ID
Returns:
int: Bitmask of enabled sensors (bit 0-4 for each finger)
Example:
if ctx.is_touch_hand(slave_id):
enabled = await ctx.get_touch_sensor_enabled(slave_id=1)
if enabled == 0:
print("Touch sensor not enabled, please enable first")
else:
print(f"Touch sensors enabled: 0x{enabled:02X}")
"""
return await ctx.get_touch_sensor_enabled(slave_id)
async def touch_sensor_setup(ctx: DeviceContext, slave_id: int, bits: int):
"""
Enable and initialize touch sensor system
Args:
ctx: Device context object
slave_id: Device slave ID
bits: Sensor bitmask specifying which sensors to enable
- 0x1F (0b11111) enables all 5 fingers
- 0x03 (0b00011) enables only thumb and index
Sensor bitmask:
- Bit 0: Thumb
- Bit 1: Index
- Bit 2: Middle
- Bit 3: Ring
- Bit 4: Pinky
Example:
# Enable all finger touch sensors
await ctx.touch_sensor_setup(slave_id=1, bits=0x1F)
print("All touch sensors enabled")
"""
await ctx.touch_sensor_setup(slave_id, bits)
async def touch_sensor_reset(ctx: DeviceContext, slave_id: int, bits: int):
"""
Reset specified touch sensors
Args:
ctx: Device context object
slave_id: Device slave ID
bits: Sensor bitmask specifying which sensors to reset
Example:
# Reset all touch sensors
await ctx.touch_sensor_reset(slave_id=1, bits=0x1F)
"""
await ctx.touch_sensor_reset(slave_id, bits)
async def touch_sensor_calibrate(ctx: DeviceContext, slave_id: int, bits: int):
"""
Calibrate touch sensor zero drift
Args:
ctx: Device context object
slave_id: Device slave ID
bits: Sensor bitmask specifying which sensors to calibrate
Note:
- Ensure fingers are not touching any objects during calibration
- Calibration eliminates sensor zero drift errors
Example:
print("Starting calibration, ensure fingers are not touching anything...")
await ctx.touch_sensor_calibrate(slave_id=1, bits=0x1F)
print("Calibration complete")
"""
await ctx.touch_sensor_calibrate(slave_id, bits)
async def get_single_touch_sensor_status(ctx: DeviceContext, slave_id: int, index: int) -> TouchFingerItem:
"""
Get touch sensor data for a specific finger
Args:
ctx: Device context object
slave_id: Device slave ID
index: Finger index (0-4, corresponding to thumb through pinky)
Returns:
TouchFingerItem: Touch data for the specified finger with:
- normal_force1: Normal force (0.01N units)
- tangential_force1: Tangential force (0.01N units)
- tangential_direction1: Direction (0-359 degrees)
- self_proximity1: Proximity value
- status: Sensor status
Example:
# Get thumb touch status
thumb = await ctx.get_single_touch_sensor_status(slave_id=1, index=0)
print(f"Normal force: {thumb.normal_force1 / 100:.2f}N")
print(f"Tangential force: {thumb.tangential_force1 / 100:.2f}N")
print(f"Direction: {thumb.tangential_direction1}°")
"""
return await ctx.get_single_touch_sensor_status(slave_id, index)
async def get_touch_sensor_status(ctx: DeviceContext, slave_id: int) -> List[TouchFingerItem]:
"""
Get touch sensor data for all fingers
Args:
ctx: Device context object
slave_id: Device slave ID
Returns:
List[TouchFingerItem]: Touch data for all 5 fingers
Example:
touch_data = await ctx.get_touch_sensor_status(slave_id=1)
finger_names = ["Thumb", "Index", "Middle", "Ring", "Pinky"]
for i, item in enumerate(touch_data):
print(f"{finger_names[i]}: Force={item.normal_force1/100:.2f}N, "
f"Proximity={item.self_proximity1}")
"""
return await ctx.get_touch_sensor_status(slave_id)
# ================================
# Usage Example
# ================================
async def touch_sensor_revo2_example():
"""
Basic touch sensor usage example for Revo2 Touch (Capacitive)
"""
import asyncio
slave_id = 1
# Auto-detect and connect
devices = await libstark.auto_detect()
if not devices:
print("No devices found")
return
ctx = await libstark.init_from_detected(devices[0])
# Check if device is Revo2 Touch (capacitive)
info = await ctx.get_device_info(slave_id)
if not info.uses_revo2_touch_api():
print("Device is not Revo2 Touch version")
await libstark.close_device_handler(ctx)
return
if ctx.uses_pressure_touch_api(slave_id):
print("Device uses Pressure Touch API, use touch_modulus.py instead")
await libstark.close_device_handler(ctx)
return
print(f"Revo2 Touch (Capacitive): {info.serial_number}")
# Enable touch sensors
print("Enabling touch sensors...")
await ctx.touch_sensor_setup(slave_id, bits=0x1F)
await asyncio.sleep(2)
# Calibrate
print("Calibrating (ensure fingers are not touching anything)...")
await ctx.touch_sensor_calibrate(slave_id, bits=0x1F)
await asyncio.sleep(1)
# Data acquisition loop
print("Starting touch data acquisition...")
try:
while True:
finger_names = ["Thumb", "Index", "Middle", "Ring", "Pinky"]
touch_data = await ctx.get_touch_sensor_status(slave_id)
for i, item in enumerate(touch_data):
print(f"{finger_names[i]}: N={item.normal_force1}, "
f"T={item.tangential_force1}, Dir={item.tangential_direction1}")
await asyncio.sleep(0.1)
except KeyboardInterrupt:
print("\nStopped")
finally:
await libstark.close_device_handler(ctx)High-Performance Data Collection ⭐
DataCollector
py
import libstark
from libstark import (
DeviceContext, DataCollector,
MotorStatusBuffer, TouchStatusBuffer,
PressureSummaryBuffer, PressureDetailedBuffer
)
# ================================
# High-Performance Data Collection API
# ================================
# DataCollector provides high-frequency data collection without GIL overhead.
# Uses shared memory buffers that SDK writes to and Python reads from.
# ================================
# Basic Motor Data Collection
# ================================
def create_motor_collector(ctx: DeviceContext, slave_id: int = 1,
motor_frequency: int = 1000) -> tuple:
"""
Create a basic data collector for motor status only
Args:
ctx: Device context
slave_id: Device slave ID
motor_frequency: Motor sampling frequency in Hz (default 1000)
Returns:
tuple: (DataCollector, MotorStatusBuffer)
Example:
collector, motor_buffer = create_motor_collector(ctx, slave_id=1)
collector.start()
# Read data in your loop
while running:
data = motor_buffer.pop_all()
for status in data:
print(f"Positions: {status.positions}")
time.sleep(0.01)
collector.stop()
collector.wait()
"""
motor_buffer = MotorStatusBuffer(max_size=1000)
collector = DataCollector.new_basic(
ctx=ctx,
motor_buffer=motor_buffer,
slave_id=slave_id,
motor_frequency=motor_frequency,
enable_stats=True
)
return collector, motor_buffer
# ================================
# Capacitive Touch Data Collection
# ================================
def create_capacitive_touch_collector(ctx: DeviceContext, slave_id: int = 1,
motor_frequency: int = 1000,
touch_frequency: int = 100) -> tuple:
"""
Create a data collector for motor + capacitive touch sensors
For Revo1Touch, Revo1AdvancedTouch, Revo2Touch devices.
Args:
ctx: Device context
slave_id: Device slave ID
motor_frequency: Motor sampling frequency in Hz
touch_frequency: Touch sampling frequency in Hz
Returns:
tuple: (DataCollector, MotorStatusBuffer, TouchStatusBuffer)
Example:
collector, motor_buf, touch_buf = create_capacitive_touch_collector(ctx)
collector.start()
while running:
# Read motor data
motor_data = motor_buf.pop_all()
# Read touch data for all fingers
touch_data = touch_buf.pop_latest_all()
for i, item in enumerate(touch_data):
if item:
print(f"Finger {i}: force={item.normal_force1}")
time.sleep(0.01)
collector.stop()
collector.wait()
"""
motor_buffer = MotorStatusBuffer(max_size=1000)
touch_buffer = TouchStatusBuffer(max_size=1000)
collector = DataCollector.new_capacitive(
ctx=ctx,
motor_buffer=motor_buffer,
touch_buffer=touch_buffer,
slave_id=slave_id,
motor_frequency=motor_frequency,
touch_frequency=touch_frequency,
enable_stats=True
)
return collector, motor_buffer, touch_buffer
# ================================
# Pressure Touch Data Collection (Modulus Sensors)
# ================================
def create_pressure_summary_collector(ctx: DeviceContext, slave_id: int = 1,
motor_frequency: int = 1000,
touch_frequency: int = 100) -> tuple:
"""
Create a data collector for motor + pressure touch summary data
For Revo2TouchPressure devices using Summary mode.
Summary mode provides aggregate pressure values per finger.
Args:
ctx: Device context
slave_id: Device slave ID
motor_frequency: Motor sampling frequency in Hz
touch_frequency: Touch sampling frequency in Hz
Returns:
tuple: (DataCollector, MotorStatusBuffer, PressureSummaryBuffer)
Example:
collector, motor_buf, pressure_buf = create_pressure_summary_collector(ctx)
collector.start()
while running:
# Read pressure summary for all fingers
summaries = pressure_buf.pop_latest_all()
for i, value in enumerate(summaries):
if value is not None:
print(f"Finger {i} pressure: {value}")
time.sleep(0.01)
collector.stop()
collector.wait()
"""
motor_buffer = MotorStatusBuffer(max_size=1000)
pressure_summary_buffer = PressureSummaryBuffer(max_size=1000)
collector = DataCollector.new_pressure_summary(
ctx=ctx,
motor_buffer=motor_buffer,
pressure_summary_buffer=pressure_summary_buffer,
slave_id=slave_id,
motor_frequency=motor_frequency,
touch_frequency=touch_frequency,
enable_stats=True
)
return collector, motor_buffer, pressure_summary_buffer
def create_pressure_detailed_collector(ctx: DeviceContext, slave_id: int = 1,
motor_frequency: int = 1000,
touch_frequency: int = 10) -> tuple:
"""
Create a data collector for motor + pressure touch detailed data
For Revo2TouchPressure devices using Detailed mode.
Detailed mode provides individual sensor point data:
- Fingers: 9 sensor points each
- Palm: 46 sensor points
Args:
ctx: Device context
slave_id: Device slave ID
motor_frequency: Motor sampling frequency in Hz
touch_frequency: Touch sampling frequency in Hz (default 10 for detailed)
Returns:
tuple: (DataCollector, MotorStatusBuffer, PressureDetailedBuffer)
Example:
collector, motor_buf, pressure_buf = create_pressure_detailed_collector(ctx)
collector.start()
while running:
# Read detailed pressure data
detailed = pressure_buf.pop_latest_all()
for i, item in enumerate(detailed):
if item:
print(f"Finger {i} sensors: {item.sensors}")
time.sleep(0.1) # Lower frequency for detailed data
collector.stop()
collector.wait()
"""
motor_buffer = MotorStatusBuffer(max_size=1000)
pressure_detailed_buffer = PressureDetailedBuffer(max_size=1000)
collector = DataCollector.new_pressure_detailed(
ctx=ctx,
motor_buffer=motor_buffer,
pressure_detailed_buffer=pressure_detailed_buffer,
slave_id=slave_id,
motor_frequency=motor_frequency,
touch_frequency=touch_frequency,
enable_stats=True
)
return collector, motor_buffer, pressure_detailed_buffer
def create_pressure_hybrid_collector(ctx: DeviceContext, slave_id: int = 1,
motor_frequency: int = 1000,
summary_frequency: int = 100,
detailed_frequency: int = 10) -> tuple:
"""
Create a data collector for motor + both summary and detailed pressure data
Hybrid mode collects both summary (high frequency) and detailed (low frequency)
pressure data simultaneously.
Args:
ctx: Device context
slave_id: Device slave ID
motor_frequency: Motor sampling frequency in Hz
summary_frequency: Summary data frequency in Hz
detailed_frequency: Detailed data frequency in Hz
Returns:
tuple: (DataCollector, MotorStatusBuffer, PressureSummaryBuffer, PressureDetailedBuffer)
Example:
collector, motor_buf, summary_buf, detailed_buf = create_pressure_hybrid_collector(ctx)
collector.start()
while running:
# High-frequency summary data
summaries = summary_buf.pop_all()
# Low-frequency detailed data
detailed = detailed_buf.pop_all()
time.sleep(0.01)
collector.stop()
collector.wait()
"""
motor_buffer = MotorStatusBuffer(max_size=1000)
pressure_summary_buffer = PressureSummaryBuffer(max_size=1000)
pressure_detailed_buffer = PressureDetailedBuffer(max_size=1000)
collector = DataCollector.new_pressure_hybrid(
ctx=ctx,
motor_buffer=motor_buffer,
pressure_summary_buffer=pressure_summary_buffer,
pressure_detailed_buffer=pressure_detailed_buffer,
slave_id=slave_id,
motor_frequency=motor_frequency,
summary_frequency=summary_frequency,
detailed_frequency=detailed_frequency,
enable_stats=True
)
return collector, motor_buffer, pressure_summary_buffer, pressure_detailed_buffer
# ================================
# Buffer Operations
# ================================
def read_motor_buffer(buffer: MotorStatusBuffer):
"""
Read all data from motor buffer
Buffer methods:
- pop_all(): Get and remove all data
- pop_latest(count): Get and remove latest N items
- peek_latest(): View latest item without removing
- peek_all(): View all items without removing
- len(): Get buffer size
- is_empty(): Check if empty
- clear(): Clear all data
"""
# Get all data (removes from buffer)
all_data = buffer.pop_all()
# Get latest N items
latest_10 = buffer.pop_latest(10)
# Peek without removing
latest = buffer.peek_latest()
if latest:
print(f"Latest positions: {latest.positions}")
print(f"Latest speeds: {latest.speeds}")
print(f"Latest currents: {latest.currents}")
print(f"Motor states: {latest.states}")
print(f"Is idle: {latest.is_idle()}")
print(f"Is opened: {latest.is_opened()}")
def read_touch_buffer(buffer: TouchStatusBuffer):
"""
Read data from touch buffer
Buffer methods:
- pop_all(): Get data for all 5 fingers
- pop_finger(index): Get data for single finger (0-4)
- pop_latest_all(): Get latest item for each finger
- len_all(): Get buffer sizes for all fingers
- clear(): Clear all data
"""
# Get latest for all fingers
latest = buffer.pop_latest_all()
for i, item in enumerate(latest):
if item:
print(f"Finger {i}: normal_force={item.normal_force1}, status={item.status}")
def read_pressure_summary_buffer(buffer: PressureSummaryBuffer):
"""
Read data from pressure summary buffer
Buffer methods:
- pop_all(): Get data for all 6 parts (5 fingers + palm)
- pop_finger(index): Get data for single part (0-5)
- pop_latest_all(): Get latest value for each part
- len_all(): Get buffer sizes
- clear(): Clear all data
"""
# Get latest for all parts
latest = buffer.pop_latest_all()
finger_names = ["Thumb", "Index", "Middle", "Ring", "Pinky", "Palm"]
for i, value in enumerate(latest):
if value is not None:
print(f"{finger_names[i]}: {value}")
def read_pressure_detailed_buffer(buffer: PressureDetailedBuffer):
"""
Read data from pressure detailed buffer
Buffer methods:
- pop_all(): Get data for all 6 parts
- pop_finger(index): Get data for single part (0-5)
- pop_latest_all(): Get latest item for each part
- len_all(): Get buffer sizes
- clear(): Clear all data
"""
# Get latest for all parts
latest = buffer.pop_latest_all()
for i, item in enumerate(latest):
if item:
print(f"Part {i}: {len(item.sensors)} sensors, values={item.sensors[:5]}...")Interactive Features
Action Sequence (Gestures)
py
import libstark
from libstark import DeviceContext, ActionSequenceId
from typing import Sequence
# ================================
# Action Sequence (Gesture) Control Interface
# ================================
# Action Sequence ID Enumeration
# Built-in Gestures:
# libstark.ActionSequenceId.DefaultGestureOpen - Open hand
# libstark.ActionSequenceId.DefaultGestureFist - Fist
# libstark.ActionSequenceId.DefaultGesturePinchTwo - Two-finger pinch
# libstark.ActionSequenceId.DefaultGesturePinchThree - Three-finger pinch
# libstark.ActionSequenceId.DefaultGesturePinchSide - Side pinch
# libstark.ActionSequenceId.DefaultGesturePoint - Point gesture
#
# Custom Gestures:
# Revo1: CustomGesture1 ~ CustomGesture6 (IDs 10-15)
# Revo2: CustomGesture1 ~ CustomGesture24 (IDs 7-30)
# ================================
# Get Action Sequence
# ================================
async def get_action_sequence(ctx: DeviceContext, slave_id: int, action_id: ActionSequenceId):
"""
Get action sequence by ID
Args:
ctx: Device context object
slave_id: Device slave ID
action_id: libstark.ActionSequenceId enumeration value
Returns:
ActionSequence: Action sequence object containing:
- action_id: ActionSequenceId - Action ID
- data: List[ActionSequenceItem] - Action sequence data
- description: str - Action description
Example:
# Get built-in fist gesture
action = await ctx.get_action_sequence(
slave_id=1,
action_id=libstark.ActionSequenceId.DefaultGestureFist
)
print(f"Gesture description: {action.description}")
print(f"Number of steps: {len(action.data)}")
# Get custom gesture
action = await ctx.get_action_sequence(
slave_id=1,
action_id=libstark.ActionSequenceId.CustomGesture1
)
"""
action = await ctx.get_action_sequence(slave_id, action_id)
return action
# ================================
# Upload Action Sequence
# ================================
async def transfer_action_sequence(ctx: DeviceContext, slave_id: int, action_id: ActionSequenceId,
sequences: Sequence[Sequence[int]]):
"""
Upload and set action sequence to device
Args:
ctx: Device context object
slave_id: Device slave ID
action_id: libstark.ActionSequenceId enumeration value (CustomGesture1-24)
sequences: Action sequence data list, each item is a position array (length 6, range 0~1000)
Note:
- Revo1: Supports up to 6 custom action sequences (CustomGesture1-6)
- Revo2: Supports up to 24 custom action sequences (CustomGesture1-24)
- Position values use unified range 0~1000 (SDK handles conversion)
Example:
# Define action sequence (list of position arrays)
sequences = [
[0, 0, 0, 0, 0, 0], # Step 1: Open hand
[500, 500, 500, 500, 500, 500], # Step 2: Half closed
[1000, 1000, 1000, 1000, 1000, 1000], # Step 3: Fully closed
]
# Upload to device
await ctx.transfer_action_sequence(
slave_id=1,
action_id=libstark.ActionSequenceId.CustomGesture1,
sequences=sequences
)
"""
await ctx.transfer_action_sequence(slave_id, action_id, sequences)
# ================================
# Save Action Sequence
# ================================
async def save_action_sequence(ctx: DeviceContext, slave_id: int, action_id: ActionSequenceId):
"""
Save action sequence to device flash memory (Revo2 only)
Args:
ctx: Device context object
slave_id: Device slave ID
action_id: libstark.ActionSequenceId enumeration value
Note:
- Only supported on Revo2 devices
- After uploading an action sequence with transfer_action_sequence(),
you must call save_action_sequence() to persist it to flash memory.
- Otherwise, the sequence will be lost after device reboot.
Example:
# Upload custom gesture
await ctx.transfer_action_sequence(
slave_id=1,
action_id=libstark.ActionSequenceId.CustomGesture1,
sequences=sequences
)
# Save to flash memory (Revo2 only)
await ctx.save_action_sequence(
slave_id=1,
action_id=libstark.ActionSequenceId.CustomGesture1
)
"""
await ctx.save_action_sequence(slave_id, action_id)
# ================================
# Execute Action Sequence
# ================================
async def run_action_sequence(ctx: DeviceContext, slave_id: int, action_id: ActionSequenceId):
"""
Execute action sequence
Args:
ctx: Device context object
slave_id: Device slave ID
action_id: libstark.ActionSequenceId enumeration value
Example:
# Execute built-in fist gesture
await ctx.run_action_sequence(
slave_id=1,
action_id=libstark.ActionSequenceId.DefaultGestureFist
)
# Execute custom gesture
await ctx.run_action_sequence(
slave_id=1,
action_id=libstark.ActionSequenceId.CustomGesture1
)
"""
await ctx.run_action_sequence(slave_id, action_id)
# ================================
# Clear Action Sequence
# ================================
async def clear_action_sequence(ctx: DeviceContext, slave_id: int, action_id: ActionSequenceId):
"""
Clear custom action sequence from device
Args:
ctx: Device context object
slave_id: Device slave ID
action_id: libstark.ActionSequenceId enumeration value (CustomGesture1-24)
Example:
# Clear custom gesture 1
await ctx.clear_action_sequence(
slave_id=1,
action_id=libstark.ActionSequenceId.CustomGesture1
)
"""
await ctx.clear_action_sequence(slave_id, action_id)Turbo Mode
py
# Turbo Mode Configuration (Revo1 Basic only)
# Configure turbo mode for sustained grip
import libstark
from libstark import DeviceContext, TurboConfig
# ================================
# Turbo Mode Control
# ================================
async def get_turbo_mode_enabled(ctx: DeviceContext, slave_id: int) -> bool:
"""
Get turbo mode enabled status (Revo1 Basic only)
Args:
ctx: Device context object
slave_id: Device slave ID
Returns:
bool: True if turbo mode is enabled
Example:
enabled = await ctx.get_turbo_mode_enabled(slave_id=1)
print(f"Turbo mode: {'Enabled' if enabled else 'Disabled'}")
"""
return await ctx.get_turbo_mode_enabled(slave_id)
async def set_turbo_mode_enabled(ctx: DeviceContext, slave_id: int, enabled: bool):
"""
Enable or disable turbo mode (Revo1 Basic only)
Args:
ctx: Device context object
slave_id: Device slave ID
enabled: True to enable, False to disable
Example:
await ctx.set_turbo_mode_enabled(slave_id=1, enabled=True)
"""
await ctx.set_turbo_mode_enabled(slave_id, enabled)
print(f"Turbo mode {'enabled' if enabled else 'disabled'}")
async def get_turbo_config(ctx: DeviceContext, slave_id: int) -> TurboConfig:
"""
Get turbo mode configuration (Revo1 Basic only)
Args:
ctx: Device context object
slave_id: Device slave ID
Returns:
TurboConfig: Configuration object with:
- interval: Interval time (milliseconds)
- duration: Sustained grip duration (milliseconds)
Example:
config = await ctx.get_turbo_config(slave_id=1)
print(f"Interval: {config.interval}ms, Duration: {config.duration}ms")
"""
return await ctx.get_turbo_config(slave_id)
async def set_turbo_config(ctx: DeviceContext, slave_id: int, interval: int, duration: int):
"""
Set turbo mode configuration (Revo1 Basic only)
Args:
ctx: Device context object
slave_id: Device slave ID
interval: Interval time in milliseconds
duration: Sustained grip duration in milliseconds
Example:
# Set 100ms interval, 50ms duration
config = libstark.TurboConfig(interval=100, duration=50)
await ctx.set_turbo_config(slave_id=1, turbo_config=config)
"""
config = libstark.TurboConfig(interval=interval, duration=duration)
await ctx.set_turbo_config(slave_id, config)
print(f"Turbo config set: interval={interval}ms, duration={duration}ms")
# ================================
# Complete Example
# ================================
async def configure_turbo_mode_example(ctx: DeviceContext, slave_id: int):
"""
Complete example of turbo mode configuration (Revo1 Basic only)
Note:
Turbo mode is only supported on Revo1 Basic devices.
For Revo2 devices, use set_finger_protected_currents() instead.
"""
# Check if device uses Revo1 Motor API
if not ctx.uses_revo1_motor_api(slave_id):
print("Turbo mode is only supported on Revo1 Basic devices")
return
# Enable turbo mode
await set_turbo_mode_enabled(ctx, slave_id, True)
# Configure turbo parameters
await set_turbo_config(ctx, slave_id, interval=100, duration=50)
# Verify configuration
config = await get_turbo_config(ctx, slave_id)
print(f"Turbo mode configured: {config.description}")API Quick Reference
Connection Management (Recommended)
| API | Description |
|---|---|
libstark.auto_detect() | Auto-detect devices (all protocols) ⭐ |
libstark.init_from_detected() | Initialize from detected device ⭐ |
libstark.close_device_handler() | Close device connection (unified) ⭐ |
libstark.list_zqwl_devices() | List ZQWL CAN/CANFD devices ⭐ |
libstark.init_zqwl_canfd() | Initialize ZQWL CANFD device |
libstark.init_zqwl_can() | Initialize ZQWL CAN 2.0 device |
libstark.close_zqwl() | Close ZQWL device |
Connection Management (Legacy)
| API | Description |
|---|---|
libstark.get_sdk_version() | Get SDK version |
libstark.list_available_ports() | List available serial ports |
libstark.modbus_open() | Open Modbus connection |
libstark.modbus_close() | Close Modbus connection |
libstark.init_device_handler() | Create device handler |
device.close() | Close device connection |
libstark.auto_detect_device() | Auto-detect device (Modbus only) |
libstark.auto_detect_modbus_revo2() | Auto-detect Revo2 device (Modbus only) |
Device Information
| API | Description |
|---|---|
device.get_device_info() | Get complete device information |
device.is_touch_hand() | Check if touch-enabled ⭐ |
device.uses_revo1_motor_api() | Check if uses Revo1 Motor API ⭐ |
device.uses_revo2_motor_api() | Check if uses Revo2 Motor API ⭐ |
device.uses_pressure_touch_api() | Check if uses Pressure Touch API ⭐ |
device.get_device_sn() | Get device serial number |
device.get_device_fw_version() | Get firmware version |
device.get_sku_type() | Get SKU type |
device.get_serialport_cfg() | Get serial port configuration |
device.get_canfd_baudrate() | Get CANFD baud rate |
device.set_serialport_baudrate() | Set baud rate |
device.set_slave_id() | Set slave ID |
Motor Control - Position (Unified Range 0-1000)
| API | Description |
|---|---|
device.set_finger_position() | Set single finger position |
device.set_finger_position_with_millis() | Set position with duration ⭐ |
device.set_finger_position_with_speed() | Set position with speed ⭐ |
device.set_finger_positions() | Set all finger positions |
device.set_finger_positions_and_durations() | Set positions with durations ⭐ |
device.set_finger_positions_and_speeds() | Set positions with speeds ⭐ |
device.get_finger_positions() | Get all finger positions |
Motor Control - Speed (Unified Range -1000~+1000)
| API | Description |
|---|---|
device.set_finger_speed() | Set single finger speed |
device.set_finger_speeds() | Set all finger speeds |
device.get_finger_speeds() | Get all finger speeds |
Motor Control - Current (Unified Range -1000~+1000)
| API | Description |
|---|---|
device.set_finger_current() | Set single finger current |
device.set_finger_currents() | Set all finger currents |
device.get_finger_currents() | Get all finger currents |
Motor Control - PWM (Unified Range -1000~+1000) ⭐
| API | Description |
|---|---|
device.set_finger_pwm() | Set single finger PWM |
device.set_finger_pwms() | Set all finger PWMs |
Motor Status
| API | Description |
|---|---|
device.get_motor_status() | Get comprehensive motor status |
device.get_motor_state() | Get motor running state |
Motor Settings ⭐
| API | Description |
|---|---|
device.get_finger_unit_mode() | Get unit mode |
device.set_finger_unit_mode() | Set unit mode |
device.get_all_finger_settings() | Get all finger settings |
device.get_finger_settings() | Get single finger settings |
device.set_finger_settings() | Set single finger settings |
device.get_finger_min_position() | Get minimum position limit |
device.set_finger_min_position() | Set minimum position limit |
device.get_finger_max_position() | Get maximum position limit |
device.set_finger_max_position() | Set maximum position limit |
device.get_finger_max_speed() | Get maximum speed limit |
device.set_finger_max_speed() | Set maximum speed limit |
device.get_finger_max_current() | Get maximum current limit |
device.set_finger_max_current() | Set maximum current limit |
device.get_finger_protected_current() | Get protected current |
device.set_finger_protected_current() | Set protected current |
device.get_finger_protected_currents() | Get all protected currents |
device.set_finger_protected_currents() | Set all protected currents |
device.get_thumb_aux_lock_current() | Get thumb aux lock current |
device.set_thumb_aux_lock_current() | Set thumb aux lock current |
Touch Sensors
| API | Description |
|---|---|
device.get_touch_sensor_enabled() | Get touch sensor enabled status |
device.get_touch_sensor_fw_versions() | Get touch sensor firmware versions |
device.get_touch_sensor_raw_data() | Get touch raw data |
device.get_touch_sensor_status() | Get touch sensor status |
device.get_single_touch_sensor_status() | Get single sensor status |
device.touch_sensor_setup() | Setup touch sensors |
device.touch_sensor_reset() | Reset touch sensors |
device.touch_sensor_calibrate() | Calibrate touch sensors |
Modulus Touch Sensors ⭐
| API | Description |
|---|---|
device.set_modulus_touch_data_type() | Set data type |
device.get_modulus_touch_data_type() | Get data type |
device.get_modulus_touch_summary() | Get touch summary |
device.get_single_modulus_touch_summary() | Get single finger summary |
device.get_modulus_touch_data() | Get detailed touch data |
device.get_single_modulus_touch_data() | Get single finger data |
High-Performance Data Collection ⭐
| API | Description |
|---|---|
DataCollector.new_basic() | Create basic collector (motor only) |
DataCollector.new_capacitive() | Create capacitive touch collector |
DataCollector.new_pressure_summary() | Create pressure summary collector |
DataCollector.new_pressure_detailed() | Create pressure detailed collector |
DataCollector.new_pressure_hybrid() | Create hybrid mode collector |
collector.start() | Start data collection |
collector.stop() | Stop data collection |
collector.wait() | Wait for collection thread |
collector.is_running() | Check if running |
MotorStatusBuffer | Motor status buffer |
TouchStatusBuffer | Touch status buffer |
PressureSummaryBuffer | Pressure summary buffer |
PressureDetailedBuffer | Pressure detailed buffer |
LED, Buzzer, Vibration ⭐
| API | Description |
|---|---|
device.get_led_enabled() | Get LED enabled status |
device.set_led_enabled() | Set LED enabled status |
device.get_buzzer_enabled() | Get buzzer enabled status |
device.set_buzzer_enabled() | Set buzzer enabled status |
device.get_vibration_enabled() | Get vibration enabled status |
device.set_vibration_enabled() | Set vibration enabled status |
Action Sequences
| API | Description |
|---|---|
device.get_action_sequence() | Get action sequence |
device.transfer_action_sequence() | Upload action sequence |
device.save_action_sequence() | Save action sequence to flash |
device.run_action_sequence() | Execute action sequence |
device.clear_action_sequence() | Clear custom action sequence |
Device Configuration
| API | Description |
|---|---|
device.get_force_level() | Get force level |
device.set_force_level() | Set force level |
device.get_auto_calibration_enabled() | Get auto-calibration status |
device.set_auto_calibration() | Set auto-calibration |
device.calibrate_position() | Manual position calibration |
device.get_turbo_mode_enabled() | Get turbo mode status |
device.set_turbo_mode_enabled() | Set turbo mode |
device.get_turbo_config() | Get turbo configuration |
device.set_turbo_config() | Set turbo configuration |
device.reset_default_gesture() | Reset to default gestures |
device.reset_default_settings() | Reset to default settings |
device.reboot() | Reboot device |
EtherCAT Specific ⭐
| API | Description |
|---|---|
device.ec_setup_sdo() | Setup SDO |
device.ec_reserve_master() | Reserve master |
device.ec_start_loop() | Start cyclic loop |
device.ec_stop_loop() | Stop cyclic loop |
device.ec_start_dfu() | Start firmware upgrade |
Firmware Upgrade
| API | Description |
|---|---|
device.start_dfu() | Start firmware upgrade |
Communication Callbacks
| API | Description |
|---|---|
libstark.set_modbus_read_holding_callback() | Set Modbus read holding callback |
libstark.set_modbus_read_input_callback() | Set Modbus read input callback |
libstark.set_modbus_write_callback() | Set Modbus write callback |
libstark.set_can_rx_callback() | Set CAN RX callback |
libstark.set_can_tx_callback() | Set CAN TX callback |
⭐ Indicates Revo2-specific or enhanced features