Skip to content
帮助

Python SDK - Revo2 灵巧手

系统要求

  • 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)

快速开始

克隆仓库

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 revo2
python revo2_ctrl.py          # 单手控制
python revo2_touch.py         # 触觉传感器(触觉版)
python revo2_ctrl_multi.py    # 多手控制
python revo2_action_seq.py    # 动作序列
python revo2_cfg.py           # 设备配置

# CANFD 通信协议
cd revo2_canfd
python zqwl_canfd.py          # 读取设备信息,控制设备
python zqwl_canfd_dfu.py      # 固件 OTA

# EtherCAT 通信协议
cd revo2_ethercat
python ec_sdo.py              # SDO 读取/配置
python ec_pdo.py              # PDO 读取关节状态,控制设备
python ec_dfu.py              # 固件 OTA
shell
# 安装步骤同 Ubuntu
# 注意:macOS 串口设备名称通常为 /dev/tty.usbserial-xxx
# macOS 不支持 CANFD 通信协议
shell
# 如果 USB 驱动无法识别,请在设备管理器中查看串口名称
# 串口驱动下载: https://app.brainco.cn/universal/stark-serialport-prebuild/driver/CH340-drivers.zip

# 其他安装步骤同 Ubuntu
# 注意:Windows 串口设备名称通常为 COM3, COM4 等
# Windows 不支持 EtherCAT 通信协议

示例代码

SDK 提供了丰富的示例代码,涵盖不同通信协议和应用场景。

Modbus-RTU 协议

单手/双手控制

触觉传感器

动作序列(手势)

固件升级

CANFD 协议

单手/双手控制

固件升级

EtherCAT 协议

命令行工具

shell
# 查看 EtherCAT 版本
# 推荐使用 igH EtherCAT Master 1.6.x 版本(最新稳定版)
 ethercat version
IgH EtherCAT master 1.6.6 1.6.6-5-g64899015

# 注意:如果您的 EtherCAT 版本为 1.5.x,请联系技术支持
# SDK 默认针对 1.6.x 版本编译,1.5.x 版本可能存在兼容性问题
 ethercat version
IgH EtherCAT master 1.5.3 1.5.3

# 查看主站状态
 systemctl status ethercat

# 查看设备
 ethercat slave
0  0:0  PREOP  +  BrainCo-Revo2Slave

# SDO - 读取固件版本号
 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 - 读取关节位置
 ethercat upload -t raw -p 0 0x6000 0x01 | xxd -r -p | od -An -t u2 --endian=little -w2

# 为 Python 程序设置权限
sudo setcap cap_sys_nice,cap_net_raw=eip /path/to/miniconda3/envs/py310/bin/python3.10

关于 EtherCAT 版本

  • 推荐版本:igH EtherCAT Master 1.6.x(最新稳定版)
  • SDK 兼容性:SDK 默认针对 1.6.x 版本编译
  • 1.5.x 版本:如果您使用的是 1.5.x 版本,请联系技术支持获取兼容版本
  • 纯 C++ 实现:推荐使用 纯 C++ EtherCAT 示例(不依赖 SDK,直接使用 EtherCAT 库)

PDO 通信

SDO 通信

固件升级

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)

CANFD 连接

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 连接

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 communication

设备信息与设置

设备信息

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
# ================================
# 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)

高性能数据采集 ⭐

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]}...")

交互功能

动作序列(手势)

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_zqwl_devices()列出 ZQWL CAN/CANFD 设备 ⭐
libstark.init_zqwl_canfd()初始化 ZQWL CANFD 设备
libstark.init_zqwl_can()初始化 ZQWL CAN 2.0 设备
libstark.close_zqwl()关闭 ZQWL 设备

连接管理(传统)

API说明
libstark.get_sdk_version()获取 SDK 版本
libstark.list_available_ports()列出可用串口
libstark.modbus_open()打开 Modbus 连接
libstark.modbus_close()关闭 Modbus 连接
libstark.init_device_handler()创建设备处理器
device.close()关闭设备连接
libstark.auto_detect_device()自动检测设备(仅 Modbus)
libstark.auto_detect_modbus_revo2()自动检测 Revo2 设备(仅 Modbus)

设备信息

API说明
device.get_device_info()获取设备完整信息
device.is_touch_hand()判断是否支持触觉 ⭐
device.uses_revo1_motor_api()判断是否使用 Revo1 电机 API ⭐
device.uses_revo2_motor_api()判断是否使用 Revo2 电机 API ⭐
device.uses_pressure_touch_api()判断是否使用压力触觉 API ⭐
device.get_device_sn()获取设备序列号
device.get_device_fw_version()获取固件版本
device.get_sku_type()获取 SKU 类型
device.get_serialport_cfg()获取串口配置
device.get_canfd_baudrate()获取 CANFD 波特率
device.set_serialport_baudrate()设置波特率
device.set_slave_id()设置从站 ID

电机控制 - 位置(统一范围 0-1000)

API说明
device.set_finger_position()设置单个手指位置
device.set_finger_position_with_millis()设置位置(指定时间)⭐
device.set_finger_position_with_speed()设置位置(指定速度)⭐
device.set_finger_positions()设置所有手指位置
device.set_finger_positions_and_durations()设置位置和时间 ⭐
device.set_finger_positions_and_speeds()设置位置和速度 ⭐
device.get_finger_positions()获取所有手指位置

电机控制 - 速度(统一范围 -1000~+1000)

