carm 0.0.20250822__py3-none-any.whl → 0.0.20250911__py3-none-any.whl
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.
- carm/carm.py +222 -28
- carm/carm_dds.py +21 -0
- {carm-0.0.20250822.dist-info → carm-0.0.20250911.dist-info}/METADATA +1 -1
- carm-0.0.20250911.dist-info/RECORD +9 -0
- carm-0.0.20250822.dist-info/RECORD +0 -9
- {carm-0.0.20250822.dist-info → carm-0.0.20250911.dist-info}/WHEEL +0 -0
- {carm-0.0.20250822.dist-info → carm-0.0.20250911.dist-info}/entry_points.txt +0 -0
- {carm-0.0.20250822.dist-info → carm-0.0.20250911.dist-info}/top_level.txt +0 -0
carm/carm.py
CHANGED
|
@@ -10,20 +10,20 @@ class Carm:
|
|
|
10
10
|
self.last_msg = None
|
|
11
11
|
self.ws = websocket.WebSocketApp(
|
|
12
12
|
addr, # 测试用的公开WebSocket服务
|
|
13
|
-
on_open = lambda ws: self.
|
|
14
|
-
on_close = lambda ws, code, close_msg: self.
|
|
15
|
-
on_message= lambda ws, msg: self.
|
|
13
|
+
on_open = lambda ws: self.__on_open(ws),
|
|
14
|
+
on_close = lambda ws, code, close_msg: self.__on_close(ws, code, close_msg),
|
|
15
|
+
on_message= lambda ws, msg: self.__on_message(ws, msg),
|
|
16
16
|
)
|
|
17
17
|
|
|
18
18
|
self.ops = {
|
|
19
|
-
"webSendRobotState": lambda msg: self.
|
|
20
|
-
"taskFinished": lambda msg: self.
|
|
19
|
+
"webSendRobotState": lambda msg: self.__cbk_status(msg),
|
|
20
|
+
"taskFinished": lambda msg: self.__cbk_taskfinish(msg),
|
|
21
21
|
"onCarmError": lambda msg: print("Error:", msg)
|
|
22
22
|
}
|
|
23
23
|
self.res_pool = {}
|
|
24
24
|
self.task_pool = {}
|
|
25
25
|
|
|
26
|
-
self.reader = threading.Thread(target=self.
|
|
26
|
+
self.reader = threading.Thread(target=self.__recv_loop, daemon=True).start()
|
|
27
27
|
self.open_ready = threading.Event()
|
|
28
28
|
self.open_ready.wait()
|
|
29
29
|
self.limit = self.get_limits()["params"]
|
|
@@ -32,12 +32,22 @@ class Carm:
|
|
|
32
32
|
|
|
33
33
|
@property
|
|
34
34
|
def version(self):
|
|
35
|
+
"""
|
|
36
|
+
Get the version of the arm.
|
|
37
|
+
Returns:
|
|
38
|
+
dict: The version of the arm.
|
|
39
|
+
"""
|
|
35
40
|
return self.request({"command":"getArmIntrinsicProperties",
|
|
36
41
|
"arm_index":0,
|
|
37
42
|
"type":"version"})
|
|
38
43
|
|
|
39
44
|
|
|
40
45
|
def get_limits(self):
|
|
46
|
+
"""
|
|
47
|
+
获取主要配置参数,包括关节限位、关节最大速度、加速度、加加速度等。
|
|
48
|
+
Returns:
|
|
49
|
+
dict: The limits of the arm.
|
|
50
|
+
"""
|
|
41
51
|
return self.request({"command":"getJointParams",
|
|
42
52
|
"arm_index":0,
|
|
43
53
|
"type":"version"})
|
|
@@ -58,16 +68,42 @@ class Carm:
|
|
|
58
68
|
return self.set_control_mode(1)
|
|
59
69
|
|
|
60
70
|
def set_servo_enable(self, enable=True):
|
|
71
|
+
"""
|
|
72
|
+
Set the servo enable of the arm.
|
|
73
|
+
Args:
|
|
74
|
+
enable (bool): The servo enable to set.
|
|
75
|
+
Returns:
|
|
76
|
+
dict: The response from the arm.
|
|
77
|
+
"""
|
|
61
78
|
return self.request({"command":"setServoEnable",
|
|
62
79
|
"arm_index":0,
|
|
63
80
|
"enable":enable})
|
|
64
81
|
|
|
65
82
|
def set_control_mode(self, mode=1):
|
|
83
|
+
"""
|
|
84
|
+
Set the control mode of the arm.
|
|
85
|
+
Args:
|
|
86
|
+
mode (int): The control mode to set.
|
|
87
|
+
* 0-IDLE空闲模式
|
|
88
|
+
* 1-点位控制模式
|
|
89
|
+
* 2-MIT控制模式
|
|
90
|
+
* 3-关节拖动模式
|
|
91
|
+
Returns:
|
|
92
|
+
dict: The response from the arm.
|
|
93
|
+
"""
|
|
66
94
|
return self.request({"command":"setControlMode",
|
|
67
95
|
"arm_index":0,
|
|
68
96
|
"mode":mode})
|
|
69
97
|
|
|
70
98
|
def set_end_effector(self, pos, tau):
|
|
99
|
+
"""
|
|
100
|
+
Set the end effector of the arm.
|
|
101
|
+
Args:
|
|
102
|
+
pos (float): The position of the end effector. 0-0.08m
|
|
103
|
+
tau (float): The torque of the end effector. 0-9.0N.m
|
|
104
|
+
Returns:
|
|
105
|
+
dict: The response from the arm.
|
|
106
|
+
"""
|
|
71
107
|
pos = self.__clip(pos, 0, 0.08)
|
|
72
108
|
tau = self.__clip(tau, 0, 9)
|
|
73
109
|
|
|
@@ -77,6 +113,13 @@ class Carm:
|
|
|
77
113
|
"tau": tau})
|
|
78
114
|
|
|
79
115
|
def get_tool_coordinate(self, tool):
|
|
116
|
+
"""
|
|
117
|
+
获取指定工具的坐标系(工具末端相对法兰的位姿关系).
|
|
118
|
+
Args:
|
|
119
|
+
tool (int): The tool index.
|
|
120
|
+
Returns:
|
|
121
|
+
dict: The tool coordinate of the arm.
|
|
122
|
+
"""
|
|
80
123
|
return self.request({"command":"getCoordinate",
|
|
81
124
|
"arm_index":0,
|
|
82
125
|
"type": "tool",
|
|
@@ -84,12 +127,31 @@ class Carm:
|
|
|
84
127
|
|
|
85
128
|
|
|
86
129
|
def set_collision_config(self, flag = True, level = 10):
|
|
130
|
+
"""
|
|
131
|
+
设置碰撞检测配置.
|
|
132
|
+
Args:
|
|
133
|
+
flag (bool): 是否开启碰撞检测.
|
|
134
|
+
level (int): 碰撞检测等级. 灵敏度等级 0-2,0最高,2最低
|
|
135
|
+
Returns:
|
|
136
|
+
dict: The response from the arm.
|
|
137
|
+
"""
|
|
87
138
|
return self.request({"command":"setCollisionConfig",
|
|
88
139
|
"arm_index":0,
|
|
89
140
|
"flag": flag,
|
|
90
141
|
"level": level})
|
|
91
142
|
|
|
92
143
|
def stop(self, type=0):
|
|
144
|
+
"""
|
|
145
|
+
停止carm.
|
|
146
|
+
Args:
|
|
147
|
+
type (int): 停止类型.
|
|
148
|
+
* 0-暂停
|
|
149
|
+
* 1-停止
|
|
150
|
+
* 2-禁用
|
|
151
|
+
* 3-紧急停止
|
|
152
|
+
Returns:
|
|
153
|
+
dict: The response from the arm.
|
|
154
|
+
"""
|
|
93
155
|
stop_id = ["SIG_ARM_PAUSE", "SIG_ARM_STOP",
|
|
94
156
|
"SIG_ARM_DISABLE","SIG_EMERGENCY_STOP"]
|
|
95
157
|
return self.request({"command":"stopSignals",
|
|
@@ -98,57 +160,119 @@ class Carm:
|
|
|
98
160
|
"step_cnt":5})
|
|
99
161
|
|
|
100
162
|
def stop_task(self, at_once=False):
|
|
163
|
+
"""
|
|
164
|
+
停止当前任务.
|
|
165
|
+
Args:
|
|
166
|
+
at_once (bool): 是否立即停止任务.
|
|
167
|
+
Returns:
|
|
168
|
+
dict: The response from the arm.
|
|
169
|
+
"""
|
|
101
170
|
return self.request({"command":"stopSignals",
|
|
102
171
|
"arm_index":0,
|
|
103
172
|
"stop_id": "SIG_TASK_STOP",
|
|
104
173
|
"stop_at_once": at_once})
|
|
105
174
|
|
|
106
175
|
def recover(self):
|
|
176
|
+
"""
|
|
177
|
+
恢复carm.
|
|
178
|
+
Returns:
|
|
179
|
+
dict: The response from the arm.
|
|
180
|
+
"""
|
|
107
181
|
return self.request({"command":"stopSignals",
|
|
108
182
|
"arm_index":0,
|
|
109
183
|
"stop_id": "SIG_ARM_RECOVER",
|
|
110
184
|
"step_cnt": 5})
|
|
111
185
|
|
|
112
186
|
def clean_carm_error(self):
|
|
187
|
+
"""
|
|
188
|
+
清除carm错误.
|
|
189
|
+
Returns:
|
|
190
|
+
dict: The response from the arm.
|
|
191
|
+
"""
|
|
113
192
|
return self.request({"command":"setControllerErrorReset",
|
|
114
193
|
"arm_index":0})
|
|
115
194
|
|
|
116
|
-
def set_speed_level(self, level, response_level):
|
|
195
|
+
def set_speed_level(self, level = 5.0, response_level = 20):
|
|
196
|
+
"""
|
|
197
|
+
Set the speed level of the arm.
|
|
198
|
+
Args:
|
|
199
|
+
level (float): The speed level to set. range from 0 to 10. 0 is the slowest, 10 is the fastest.
|
|
200
|
+
response_level (int): The response level to set, after how many cicles to set. From 10 to 100.
|
|
201
|
+
Returns:
|
|
202
|
+
dict: The response from the arm.
|
|
203
|
+
"""
|
|
117
204
|
return self.request({"command":"setSpeedLevel",
|
|
118
205
|
"arm_index":0,
|
|
119
206
|
"level":level,
|
|
120
207
|
"response_level":response_level})
|
|
121
|
-
|
|
208
|
+
|
|
122
209
|
def set_debug(self, flag):
|
|
210
|
+
"""
|
|
211
|
+
设置调试模式.
|
|
212
|
+
Args:
|
|
213
|
+
flag (bool): 是否开启调试模式.
|
|
214
|
+
Returns:
|
|
215
|
+
dict: The response from the arm.
|
|
216
|
+
"""
|
|
123
217
|
return self.request({"command":"setDebugMode",
|
|
124
218
|
"arm_index":0,
|
|
125
219
|
"trigger":flag})
|
|
126
220
|
|
|
127
221
|
def get_urdf(self):
|
|
222
|
+
"""
|
|
223
|
+
获取urdf模型.
|
|
224
|
+
Returns:
|
|
225
|
+
dict: The urdf model of the arm.
|
|
226
|
+
"""
|
|
128
227
|
return self.request({"command":"getArmIntrinsicProperties",
|
|
129
228
|
"arm_index":0,
|
|
130
229
|
"type":"urdf"})
|
|
131
230
|
@property
|
|
132
231
|
def joint_pos(self):
|
|
232
|
+
"""
|
|
233
|
+
获取当前关节位置.
|
|
234
|
+
Returns:
|
|
235
|
+
list: The joint position of the arm.
|
|
236
|
+
"""
|
|
133
237
|
return self.state["arm"][0]["reality"]["pose"]
|
|
134
238
|
|
|
135
239
|
@property
|
|
136
240
|
def joint_vel(self):
|
|
241
|
+
"""
|
|
242
|
+
获取当前关节速度.
|
|
243
|
+
Returns:
|
|
244
|
+
list: The joint velocity of the arm.
|
|
245
|
+
"""
|
|
137
246
|
return self.state["arm"][0]["reality"]["vel"]
|
|
138
247
|
|
|
139
248
|
@property
|
|
140
249
|
def joint_tau(self):
|
|
250
|
+
"""
|
|
251
|
+
获取当前关节力矩.
|
|
252
|
+
Returns:
|
|
253
|
+
list: The joint torque of the arm.
|
|
254
|
+
"""
|
|
141
255
|
return self.state["arm"][0]["reality"]["torque"]
|
|
142
256
|
|
|
143
257
|
@property
|
|
144
258
|
def cart_pose(self):
|
|
259
|
+
"""
|
|
260
|
+
获取当前笛卡尔位置.
|
|
261
|
+
Returns:
|
|
262
|
+
list: The cartesian position of the arm.
|
|
263
|
+
"""
|
|
145
264
|
return self.state["arm"][0]["pose"]
|
|
146
265
|
|
|
147
266
|
@property
|
|
148
267
|
def gripper_state(self):
|
|
268
|
+
"""
|
|
269
|
+
获取当前夹爪状态.
|
|
270
|
+
Returns:
|
|
271
|
+
dict: The gripper state of the arm.
|
|
272
|
+
"""
|
|
149
273
|
return self.state["arm"][0]["gripper"]
|
|
150
274
|
|
|
151
|
-
def
|
|
275
|
+
def __clip_joints(self, joints):
|
|
152
276
|
lower = self.limit['limit_lower']
|
|
153
277
|
upper = self.limit["limit_upper"]
|
|
154
278
|
for i,v in enumerate(joints):
|
|
@@ -156,7 +280,15 @@ class Carm:
|
|
|
156
280
|
return joints
|
|
157
281
|
|
|
158
282
|
def track_joint(self, pos, end_effector = -1):
|
|
159
|
-
|
|
283
|
+
"""
|
|
284
|
+
关节轨迹跟踪.
|
|
285
|
+
Args:
|
|
286
|
+
pos (list): The joint position to track.
|
|
287
|
+
end_effector (float, optional): The end effector width. -1 means not set.
|
|
288
|
+
Returns:
|
|
289
|
+
dict: The response from the arm.
|
|
290
|
+
"""
|
|
291
|
+
pos = self.__clip_joints(pos)
|
|
160
292
|
req = {"command":"trajectoryTrackingTasks",
|
|
161
293
|
"task_id":"TASK_TRACKING",
|
|
162
294
|
"arm_index":0,
|
|
@@ -169,6 +301,14 @@ class Carm:
|
|
|
169
301
|
return self.request(req)
|
|
170
302
|
|
|
171
303
|
def track_pose(self, pos, end_effector = -1):
|
|
304
|
+
"""
|
|
305
|
+
笛卡尔轨迹跟踪.
|
|
306
|
+
Args:
|
|
307
|
+
pos (list): The cartesian position to track.
|
|
308
|
+
end_effector (float, optional): The end effector width. -1 means not set.
|
|
309
|
+
Returns:
|
|
310
|
+
dict: The response from the arm.
|
|
311
|
+
"""
|
|
172
312
|
req = {"command":"trajectoryTrackingTasks",
|
|
173
313
|
"task_id":"TASK_TRACKING",
|
|
174
314
|
"arm_index":0,
|
|
@@ -181,7 +321,18 @@ class Carm:
|
|
|
181
321
|
return self.request(req)
|
|
182
322
|
|
|
183
323
|
def move_joint(self, pos, tm=-1, sync=True, user=0, tool=0):
|
|
184
|
-
|
|
324
|
+
"""
|
|
325
|
+
关节到点运动
|
|
326
|
+
Args:
|
|
327
|
+
pos (list): The joint position to move.
|
|
328
|
+
tm (float, optional): The time to move. -1 means not set.
|
|
329
|
+
sync (bool, optional): Whether to wait for the movement to finish.
|
|
330
|
+
user (int, optional): The user index.
|
|
331
|
+
tool (int, optional): The tool index.
|
|
332
|
+
Returns:
|
|
333
|
+
dict: The response from the arm.
|
|
334
|
+
"""
|
|
335
|
+
pos = self.__clip_joints(pos)
|
|
185
336
|
|
|
186
337
|
res = self.request({"command":"webRecieveTasks",
|
|
187
338
|
"task_id":"TASK_MOVJ",
|
|
@@ -191,11 +342,22 @@ class Carm:
|
|
|
191
342
|
"data":{"user":user,"tool":tool, "target_pos": pos, "speed":100}})
|
|
192
343
|
|
|
193
344
|
if sync and res["recv"]=="Task_Recieve":
|
|
194
|
-
self.
|
|
345
|
+
self.__wait_task(res["task_key"])
|
|
195
346
|
|
|
196
347
|
return res
|
|
197
348
|
|
|
198
349
|
def move_pose(self, pos, tm=-1, sync=True, user=0, tool=0):
|
|
350
|
+
"""
|
|
351
|
+
笛卡尔到点运动
|
|
352
|
+
Args:
|
|
353
|
+
pos (list): The cartesian position to move.
|
|
354
|
+
tm (float, optional): The time to move. -1 means not set.
|
|
355
|
+
sync (bool, optional): Whether to wait for the movement to finish.
|
|
356
|
+
user (int, optional): The user index.
|
|
357
|
+
tool (int, optional): The tool index.
|
|
358
|
+
Returns:
|
|
359
|
+
dict: The response from the arm.
|
|
360
|
+
"""
|
|
199
361
|
res = self.request({"command":"webRecieveTasks",
|
|
200
362
|
"task_id":"TASK_MOVJ",
|
|
201
363
|
"task_level":"Task_General",
|
|
@@ -204,25 +366,42 @@ class Carm:
|
|
|
204
366
|
"data":{"user":user,"tool":tool, "target_pos": pos, "speed":100}})
|
|
205
367
|
|
|
206
368
|
if sync and res["recv"]=="Task_Recieve":
|
|
207
|
-
self.
|
|
369
|
+
self.__wait_task(res["task_key"])
|
|
208
370
|
|
|
209
371
|
return res
|
|
210
372
|
|
|
211
373
|
|
|
212
374
|
def move_line(self, pos, speed=50, sync=True, user=0, tool=0):
|
|
375
|
+
"""
|
|
376
|
+
笛卡尔直线运动
|
|
377
|
+
Args:
|
|
378
|
+
pos (list): The cartesian position to move.
|
|
379
|
+
speed (float, optional): The speed to move. 0 - 100%.
|
|
380
|
+
sync (bool, optional): Whether to wait for the movement to finish.
|
|
381
|
+
user (int, optional): The user index.
|
|
382
|
+
tool (int, optional): The tool index.
|
|
383
|
+
Returns:
|
|
384
|
+
dict: The response from the arm.
|
|
385
|
+
"""
|
|
386
|
+
ret = self.invK(pos, self.joint_pos, user, tool) # check IK first
|
|
387
|
+
if ret["recv"] != "Task_Recieve":
|
|
388
|
+
print("Inverse kinematics failed:", ret)
|
|
389
|
+
return ret
|
|
390
|
+
|
|
391
|
+
pos = ret["data"]["joint1"]
|
|
213
392
|
res = self.request({"command":"webRecieveTasks",
|
|
214
393
|
"task_id":"TASK_MOVL",
|
|
215
394
|
"task_level":"Task_General",
|
|
216
395
|
"arm_index":0,
|
|
217
|
-
"point_type":{"space":
|
|
218
|
-
"data":{"user":user,"tool":tool, "
|
|
396
|
+
"point_type":{"space":0},
|
|
397
|
+
"data":{"user":user,"tool":tool, "point": pos, "speed":speed}})
|
|
219
398
|
|
|
220
399
|
if sync and res["recv"]=="Task_Recieve":
|
|
221
|
-
self.
|
|
400
|
+
self.__wait_task(res["task_key"])
|
|
222
401
|
|
|
223
402
|
return res
|
|
224
403
|
|
|
225
|
-
def
|
|
404
|
+
def __wait_task(self, task_key):
|
|
226
405
|
event = threading.Event()
|
|
227
406
|
self.task_pool[task_key] = {"event":event}
|
|
228
407
|
event.wait()
|
|
@@ -247,13 +426,28 @@ class Carm:
|
|
|
247
426
|
pass # TODO
|
|
248
427
|
|
|
249
428
|
def invK(self, cart_pose, ref_joints, user=0, tool=0):
|
|
429
|
+
"""
|
|
430
|
+
逆解
|
|
431
|
+
Args:
|
|
432
|
+
cart_pose (list): The cartesian position to move.
|
|
433
|
+
ref_joints (list): The reference joint position.
|
|
434
|
+
user (int, optional): The user index.
|
|
435
|
+
tool (int, optional): The tool index.
|
|
436
|
+
Returns:
|
|
437
|
+
dict: The response from the arm.
|
|
438
|
+
"""
|
|
250
439
|
if not type(cart_pose[0]) is list:
|
|
251
440
|
cart_pose = [cart_pose, ]
|
|
441
|
+
ref_joints = [ref_joints, ]
|
|
252
442
|
assert(len(cart_pose) == len(ref_joints))
|
|
443
|
+
data = {"user":user,"tool":tool,"point_cnt":len(cart_pose)}
|
|
444
|
+
for i in range(len(ref_joints)):
|
|
445
|
+
data[f"point{i+1}"] = cart_pose[i]
|
|
446
|
+
data[f"refer{i+1}"] = ref_joints[i]
|
|
253
447
|
return self.request({"command":"getKinematics",
|
|
254
448
|
"task_id":"inverse",
|
|
255
449
|
"arm_index":0,
|
|
256
|
-
"data":
|
|
450
|
+
"data":data})
|
|
257
451
|
|
|
258
452
|
def request(self, req):
|
|
259
453
|
event = threading.Event()
|
|
@@ -261,43 +455,43 @@ class Carm:
|
|
|
261
455
|
req["task_key"] = task_key
|
|
262
456
|
self.res_pool[task_key] = {"req":req,"event":event}
|
|
263
457
|
|
|
264
|
-
self.
|
|
458
|
+
self.__send(req)
|
|
265
459
|
|
|
266
460
|
event.wait()
|
|
267
461
|
return self.res_pool.pop(task_key)["res"]
|
|
268
462
|
|
|
269
|
-
def
|
|
463
|
+
def __send(self, msg):
|
|
270
464
|
self.ws.send(json.dumps(msg))
|
|
271
465
|
|
|
272
|
-
def
|
|
466
|
+
def __cbk_status(self, message):
|
|
273
467
|
self.state = message
|
|
274
468
|
|
|
275
|
-
def
|
|
469
|
+
def __cbk_taskfinish(self, message):
|
|
276
470
|
task = message["task_key"]
|
|
277
471
|
self.task_pool[task]["event"].set()
|
|
278
472
|
|
|
279
|
-
def
|
|
473
|
+
def __on_open(self, ws):
|
|
280
474
|
self.open_ready.set()
|
|
281
475
|
print("Connected successfully.")
|
|
282
476
|
|
|
283
|
-
def
|
|
477
|
+
def __on_close(self, ws, code, close_msg):
|
|
284
478
|
print("Disconnected, please check your --addr",code, close_msg)
|
|
285
479
|
|
|
286
|
-
def
|
|
480
|
+
def __on_message(self, ws, message):
|
|
287
481
|
msg = json.loads(message)
|
|
288
482
|
self.last_msg = msg
|
|
289
483
|
cmd = msg["command"]
|
|
290
|
-
op = self.ops.get(cmd, lambda msg: self.
|
|
484
|
+
op = self.ops.get(cmd, lambda msg: self.__response_op(msg))
|
|
291
485
|
op(msg)
|
|
292
486
|
|
|
293
|
-
def
|
|
487
|
+
def __response_op(self, res):
|
|
294
488
|
id = res.get("task_key","")
|
|
295
489
|
data = self.res_pool[id]
|
|
296
490
|
data["res"] = res
|
|
297
491
|
data["event"].set() # notify request thread
|
|
298
492
|
|
|
299
493
|
|
|
300
|
-
def
|
|
494
|
+
def __recv_loop(self):
|
|
301
495
|
print("Recv loop started.")
|
|
302
496
|
self.ws.run_forever()
|
|
303
497
|
|
carm/carm_dds.py
CHANGED
|
@@ -18,8 +18,11 @@ class ArmDriver:
|
|
|
18
18
|
else:
|
|
19
19
|
self.arm.set_control_mode(1)
|
|
20
20
|
|
|
21
|
+
self.arm.set_speed_level(args.speed)
|
|
22
|
+
|
|
21
23
|
self.pub_joint = messenger.advertise(args.joint_topic, 0)
|
|
22
24
|
self.pub_end = messenger.advertise(args.end_topic, 0)
|
|
25
|
+
self.pub_joint_ik = messenger.advertise(args.joint_cmd_ik_topic, 0)
|
|
23
26
|
|
|
24
27
|
self.sub_joint = messenger.subscribe(args.joint_cmd_topic, 0, lambda msg:self.joint_callback(msg))
|
|
25
28
|
self.sub_end = messenger.subscribe(args.end_cmd_topic, 0, lambda msg:self.end_callback(msg))
|
|
@@ -28,6 +31,16 @@ class ArmDriver:
|
|
|
28
31
|
position = np.frombuffer(msg["position"],dtype=np.float64).tolist()
|
|
29
32
|
self.arm.track_pose(position)
|
|
30
33
|
|
|
34
|
+
if self.args.enable_ik:
|
|
35
|
+
ret = self.arm.invK(position, ref_joints=self.arm.joint_pos)
|
|
36
|
+
if ret["recv"] != "Task_Recieve":
|
|
37
|
+
print("Inverse kinematics failed:", ret)
|
|
38
|
+
return
|
|
39
|
+
|
|
40
|
+
pos = ret["data"]["joint1"]
|
|
41
|
+
self.pub_joint_ik.publish({"header": msg["header"], "position": pos})
|
|
42
|
+
|
|
43
|
+
|
|
31
44
|
def joint_callback(self, msg):
|
|
32
45
|
position = np.frombuffer(msg["position"],dtype=np.float64).tolist()
|
|
33
46
|
self.arm.track_joint(position)
|
|
@@ -66,6 +79,7 @@ def driver_main(args):
|
|
|
66
79
|
transfer = ros2.Transfer({"node": "carm_driver" + args.device,
|
|
67
80
|
"publishers":[[args.joint_topic, "sensor_msgs/msg/JointState",10],
|
|
68
81
|
[args.end_topic, "sensor_msgs/msg/JointState",10],
|
|
82
|
+
[args.joint_cmd_ik_topic, "sensor_msgs/msg/JointState",10],
|
|
69
83
|
],
|
|
70
84
|
"subscriptions":[[args.joint_cmd_topic, "sensor_msgs/msg/JointState",10],
|
|
71
85
|
[args.end_cmd_topic, "sensor_msgs/msg/JointState",10]]})
|
|
@@ -82,7 +96,9 @@ def main():
|
|
|
82
96
|
parser.add_argument("--joint_topic", type=str, default="", help="the joints status topic")
|
|
83
97
|
parser.add_argument("--end_topic", type=str, default="", help="the joints status topic")
|
|
84
98
|
parser.add_argument("--joint_cmd_topic", type=str, default="", help="the joints cmd topic")
|
|
99
|
+
parser.add_argument("--joint_cmd_ik_topic", type=str, default="", help="the joints cmd ik topic, this means both end_cmd_topic will be transformed with ik")
|
|
85
100
|
parser.add_argument("--end_cmd_topic", type=str, default="", help="the end cmd topic")
|
|
101
|
+
parser.add_argument("--speed", type=float, default=5.0, help="the speed level")
|
|
86
102
|
|
|
87
103
|
args = parser.parse_args()
|
|
88
104
|
|
|
@@ -94,6 +110,11 @@ def main():
|
|
|
94
110
|
args.joint_cmd_topic = "/"+args.device + "/joints_cmd"
|
|
95
111
|
if args.end_cmd_topic == "":
|
|
96
112
|
args.end_cmd_topic = "/"+args.device + "/end_cmd"
|
|
113
|
+
if args.joint_cmd_ik_topic == "":
|
|
114
|
+
args.joint_cmd_ik_topic = "/"+args.device + "/joints_cmd_ik"
|
|
115
|
+
args.__dict__["enable_ik"] = False
|
|
116
|
+
else:
|
|
117
|
+
args.__dict__["enable_ik"] = True
|
|
97
118
|
|
|
98
119
|
if args.cmd == "":
|
|
99
120
|
driver_main(args)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
carm/__init__.py,sha256=lfNjXYpO8FjQVunCqiaUzjsNUnyuhcyO8Je0ixh1RJY,24
|
|
2
|
+
carm/carm.py,sha256=yVKWmDov9c69l7ye1jcWwBWluWgarEUbFhU6tSfaVoA,17159
|
|
3
|
+
carm/carm_dds.py,sha256=9IkexhHYrjNx2nzplEa4Kj0KdLayzACPChtIF1G29BM,5137
|
|
4
|
+
carm/carm_ros2.py,sha256=IxQD4pglxCH2Vbfj6mm2DlV8KgkqMnS0k1-mIICV8I8,3709
|
|
5
|
+
carm-0.0.20250911.dist-info/METADATA,sha256=hpgdZE1IgDYSIAC3HU-RMdfVtbVGgYlhcLWKuWyslJA,389
|
|
6
|
+
carm-0.0.20250911.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
|
|
7
|
+
carm-0.0.20250911.dist-info/entry_points.txt,sha256=qsJWC39p-s4UO3KZ8BfV2hikeMX693mahkYbR3w67Lk,76
|
|
8
|
+
carm-0.0.20250911.dist-info/top_level.txt,sha256=nZ1bTssUAnAqc2CMka3erGx_2LsdZrSkqtjNf9Ce_d8,5
|
|
9
|
+
carm-0.0.20250911.dist-info/RECORD,,
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
carm/__init__.py,sha256=lfNjXYpO8FjQVunCqiaUzjsNUnyuhcyO8Je0ixh1RJY,24
|
|
2
|
-
carm/carm.py,sha256=8PaBSryLOW9RPzz8o5KUqHiGdPONGiw9HuCJvdWMQgg,10978
|
|
3
|
-
carm/carm_dds.py,sha256=1LTwExF3fuRfjI_Ev8P5TVrv62mxiFRwPdEmeyySbM8,4107
|
|
4
|
-
carm/carm_ros2.py,sha256=IxQD4pglxCH2Vbfj6mm2DlV8KgkqMnS0k1-mIICV8I8,3709
|
|
5
|
-
carm-0.0.20250822.dist-info/METADATA,sha256=RhO7IwJGvpxCOhaOrqDCcSyPYFpnPms2KHqlLqHAJSo,389
|
|
6
|
-
carm-0.0.20250822.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
|
|
7
|
-
carm-0.0.20250822.dist-info/entry_points.txt,sha256=qsJWC39p-s4UO3KZ8BfV2hikeMX693mahkYbR3w67Lk,76
|
|
8
|
-
carm-0.0.20250822.dist-info/top_level.txt,sha256=nZ1bTssUAnAqc2CMka3erGx_2LsdZrSkqtjNf9Ce_d8,5
|
|
9
|
-
carm-0.0.20250822.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|