预编译 Python 扩展模块(pybind11)。整个 SDK 只控制夹爪,独立交付、开箱即用。
模块名:
import onerogripper(pybind11 原生扩展,包名onerogripper)。
python/
├── conda_channel/ # 离线 conda 渠道
│ ├── linux/{linux-64, linux-aarch64}/
│ └── windows/win-64/
└── wheels/
└── linux-riscv64/onerogripper-*.whl # RISC-V wheel
类型存根 onerogripper.pyi 随包自带,安装后位于
<env>/lib/python3.12/site-packages/onerogripper.pyi;预编译扩展位于同目录的
onerogripper.cpython-312-*.so(Linux)或 onerogripper.cp312-*.pyd(Windows)。
conda create -n onerogripper python=3.12 -y
conda activate onerogripper
# Linux
conda install -c conda-forge -c ./python/conda_channel/linux onerogripper -y
# Windows (PowerShell / cmd)
conda install -c conda-forge -c ./python/conda_channel/windows onerogripper -y
⚠️ 不要用反斜杠.\python\conda_channel\windows。conda 只把开头为./..//~或盘符C:\的字符串识别为本地路径;.\不在此列,会被当成渠道名拼到https://conda.anaconda.org/后面去联网(Windows 必现)。正斜杠在 Windows 上同样有效。若仍想彻底避免歧义,可改用绝对路径或
file://URL(在仓库根目录执行):conda install -c conda-forge -c "file://$PWD/python/conda_channel/linux" onerogripper -y # Linuxconda install -c conda-forge -c "file:///$($PWD.Path -replace '\\','/')/python/conda_channel/windows" onerogripper -y # Windows PowerShell也可用
micromamba install ...替代conda install。安装时必须保留
-c conda-forge,本地 channel 仅提供onerogripper自身,依赖从 conda-forge 拉取。
python -c "import onerogripper; print('OK,', onerogripper.__file__)"无硬件连接时 OneroGripper("/dev/ttyACM0") 不会抛异常,但 valid() 返回 False——
这是预期行为,可用于纯环境自检。
RISC-V 随包提供 linux-riscv64 wheel,不走 conda channel:
# 1. 进入用户仓根目录
# 2. 使用 Python 3.12;wheel 标签是 cp312
python3.12 -m venv .venv_onerogripper
. .venv_onerogripper/bin/activate
python -m pip install --upgrade pip
# 3. 安装随包 wheel
python -m pip install --no-deps ./python/wheels/linux-riscv64/onerogripper-*.whl
# 4. 自检
python -c "import onerogripper; print('OK,', onerogripper.__file__)"
onerogripper的 RISC-V wheel 文件名通常类似onerogripper-<version>-cp312-abi3-linux_riscv64.whl。其中cp312表示 Python 3.12,abi3是预期的稳定 ABI 标签,linux_riscv64是平台标签;请不要手动改名。夹爪 Python wheel 不打包第三方机器人 / 数学库;运行时只需要目标系统的标准 C/C++ 运行时库。若
import onerogripper报动态库加载错误,先确认当前机器是 riscv64、 Python 是 3.12,且 wheel 来自python/wheels/linux-riscv64/。
import onerogripper
s = onerogripper.GripperStatus() # position / velocity / force / error / valid| 字段 | 类型 | 单位 / 含义 |
|---|---|---|
position |
float |
开合位置,百分比 0..100 |
velocity |
float |
速度,百分比/s |
force |
float |
力,N,限幅 ±40 |
error |
int |
故障码,0 = 正常 |
valid |
bool |
该帧状态是否有效 |
夹爪触觉数据类(get_tactile() 返回):
ts = onerogripper.GripperTactileStatus() # sensors / valid
sv = onerogripper.GripperTactileSensorStatus() # sensor_id / total_force / points / valid
pt = onerogripper.GripperTactileValue() # point_id / fx / fy / fz / valid| 类 | 字段 | 类型 | 含义 |
|---|---|---|---|
GripperTactileStatus |
sensors |
list[GripperTactileSensorStatus] |
2 个触觉传感器 |
valid |
bool |
是否读到有效数据 | |
GripperTactileSensorStatus |
sensor_id |
int |
传感器编号 |
total_force |
GripperTactileValue |
该传感器合力 | |
points |
list[GripperTactileValue] |
各测点读数 | |
valid |
bool |
该传感器是否有效 | |
GripperTactileValue |
point_id |
int |
0 = 合力,其余为各测点 |
fx / fy / fz |
float |
三轴受力,N | |
valid |
bool |
该读数是否有效 |
0 # SUCCESS 成功
-1 # INVALID_PARAMS 会话未就绪 / 参数非法(如 max_* <= 0)
-4 # EXECUTION_FAILED 串口/总线写失败或状态刷新失败
-6 # INTERRUPTED move_position 被 request_stop() 取消class OneroGripper:
def __init__(self, device: str) -> None: ... # 波特率固定 921600
def valid(self) -> bool: ...
def enable(self) -> int: ...
def disable(self) -> int: ...
def status(self) -> GripperStatus: ...
def get_tactile(self) -> GripperTactileStatus: ...
def set_position(self, percent: float) -> int: ...
def move_position(self, percent: float, max_vel: float = 100.0,
max_acc: float = 250.0, max_jerk: float = 1000.0) -> int: ...
def force_control(self, torque: float) -> int: ...
def request_stop(self) -> None: ...
def clear_stop(self) -> None: ...构造时打开独立串口会话;构造不抛异常,需用 valid() 判断会话是否就绪。
| 方法 | 参数 | 返回 | 语义 |
|---|---|---|---|
OneroGripper(device) |
device:Linux "/dev/ttyACM0" / Windows "COM3" |
– | 打开独立串口会话 |
valid() |
– | bool |
会话是否就绪(串口已打开且夹爪已注册) |
enable() / disable() |
– | int |
使能 / 失能夹爪电机;运动前先 enable() |
set_position(percent) |
0..100 |
int |
单帧位置保持(非阻塞) |
move_position(percent, max_vel=100.0, max_acc=250.0, max_jerk=1000.0) |
percent:0..100;max_* 速度/加速度/加加速度上限(须 >0) |
int |
100 Hz 点到点 S 曲线规划,阻塞直到到位 |
force_control(torque) |
torque:N |
int |
单帧力保持,内部钳位 ±40 N |
status() |
– | GripperStatus |
刷新并返回夹爪状态 |
get_tactile() |
– | GripperTactileStatus |
刷新并返回 2 个触觉传感器的合力与各测点读数 |
request_stop() / clear_stop() |
– | None |
置位 / 复位中断标志:request_stop() 使正在进行的 move_position() 尽快返回 INTERRUPTED(-6);新一轮运动前 clear_stop() 复位 |
enable/disable/status/get_tactile/set_position/move_position/force_control在执行期间释放 GIL, 因此阻塞的move_position()进行中,可从另一个线程调用request_stop()将其取消。
get_tactile()会触发一次读取;读数前先判tactile.valid/sensor.valid/point.valid, 通常需先enable()并施加一定夹持力才会读到非零数据。
import onerogripper as g
grip = g.OneroGripper("/dev/ttyACM0") # Windows: "COM3"
assert grip.valid(), "failed to open gripper"
grip.enable()
grip.move_position(80.0) # 闭合到 80%(默认速度/加速度上限)
s = grip.status()
print(f"pos={s.position:.1f}% vel={s.velocity:.1f} force={s.force:.2f}N")
grip.force_control(20.0) # 20 N 力保持(±40 N 上限)
grip.disable()线程取消正在进行的运动:
import threading, onerogripper as g
grip = g.OneroGripper("/dev/ttyACM0")
grip.enable()
# 后台线程跑一段长行程
t = threading.Thread(target=lambda: grip.move_position(100.0, 10.0, 20.0, 50.0))
t.start()
# 主线程需要时取消
grip.request_stop() # move_position 将返回 -6 INTERRUPTED
t.join()
grip.clear_stop() # 复位后才能再次运动读取触觉传感器:
import onerogripper as g
grip = g.OneroGripper("/dev/ttyACM0")
assert grip.valid(), "failed to open gripper"
grip.enable()
grip.move_position(100.0) # 闭合到位
grip.force_control(10.0) # 施加一点夹持力以产生触觉读数
tac = grip.get_tactile()
if tac.valid:
for sensor in tac.sensors:
if not sensor.valid:
continue
tf = sensor.total_force # 合力
print(f"sensor {sensor.sensor_id} total "
f"x={tf.fx:.2f} y={tf.fy:.2f} z={tf.fz:.2f} N")
for p in sensor.points: # 各测点
if p.valid:
print(f" point {p.point_id} "
f"x={p.fx:.2f} y={p.fy:.2f} z={p.fz:.2f} N")
grip.disable()| 现象 | 原因 / 处理 |
|---|---|
PackagesNotFoundError: onerogripper |
-c channel 路径不对;python/conda_channel/linux/ 下应有 linux-64/(或 linux-aarch64/)子目录及 repodata.json |
UnsatisfiableError |
用全新环境:conda create -n onerogripper python=3.12 -y;安装命令保留 -c conda-forge |
not a supported wheel on this platform |
当前 Python / 架构与 wheel 标签不匹配;RISC-V wheel 需要 riscv64 机器和 Python 3.12 |
python/wheels/linux-riscv64/onerogripper-*.whl 找不到 |
用户仓尚未同步 RISC-V wheel;确认存在 python/wheels/linux-riscv64/onerogripper-*.whl |
import onerogripper 报 ImportError / DLL load failed(Windows) |
确认已 conda activate onerogripper,IDE 解释器是该环境的 Python |
OneroGripper(...).valid() 返回 False |
串口路径 / 权限:Linux ls /dev/ttyACM*,必要时 sudo chmod 666 /dev/ttyACM0 或加入 dialout 组;Windows 在设备管理器查 COM 号 |
同一设备第二次打开 valid() 仍为 False |
串口被独占:确认没有其他进程正占用该设备 |
方法返回 -1 |
会话未就绪(valid()==False);或 move_position 的 max_vel/acc/jerk <= 0 |
方法返回 -4 |
串口 / 总线写失败或状态刷新失败:检查连线、供电、设备是否被拔出 |
move_position 返回 -6 |
运动期间被 request_stop() 取消;下次运动前调用 clear_stop() 复位 |
get_tactile().valid 为 False 或读数全 0 |
会话未就绪(valid()==False),或夹爪未 enable() / 未接触受力;先 enable() 并施加夹持力再读 |