API说明
device.set_finger_speed()设置单个手指速度
device.set_finger_speeds()设置所有手指速度
device.get_finger_speeds()获取所有手指速度

电机控制 - 电流(统一范围 -1000~+1000)

API说明
device.set_finger_current()设置单个手指电流
device.set_finger_currents()设置所有手指电流
device.get_finger_currents()获取所有手指电流

电机控制 - PWM(统一范围 -1000~+1000)⭐

API说明
device.set_finger_pwm()设置单个手指 PWM
device.set_finger_pwms()设置所有手指 PWM

电机状态

API说明
device.get_motor_status()获取电机综合状态
device.get_motor_state()获取电机运行状态

电机设置 ⭐

API说明
device.get_finger_unit_mode()获取单位模式
device.set_finger_unit_mode()设置单位模式
device.get_all_finger_settings()获取所有手指设置
device.get_finger_settings()获取单个手指设置
device.set_finger_settings()设置单个手指设置
device.get_finger_min_position()获取最小位置限制
device.set_finger_min_position()设置最小位置限制
device.get_finger_max_position()获取最大位置限制
device.set_finger_max_position()设置最大位置限制
device.get_finger_max_speed()获取最大速度限制
device.set_finger_max_speed()设置最大速度限制
device.get_finger_max_current()获取最大电流限制
device.set_finger_max_current()设置最大电流限制
device.get_finger_protected_current()获取保护电流
device.set_finger_protected_current()设置保护电流
device.get_finger_protected_currents()获取所有保护电流
device.set_finger_protected_currents()设置所有保护电流
device.get_thumb_aux_lock_current()获取拇指辅助锁定电流
device.set_thumb_aux_lock_current()设置拇指辅助锁定电流

触觉传感器

API说明
device.get_touch_sensor_enabled()获取触觉传感器启用状态
device.get_touch_sensor_fw_versions()获取触觉传感器固件版本
device.get_touch_sensor_raw_data()获取触觉原始数据
device.get_touch_sensor_status()获取触觉传感器状态
device.get_single_touch_sensor_status()获取单个传感器状态
device.touch_sensor_setup()设置触觉传感器
device.touch_sensor_reset()重置触觉传感器
device.touch_sensor_calibrate()校准触觉传感器

Modulus 触觉传感器 ⭐

API说明
device.set_modulus_touch_data_type()设置数据类型
device.get_modulus_touch_data_type()获取数据类型
device.get_modulus_touch_summary()获取触觉摘要
device.get_single_modulus_touch_summary()获取单指触觉摘要
device.get_modulus_touch_data()获取触觉详细数据
device.get_single_modulus_touch_data()获取单指触觉数据

高性能数据采集 ⭐

API说明
DataCollector.new_basic()创建基础采集器(仅电机)
DataCollector.new_capacitive()创建电容触觉采集器
DataCollector.new_pressure_summary()创建压力摘要采集器
DataCollector.new_pressure_detailed()创建压力详细采集器
DataCollector.new_pressure_hybrid()创建混合模式采集器
collector.start()启动数据采集
collector.stop()停止数据采集
collector.wait()等待采集线程结束
collector.is_running()检查是否正在运行
MotorStatusBuffer电机状态缓冲区
TouchStatusBuffer触觉状态缓冲区
PressureSummaryBuffer压力摘要缓冲区
PressureDetailedBuffer压力详细缓冲区

LED、蜂鸣器、震动 ⭐

API说明
device.get_led_enabled()获取 LED 启用状态
device.set_led_enabled()设置 LED 启用状态
device.get_buzzer_enabled()获取蜂鸣器启用状态
device.set_buzzer_enabled()设置蜂鸣器启用状态
device.get_vibration_enabled()获取震动启用状态
device.set_vibration_enabled()设置震动启用状态

动作序列

API说明
device.get_action_sequence()获取动作序列
device.transfer_action_sequence()上传动作序列
device.save_action_sequence()保存动作序列到闪存
device.run_action_sequence()执行动作序列
device.clear_action_sequence()清除自定义动作序列

设备配置

API说明
device.get_force_level()获取力度等级
device.set_force_level()设置力度等级
device.get_auto_calibration_enabled()获取自动校准状态
device.set_auto_calibration()设置自动校准
device.calibrate_position()手动校准位置
device.get_turbo_mode_enabled()获取 Turbo 模式状态
device.set_turbo_mode_enabled()设置 Turbo 模式
device.get_turbo_config()获取 Turbo 配置
device.set_turbo_config()设置 Turbo 配置
device.reset_default_gesture()恢复默认手势
device.reset_default_settings()恢复默认设置
device.reboot()重启设备

EtherCAT 专用 ⭐

API说明
device.ec_setup_sdo()设置 SDO
device.ec_reserve_master()预留主站
device.ec_start_loop()启动循环
device.ec_stop_loop()停止循环
device.ec_start_dfu()启动固件升级

固件升级

API说明
device.start_dfu()启动固件升级

通信回调

API说明
libstark.set_modbus_read_holding_callback()设置 Modbus 读保持寄存器回调
libstark.set_modbus_read_input_callback()设置 Modbus 读输入寄存器回调
libstark.set_modbus_write_callback()设置 Modbus 写回调
libstark.set_can_rx_callback()设置 CAN 接收回调
libstark.set_can_tx_callback()设置 CAN 发送回调

⭐ 标记表示 Revo2 专有或增强功能