diff --git a/CMakeLists.txt b/CMakeLists.txt index b2f5e85..34515bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,14 +1,12 @@ cmake_minimum_required(VERSION 3.16) project(litegrip_cpp VERSION 0.1.0 LANGUAGES CXX) -# litegrip_cpp — ROS-agnostic C++ SDK for the LiteGrip adaptive two-finger gripper. +# litegrip_cpp — C++ SDK for the LiteGrip adaptive two-finger gripper. # # Design constraints (see ../PLAN-litegrip-cpp.md): # * C++17, zero third-party dependencies (stdlib + Linux SocketCAN only). -# * MUST NOT depend on ROS / ament / ros2_control — this library is the bottom -# layer that ros2_control links, and is usable from any plain C++ program. -# * Installable both into a ROS workspace (colcon, plain-cmake package.xml) -# and into a normal prefix (find_package + pkg-config). +# * No framework dependencies — usable from any plain C++ program. +# * Installable into a normal prefix (find_package + pkg-config). if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) set(LITEGRIP_CPP_IS_TOP_LEVEL ON) diff --git a/README.md b/README.md index d9e6e42..1afd6bc 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,18 @@ # litegrip_cpp -ROS-agnostic **C++ SDK** for the LiteGrip adaptive two-finger gripper. +**C++ SDK** for the LiteGrip adaptive two-finger gripper. **English** · [简体中文](README_zh.md) -This is layer 1 of the litegrip stack — `litegrip_cpp` (SDK) → `litegrip_ros2_control` -(hardware interface) → `litegrip_moveit_config` (MoveIt). It speaks SocketCAN and -the Damiao DM4310 MIT protocol directly and depends on **nothing** but the C++17 -standard library, `pthread`, and the Linux SocketCAN headers: no ROS, no ament, -no third-party libraries. Non-ROS implementations can link it as-is. +The bottom layer of the litegrip stack. It speaks SocketCAN and the Damiao +DM4310 MIT protocol directly and depends on **nothing** but the C++17 standard +library, `pthread`, and the Linux SocketCAN headers: no third-party libraries. +Any plain C++ program can link it as-is. -> Status: **layer 1 is complete** — `can/*`, `GripperBus`, `LiteGrip`, +> Status: **the SDK is complete** — `can/*`, `GripperBus`, `LiteGrip`, > `json`/calibration, `SafetyGuard` and `ControlLoop` are all implemented and > tested. -## What is **not** in this version - -Per the agreed v1 scope: `grasp()`, `set_force()`, `move_at_speed*()` and the -public zero-gravity mode. `close(force_n=...)` accepts the argument, ignores it -and says so, because applying a grip force needs torque feed-forward and -verified force calibration. - ## Safety wiring The motion path (`goto_rad` / `move_to` / `open` / `close` / `home`) passes @@ -80,7 +72,7 @@ motion, calibration, and the transport send/receive path. | `GripperBus` | single-gripper bus API (init = hold) | `protocols/can_bus.py` | | `LiteGrip` | high-level API | `gripper.py` | | `SafetyGuard` + `SafetyLimits` | red lines, torque budget, watchdog, modes | `safety_limits.py` (core) | -| `ControlLoop` | background 200 Hz streaming + rate limit + gate | old ROS-side daemon | +| `ControlLoop` | background 200 Hz streaming + rate limit + gate | old Python-side daemon | ## Build @@ -92,21 +84,18 @@ cmake --build build -j ctest --test-dir build --output-on-failure ``` -It is also buildable by `colcon` (declared as a plain-cmake package via -`package.xml`) so a ROS workspace can build it beside the ROS packages. - ## Consume ```cmake find_package(litegrip_cpp REQUIRED) -target_link_libraries(my_node PRIVATE litegrip_cpp::litegrip_cpp) +target_link_libraries(my_app PRIVATE litegrip_cpp::litegrip_cpp) ``` ```bash pkg-config --cflags --libs litegrip_cpp ``` -## Non-ROS usage +## Minimal example ```cpp #include @@ -133,11 +122,3 @@ These are the safety argument and must not be relaxed: be bounded ⇒ do not move that way. 4. **Strict numeric boundary** — NaN / ±inf / non-numbers are rejected before any comparison. - -## Red lines are not yet unit-specific - -The packaged safety baseline carries the reference unit's hand-push measurement. -They must be re-derived per gripper (caliper + closed-end re-zero) before -real-hardware motion, and `ControlLoopConfig::max_feedback_velocity_rad_s` must -be calibrated first — until it is, the loop refuses to send any motion frame -(deliberate fail-closed). diff --git a/README_zh.md b/README_zh.md index 67c110a..8cbaff9 100644 --- a/README_zh.md +++ b/README_zh.md @@ -1,13 +1,12 @@ # litegrip_cpp -LiteGrip 自适应两指夹爪的 **ROS 无关 C++ SDK**。 +LiteGrip 自适应两指夹爪的 **C++ SDK**。 -本包是 litegrip 栈的第 1 层 —— `litegrip_cpp`(SDK)→ `litegrip_ros2_control` -(硬件接口)→ `litegrip_moveit_config`(MoveIt)。它直接讲 SocketCAN 与达妙 -DM4310 的 MIT 协议,依赖**只有** C++17 标准库、`pthread` 和 Linux SocketCAN -头文件:没有 ROS、没有 ament、没有第三方库。非 ROS 实现可以直接链接使用。 +litegrip 栈的最底层。它直接讲 SocketCAN 与达妙 DM4310 的 MIT 协议,依赖 +**只有** C++17 标准库、`pthread` 和 Linux SocketCAN 头文件:没有第三方库。 +任何普通 C++ 程序都可以直接链接。 -> 状态:**第 1 层已全部实现**(`can/*`、`GripperBus`、`LiteGrip`、 +> 状态:**SDK 已全部实现**(`can/*`、`GripperBus`、`LiteGrip`、 > `json`/标定、`SafetyGuard`、`ControlLoop`)。 ## 分层 @@ -21,7 +20,7 @@ DM4310 的 MIT 协议,依赖**只有** C++17 标准库、`pthread` 和 Linux S | `GripperBus` | 单爪总线 API(`init` = 持位) | `protocols/can_bus.py` | | `LiteGrip` | 高层 API | `gripper.py` | | `SafetyGuard` + `SafetyLimits` | 红线、力矩预算、看门狗、模式 | `safety_limits.py`(核心) | -| `ControlLoop` | 后台 200 Hz 流式发送 + 限速 + 闸门 | 旧的 ROS 侧守护进程 | +| `ControlLoop` | 后台 200 Hz 流式发送 + 限速 + 闸门 | 旧的 Python 侧守护进程 | ## 构建 @@ -33,21 +32,18 @@ cmake --build build -j ctest --test-dir build --output-on-failure ``` -它同时可以被 `colcon` 构建(通过 `package.xml` 声明为 plain-cmake 包), -因此 ROS 工作空间能把它和其余 ROS 包一起构建。 - ## 消费方式 ```cmake find_package(litegrip_cpp REQUIRED) -target_link_libraries(my_node PRIVATE litegrip_cpp::litegrip_cpp) +target_link_libraries(my_app PRIVATE litegrip_cpp::litegrip_cpp) ``` ```bash pkg-config --cflags --libs litegrip_cpp ``` -## 非 ROS 用法 +## 最小示例 ```cpp #include @@ -63,12 +59,6 @@ int main() { } ``` -## 本版本**不包含** - -按已确认的 v1 范围:`grasp()`、`set_force()`、`move_at_speed*()`,以及公开的零重力 -模式。`close(force_n=...)` 接受该参数但**忽略并明确告警**,因为施加夹持力需要力矩 -前馈与经过验证的力标定,两者都不在 v1 范围内。 - ## 安全不变量 这些是安全论证本身,**不得放宽**: @@ -90,16 +80,6 @@ int main() { - **标定流程** —— 它们本来就要把机构顶到**机械**端点,而机械端点在红线之外。 (标定与红线之间的正确关系仍是一个待定事项,见方案中的未决项。) -## 红线尚未按本台夹爪重建 - -随包的安全基线携带的是**参考台**的手推实测值,且文件内已明确标注 -**未在本机验证**。在真机运动之前必须重新标定(卡尺 + 闭合端重设零点)并以实测值 -重建红线;同时 `ControlLoopConfig::max_feedback_velocity_rad_s` 必须先行标定 —— -在该值给出之前,控制环**拒绝发送任何运动帧**(这是刻意的 fail-closed)。 - -推论:若某台夹爪的标定使闭合端落在红线之外,本 SDK 会(正确地)**拒绝一切运动**, -直到红线被重建。 - ## 测试 ```bash @@ -125,7 +105,3 @@ ctest --test-dir build --output-on-failure 覆盖** —— 需要 vcan 接口(需 root)或真机。 同样没有覆盖、需要真机的部分:连接、`init`/使能、运动、标定。 - -## 许可证 - -MIT。 diff --git a/cmake/litegrip_cpp.pc.in b/cmake/litegrip_cpp.pc.in index c1563a5..701cfc6 100644 --- a/cmake/litegrip_cpp.pc.in +++ b/cmake/litegrip_cpp.pc.in @@ -9,7 +9,7 @@ includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ datadir=${prefix}/@CMAKE_INSTALL_DATADIR@ Name: litegrip_cpp -Description: ROS-agnostic C++ SDK for the LiteGrip adaptive two-finger gripper (SocketCAN / Damiao DM4310 MIT protocol) +Description: C++ SDK for the LiteGrip adaptive two-finger gripper (SocketCAN / Damiao DM4310 MIT protocol) Version: @PROJECT_VERSION@ Libs: -L${libdir} -llitegrip_cpp Libs.private: -lpthread diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 85fa0b1..6555443 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,5 +1,6 @@ -# Examples are plain C++ programs that link the SDK. They are the -# "non-ROS consumer" proof: nothing here may include ROS headers. +# Examples are plain C++ programs that link the SDK. They are the "plain C++ +# consumer" proof: nothing here may include anything beyond the SDK and the +# standard library. # # ⚠ Examples that open can0 and drive the motor are added in T2–T4; the T1 set # is limited to things that cannot move hardware. diff --git a/include/litegrip/can/controller.hpp b/include/litegrip/can/controller.hpp index 2556d2d..109c54a 100644 --- a/include/litegrip/can/controller.hpp +++ b/include/litegrip/can/controller.hpp @@ -1,8 +1,8 @@ // litegrip/can/controller.hpp — manages DM motors over one CAN transport. // // Port of litegrip_driver/litegrip/can/controller.py. Kept multi-motor capable -// even though LiteGrip uses a single motor: it is the reusable "outside ROS" -// surface for anyone driving several Damiao motors on one bus. +// even though LiteGrip uses a single motor: it is the general-purpose surface +// for anyone driving several Damiao motors on one bus. #pragma once diff --git a/include/litegrip/control_loop.hpp b/include/litegrip/control_loop.hpp index c42931c..becb3f2 100644 --- a/include/litegrip/control_loop.hpp +++ b/include/litegrip/control_loop.hpp @@ -1,13 +1,13 @@ // litegrip/control_loop.hpp — background streaming control loop. // -// Replaces the old ros2_control Python daemon (hw_daemon.py + sdk_adapter.py + -// the shared-memory bridge). With a C++ SDK the two-process split has no reason -// to exist: the ros2_control hardware component links this class directly. +// Replaces the old Python daemon (hw_daemon.py + sdk_adapter.py + the +// shared-memory bridge). With a C++ SDK the two-process split has no reason to +// exist: the layer above links this class directly. // // R1: the loop runs on its own background thread. A DM motor needs a continuous // MIT frame stream (~900 ms of silence latches the 0xD comm-loss fault), and -// the controller_manager cycle is not guaranteed stable — so the plugin's -// write() only posts a target and its read() only reads a cached snapshot. +// the caller's cycle is not guaranteed stable — so the layer above only posts a +// target and reads a cached snapshot. // // What the loop owns (all of it used to be spread across safety_gate.py, // driver_adapter.py's TrajectoryLimiter and sdk_adapter.py's _send_motion): diff --git a/include/litegrip/gripper.hpp b/include/litegrip/gripper.hpp index 6db5ed6..9f71ff3 100644 --- a/include/litegrip/gripper.hpp +++ b/include/litegrip/gripper.hpp @@ -1,8 +1,7 @@ // litegrip/gripper.hpp — high-level gripper API (LiteGrip). // // Port of litegrip_driver/litegrip/gripper.py. This is the entry point most -// non-ROS consumers use: connect, init (hold), open/close/goto, calibrate, -// read state. +// consumers use: connect, init (hold), open/close/goto, calibrate, read state. // // v1 capability scope (PLAN-litegrip-cpp.md D6). Deliberately NOT in v1: // * grasp() / set_force() — force control, deferred @@ -43,7 +42,7 @@ class LiteGrip { LiteGrip& operator=(LiteGrip&& other) noexcept; /// Connect and return a live instance (throws ConnectError on failure). - /// The RAII one-liner for the non-ROS case. + /// The RAII one-liner: the returned object disconnects on destruction. static LiteGrip connect_raii(GripperConfig config = GripperConfig{}); // ── properties ──────────────────────────────────────────────────────── diff --git a/include/litegrip/safety.hpp b/include/litegrip/safety.hpp index a3b1cd7..4d6a5e4 100644 --- a/include/litegrip/safety.hpp +++ b/include/litegrip/safety.hpp @@ -2,10 +2,10 @@ // // Ported from the safety-aware SDK variant's safety_limits.py (core only — // exclude the contact/force/stall/no-load physics models, see -// PLAN-litegrip-cpp.md D5), plus the ROS-side gate's two hard ceilings +// PLAN-litegrip-cpp.md D5), plus the old Python gate's two hard ceilings // (TORQUE_LIMIT_CEILING_NM / MAX_COMMAND_VELOCITY_CEILING_RAD_S) so that the -// whole stack keeps a single source of truth now that the ROS-side Python is -// going away (D2/D4). +// whole stack keeps a single source of truth now that the old Python is going +// away (D2/D4). // // The Python original's long-form Chinese rationale is NOT copied here — it // lives in safety_limits.py and in the plan. What is preserved is the set of @@ -62,7 +62,7 @@ inline constexpr double kProtocolQMaxRad = 12.5; /// protocol range / a fake 0 read from nothing. inline constexpr double kZeroTorqueQFallback = -0.6; -/// ROS-side torque hard ceiling, N.m. Read-only: limits may only go below it. +/// Torque hard ceiling, N.m. Read-only: limits may only go below it. inline constexpr double kTorqueLimitCeilingNm = 3.5; /// Command-trajectory velocity hard ceiling, rad/s. Read-only. diff --git a/package.xml b/package.xml index e75b366..5f1c71c 100644 --- a/package.xml +++ b/package.xml @@ -1,19 +1,16 @@ - litegrip_cpp 0.1.0 - ROS-agnostic C++ SDK for the LiteGrip adaptive two-finger gripper. + C++ SDK for the LiteGrip adaptive two-finger gripper. - This is the bottom layer of the litegrip stack (sdk → ros2_control → - moveit_config). It speaks SocketCAN and the Damiao DM4310 MIT protocol - directly and depends on nothing but the C++17 standard library and the - Linux SocketCAN headers — deliberately no ROS, no ament, no third-party - libraries, so that non-ROS implementations can reuse it as-is. + This is the bottom layer of the litegrip stack. It speaks SocketCAN and the + Damiao DM4310 MIT protocol directly and depends on nothing but the C++17 + standard library and the Linux SocketCAN headers — no third-party + libraries. - Declared as a plain-cmake package (build_type cmake) purely so a colcon - workspace can build it alongside the ROS packages; the library itself is + Declared as a plain-cmake package (build_type cmake); the library itself is built and installed like any ordinary CMake project. TODO diff --git a/src/control_loop.cpp b/src/control_loop.cpp index 6c8a456..c025596 100644 --- a/src/control_loop.cpp +++ b/src/control_loop.cpp @@ -1,20 +1,20 @@ // control_loop.cpp — the background control loop. // -// Replaces the old ros2_control Python daemon + shared-memory bridge: with a -// C++ SDK the two-process split has no reason to exist, so "rate-limit the -// target, allocate the torque budget, gate the frame, stream it, watch the -// feedback" now lives in one thread inside the library. +// Replaces the old Python daemon + shared-memory bridge: with a C++ SDK the +// two-process split has no reason to exist, so "rate-limit the target, allocate +// the torque budget, gate the frame, stream it, watch the feedback" now lives +// in one thread inside the library. // // R1: the loop owns a background thread. A DM motor needs a continuous MIT // frame stream (~900 ms of silence latches the 0xD comm-loss fault) and the -// controller_manager cycle is not guaranteed stable, so the layer above only -// posts a target and reads a cached snapshot. +// caller's cycle is not guaranteed stable, so the layer above only posts a +// target and reads a cached snapshot. // // dry_run is not "do nothing": it runs the whole control path — rate limiting, // torque-budget allocation and the safety gate — against a simulated plant and // only skips opening CAN and sending. That makes the gate and the // deploy-config fail-closed behaviour testable without hardware, and is what -// makes a dry-run ros2_control stack meaningful. +// makes a dry-run deployment meaningful. #include "litegrip/control_loop.hpp" diff --git a/src/safety.cpp b/src/safety.cpp index d8f66d1..5fe4fcb 100644 --- a/src/safety.cpp +++ b/src/safety.cpp @@ -731,7 +731,7 @@ SafetyLimits load_safety_baseline(const std::optional& version) { : safety_baseline_path(wanted); if (!file_exists(path)) { // Fail-closed: silently falling back would make "the config was lost" look - // identical to "the config is correct", and the node would run with a + // identical to "the config is correct", and the process would run with a // torque ceiling nobody confirmed. throw SafetyConfigError("safety baseline '" + wanted + "' file does not exist: " + path + diff --git a/src/version.cpp b/src/version.cpp index 1954735..69e0948 100644 --- a/src/version.cpp +++ b/src/version.cpp @@ -1,4 +1,4 @@ -// litegrip_cpp — ROS-agnostic C++ SDK for the LiteGrip adaptive two-finger gripper. +// litegrip_cpp — C++ SDK for the LiteGrip adaptive two-finger gripper. #include "litegrip/version.hpp"