Metadata-Version: 2.4
Name: rabo_robolib
Version: 3.0.0
Summary: rabo_robolib: ROS2 机器人能力封装
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Requires-Dist: numpy
Provides-Extra: test
Requires-Dist: pytest>=7.0; extra == "test"
Requires-Dist: pytest-cov; extra == "test"
Provides-Extra: build
Requires-Dist: oss2; extra == "build"

# rabo_robolib

ROS2 机器人能力封装 SDK，为 rabo sim 仿真中的机器人提供高级控制接口。

支持热更新：`pip install` 一次后，每次 `import` 自动获取最新版本。

> **3.0（`rabo_robolib`）与 2.x（`rabo_robocap`）的关系**：3.0 起 pip 包 / import 名改为 `rabo_robolib`，
> 部分机器人 API 不再向前兼容（AgilexPiper、LinkerHandO6 以实机驱动为准重做，见 `docs/features/`）。
> 老包 `rabo_robocap` 继续从 OSS `rabo_robocap/` 前缀热更新、缓存 `~/.rabo_robocap`、核心包 `_rabo_core`，
> 完全不受影响；新包走 `rabo_robolib/` 前缀、`~/.rabo_robolib`、`_robolib_core`，两者可同机共存。
> ROS 消息包 `rabo_robocap_msgs` 与节点/接口名不变，无需重编。

## 安装

```bash
# 1. 安装 Python 包（仅需一次）
pip install rabo_robolib

# 2. 构建 ROS2 消息包（需要 ROS2 环境）
cd ~/ros2_ws/src/rabo-lib
colcon build --paths rabo_robocap_msgs
source install/setup.bash
```

详细构建说明请参考 [构建指南](docs/build.md)。

## 使用

### 移动底盘

```python
from rabo_robolib import AgilexScoutMini

# 仿真模式（自动从 API 获取配置，rclpy 自动初始化）
base = AgilexScoutMini(robot_id='scout_model', mode='sim')

# 或 真实硬件模式
# base = AgilexScoutMini(robot_id='scout', mode='real')

base.set_velocity(linear_x=0.5, angular_z=0.0)
base.move_distance(1.0)
x, y, theta = base.get_odometry()
print(f"Position: ({x:.2f}, {y:.2f}), Heading: {theta:.2f}")

base.shutdown()
```

### 机械臂

```python
import numpy as np
from rabo_robolib import UniversalRobotsUR5

# 仿真模式
arm = UniversalRobotsUR5(robot_id='ur5_model', mode='sim')

# 或 真实硬件
# arm = UniversalRobotsUR5(robot_id='ur5', mode='real')

# 移动到 ready 位置
arm.move_joints([0, -np.pi/2, np.pi/2, -np.pi/2, -np.pi/2, 0])

# 移动到目标位置
arm.move_to(0.3, 0.2, 0.4)

# 获取当前位姿
pos, ori = arm.get_pose()
print(f"Position: {pos}")

arm.shutdown()
```

### AgileX Piper（sim / real 同一份 API）

`AgilexPiper` 的接口以实机 piper_ws 驱动为准，仿真与实机同一份脚本只改 `mode`：

```python
from rabo_robolib import AgilexPiper

arm = AgilexPiper(robot_id='piper', mode='sim')     # 或 mode='real'（机器上跑着 piper_ws 驱动）
arm.enable()                                         # real 默认 auto_enable=True 已自动使能
arm.move_joints([0, 0.5, -0.5, 0, 0.3, 0], speed=30)  # speed: 全臂速度百分比 1~100（默认 20）
arm.move_to(0.25, 0.0, 0.3, 0.0, 1.2, 0.0)           # base_link 系，m / rad
arm.set_gripper(0.05)                                # 夹爪开度 m（无夹爪的臂返回 False）
arm.home()                                           # 默认 10% 速度
arm.stop()                                           # 保持当前位置
arm.disable()
arm.shutdown()
```

未使能时运动指令一律拒绝（返回 False + error 日志），sim 亦然。完整示例见 `demo/piper_demo.py`。

### LinkerHand O6 灵巧手（sim / real 同一份 API）

`LinkerHandO6Left/Right` 的接口以实机 linkerhand_o6 驱动为准：6 个主动电机、归一化 0=张开/1=闭合，顺序 `[thumb_rotation, thumb_bend, index, middle, ring, pinky]`；sim 的 11 关节 = 6 主动 + 5 从动自动随动。

```python
from rabo_robolib import LinkerHandO6Right

hand = LinkerHandO6Right(robot_id='hand_right', mode='sim')   # 或 mode='real'（robot_id = 驱动实例名）
hand.clench(index=1.0, middle=1.0)                             # None = 该指保持
hand.move_joints([0, 0, 1, 1, 1, 1], speed=50)                 # speed 1~100%
hand.grasp_force(0.5)                                          # 抓取：握到接触为止
hand.open(); hand.close(); hand.home()
hand.shutdown()
```

`close()/move_joints()` 是位置目标，被物体挡住返回 False；抓取请用 `grasp_force`。完整示例见 `demo/linkerhand_o6_demo.py`。

### 版本管理

```python
import rabo_robolib

# 查看当前版本
print(rabo_robolib.__version__)

# 查看更新状态
rabo_robolib.check_update()
```

**注意**：
- rclpy 自动初始化，无需手动调用 `rclpy.init()`
- 节点内部自动管理 ROS2 回调，**不要**将节点添加到外部 executor

## 文档

- [构建指南](docs/build.md)
- [整体架构](docs/architecture.md)
- [AgilexScoutMini 移动底盘](docs/robots/AgilexScoutMini.md)
- [GalaxeaR1LiteChassis 移动底盘](docs/robots/GalaxeaR1LiteChassis.md)
- [UniversalRobotsUR5 机械臂](docs/robots/UniversalRobotsUR5.md)
- [UniversalRobotsUR10 机械臂](docs/robots/UniversalRobotsUR10.md)
- [AgilexPiper 机械臂（sim/real 统一）](docs/robots/AgilexPiper.md)
- [LinkerHandO6 灵巧手（sim/real 统一）](docs/robots/LinkerHandO6Right.md)
- [设计规则](CLAUDE.md)
