roslib-ts 0.1.1 → 1.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/API.md +293 -0
- package/LICENSE +21 -0
- package/README.md +63 -21
- package/README.zh-CN.md +96 -0
- package/dist/index.cjs.js +661 -70
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +212 -8
- package/dist/index.esm.js +658 -71
- package/dist/index.esm.js.map +1 -1
- package/dist/next.cjs.js +22 -0
- package/dist/next.cjs.js.map +1 -0
- package/dist/next.d.ts +1 -0
- package/dist/next.esm.js +2 -0
- package/dist/next.esm.js.map +1 -0
- package/dist/types/EnhancedRos.d.ts +131 -0
- package/dist/types/EnhancedRos.d.ts.map +1 -0
- package/dist/types/Param.d.ts +2 -2
- package/dist/types/Param.d.ts.map +1 -1
- package/dist/types/Ros.d.ts +10 -2
- package/dist/types/Ros.d.ts.map +1 -1
- package/dist/types/RosManagers.d.ts +40 -0
- package/dist/types/RosManagers.d.ts.map +1 -0
- package/dist/types/Service.d.ts +18 -3
- package/dist/types/Service.d.ts.map +1 -1
- package/dist/types/Topic.d.ts +19 -3
- package/dist/types/Topic.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/next.d.ts +9 -0
- package/dist/types/next.d.ts.map +1 -0
- package/package.json +14 -5
package/API.md
ADDED
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
# roslib-ts API 文档
|
|
2
|
+
|
|
3
|
+
本文档覆盖以下文件导出的公开 API:
|
|
4
|
+
- [EnhancedRos.ts](./src/EnhancedRos.ts)
|
|
5
|
+
- [RosManagers.ts](./src/RosManagers.ts)
|
|
6
|
+
- [Topic.ts](./src/Topic.ts)
|
|
7
|
+
- [Service.ts](./src/Service.ts)
|
|
8
|
+
- [Param.ts](./src/Param.ts)
|
|
9
|
+
- [next.ts](./src/next.ts)
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 入口与导出(next.ts)
|
|
14
|
+
|
|
15
|
+
文件:[next.ts](./src/next.ts)
|
|
16
|
+
|
|
17
|
+
### 导出项
|
|
18
|
+
|
|
19
|
+
- `SimpleRos`:原始轻量 Ros 实现(无增强能力),来自 `./Ros`
|
|
20
|
+
- `Ros`:增强版连接实现(EnhancedRos 的默认导出别名)
|
|
21
|
+
- `RosState`:增强版连接状态枚举(`EnhancedRosState` 的别名)
|
|
22
|
+
- `Topic`:话题 API
|
|
23
|
+
- `Service`:服务 API
|
|
24
|
+
- `ServiceRequest` / `ServiceResponse`:服务请求/响应容器
|
|
25
|
+
- `Param`:参数 API
|
|
26
|
+
- `EventEmitter`:简单事件系统
|
|
27
|
+
- `TopicManager` / `ServiceManager` / `ParamManager`:可选的管理器封装
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## EnhancedRos(增强连接封装)
|
|
32
|
+
|
|
33
|
+
文件:[EnhancedRos.ts](./src/EnhancedRos.ts)
|
|
34
|
+
|
|
35
|
+
EnhancedRos 是一个面向工程可靠性的 RosBridge WebSocket 封装层:
|
|
36
|
+
- 自动重连:指数退避(Exponential Backoff)
|
|
37
|
+
- 离线队列:未连接时消息进入 FIFO 队列,连接成功后自动清空发送
|
|
38
|
+
- 心跳保活:周期性发送轻量消息;若连续 2 个心跳周期未收到任何服务端消息,强制断开并触发重连
|
|
39
|
+
- 资源回收:每次 `connect()` 会清理定时器、关闭旧连接并重置瞬态状态
|
|
40
|
+
- 状态机:`IDLE / CONNECTING / CONNECTED / RECONNECTING / CLOSED / ERROR`
|
|
41
|
+
|
|
42
|
+
### EnhancedRosState(连接状态枚举)
|
|
43
|
+
|
|
44
|
+
- `IDLE`:空闲/初始状态
|
|
45
|
+
- `CONNECTING`:正在连接
|
|
46
|
+
- `CONNECTED`:已连接,可发送消息
|
|
47
|
+
- `RECONNECTING`:异常断线后正在重连
|
|
48
|
+
- `CLOSED`:用户主动关闭,不再自动重连
|
|
49
|
+
- `ERROR`:不可恢复错误(例如无 URL 等)
|
|
50
|
+
|
|
51
|
+
> EnhancedRos 会在状态变化时触发事件:`ros.emit('state', nextState)`
|
|
52
|
+
|
|
53
|
+
### EnhancedRosOptions(构造参数)
|
|
54
|
+
|
|
55
|
+
- `url?: string`:默认连接地址,提供则构造时自动连接
|
|
56
|
+
- `WebSocket?: typeof WebSocket`:自定义 WebSocket 实现(测试/特殊运行环境)
|
|
57
|
+
- `reconnect_min_delay?: number`:首次重连延迟,默认 `1000ms`
|
|
58
|
+
- `reconnect_max_delay?: number`:最大重连延迟,默认 `30000ms`
|
|
59
|
+
- `heartbeat_interval_ms?: number`:心跳间隔;`<=0` 表示禁用
|
|
60
|
+
- `heartbeat_fn?: () => void`:自定义心跳发送函数(可选);未提供则使用默认心跳策略
|
|
61
|
+
|
|
62
|
+
### 构造函数
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
new EnhancedRos(options?: EnhancedRosOptions)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 属性
|
|
69
|
+
|
|
70
|
+
- `state: EnhancedRosState`:当前连接语义状态
|
|
71
|
+
- `isConnected: boolean`:是否处于 `CONNECTED`
|
|
72
|
+
|
|
73
|
+
### 方法
|
|
74
|
+
|
|
75
|
+
- `connect(url: string): void`
|
|
76
|
+
- 建立/切换连接
|
|
77
|
+
- 会清理:重连定时器、心跳定时器、旧 WebSocket、离线队列与瞬态状态
|
|
78
|
+
- 状态迁移:`IDLE -> CONNECTING -> CONNECTED`,异常断线进入 `RECONNECTING`
|
|
79
|
+
|
|
80
|
+
- `close(): void`
|
|
81
|
+
- 主动关闭连接,不触发自动重连
|
|
82
|
+
- 会清理:重连/心跳定时器、离线队列,并关闭 WebSocket
|
|
83
|
+
- 状态:进入 `CLOSED`
|
|
84
|
+
|
|
85
|
+
- `callOnConnection(message: any): void`
|
|
86
|
+
- 发送 rosbridge 消息
|
|
87
|
+
- 若非 `CONNECTED`:进入离线队列(FIFO)
|
|
88
|
+
- 连接成功后会自动 flush 队列按顺序发送
|
|
89
|
+
|
|
90
|
+
- `getNextId(): string`
|
|
91
|
+
- 生成递增字符串 ID,用于 service call 的请求-响应匹配
|
|
92
|
+
|
|
93
|
+
- `cast(message: any): void`
|
|
94
|
+
- “立即发送”接口(不入队)
|
|
95
|
+
- 仅当 WebSocket `OPEN` 才发送,否则直接返回
|
|
96
|
+
|
|
97
|
+
### 事件
|
|
98
|
+
|
|
99
|
+
EnhancedRos 继承自 `EventEmitter`,并对外提供以下关键事件:
|
|
100
|
+
|
|
101
|
+
- `connection`:WebSocket 连接建立
|
|
102
|
+
- `close`:WebSocket 关闭(主动/被动都会触发)
|
|
103
|
+
- `error`:WebSocket 错误
|
|
104
|
+
- `state`:状态机变化,payload 为 `EnhancedRosState`
|
|
105
|
+
|
|
106
|
+
此外,EnhancedRos 会将 rosbridge 下行消息按原 Ros 的事件模型分发:
|
|
107
|
+
|
|
108
|
+
- 话题消息:`emit(topicName, msg)`(当收到 `{ op:'publish', topic, msg }`)
|
|
109
|
+
- 服务响应:`emit(id, message)`(当收到 `{ op:'service_response', id, ... }`)
|
|
110
|
+
- 状态消息:`emit('status', message)` 或 `emit('status:' + id, message)`
|
|
111
|
+
- 服务请求:`emit('service_request:' + serviceName, message)`(用于 `Service.advertise`)
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Topic(话题)
|
|
116
|
+
|
|
117
|
+
文件:[Topic.ts](./src/Topic.ts)
|
|
118
|
+
|
|
119
|
+
### 构造参数
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
new Topic({
|
|
123
|
+
ros,
|
|
124
|
+
name,
|
|
125
|
+
messageType,
|
|
126
|
+
compression?,
|
|
127
|
+
throttle_rate?,
|
|
128
|
+
queue_size?,
|
|
129
|
+
latch?,
|
|
130
|
+
queue_length?,
|
|
131
|
+
})
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
字段:
|
|
135
|
+
- `ros: RosLike`:可传 `SimpleRos` 或 `EnhancedRos`
|
|
136
|
+
- `name: string`:话题名(例:`/chatter`)
|
|
137
|
+
- `messageType: string`:消息类型(例:`std_msgs/String`)
|
|
138
|
+
- `compression?: string`:压缩方式
|
|
139
|
+
- `throttle_rate?: number`:限流(ms)
|
|
140
|
+
- `queue_size?: number`:发布队列大小
|
|
141
|
+
- `latch?: boolean`:latched topic
|
|
142
|
+
- `queue_length?: number`:队列长度
|
|
143
|
+
|
|
144
|
+
### 方法
|
|
145
|
+
|
|
146
|
+
- `subscribe(callback?: (message: any) => void): void`
|
|
147
|
+
- 发送 rosbridge `subscribe` 指令
|
|
148
|
+
- 同时监听 `ros.on(name, ...)` 接收消息并触发本 Topic 的 `message` 事件与回调
|
|
149
|
+
|
|
150
|
+
- `unsubscribe(): void`
|
|
151
|
+
- 发送 rosbridge `unsubscribe` 指令
|
|
152
|
+
- 移除 `ros.off(name)` 监听
|
|
153
|
+
|
|
154
|
+
- `publish(message: any): void`
|
|
155
|
+
- 若未 advertise 会先 `advertise()`
|
|
156
|
+
- 发送 rosbridge `publish` 指令
|
|
157
|
+
|
|
158
|
+
- `advertise(): void`
|
|
159
|
+
- 发送 rosbridge `advertise` 指令
|
|
160
|
+
|
|
161
|
+
- `unadvertise(): void`
|
|
162
|
+
- 发送 rosbridge `unadvertise` 指令
|
|
163
|
+
|
|
164
|
+
### 事件
|
|
165
|
+
|
|
166
|
+
- `message`:每次收到消息会 `emit('message', msg)`
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Service(服务)
|
|
171
|
+
|
|
172
|
+
文件:[Service.ts](./src/Service.ts)
|
|
173
|
+
|
|
174
|
+
### 构造参数
|
|
175
|
+
|
|
176
|
+
```ts
|
|
177
|
+
new Service({ ros, name, serviceType })
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
- `ros: RosLike`
|
|
181
|
+
- `name: string`:服务名(例:`/rosapi/get_time`)
|
|
182
|
+
- `serviceType: string`:服务类型(例:`rosapi/GetTime`)
|
|
183
|
+
|
|
184
|
+
### 方法
|
|
185
|
+
|
|
186
|
+
- `callService(request: ServiceRequest, callback?, failedCallback?): Promise<ServiceResponse>`
|
|
187
|
+
- 生成请求 id:`ros.getNextId()`
|
|
188
|
+
- 发送 rosbridge `call_service`
|
|
189
|
+
- 监听 `ros.on(id, ...)` 等待 `service_response`
|
|
190
|
+
- Promise resolve 为 `ServiceResponse`
|
|
191
|
+
|
|
192
|
+
- `advertise(callback: (request: ServiceRequest, response: ServiceResponse) => boolean | void): void`
|
|
193
|
+
- 发送 rosbridge `advertise_service`
|
|
194
|
+
- 监听 `ros.on('service_request:' + name, ...)` 处理请求
|
|
195
|
+
- 根据 callback 返回值发送 `service_response`(`result: result !== false`)
|
|
196
|
+
|
|
197
|
+
- `unadvertise(): void`
|
|
198
|
+
- 发送 rosbridge `unadvertise_service`
|
|
199
|
+
- `ros.off('service_request:' + name)`
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## ServiceRequest / ServiceResponse
|
|
204
|
+
|
|
205
|
+
文件:[ServiceRequest.ts](./src/ServiceRequest.ts)
|
|
206
|
+
|
|
207
|
+
```ts
|
|
208
|
+
new ServiceRequest(values?: Record<string, any>)
|
|
209
|
+
new ServiceResponse(values?: Record<string, any>)
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
这两个类是轻量对象容器:会把 `values` 的字段拷贝到实例本身上。
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## Param(参数)
|
|
217
|
+
|
|
218
|
+
文件:[Param.ts](./src/Param.ts)
|
|
219
|
+
|
|
220
|
+
### 构造参数
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
new Param({ ros, name })
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
- `ros: RosLike`
|
|
227
|
+
- `name: string`:参数名(例:`/demo_param`)
|
|
228
|
+
|
|
229
|
+
### 方法
|
|
230
|
+
|
|
231
|
+
- `get(callback?): Promise<any>`
|
|
232
|
+
- 调用 `/rosapi/get_param`(`rosapi/GetParam`)
|
|
233
|
+
- resolve 为 `response.value`
|
|
234
|
+
|
|
235
|
+
- `set(value: any, callback?): Promise<void>`
|
|
236
|
+
- 调用 `/rosapi/set_param`(`rosapi/SetParam`)
|
|
237
|
+
- value 会在内部 `JSON.stringify(value)`
|
|
238
|
+
|
|
239
|
+
- `delete(callback?): Promise<void>`
|
|
240
|
+
- 调用 `/rosapi/delete_param`(`rosapi/DeleteParam`)
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## RosManagers(可选管理器封装)
|
|
245
|
+
|
|
246
|
+
文件:[RosManagers.ts](./src/RosManagers.ts)
|
|
247
|
+
|
|
248
|
+
这些 Manager 是业务侧便利封装,依赖 `EnhancedRos`。
|
|
249
|
+
|
|
250
|
+
### TopicManager
|
|
251
|
+
|
|
252
|
+
用途:
|
|
253
|
+
- 对同名 topic 进行集中管理
|
|
254
|
+
- 同一个 topic 多个回调时只创建/订阅一次 Topic
|
|
255
|
+
|
|
256
|
+
构造:
|
|
257
|
+
```ts
|
|
258
|
+
new TopicManager(ros: EnhancedRos)
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
方法:
|
|
262
|
+
- `subscribe(name: string, messageType: string, callback: (msg:any)=>void): void`
|
|
263
|
+
- `unsubscribe(name: string, callback?: (msg:any)=>void): void`
|
|
264
|
+
- `publish(name: string, messageType: string, data: any): void`
|
|
265
|
+
- `clearAll(): void`
|
|
266
|
+
- `resubscribeAll(ros: any): void`
|
|
267
|
+
|
|
268
|
+
### ServiceManager
|
|
269
|
+
|
|
270
|
+
用途:为 service call 增加统一超时控制
|
|
271
|
+
|
|
272
|
+
构造:
|
|
273
|
+
```ts
|
|
274
|
+
new ServiceManager(ros: EnhancedRos, timeoutMs = 10000)
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
方法:
|
|
278
|
+
- `call(name: string, serviceType: string, request?: any, timeoutMs = defaultTimeout): Promise<any>`
|
|
279
|
+
|
|
280
|
+
### ParamManager
|
|
281
|
+
|
|
282
|
+
用途:为参数 get/set/delete 提供统一超时与错误包装
|
|
283
|
+
|
|
284
|
+
构造:
|
|
285
|
+
```ts
|
|
286
|
+
new ParamManager(ros: EnhancedRos, timeoutMs = 10000)
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
方法:
|
|
290
|
+
- `get(name: string, timeoutMs = defaultTimeout): Promise<any>`
|
|
291
|
+
- `set(name: string, value: any): Promise<void>`
|
|
292
|
+
- `delete(name: string): Promise<void>`
|
|
293
|
+
|
package/LICENSE
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 [naviai]
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,50 +1,92 @@
|
|
|
1
1
|
# roslib-ts
|
|
2
2
|
|
|
3
|
-
TypeScript-first ROSLIB implementation.
|
|
3
|
+
🚀 **TypeScript-first ROSLIB implementation.** A lightweight, robust ROSbridge Web client designed for modern frontend engineering.
|
|
4
4
|
|
|
5
5
|
## ✨ Features
|
|
6
6
|
|
|
7
|
-
✅
|
|
8
|
-
✅
|
|
9
|
-
✅
|
|
10
|
-
✅
|
|
11
|
-
|
|
12
|
-
❌ No WebRTC support
|
|
7
|
+
* ✅ **Dual Entrypoints**: Support for Standard (compatible) and `Next` (Production-ready) versions.
|
|
8
|
+
* ✅ **Self-healing Connections**: `Next` version features exponential backoff reconnection and application-level heartbeat detection.
|
|
9
|
+
* ✅ **Offline Message Queueing**: Messages sent while offline are queued and auto-flushed upon reconnection.
|
|
10
|
+
* ✅ **Lifecycle Management**: `TopicManager` with reference counting for automatic sub/unsub and resource cleanup.
|
|
11
|
+
* ✅ **100% TypeScript**: Full interface support with perfect type inference and generics.
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 📦 Install
|
|
15
16
|
|
|
16
17
|
```bash
|
|
18
|
+
# Install stable version
|
|
17
19
|
pnpm add roslib-ts
|
|
20
|
+
|
|
21
|
+
# Install the latest enhanced version (Beta)
|
|
22
|
+
pnpm add roslib-ts@beta
|
|
23
|
+
|
|
18
24
|
```
|
|
19
25
|
|
|
20
|
-
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 🚀 Quick Start
|
|
29
|
+
|
|
30
|
+
### 1. Using Next Version (Recommended for Production)
|
|
31
|
+
|
|
32
|
+
Import via sub-path `/next`. This version is designed to handle network instability.
|
|
21
33
|
|
|
22
34
|
```typescript
|
|
23
|
-
import { Ros,
|
|
35
|
+
import { Ros, TopicManager, ServiceManager } from 'roslib-ts/next';
|
|
24
36
|
|
|
37
|
+
// Initialize enhanced connection
|
|
25
38
|
const ros = new Ros({
|
|
26
|
-
url: 'ws://
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
ros.on('connection', () => {
|
|
30
|
-
console.log('Connected');
|
|
39
|
+
url: 'ws://192.168.1.10:9090',
|
|
40
|
+
heartbeat_interval_ms: 5000, // 5s heartbeat
|
|
41
|
+
reconnect_min_delay: 1000 // Exponential backoff
|
|
31
42
|
});
|
|
32
43
|
|
|
33
|
-
|
|
34
|
-
|
|
44
|
+
// Use Managers for simplified operations
|
|
45
|
+
TopicManager.subscribe('/chatter', 'std_msgs/String', (msg) => {
|
|
46
|
+
console.log('Received:', msg.data);
|
|
35
47
|
});
|
|
36
48
|
|
|
49
|
+
// Publish messages (Automatic queueing if disconnected)
|
|
50
|
+
TopicManager.public('/cmd_vel', 'geometry_msgs/Twist', { linear: { x: 0.5 }, angular: { z: 0.1 } });
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 2. Using Standard Version
|
|
55
|
+
|
|
56
|
+
For simple use cases requiring basic ROSbridge wrapping.
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
import { Ros, Topic } from 'roslib-ts';
|
|
60
|
+
|
|
61
|
+
const ros = new Ros({ url: 'ws://localhost:9090' });
|
|
37
62
|
const cmdVel = new Topic({
|
|
38
63
|
ros,
|
|
39
64
|
name: '/cmd_vel',
|
|
40
65
|
messageType: 'geometry_msgs/Twist'
|
|
41
|
-
})
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
cmdVel.publish({ linear: { x: 0.1 }, angular: { z: 0 } });
|
|
42
69
|
|
|
43
|
-
cmdVel.subscribe(msg => {
|
|
44
|
-
console.log(msg.linear.x)
|
|
45
|
-
})
|
|
46
70
|
```
|
|
47
71
|
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 🛠 Philosophy
|
|
75
|
+
|
|
76
|
+
* **State Machine Isolation**: Underlying connections are abstracted into strict states like `IDLE`, `CONNECTED`, `RECONNECTING`.
|
|
77
|
+
* **Offline Barrier**: Use `messageQueue` to shield business logic from network instability. No `if(isConnected)` checks needed.
|
|
78
|
+
* **Resource Transparency**: Managers handle `advertise` declarations automatically. Physical `unsubscribe` is executed only when the last callback is removed.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 📖 API Reference
|
|
83
|
+
|
|
84
|
+
More see [API.md](./API.md)
|
|
85
|
+
|
|
86
|
+
---
|
|
48
87
|
|
|
88
|
+
## 🤝 Contribution
|
|
49
89
|
|
|
90
|
+
Issues and Pull Requests are welcome.
|
|
50
91
|
|
|
92
|
+
---
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# roslib-ts
|
|
2
|
+
|
|
3
|
+
🚀 **TypeScript 优先的 ROSLIB 实现。** 轻量级、健壮且专为现代前端工程设计的 ROSbridge Web 客户端。
|
|
4
|
+
|
|
5
|
+
## ✨ 特性
|
|
6
|
+
|
|
7
|
+
* ✅ **双版本入口**:提供标准版(兼容型)与 `Next` 增强版(生产级)。
|
|
8
|
+
* ✅ **连接自愈**:`Next` 版本内置指数退避重连与应用层心跳侦测,解决“假在线”痛点。
|
|
9
|
+
* ✅ **离线指令队列**:断网时发送的消息自动缓存,并在连接恢复后按序补发。
|
|
10
|
+
* ✅ **自动化管理**:`TopicManager` 提供引用计数,自动处理订阅与资源回收。
|
|
11
|
+
* ✅ **100% TypeScript**:全接口支持,提供完美的类型推导与泛型定义。
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 📦 安装
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# 安装稳定版
|
|
19
|
+
pnpm add roslib-ts
|
|
20
|
+
|
|
21
|
+
# 体验最新增强版 (Beta)
|
|
22
|
+
pnpm add roslib-ts@beta
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 🚀 快速开始
|
|
29
|
+
|
|
30
|
+
### 1. 使用增强版 (推荐用于生产环境)
|
|
31
|
+
|
|
32
|
+
通过子路径 `/next` 导入。该版本解决了网络波动导致的指令丢失问题。
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
import { Ros, TopicManager, ServiceManager } from 'roslib-ts/next';
|
|
36
|
+
|
|
37
|
+
// 初始化连接
|
|
38
|
+
const ros = new Ros({
|
|
39
|
+
url: 'ws://192.168.1.10:9090',
|
|
40
|
+
heartbeat_interval_ms: 5000, // 5秒心跳检测
|
|
41
|
+
reconnect_min_delay: 1000 // 指数退避重连
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// 初始化 TopicManager 与 ServiceManager
|
|
45
|
+
const topicManager = new TopicManager(ros);
|
|
46
|
+
const serviceManager = new ServiceManager(ros);
|
|
47
|
+
|
|
48
|
+
// 使用 Manager 直接操作,无需手动维护 Topic 实例
|
|
49
|
+
topicManager.subscribe('/chatter', 'std_msgs/String', (msg) => {
|
|
50
|
+
console.log('收到数据:', msg.data);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// 发布消息 (即使连接未建立也会自动排队)
|
|
54
|
+
topicManager.public('/cmd_vel', 'geometry_msgs/Twist', { linear: { x: 0.5 }, angular: { z: 0.1 } });
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 2. 使用标准版 (基础功能)
|
|
59
|
+
|
|
60
|
+
如果你只需要最基础的 ROSbridge 封装,可以使用标准入口。
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { Ros, Topic } from 'roslib-ts';
|
|
64
|
+
|
|
65
|
+
const ros = new Ros({ url: 'ws://localhost:9090' });
|
|
66
|
+
const cmdVel = new Topic({
|
|
67
|
+
ros,
|
|
68
|
+
name: '/cmd_vel',
|
|
69
|
+
messageType: 'geometry_msgs/Twist'
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
cmdVel.publish({ linear: { x: 0.1 }, angular: { z: 0 } });
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## 🛠 设计思想
|
|
79
|
+
|
|
80
|
+
* **状态机隔离**:底层连接被抽象为 `IDLE`, `CONNECTED`, `RECONNECTING` 等严格状态,确保复杂网络下的行为可预测。
|
|
81
|
+
* **离线屏障**:通过 `messageQueue` 屏蔽物理连接的不稳定性。业务层调用 `publish` 时,不需判断 `isConnected`。
|
|
82
|
+
* **资源透明**:Manager 自动处理 `advertise` 声明。当最后一个订阅回调移除时,底层自动执行 `unsubscribe` 以节省资源。
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## 📖 API 手册
|
|
87
|
+
|
|
88
|
+
更多见 [API.md](./API.md)
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## 🤝 贡献与反馈
|
|
93
|
+
|
|
94
|
+
欢迎提交 Issue 或 PR。
|
|
95
|
+
|
|
96
|
+
---
|