Python SDK - Revo1 灵巧手
系统要求
- Linux: Ubuntu 20.04/22.04 LTS
- macOS: 10.15+
- Windows: 10/11
- Python: 3.8 ~ 3.12 (推荐 Conda)
快速开始
克隆仓库
shell
# 使用 HTTPS 方式
git clone https://github.com/BrainCoTech/stark-serialport-example.git
# 或使用 SSH 方式
git clone git@github.com:BrainCoTech/stark-serialport-example.git安装与配置
shell
# 进入 Python 目录
cd stark-serialport-example/python
# 激活 Conda 环境(推荐)
conda activate py310
# 安装 SDK 依赖
pip install -r requirements.txt --index-url https://pypi.org/simple/
# 如果无法通过 PyPI 安装,可手动下载 .whl 文件安装
# 下载地址: 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'
# 配置串口设备权限
# Linux 系统中,串口设备(如 /dev/ttyUSB0)通常归属于 dialout 用户组
# 将当前用户添加到 dialout 组
sudo usermod -aG dialout $USER
# 注意:添加后需要重新登录才能生效
# 运行示例
cd revo1
python revo1_ctrl.py # 单手控制
python revo1_touch.py # 触觉传感器(触觉版)
python revo1_ctrl_multi.py # 多手控制
python revo1_action_seq.py # 动作序列
python revo1_cfg.py # 设备配置
python revo1_dfu.py # 固件升级shell
# 安装步骤同 Ubuntu
# 注意:macOS 串口设备名称通常为 /dev/tty.usbserial-xxxshell
# 如果 USB 驱动无法识别,请在设备管理器中查看串口名称
# 串口驱动下载: https://app.brainco.cn/universal/stark-serialport-prebuild/driver/CH340-drivers.zip
# 其他安装步骤同 Ubuntu
# 注意:Windows 串口设备名称通常为 COM3, COM4 等示例代码
SDK 提供了丰富的示例代码,涵盖不同通信协议和应用场景。
Modbus-RTU 协议
单手/双手控制
触觉传感器
动作序列(手势)
固件升级
CAN 2.0 协议
单手控制示例
- 自定义 CAN 设备 - C++ 示例
- ZLG USBCAN 设备 - C++ 示例
- ZQWL USBCAN 设备(Windows) - C++ 示例
- ZQWL USBCAN 设备 - Python 示例
API 参考
连接管理
Modbus-RTU 连接
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)CAN 2.0 连接
py
import libstark
from libstark import DeviceContext, StarkProtocolType
# ================================
# Recommended: Auto-Detect CAN Devices
# ================================
async def auto_detect_can_device():
"""
Auto-detect CAN devices (Recommended)
This is the recommended way to connect to CAN devices. It automatically:
- Scans for ZQWL CAN adapters
- Detects devices on the CAN bus
- Initializes the appropriate transport
Returns:
tuple: (DeviceContext, DetectedDevice) or (None, None) if not found
Example:
ctx, device = await auto_detect_can_device()
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)
"""
try:
# Scan for CAN devices only
devices = await libstark.auto_detect(scan_all=False, protocol="Can")
if not devices:
print("No CAN 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
# ================================
# ZQWL CAN Adapter (Built-in SDK Support)
# ================================
def list_zqwl_can_devices():
"""
List all ZQWL USB CAN devices
Returns:
List[ZqwlDeviceInfo]: List of ZQWL devices
Example:
devices = list_zqwl_can_devices()
for dev in devices:
print(f"ZQWL: {dev.port_name}, Channels: {dev.channel_count}")
"""
try:
devices = libstark.list_zqwl_devices()
# Filter for CAN-only devices (not CANFD)
can_devices = [d for d in devices if not d.supports_canfd]
print(f"Found {len(can_devices)} ZQWL CAN device(s)")
return can_devices
except Exception as e:
print(f"Failed to list ZQWL devices: {e}")
return []
def connect_zqwl_can(port_name: str, arb_baudrate: int = 1000000) -> DeviceContext:
"""
Connect via ZQWL CAN adapter (Low-level API)
Note: Recommend using auto_detect_can_device() instead for automatic setup.
Args:
port_name: Serial port name (e.g., "/dev/cu.usbmodem*" on macOS, "COM3" on Windows)
arb_baudrate: CAN arbitration baudrate (default 1Mbps)
Returns:
DeviceContext: Device connection object
Example:
# Initialize ZQWL CAN
result = libstark.init_zqwl_can(port_name, arb_baudrate=1000000)
if result != 0:
raise Exception("Failed to initialize ZQWL CAN")
# Create device handler
ctx = libstark.init_device_handler(StarkProtocolType.Can, master_id=0)
# Use the device...
info = await ctx.get_device_info(slave_id=1)
# Cleanup
await libstark.close_device_handler(ctx) # Also closes ZQWL
"""
try:
result = libstark.init_zqwl_can(port_name, arb_baudrate)
if result != 0:
raise Exception(f"Failed to initialize ZQWL CAN: {result}")
ctx = libstark.init_device_handler(StarkProtocolType.Can, master_id=0)
print(f"ZQWL CAN connection successful: {port_name}")
return ctx
except Exception as e:
print(f"ZQWL CAN connection failed: {e}")
raise
# ================================
# Custom CAN Adapter (Manual Callbacks)
# ================================
def connect_custom_can() -> DeviceContext:
"""
Connect via custom CAN adapter with manual callbacks
Use this when you have a non-ZQWL CAN adapter (e.g., ZLG, PEAK, etc.)
and need to implement your own send/receive logic.
Returns:
DeviceContext: Device connection object
Note:
- Requires implementing _can_send and _can_read callback functions
- For ZLG adapters, see the multi-frame protocol handling below
"""
try:
# Create device handler for CAN protocol
ctx = libstark.init_device_handler(StarkProtocolType.Can, master_id=0)
# Set CAN communication callback functions
# Note: Users need to implement these callback functions
libstark.set_can_tx_callback(_can_send) # Set send callback
libstark.set_can_rx_callback(_can_read) # Set receive callback
return ctx
except Exception as e:
print(f"CAN connection failed: {e}")
raise
# ================================
# CAN Communication Callback Examples
# ================================
def _can_send(slave_id: int, can_id: int, data: bytes, data_len: int) -> int:
"""
CAN data send callback function
Args:
slave_id: Slave ID
can_id: CAN ID
data: CAN data to send (bytes)
data_len: Length of data
Returns:
int: 0 on success, non-zero on failure
Note:
- Implement this function according to your CAN adapter
- Function is responsible for sending data to bus via CAN adapter
"""
# Example implementation (adjust according to actual hardware)
# return can_interface.send(can_id, data[:data_len])
print(f"TX: CAN ID=0x{can_id:X}, Data={data[:data_len].hex()}")
return 0
def _can_read(slave_id: int, expected_can_id: int, expected_frames: int,
can_id_out, data_out, data_len_out) -> int:
"""
CAN data receive callback function
Args:
slave_id: Slave ID
expected_can_id: Expected CAN ID to filter responses
expected_frames: Expected frame count (0=auto-detect, >0=specific count)
can_id_out: Output pointer for received CAN ID
data_out: Output buffer for received data (at least 512 bytes for multi-frame)
data_len_out: Output pointer for data length
Returns:
int: 0 on success, non-zero on failure
Note:
- For ZLG adapters, handle multi-frame protocol (expected_frames > 1)
- SDK handles frame reassembly for ZQWL adapters automatically
"""
# Example implementation (adjust according to actual hardware)
# can_id, data = can_interface.recv(timeout_ms=100)
# can_id_out[0] = can_id
# data_out[:len(data)] = data
# data_len_out[0] = len(data)
print(f"RX: Waiting for CAN ID=0x{expected_can_id:X}")
return 0
# ================================
# Close Connection
# ================================
async def close_can_device(ctx: DeviceContext):
"""
Close CAN device connection
This function handles cleanup for CAN connections:
- For ZQWL: Closes adapter automatically
- For custom adapters: Releases device handler
Args:
ctx: Device connection object
Example:
await libstark.close_device_handler(ctx)
"""
await libstark.close_device_handler(ctx)设备信息与设置
设备信息
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)运动控制
关节控制(位置/速度/电流)
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)电机状态
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)传感器
触觉信息
py
from typing import List
import libstark
from libstark import DeviceContext, TouchFingerData, TouchFingerItem, TouchRawData
# ================================
# Touch Sensor API (Revo1 Touch)
# ================================
# Touch sensor data structure
# 3D force values, self-capacitance, mutual-capacitance, and sensor status
# class TouchFingerItem:
# normal_force1: int # Normal force 1, unit: 0.01N, e.g., 1000 = 10N. Range: 0 ~ 25N
# normal_force2: int # Normal force 2, unit: 0.01N
# normal_force3: int # Normal force 3, unit: 0.01N
# tangential_force1: int # Tangential force 1, unit: 0.01N, e.g., 1000 = 10N. Range: 0 ~ 25N
# tangential_force2: int # Tangential force 2, unit: 0.01N
# tangential_force3: int # Tangential force 3, unit: 0.01N
# tangential_direction1: int # Tangential direction 1, range: 0 ~ 359 degrees. 0° points to fingertip, clockwise. 0xFFFF = invalid
# tangential_direction2: int # Tangential direction 2
# tangential_direction3: int # Tangential direction 3
# self_proximity1: int # Self-capacitance 1
# self_proximity2: int # Self-capacitance 2
# mutual_proximity: int # Mutual-capacitance
# status: int # Status
# description: str # Description
# def is_normal(self) -> bool: ...
# def is_abnormal(self) -> bool: ...
# def desc(self) -> str: ...
"""
Touch Sensor API for Revo1 Touch version.
Touch sensor features:
- Multi-dimensional force detection: 3 normal forces, 3 tangential forces, 3 tangential directions
- Proximity detection: self-capacitance and mutual-capacitance
- Real-time data streaming: high-frequency data acquisition and callbacks
Check device type before use:
device_info = await ctx.get_device_info(slave_id=1)
if device_info.is_touch():
print("Device supports touch sensors")
if device_info.uses_revo1_touch_api():
print("Revo1 Touch - First generation touch version")
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
"""
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)
Note:
- Touch sensors are disabled by default to save power
- Must be enabled before getting touch data
- Applicable to all touch-enabled devices
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 get_touch_sensor_fw_versions(ctx: DeviceContext, slave_id: int) -> List[str]:
"""
Get touch sensor firmware version list
Args:
ctx: Device context object
slave_id: Device slave ID
Returns:
List[str]: Firmware version list for each finger's touch sensor
Note:
- Touch sensors must be enabled first
- Each finger's sensor may have different firmware versions
- Version info helps with diagnostics and compatibility checks
Example:
enabled = await ctx.get_touch_sensor_enabled(slave_id=1)
if enabled:
versions = await ctx.get_touch_sensor_fw_versions(slave_id=1)
finger_names = ["Thumb", "Index", "Middle", "Ring", "Pinky"]
for i, version in enumerate(versions):
if i < len(finger_names):
print(f"{finger_names[i]} touch sensor firmware: {version}")
else:
print("Please enable touch sensors first")
"""
return await ctx.get_touch_sensor_fw_versions(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
- Use bitwise operations to specify fingers
- Example: 0x1F (0b11111) enables all 5 fingers
- Example: 0x03 (0b00011) enables only thumb and index
Sensor bitmask:
- Bit 0: Thumb
- Bit 1: Index
- Bit 2: Middle
- Bit 3: Ring
- Bit 4: Pinky
Note:
- This is the first step to use touch sensors
- Sensors will initialize and self-test after enabling
- Initialization may take a few seconds
Example:
# Enable all finger touch sensors
await ctx.touch_sensor_setup(slave_id=1, bits=0x1F)
print("All touch sensors enabled")
# Enable only thumb and index touch sensors
await ctx.touch_sensor_setup(slave_id=1, bits=0x03)
print("Thumb and index touch sensors enabled")
# Enable only index touch sensor
await ctx.touch_sensor_setup(slave_id=1, bits=0x02)
print("Index touch sensor 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
Note:
- Sensor status registers will return abnormal status during reset
- Sensors will resume normal operation after reset completes
- Used to resolve sensor anomalies or reinitialize
- Reset does not change sensor enabled status
Example:
# Reset all touch sensors
await ctx.touch_sensor_reset(slave_id=1, bits=0x1F)
print("All touch sensors reset")
# Reset only thumb sensor (if anomaly detected)
await ctx.touch_sensor_reset(slave_id=1, bits=0x01)
print("Thumb touch sensor reset")
"""
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
Calibration notes:
- Ensure fingers are not touching any objects during calibration
- Calibration eliminates sensor zero drift errors
- Recommended to calibrate after ambient temperature stabilizes
- Sensor accuracy significantly improves after calibration
Recommended calibration timing:
- First time using the device
- After significant ambient temperature changes
- When sensor readings show obvious drift
- During regular maintenance
Example:
# Calibrate all touch sensors
print("Starting touch sensor calibration, ensure fingers are not touching anything...")
await ctx.touch_sensor_calibrate(slave_id=1, bits=0x1F)
print("Touch sensor calibration complete")
# Calibrate only thumb sensor
await ctx.touch_sensor_calibrate(slave_id=1, bits=0x01)
print("Thumb touch sensor calibration complete")
"""
await ctx.touch_sensor_calibrate(slave_id, bits)
async def get_touch_raw_data(ctx: DeviceContext, slave_id: int) -> TouchRawData:
"""
Get raw channel data from touch sensors (Revo1 Touch)
Args:
ctx: Device context object
slave_id: Device slave ID
Returns:
TouchRawData: Raw touch data object with the following attributes:
- thumb: List[int] - Thumb raw sensor data (7 channels)
- index: List[int] - Index finger raw sensor data (11 channels)
- middle: List[int] - Middle finger raw sensor data (11 channels)
- ring: List[int] - Ring finger raw sensor data (11 channels)
- pinky: List[int] - Pinky finger raw sensor data (7 channels)
- description: str - Data description
TouchRawData methods:
- desc() -> str: Get data description
Note:
- Only applicable to Revo1 Touch devices
- Touch sensors must be enabled first
- Raw data is unprocessed sensor readings, requires manual parsing
- Data format: thumb/pinky have 7 channels, other fingers have 11 channels
Example:
info = await ctx.get_device_info(slave_id=1)
if info.uses_revo1_touch_api():
enabled = await ctx.get_touch_sensor_enabled(slave_id=1)
if enabled:
raw_data = await ctx.get_touch_sensor_raw_data(slave_id=1)
print(f"Thumb raw data (7 channels): {raw_data.thumb}")
print(f"Index raw data (11 channels): {raw_data.index}")
print(f"Data description: {raw_data.desc()}")
# Raw data processing example
if len(raw_data.thumb) > 0:
avg_thumb = sum(raw_data.thumb) / len(raw_data.thumb)
print(f"Thumb average: {avg_thumb}")
"""
return await ctx.get_touch_sensor_raw_data(slave_id)
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:
- 3 normal force values
- 3 tangential force values
- 3 tangential direction values
- 2 self-capacitance values
- 1 mutual-capacitance value
- Sensor status
Note:
- Touch sensor for the specified finger must be enabled first
- Revo1 provides more detailed 3D force information than Revo2
Example:
info = await ctx.get_device_info(slave_id=1)
if info.uses_revo1_touch_api():
# Get thumb touch status
thumb_status = await ctx.get_single_touch_sensor_status(slave_id=1, index=0)
print(f"Normal forces: {thumb_status.normal_force1}, {thumb_status.normal_force2}, {thumb_status.normal_force3}")
print(f"Tangential forces: {thumb_status.tangential_force1}, {thumb_status.tangential_force2}, {thumb_status.tangential_force3}")
"""
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 fingers
Note:
- Gets all finger touch status in one call, more efficient
- Suitable for applications that need to process multiple finger touch info
- Each finger provides 3D force data with 3 normal and 3 tangential force sensors
Example:
info = await ctx.get_device_info(slave_id=1)
if info.uses_revo1_touch_api():
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):
if i < len(finger_names):
print(f"{finger_names[i]}: Normal={item.normal_force1}, Tangential={item.tangential_force1}")
"""
return await ctx.get_touch_sensor_status(slave_id)
async def check_touch_sensor_health(ctx: DeviceContext, slave_id: int) -> dict:
"""
Check touch sensor health status (utility function)
Args:
ctx: Device context object
slave_id: Device slave ID
Returns:
dict: Sensor health status report with:
- enabled: int - Bitmask of enabled sensors
- fw_versions: List[str] - Firmware versions for each finger
- sensor_status: List[dict] - Status for each finger
- errors: List[str] - Any detected errors
Example:
health_report = await check_touch_sensor_health(ctx, slave_id=1)
print(f"Health status report: {health_report}")
if health_report["errors"]:
print("Errors detected:")
for error in health_report["errors"]:
print(f" - {error}")
"""
health_report = {
"enabled": 0,
"fw_versions": [],
"sensor_status": [],
"errors": []
}
try:
# Check if device supports touch
if not ctx.is_touch_hand(slave_id):
health_report["errors"].append("Device does not support touch functionality")
return health_report
# Check if enabled
touch_enabled = await ctx.get_touch_sensor_enabled(slave_id)
if touch_enabled == 0:
health_report["errors"].append("Touch sensors not enabled")
return health_report
health_report["enabled"] = touch_enabled
# Get firmware versions
health_report["fw_versions"] = await ctx.get_touch_sensor_fw_versions(slave_id)
# Check each sensor status
touch_data = await ctx.get_touch_sensor_status(slave_id)
finger_names = ["Thumb", "Index", "Middle", "Ring", "Pinky"]
for i, item in enumerate(touch_data):
finger_name = finger_names[i] if i < len(finger_names) else f"Finger{i}"
status = {
"finger": finger_name,
"normal": item.is_normal(),
"description": item.desc()
}
health_report["sensor_status"].append(status)
if not item.is_normal():
health_report["errors"].append(f"{finger_name} sensor abnormal: {item.desc()}")
except Exception as e:
health_report["errors"].append(f"Error during check: {str(e)}")
return health_report
# ================================
# Usage Example
# ================================
async def touch_sensor_basic_example():
"""
Basic touch sensor usage example for Revo1 Touch
"""
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 supports touch
device_info = await ctx.get_device_info(slave_id)
if not device_info.uses_revo1_touch_api():
print("Device is not Revo1 Touch version")
await libstark.close_device_handler(ctx)
return
print(f"Device supports touch: {device_info.sku_type}")
# Enable touch sensors
print("Enabling touch sensors...")
await ctx.touch_sensor_setup(slave_id, bits=0x1F) # Enable all fingers
# Wait for initialization
await asyncio.sleep(2)
# Check if successfully enabled
enabled = await ctx.get_touch_sensor_enabled(slave_id)
if enabled:
print(f"Touch sensors enabled: 0x{enabled:02X}")
# Get firmware versions
versions = await ctx.get_touch_sensor_fw_versions(slave_id)
print(f"Sensor firmware versions: {versions}")
# Perform calibration
print("Performing calibration (ensure fingers are not touching anything)...")
await ctx.touch_sensor_calibrate(slave_id, bits=0x1F)
await asyncio.sleep(3)
print("Calibration complete")
else:
print("Failed to enable touch sensors")
await libstark.close_device_handler(ctx)
return
# Data acquisition loop
print("Starting touch data acquisition...")
try:
while True:
finger_names = ["Thumb", "Index", "Middle", "Ring", "Pinky"]
# Get 3D force data
touch_data = await ctx.get_touch_sensor_status(slave_id)
for i, item in enumerate(touch_data):
if i < len(finger_names):
print(f"{finger_names[i]}: N1={item.normal_force1}, T1={item.tangential_force1}, Dir1={item.tangential_direction1}")
# Get raw data
raw_data = await ctx.get_touch_sensor_raw_data(slave_id)
print(f"Thumb raw channels: {len(raw_data.thumb)}, Index raw channels: {len(raw_data.index)}")
await asyncio.sleep(0.1) # 10Hz update rate
except KeyboardInterrupt:
print("\nStopped touch data acquisition")
finally:
await libstark.close_device_handler(ctx)交互功能
动作序列(手势)
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 模式
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 快速参考
连接管理
| API | 说明 |
|---|---|
libstark.auto_detect() | 自动检测设备(推荐,支持所有协议) |
libstark.init_from_detected() | 从检测结果初始化设备 |
libstark.close_device_handler() | 关闭设备连接(推荐) |
libstark.list_available_ports() | 列出可用串口 |
libstark.list_zqwl_devices() | 列出 ZQWL CAN 适配器 |
libstark.modbus_open() | 打开 Modbus 连接 |
libstark.modbus_close() | 关闭 Modbus 连接 |
libstark.init_device_handler() | 创建设备处理器(CAN/CANFD) |
libstark.init_zqwl_can() | 初始化 ZQWL CAN 适配器 |
libstark.auto_detect_device() | 自动检测设备(已弃用) |
libstark.auto_detect_modbus_revo1() | 自动检测 Revo1 设备(已弃用) |
设备信息
| API | 说明 |
|---|---|
ctx.get_device_info() | 获取设备完整信息 |
ctx.get_device_sn() | 获取设备序列号 |
ctx.get_device_fw_version() | 获取固件版本 |
ctx.get_sku_type() | 获取 SKU 类型 |
ctx.get_voltage() | 获取电池电压 |
ctx.get_serialport_cfg() | 获取串口配置 |
ctx.get_serialport_baudrate() | 获取波特率 |
ctx.set_serialport_baudrate() | 设置波特率 |
ctx.set_slave_id() | 设置从站 ID |
设备类型检查
| API | 说明 |
|---|---|
ctx.is_touch_hand() | 检查是否有触觉传感器 |
ctx.uses_revo1_motor_api() | 检查是否使用 Revo1 电机 API |
ctx.uses_revo2_motor_api() | 检查是否使用 Revo2 电机 API |
ctx.uses_pressure_touch_api() | 检查是否使用压力触觉 API |
电机控制 - 位置
| API | 说明 |
|---|---|
ctx.set_finger_position() | 设置单个手指位置(0~1000) |
ctx.set_finger_positions() | 设置所有手指位置 |
ctx.get_finger_positions() | 获取所有手指位置 |
电机控制 - 速度
| API | 说明 |
|---|---|
ctx.set_finger_speed() | 设置单个手指速度(-1000~+1000) |
ctx.set_finger_speeds() | 设置所有手指速度 |
ctx.get_finger_speeds() | 获取所有手指速度 |
电机控制 - 电流
| API | 说明 |
|---|---|
ctx.set_finger_current() | 设置单个手指电流(-1000~+1000) |
ctx.set_finger_currents() | 设置所有手指电流 |
ctx.get_finger_currents() | 获取所有手指电流 |
电机状态
| API | 说明 |
|---|---|
ctx.get_motor_status() | 获取电机综合状态 |
ctx.get_motor_state() | 获取电机运行状态 |
触觉传感器
| API | 说明 |
|---|---|
ctx.get_touch_sensor_enabled() | 获取触觉传感器启用状态 |
ctx.get_touch_sensor_fw_versions() | 获取触觉传感器固件版本 |
ctx.get_touch_sensor_raw_data() | 获取触觉原始数据 |
ctx.get_touch_sensor_status() | 获取触觉传感器状态 |
ctx.touch_sensor_setup() | 设置触觉传感器 |
ctx.touch_sensor_reset() | 重置触觉传感器 |
ctx.touch_sensor_calibrate() | 校准触觉传感器 |
LED 和按钮
| API | 说明 |
|---|---|
ctx.get_led_info() | 获取 LED 状态 |
ctx.set_led_info() | 设置 LED 状态 |
ctx.get_button_event() | 获取按钮事件 |
动作序列
| API | 说明 |
|---|---|
ctx.get_action_sequence() | 获取动作序列 |
ctx.transfer_action_sequence() | 上传动作序列 |
ctx.save_action_sequence() | 保存动作序列到闪存 |
ctx.run_action_sequence() | 执行动作序列 |
ctx.clear_action_sequence() | 清除自定义动作序列 |
设备配置
| API | 说明 |
|---|---|
ctx.get_force_level() | 获取力度等级 |
ctx.set_force_level() | 设置力度等级 |
ctx.get_auto_calibration_enabled() | 获取自动校准状态 |
ctx.set_auto_calibration() | 设置自动校准 |
ctx.calibrate_position() | 手动校准位置 |
ctx.get_turbo_mode_enabled() | 获取 Turbo 模式状态 |
ctx.set_turbo_mode_enabled() | 设置 Turbo 模式 |
ctx.get_turbo_config() | 获取 Turbo 配置 |
ctx.set_turbo_config() | 设置 Turbo 配置 |
ctx.reset_default_gesture() | 恢复默认手势 |
ctx.reset_default_settings() | 恢复默认设置 |
ctx.reboot() | 重启设备 |
固件升级
| API | 说明 |
|---|---|
ctx.start_dfu() | 启动固件升级 |