Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
265 changes: 257 additions & 8 deletions doc/tutorials/rdt/rdt_lpss.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ LPSS CLI 工具 {#tutorial_rdt_lpss}
============

@author 赵曦
@date 2026/06/06
@version 1.0
@date 2026/07/31
@version 1.1
@brief LPSS 命令行工具的使用教程

@prev_tutorial{tutorial_rdt_rdt}
Expand Down Expand Up @@ -35,6 +35,7 @@ LPSS 是一个轻量级的发布订阅通信框架,采用去中心化设计,
@dl_item{create,创建一个依赖 lpss 的新项目}
@dl_item{node,节点 CLI 工具}
@dl_item{topic,话题 CLI 工具}
@dl_item{service,服务 CLI 工具}
@dl_item{interface,内置消息接口查看工具}
@dl_item{graph,节点图工具}
@dl_item{viz,3D 可视化工具 LViz}
Expand Down Expand Up @@ -87,9 +88,32 @@ LPSS 是一个轻量级的发布订阅通信框架,采用去中心化设计,
@dl_begin{命令}
@dl_item{help,显示此帮助信息}
@dl_item{info,显示节点信息}
@dl_item{list,列出所有节点}
@dl_item{list,列出所有节点,可使用 `-c` 仅显示数量}
@dl_end

#### list 子命令

列出当前发现的所有 LPSS 节点。

**用法**

<div class="fragment">
<div class="line"><span class="keywordflow">lpss</span> node list [<span class="comment">-c</span>]</div>
</div>

@dl_begin{选项}
@dl_item{\-c,仅输出节点数量}
@dl_end

**示例**

<div class="fragment">
<div class="line"><span class="comment"># 列出节点名称</span></div>
<div class="line"><span class="keywordflow">lpss</span> node list</div>
<div class="line"><span class="comment"># 仅输出节点数量</span></div>
<div class="line"><span class="keywordflow">lpss</span> node list <span class="comment">-c</span></div>
</div>

#### info 子命令

查看指定节点的信息,输出形如以下的内容
Expand All @@ -102,6 +126,12 @@ Publish Topics:

Subscribe Topics:
xxx

Server Services:
xxx

Client Services:
xxx
```

**用法**
Expand All @@ -126,20 +156,60 @@ Subscribe Topics:
**用法**

<div class="fragment">
<div class="line"><span class="keywordflow">lpss</span> topic <span class="comment">[help | info | list | echo | pub | type | hz | bw]</span> [args...]</div>
<div class="line"><span class="keywordflow">lpss</span> topic <span class="comment">[help | info | list | find | echo | pub | type | hz | bw]</span> [args...]</div>
</div>

@dl_begin{命令}
@dl_item{help,显示此帮助信息}
@dl_item{info,显示话题信息}
@dl_item{list,列出所有话题}
@dl_item{list,列出所有话题,可使用 `-c` 仅显示数量}
@dl_item{find,按消息类型查找话题,可使用 `-c` 仅显示数量}
@dl_item{echo,显示话题内容}
@dl_item{pub,发布话题}
@dl_item{type,显示话题类型}
@dl_item{hz,测量话题发布频率,单位为 Hz}
@dl_item{bw,测量话题带宽,单位为 MB/s、kB/s 或 B/s}
@dl_end

#### list 子命令

列出当前发现的所有话题,话题名称按字典序输出。

**用法**

<div class="fragment">
<div class="line"><span class="keywordflow">lpss</span> topic list [<span class="comment">-c</span>]</div>
</div>

@dl_begin{选项}
@dl_item{\-c,仅输出话题数量}
@dl_end

#### find 子命令

按完整消息类型查找话题,查询结果按话题名称的字典序输出。

**用法**

<div class="fragment">
<div class="line"><span class="keywordflow">lpss</span> topic find <span class="comment">&lt;msg_type&gt;</span> [<span class="comment">-c</span>]</div>
</div>

@param msg_type 消息类型,例如 `std/String`

@dl_begin{选项}
@dl_item{\-c,仅输出匹配的话题数量}
@dl_end

**示例**

<div class="fragment">
<div class="line"><span class="comment"># 查找所有使用 std/String 消息类型的话题</span></div>
<div class="line"><span class="keywordflow">lpss</span> topic find std/String</div>
<div class="line"><span class="comment"># 仅输出匹配话题的数量</span></div>
<div class="line"><span class="keywordflow">lpss</span> topic find std/String <span class="comment">-c</span></div>
</div>

#### info 子命令

查看指定话题的信息,输出形如以下的内容
Expand Down Expand Up @@ -259,6 +329,146 @@ Subscriber Node:
<div class="line"><span class="keywordflow">lpss</span> topic bw /str</div>
</div>

### service 命令

服务工具,用于查看已发现的 LPSS 服务,并使用 JSON 请求调用内置服务。

**用法**

<div class="fragment">
<div class="line"><span class="keywordflow">lpss</span> service <span class="comment">[help | info | list | type | find | call]</span> [args...]</div>
</div>

@dl_begin{命令}
@dl_item{help,显示此帮助信息}
@dl_item{info,显示服务信息}
@dl_item{list,列出所有服务,可使用 `-c` 仅显示数量}
@dl_item{type,显示服务类型}
@dl_item{find,按服务类型查找服务,可使用 `-c` 仅显示数量}
@dl_item{call,使用 JSON 请求调用内置服务}
@dl_end

#### list 子命令

列出当前发现的所有服务,服务名称按字典序输出。

**用法**

<div class="fragment">
<div class="line"><span class="keywordflow">lpss</span> service list [<span class="comment">-c</span>]</div>
</div>

@dl_begin{选项}
@dl_item{\-c,仅输出服务数量}
@dl_end

#### info 子命令

查看指定服务的类型、服务端节点和客户端节点,输出形如以下内容。

```
Type: std/SetBool

Server Node:
server_node

Client Node:
client_node
```

**用法**

<div class="fragment">
<div class="line"><span class="keywordflow">lpss</span> service info <span class="comment">&lt;service_name&gt;</span></div>
</div>

@param service_name 服务名称

**示例**

<div class="fragment">
<div class="line"><span class="keywordflow">lpss</span> service info /set_enabled</div>
</div>

#### type 子命令

显示指定服务的服务类型。

**用法**

<div class="fragment">
<div class="line"><span class="keywordflow">lpss</span> service type <span class="comment">&lt;service_name&gt;</span></div>
</div>

@param service_name 服务名称

**示例**

<div class="fragment">
<div class="line"><span class="comment"># 输出 std/SetBool</span></div>
<div class="line"><span class="keywordflow">lpss</span> service type /set_enabled</div>
</div>

#### find 子命令

按类型精确匹配服务。`service_type` 可以是完整服务类型,也可以是对应的请求或响应消息类型。查询结果按服务名称的字典序输出。

**用法**

<div class="fragment">
<div class="line"><span class="keywordflow">lpss</span> service find <span class="comment">&lt;service_type&gt;</span> [<span class="comment">-c</span>]</div>
</div>

@param service_type 服务类型,例如 `std/SetBool`;也可使用 `std/SetBool_Request` 或 `std/SetBool_Response`

@dl_begin{选项}
@dl_item{\-c,仅输出匹配的服务数量}
@dl_end

**示例**

<div class="fragment">
<div class="line"><span class="comment"># 列出所有 std/SetBool 服务</span></div>
<div class="line"><span class="keywordflow">lpss</span> service find std/SetBool</div>
<div class="line"><span class="comment"># 仅输出匹配服务的数量</span></div>
<div class="line"><span class="keywordflow">lpss</span> service find std/SetBool <span class="comment">-c</span></div>
</div>

#### call 子命令

使用 JSON 对象作为请求调用指定服务,并将响应输出为 JSON。`json_request` 省略或为空时按 `{}` 处理,命令等待响应的超时时间为 3 秒。

**用法**

<div class="fragment">
<div class="line"><span class="keywordflow">lpss</span> service call <span class="comment">&lt;service_name&gt;</span> [<span class="comment">json_request</span>]</div>
</div>

@param service_name 服务名称
@param json_request JSON 对象形式的请求,建议使用单引号包围,避免 Shell 改写引号等字符

目前 `call` 支持以下内置服务类型。

| 服务类型 | JSON 请求 |
| --- | --- |
| `std/Empty` | `{}`,可省略 |
| `std/Trigger` | `{}`,可省略 |
| `std/SetBool` | 必须包含布尔字段 `data` |
| `sensor/SetCameraInfo` | 必须包含对象字段 `camera_info`;其中 `D` 和 `K` 如果出现,必须分别包含 5 个和 9 个数字 |

**示例**

<div class="fragment">
<div class="line"><span class="comment"># 调用无请求字段的 Trigger 服务</span></div>
<div class="line"><span class="keywordflow">lpss</span> service call /trigger</div>
<div class="line"><span class="comment"># 使用 JSON 请求调用 SetBool 服务</span></div>
<div class="line"><span class="keywordflow">lpss</span> service call /set_enabled <span class="stringliteral">'{"data":true}'</span></div>
<div class="line"><span class="comment"># 调用 SetCameraInfo 服务,未填写的 CameraInfo 字段使用默认值</span></div>
<div class="line"><span class="keywordflow">lpss</span> service call /set_camera_info <span class="stringliteral">'{"camera_info":{"height":1080,"width":1920}}'</span></div>
</div>

@note `call` 暂不支持自定义服务类型;发现到不支持的类型时会输出 `unsupported service type`。

### interface 命令

内置消息接口查看工具
Expand Down Expand Up @@ -346,10 +556,49 @@ geometry/Quaternion orientation

### graph 命令

节点图工具
节点图工具 LGraph,用于在浏览器中查看 LPSS 通信拓扑,包括节点、话题、服务及其发布/订阅、服务端/客户端关系。也可直接使用 `lgraph` 命令启动。

@warning 未完成,敬请期待
**用法**

<div class="fragment">
<div class="line"><span class="keywordflow">lpss</span> graph [<span class="comment">name_subfix</span>]</div>
<div class="line"><span class="comment"># 等价命令</span></div>
<div class="line"><span class="keywordflow">lgraph</span> [<span class="comment">name_subfix</span>]</div>
</div>

@param name_subfix 可选的实例名称,用于生成 LPSS 节点名 `lgraph_<name_subfix>`;省略时自动生成 5 位随机标识

启动成功后,终端会输出本机和局域网访问地址。LGraph 默认监听 `17493` 端口,本机可访问:

<div class="fragment">
<div class="line"><span class="keywordflow">http://localhost:17493</span></div>
</div>

**示例**

<div class="fragment">
<div class="line"><span class="comment"># 使用自动生成的实例名启动</span></div>
<div class="line"><span class="keywordflow">lpss</span> graph</div>
<div class="line"><span class="comment"># LPSS 节点名为 lgraph_debug</span></div>
<div class="line"><span class="keywordflow">lgraph</span> debug</div>
</div>

@note Web 服务使用固定端口 `17493`,同一主机上不能同时启动多个 LGraph 实例。按 `Ctrl+C` 可停止工具。

@note 如果提示 `%lpss graph 工具尚未安装`,请在 `rmvl-dev-tools` 中重新运行 `install.bash`。

### viz 命令

3D 可视化工具 LViz,也可直接使用 `lviz` 命令来启动。
3D 可视化工具 LViz,也可直接使用 `lviz` 命令启动。

**用法**

<div class="fragment">
<div class="line"><span class="keywordflow">lpss</span> viz [<span class="comment">name_subfix</span>]</div>
<div class="line"><span class="comment"># 等价命令</span></div>
<div class="line"><span class="keywordflow">lviz</span> [<span class="comment">name_subfix</span>]</div>
</div>

@param name_subfix 可选的实例名称,用于生成 LPSS 节点名 `lviz_node_<name_subfix>`;省略时自动生成 5 位随机标识

LViz 默认监听 `17492` 端口,启动后可通过 `http://localhost:17492` 访问,按 `Ctrl+C` 停止工具。
4 changes: 4 additions & 0 deletions doc/tutorials/rdt/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ RMVL Dev Tools(简称 `rdt`)是一个 CLI 命令行工具,能够极大幅
<div class="fragment">
<div class="line"><span class="keywordflow">wget</span> https://cv-rmvl.github.io/install <span class="comment">-qO</span> - | <span class="keywordflow">bash</span></div>
</div>
Windows 用户可以使用如下的一键安装命令,在开始菜单找到 Windows Powershell 后点击进入,或者按下 `Win+X` 唤起对话框,按下 `I` 进入 Windows Powershell,输入以下内容,根据提示操作即可完成 RMVL 以及 rdt 工具的安装:
<div class="fragment">
<div class="line"><span class="keywordflow">irm</span> https://cv-rmvl.github.io/install-win <span class="comment">|</span> <span class="keywordflow">iex</span></div>
</div>

`rdt` 的使用非常简单,安装完成后在终端输入以下命令即可查看帮助文档:

Expand Down
4 changes: 2 additions & 2 deletions extra/detector/include/rmvl/detector/armor_detector.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
#pragma once

#include "rmvl/combo/armor.h"
#include "rmvl/tracker/tracker.h"
#include "rmvl/ml/ort.h"
#include "rmvl/tracker/tracker.h"

namespace rm {

Expand All @@ -39,7 +39,7 @@ struct RMVL_EXPORTS_W_AG ArmorDetectorInfo {
class RMVL_EXPORTS_W ArmorDetector final {
double _tick; //!< 每一帧对应的时间点
ImuData _imu_data; //!< 每一帧对应的 IMU 数据
std::unique_ptr<OnnxNet> _ort;
std::unique_ptr<ClassificationNet> _ort;
std::unordered_map<int, RobotType> _robot_t;

public:
Expand Down
2 changes: 1 addition & 1 deletion extra/detector/include/rmvl/detector/gyro_detector.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class RMVL_EXPORTS_W GyroDetector final {
ImuData _imu_data; //!< 每一帧对应的 IMU 数据
int _armor_num; //!< 默认装甲板数目

std::unique_ptr<OnnxNet> _ort;
std::unique_ptr<ClassificationNet> _ort;
std::unordered_map<int, RobotType> _robot_t;

public:
Expand Down
7 changes: 3 additions & 4 deletions extra/detector/src/armor_detector/find.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,9 @@ void ArmorDetector::find(cv::Mat &src, std::vector<feature::ptr> &features, std:
rois.reserve(armors.size());
for (const auto &armor : armors) {
cv::Mat roi = Armor::getNumberROI(src, armor);
PreprocessOptions preop;
preop.means = {para::armor_detector_param.MODEL_MEAN};
preop.stds = {para::armor_detector_param.MODEL_STD};
int idx = ClassificationNet::cast(_ort->inference({roi}, preop, {})).first;
int idx = _ort->inference({roi}, {para::armor_detector_param.MODEL_MEAN},
{para::armor_detector_param.MODEL_STD})
.first;
armor->setType(_robot_t[idx]);
rois.emplace_back(roi);
}
Expand Down
7 changes: 3 additions & 4 deletions extra/detector/src/gyro_detector/find.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,9 @@ void GyroDetector::find(cv::Mat &src, std::vector<feature::ptr> &features, std::
rois.reserve(armors.size());
for (const auto &armor : armors) {
cv::Mat roi = Armor::getNumberROI(src, armor);
PreprocessOptions preop;
preop.means = {para::gyro_detector_param.MODEL_MEAN};
preop.stds = {para::gyro_detector_param.MODEL_STD};
int idx = ClassificationNet::cast(_ort->inference({roi}, preop, {})).first;
int idx = _ort->inference({roi}, {para::gyro_detector_param.MODEL_MEAN},
{para::gyro_detector_param.MODEL_STD})
.first;
armor->setType(_robot_t[idx]);
rois.emplace_back(roi);
}
Expand Down
Loading