xarm-python-sdk 1.15.2__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.
- xarm/__init__.py +2 -0
- xarm/build_backend.py +17 -0
- xarm/core/__init__.py +2 -0
- xarm/core/comm/__init__.py +5 -0
- xarm/core/comm/base.py +303 -0
- xarm/core/comm/serial_port.py +44 -0
- xarm/core/comm/socket_port.py +150 -0
- xarm/core/comm/uxbus_cmd_protocol.py +100 -0
- xarm/core/config/__init__.py +0 -0
- xarm/core/config/x_code.py +1427 -0
- xarm/core/config/x_config.py +553 -0
- xarm/core/utils/__init__.py +3 -0
- xarm/core/utils/convert.py +124 -0
- xarm/core/utils/crc16.py +76 -0
- xarm/core/utils/debug_print.py +21 -0
- xarm/core/utils/log.py +98 -0
- xarm/core/version.py +1 -0
- xarm/core/wrapper/__init__.py +11 -0
- xarm/core/wrapper/uxbus_cmd.py +1457 -0
- xarm/core/wrapper/uxbus_cmd_ser.py +94 -0
- xarm/core/wrapper/uxbus_cmd_tcp.py +305 -0
- xarm/tools/__init__.py +0 -0
- xarm/tools/blockly/__init__.py +1 -0
- xarm/tools/blockly/_blockly_base.py +416 -0
- xarm/tools/blockly/_blockly_handler.py +1338 -0
- xarm/tools/blockly/_blockly_highlight.py +94 -0
- xarm/tools/blockly/_blockly_node.py +61 -0
- xarm/tools/blockly/_blockly_tool.py +480 -0
- xarm/tools/blockly_tool.py +1864 -0
- xarm/tools/gcode.py +90 -0
- xarm/tools/list_ports.py +39 -0
- xarm/tools/modbus_tcp.py +205 -0
- xarm/tools/threads.py +30 -0
- xarm/tools/utils.py +36 -0
- xarm/version.py +1 -0
- xarm/wrapper/__init__.py +1 -0
- xarm/wrapper/studio_api.py +34 -0
- xarm/wrapper/xarm_api.py +4416 -0
- xarm/x3/__init__.py +2 -0
- xarm/x3/base.py +2638 -0
- xarm/x3/base_board.py +198 -0
- xarm/x3/code.py +62 -0
- xarm/x3/decorator.py +104 -0
- xarm/x3/events.py +166 -0
- xarm/x3/ft_sensor.py +264 -0
- xarm/x3/gpio.py +457 -0
- xarm/x3/grammar_async.py +21 -0
- xarm/x3/grammar_coroutine.py +24 -0
- xarm/x3/gripper.py +830 -0
- xarm/x3/modbus_tcp.py +84 -0
- xarm/x3/parse.py +110 -0
- xarm/x3/record.py +216 -0
- xarm/x3/report.py +204 -0
- xarm/x3/robotiq.py +220 -0
- xarm/x3/servo.py +485 -0
- xarm/x3/studio.py +138 -0
- xarm/x3/track.py +424 -0
- xarm/x3/utils.py +43 -0
- xarm/x3/xarm.py +1928 -0
- xarm_python_sdk-1.15.2.dist-info/METADATA +103 -0
- xarm_python_sdk-1.15.2.dist-info/RECORD +63 -0
- xarm_python_sdk-1.15.2.dist-info/WHEEL +4 -0
- xarm_python_sdk-1.15.2.dist-info/licenses/LICENSE +27 -0
xarm/x3/servo.py
ADDED
|
@@ -0,0 +1,485 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Software License Agreement (BSD License)
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2019, UFACTORY, Inc.
|
|
5
|
+
# All rights reserved.
|
|
6
|
+
#
|
|
7
|
+
# Author: Vinman <vinman.wen@ufactory.cc> <vinman.cub@gmail.com>
|
|
8
|
+
|
|
9
|
+
from ..core.config.x_config import XCONF
|
|
10
|
+
from ..core.config.x_code import ServoError
|
|
11
|
+
from ..core.utils.log import logger, pretty_print
|
|
12
|
+
from .base import Base
|
|
13
|
+
from .decorator import xarm_is_connected
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Servo(Base):
|
|
17
|
+
def __init__(self):
|
|
18
|
+
super(Servo, self).__init__()
|
|
19
|
+
|
|
20
|
+
@xarm_is_connected(_type='get')
|
|
21
|
+
def get_servo_debug_msg(self, show=False, lang='en'):
|
|
22
|
+
ret = self.arm_cmd.servo_get_dbmsg()
|
|
23
|
+
dbmsg = []
|
|
24
|
+
lang = lang if lang == 'cn' else 'en'
|
|
25
|
+
if self._check_code(ret[0]) == 0:
|
|
26
|
+
for i in range(1, 9):
|
|
27
|
+
servo_error = ServoError(ret[i * 2], status=ret[i * 2 - 1])
|
|
28
|
+
name = ('伺服-{}'.format(i) if lang == 'cn' else 'Servo-{}'.format(i)) if i < 8 else ('机械爪' if lang == 'cn' else 'Gripper')
|
|
29
|
+
dbmsg.append({
|
|
30
|
+
'name': name,
|
|
31
|
+
'servo_id': i,
|
|
32
|
+
'status': servo_error.status,
|
|
33
|
+
'code': servo_error.code,
|
|
34
|
+
'title': servo_error.title[lang],
|
|
35
|
+
'desc': servo_error.description[lang]
|
|
36
|
+
})
|
|
37
|
+
if show:
|
|
38
|
+
pretty_print('************* {}, {}: {} **************'.format(
|
|
39
|
+
'获取伺服信息' if lang == 'cn' else 'GetServoDebugMsg',
|
|
40
|
+
'状态' if lang == 'cn' else 'Status',
|
|
41
|
+
ret[0]), color='light_blue')
|
|
42
|
+
for servo_info in dbmsg:
|
|
43
|
+
color = 'red' if servo_info['code'] != 0 or servo_info['status'] != 0 else 'white'
|
|
44
|
+
pretty_print('* {}, {}: {}, {}: {}, {}: {}'.format(
|
|
45
|
+
servo_info['name'],
|
|
46
|
+
'状态' if lang == 'cn' else 'Status',
|
|
47
|
+
servo_info['status'],
|
|
48
|
+
'错误码' if lang == 'cn' else 'Code',
|
|
49
|
+
servo_info['code'],
|
|
50
|
+
'信息' if lang == 'cn' else 'Info',
|
|
51
|
+
servo_info['title']), color=color)
|
|
52
|
+
pretty_print('*' * 50, color='light_blue')
|
|
53
|
+
return ret[0], dbmsg
|
|
54
|
+
|
|
55
|
+
@xarm_is_connected(_type='set')
|
|
56
|
+
def set_servo_zero(self, servo_id=None):
|
|
57
|
+
"""
|
|
58
|
+
Danger, do not use, may cause the arm to be abnormal, just for debugging
|
|
59
|
+
:param servo_id:
|
|
60
|
+
:return:
|
|
61
|
+
"""
|
|
62
|
+
assert isinstance(servo_id, int) and 1 <= servo_id <= 8, 'The value of parameter servo_id can only be 1-8.'
|
|
63
|
+
ret = self.arm_cmd.servo_set_zero(servo_id)
|
|
64
|
+
self.log_api_info('API -> set_servo_zero(servo_id={}) -> code={}'.format(servo_id, ret[0]), code=ret[0])
|
|
65
|
+
return ret[0]
|
|
66
|
+
|
|
67
|
+
@xarm_is_connected(_type='set')
|
|
68
|
+
def set_servo_addr_16(self, servo_id=None, addr=None, value=None, id_check=True):
|
|
69
|
+
"""
|
|
70
|
+
Danger, do not use, may cause the arm to be abnormal, just for debugging
|
|
71
|
+
:param servo_id:
|
|
72
|
+
:param addr:
|
|
73
|
+
:param value:
|
|
74
|
+
:param id_check:
|
|
75
|
+
:return:
|
|
76
|
+
"""
|
|
77
|
+
if id_check:
|
|
78
|
+
assert isinstance(servo_id, int) and 1 <= servo_id <= 7, 'The value of parameter servo_id can only be 1-7.'
|
|
79
|
+
assert addr is not None, 'The value of parameter addr cannot be None.'
|
|
80
|
+
assert value is not None, 'The value of parameter value cannot be None.'
|
|
81
|
+
ret = self.arm_cmd.servo_addr_w16(servo_id, addr, value)
|
|
82
|
+
self.log_api_info('API -> set_servo_addr_16(servo_id={}, addr={}, value={}) -> code={}'.format(servo_id, addr, value, ret[0]), code=ret[0])
|
|
83
|
+
return ret[0]
|
|
84
|
+
|
|
85
|
+
@xarm_is_connected(_type='get')
|
|
86
|
+
def get_servo_addr_16(self, servo_id=None, addr=None, id_check=True):
|
|
87
|
+
"""
|
|
88
|
+
Danger, do not use, may cause the arm to be abnormal, just for debugging
|
|
89
|
+
:param servo_id:
|
|
90
|
+
:param addr:
|
|
91
|
+
:return:
|
|
92
|
+
"""
|
|
93
|
+
if id_check:
|
|
94
|
+
assert isinstance(servo_id, int) and 1 <= servo_id <= 7, 'The value of parameter servo_id can only be 1-7.'
|
|
95
|
+
assert addr is not None, 'The value of parameter addr cannot be None.'
|
|
96
|
+
ret = self.arm_cmd.servo_addr_r16(servo_id, addr)
|
|
97
|
+
return ret[0], ret[1]
|
|
98
|
+
|
|
99
|
+
@xarm_is_connected(_type='set')
|
|
100
|
+
def set_servo_addr_32(self, servo_id=None, addr=None, value=None, id_check=True):
|
|
101
|
+
"""
|
|
102
|
+
Danger, do not use, may cause the arm to be abnormal, just for debugging
|
|
103
|
+
:param servo_id:
|
|
104
|
+
:param addr:
|
|
105
|
+
:param value:
|
|
106
|
+
:return:
|
|
107
|
+
"""
|
|
108
|
+
if id_check:
|
|
109
|
+
assert isinstance(servo_id, int) and 1 <= servo_id <= 7, 'The value of parameter servo_id can only be 1-7.'
|
|
110
|
+
assert addr is not None, 'The value of parameter addr cannot be None.'
|
|
111
|
+
assert value is not None, 'The value of parameter value cannot be None.'
|
|
112
|
+
ret = self.arm_cmd.servo_addr_w32(servo_id, addr, value)
|
|
113
|
+
self.log_api_info('API -> set_servo_addr_32(servo_id={}, addr={}, value={}) -> code={}'.format(servo_id, addr, value, ret[0]), code=ret[0])
|
|
114
|
+
return ret[0]
|
|
115
|
+
|
|
116
|
+
@xarm_is_connected(_type='get')
|
|
117
|
+
def get_servo_addr_32(self, servo_id=None, addr=None, id_check=True):
|
|
118
|
+
"""
|
|
119
|
+
Danger, do not use, may cause the arm to be abnormal, just for debugging
|
|
120
|
+
:param servo_id:
|
|
121
|
+
:param addr:
|
|
122
|
+
:return:
|
|
123
|
+
"""
|
|
124
|
+
if id_check:
|
|
125
|
+
assert isinstance(servo_id, int) and 1 <= servo_id <= 7, 'The value of parameter servo_id can only be 1-7.'
|
|
126
|
+
assert addr is not None, 'The value of parameter addr cannot be None.'
|
|
127
|
+
ret = self.arm_cmd.servo_addr_r32(servo_id, addr)
|
|
128
|
+
return ret[0], ret[1]
|
|
129
|
+
|
|
130
|
+
@xarm_is_connected(_type='set')
|
|
131
|
+
def clean_servo_error(self, servo_id=None):
|
|
132
|
+
"""
|
|
133
|
+
Danger, do not use, may cause the arm to be abnormal, just for debugging
|
|
134
|
+
:param servo_id:
|
|
135
|
+
:return:
|
|
136
|
+
"""
|
|
137
|
+
return self.set_servo_addr_16(servo_id, 0x0109, 1)
|
|
138
|
+
|
|
139
|
+
@xarm_is_connected(_type='get')
|
|
140
|
+
def get_servo_state(self, servo_id):
|
|
141
|
+
"""
|
|
142
|
+
获取运行状态
|
|
143
|
+
:param servo_id:
|
|
144
|
+
:return:
|
|
145
|
+
"""
|
|
146
|
+
ret = self.get_servo_addr_16(servo_id, 0x0000)
|
|
147
|
+
return ret
|
|
148
|
+
|
|
149
|
+
@xarm_is_connected(_type='get')
|
|
150
|
+
def get_servo_rotate_speed(self, servo_id):
|
|
151
|
+
"""
|
|
152
|
+
获取转速
|
|
153
|
+
:param servo_id:
|
|
154
|
+
:return:
|
|
155
|
+
"""
|
|
156
|
+
ret = self.get_servo_addr_16(servo_id, 0x0001)
|
|
157
|
+
return ret
|
|
158
|
+
|
|
159
|
+
@xarm_is_connected(_type='get')
|
|
160
|
+
def get_servo_current_percentage(self, servo_id):
|
|
161
|
+
"""
|
|
162
|
+
获取电流百分比
|
|
163
|
+
:param servo_id:
|
|
164
|
+
:return:
|
|
165
|
+
"""
|
|
166
|
+
ret = self.get_servo_addr_16(servo_id, 0x0002)
|
|
167
|
+
return ret
|
|
168
|
+
|
|
169
|
+
@xarm_is_connected(_type='get')
|
|
170
|
+
def get_servo_current(self, servo_id):
|
|
171
|
+
"""
|
|
172
|
+
获取电流
|
|
173
|
+
:param servo_id:
|
|
174
|
+
:return:
|
|
175
|
+
"""
|
|
176
|
+
ret = self.get_servo_addr_16(servo_id, 0x0003)
|
|
177
|
+
return ret[0], ret[1] / 100
|
|
178
|
+
|
|
179
|
+
@xarm_is_connected(_type='get')
|
|
180
|
+
def get_servo_command_position(self, servo_id):
|
|
181
|
+
"""
|
|
182
|
+
获取指令位置
|
|
183
|
+
:param servo_id:
|
|
184
|
+
:return:
|
|
185
|
+
"""
|
|
186
|
+
ret = self.get_servo_addr_32(servo_id, 0x0004)
|
|
187
|
+
return ret
|
|
188
|
+
|
|
189
|
+
@xarm_is_connected(_type='get')
|
|
190
|
+
def get_servo_position(self, servo_id):
|
|
191
|
+
"""
|
|
192
|
+
获取电机位置
|
|
193
|
+
:param servo_id:
|
|
194
|
+
:return:
|
|
195
|
+
"""
|
|
196
|
+
ret = self.get_servo_addr_32(servo_id, 0x0006)
|
|
197
|
+
return ret
|
|
198
|
+
|
|
199
|
+
@xarm_is_connected(_type='get')
|
|
200
|
+
def get_servo_position_deviation(self, servo_id):
|
|
201
|
+
"""
|
|
202
|
+
获取位置误差
|
|
203
|
+
:param servo_id:
|
|
204
|
+
:return:
|
|
205
|
+
"""
|
|
206
|
+
ret = self.get_servo_addr_32(servo_id, 0x0008)
|
|
207
|
+
return ret
|
|
208
|
+
|
|
209
|
+
@xarm_is_connected(_type='get')
|
|
210
|
+
def get_servo_electrical_angle(self, servo_id):
|
|
211
|
+
"""
|
|
212
|
+
获取电角度
|
|
213
|
+
:param servo_id:
|
|
214
|
+
:return:
|
|
215
|
+
"""
|
|
216
|
+
ret = self.get_servo_addr_16(servo_id, 0x000B)
|
|
217
|
+
return ret
|
|
218
|
+
|
|
219
|
+
@xarm_is_connected(_type='get')
|
|
220
|
+
def get_servo_drv8323_sr0_register(self, servo_id):
|
|
221
|
+
"""
|
|
222
|
+
获取DRV8323_SR0状态寄存器
|
|
223
|
+
:param servo_id:
|
|
224
|
+
:return:
|
|
225
|
+
"""
|
|
226
|
+
ret = self.get_servo_addr_16(servo_id, 0x000C)
|
|
227
|
+
return ret
|
|
228
|
+
|
|
229
|
+
@xarm_is_connected(_type='get')
|
|
230
|
+
def get_servo_drv8323_sr1_register(self, servo_id):
|
|
231
|
+
"""
|
|
232
|
+
获取DRV8323_SR1状态寄存器
|
|
233
|
+
:param servo_id:
|
|
234
|
+
:return:
|
|
235
|
+
"""
|
|
236
|
+
ret = self.get_servo_addr_16(servo_id, 0x000D)
|
|
237
|
+
return ret
|
|
238
|
+
|
|
239
|
+
@xarm_is_connected(_type='get')
|
|
240
|
+
def get_servo_temperature(self, servo_id):
|
|
241
|
+
"""
|
|
242
|
+
获取当前温度
|
|
243
|
+
:param servo_id:
|
|
244
|
+
:return:
|
|
245
|
+
"""
|
|
246
|
+
ret = self.get_servo_addr_16(servo_id, 0x000E)
|
|
247
|
+
return ret
|
|
248
|
+
|
|
249
|
+
@xarm_is_connected(_type='get')
|
|
250
|
+
def get_servo_alarm_code(self, servo_id):
|
|
251
|
+
"""
|
|
252
|
+
获取当前报警代码
|
|
253
|
+
:param servo_id:
|
|
254
|
+
:return:
|
|
255
|
+
"""
|
|
256
|
+
ret = self.get_servo_addr_16(servo_id, 0x000F)
|
|
257
|
+
return ret
|
|
258
|
+
|
|
259
|
+
@xarm_is_connected(_type='get')
|
|
260
|
+
def get_servo_alarm_current(self, servo_id):
|
|
261
|
+
"""
|
|
262
|
+
获取报警发生时的电流值
|
|
263
|
+
:param servo_id:
|
|
264
|
+
:return:
|
|
265
|
+
"""
|
|
266
|
+
ret = self.get_servo_addr_16(servo_id, 0x0010)
|
|
267
|
+
return ret
|
|
268
|
+
|
|
269
|
+
@xarm_is_connected(_type='get')
|
|
270
|
+
def get_servo_alarm_speed(self, servo_id):
|
|
271
|
+
"""
|
|
272
|
+
获取报警发生时的速度值
|
|
273
|
+
:param servo_id:
|
|
274
|
+
:return:
|
|
275
|
+
"""
|
|
276
|
+
ret = self.get_servo_addr_16(servo_id, 0x0011)
|
|
277
|
+
return ret
|
|
278
|
+
|
|
279
|
+
@xarm_is_connected(_type='get')
|
|
280
|
+
def get_servo_alarm_voltage(self, servo_id):
|
|
281
|
+
"""
|
|
282
|
+
获取报警发生时的输入电压值
|
|
283
|
+
:param servo_id:
|
|
284
|
+
:return:
|
|
285
|
+
"""
|
|
286
|
+
ret = self.get_servo_addr_16(servo_id, 0x0012)
|
|
287
|
+
return ret
|
|
288
|
+
|
|
289
|
+
@xarm_is_connected(_type='get')
|
|
290
|
+
def get_servo_bus_voltage(self, servo_id):
|
|
291
|
+
"""
|
|
292
|
+
获取母线电压
|
|
293
|
+
:param servo_id:
|
|
294
|
+
:return:
|
|
295
|
+
"""
|
|
296
|
+
ret = self.get_servo_addr_16(servo_id, 0x0018)
|
|
297
|
+
return ret[0], ret[1] / 100
|
|
298
|
+
|
|
299
|
+
@xarm_is_connected(_type='get')
|
|
300
|
+
def get_servo_mu_state(self, servo_id):
|
|
301
|
+
"""
|
|
302
|
+
获取MU当前状态
|
|
303
|
+
:param servo_id:
|
|
304
|
+
:return:
|
|
305
|
+
"""
|
|
306
|
+
ret = self.get_servo_addr_16(servo_id, 0x001E)
|
|
307
|
+
return ret
|
|
308
|
+
|
|
309
|
+
@xarm_is_connected(_type='get')
|
|
310
|
+
def get_servo_mu_alarm_count(self, servo_id):
|
|
311
|
+
"""
|
|
312
|
+
获取MU上电后报警次数
|
|
313
|
+
:param servo_id:
|
|
314
|
+
:return:
|
|
315
|
+
"""
|
|
316
|
+
ret = self.get_servo_addr_16(servo_id, 0x001F)
|
|
317
|
+
return ret
|
|
318
|
+
|
|
319
|
+
@xarm_is_connected(_type='get')
|
|
320
|
+
def get_servo_feedback_position(self, servo_id):
|
|
321
|
+
"""
|
|
322
|
+
获取关节反馈位置
|
|
323
|
+
:param servo_id:
|
|
324
|
+
:return:
|
|
325
|
+
"""
|
|
326
|
+
ret = self.get_servo_addr_32(servo_id, 0x0040)
|
|
327
|
+
return ret
|
|
328
|
+
|
|
329
|
+
# @xarm_is_connected(_type='get')
|
|
330
|
+
# def get_servo_current(self, servo_id):
|
|
331
|
+
# """
|
|
332
|
+
# 获取电流
|
|
333
|
+
# :param servo_id:
|
|
334
|
+
# :return:
|
|
335
|
+
# """
|
|
336
|
+
# ret = self.get_servo_addr_16(servo_id, 0x0042)
|
|
337
|
+
# return ret
|
|
338
|
+
|
|
339
|
+
@xarm_is_connected(_type='get')
|
|
340
|
+
def get_servo_version(self, servo_id=1):
|
|
341
|
+
"""
|
|
342
|
+
获取关节版本
|
|
343
|
+
:param servo_id:
|
|
344
|
+
:return:
|
|
345
|
+
"""
|
|
346
|
+
assert isinstance(servo_id, int) and 1 <= servo_id <= 8, 'The value of parameter servo_id can only be 1-8.'
|
|
347
|
+
|
|
348
|
+
def _get_servo_version(id_num):
|
|
349
|
+
versions = ['*', '*', '*']
|
|
350
|
+
ret1 = self.get_servo_addr_16(id_num, 0x0801)
|
|
351
|
+
ret2 = self.get_servo_addr_16(id_num, 0x0802)
|
|
352
|
+
ret3 = self.get_servo_addr_16(id_num, 0x0803)
|
|
353
|
+
code = 0
|
|
354
|
+
if ret1[0] == 0:
|
|
355
|
+
versions[0] = ret1[1]
|
|
356
|
+
else:
|
|
357
|
+
code = ret1[0]
|
|
358
|
+
if ret2[0] == 0:
|
|
359
|
+
versions[1] = ret2[1]
|
|
360
|
+
else:
|
|
361
|
+
code = ret2[0]
|
|
362
|
+
if ret3[0] == 0:
|
|
363
|
+
versions[2] = ret3[1]
|
|
364
|
+
else:
|
|
365
|
+
code = ret3[0]
|
|
366
|
+
# if code != 0:
|
|
367
|
+
# _, err_warn = self.get_err_warn_code()
|
|
368
|
+
# if _ in [0, 1, 2]:
|
|
369
|
+
# if err_warn[0] not in [10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 28]:
|
|
370
|
+
# versions = [ret1[1], ret2[1], ret3[1]]
|
|
371
|
+
return code, '.'.join(map(str, versions))
|
|
372
|
+
|
|
373
|
+
if servo_id > self.axis:
|
|
374
|
+
code = 0
|
|
375
|
+
versions = []
|
|
376
|
+
for i in range(1, self.axis + 1):
|
|
377
|
+
ret = _get_servo_version(i)
|
|
378
|
+
if ret[0] != 0:
|
|
379
|
+
code = ret[0]
|
|
380
|
+
versions.append(ret[1])
|
|
381
|
+
return code, versions
|
|
382
|
+
else:
|
|
383
|
+
return _get_servo_version(servo_id)
|
|
384
|
+
|
|
385
|
+
@xarm_is_connected(_type='get')
|
|
386
|
+
def get_harmonic_type(self, servo_id=1):
|
|
387
|
+
"""
|
|
388
|
+
获取关节版本
|
|
389
|
+
:param servo_id:
|
|
390
|
+
:return:
|
|
391
|
+
"""
|
|
392
|
+
assert isinstance(servo_id, int) and 1 <= servo_id <= 8, 'The value of parameter servo_id can only be 1-8.'
|
|
393
|
+
|
|
394
|
+
if servo_id > self.axis:
|
|
395
|
+
code = 0
|
|
396
|
+
types = []
|
|
397
|
+
for i in range(1, self.axis + 1):
|
|
398
|
+
ret = self.get_servo_addr_16(i, 0x081F)
|
|
399
|
+
if ret[0] != 0:
|
|
400
|
+
code = ret[0]
|
|
401
|
+
types.append(ret[1])
|
|
402
|
+
return code, types
|
|
403
|
+
else:
|
|
404
|
+
return self.get_servo_addr_16(servo_id, 0x081F)
|
|
405
|
+
|
|
406
|
+
@xarm_is_connected(_type='get')
|
|
407
|
+
def get_servo_error_code(self, servo_id=None):
|
|
408
|
+
assert servo_id is None or (isinstance(servo_id, int) and servo_id >= 1), \
|
|
409
|
+
'The value of parameter servo_id must be greater than 1 or None.'
|
|
410
|
+
code = 0
|
|
411
|
+
if servo_id is None or servo_id > self.axis:
|
|
412
|
+
count = 7 if servo_id == 8 else self.axis
|
|
413
|
+
errcodes = [0] * count
|
|
414
|
+
for i in range(count):
|
|
415
|
+
ret = self.get_servo_addr_32(i + 1, XCONF.ServoConf.CURR_POS)
|
|
416
|
+
if ret[0] == XCONF.UxbusState.ERR_CODE:
|
|
417
|
+
_, err_warn = self.get_err_warn_code()
|
|
418
|
+
if _ == 0:
|
|
419
|
+
if i + 11 == err_warn[0]:
|
|
420
|
+
errcodes[i] = ret[1]
|
|
421
|
+
else:
|
|
422
|
+
errcodes[i] = 0
|
|
423
|
+
else:
|
|
424
|
+
code = _
|
|
425
|
+
logger.error('Get controller errwarn: ret={}, errwarn={}'.format(code, err_warn))
|
|
426
|
+
errcodes[i] = ret[1]
|
|
427
|
+
else:
|
|
428
|
+
errcodes = 0
|
|
429
|
+
ret = self.get_servo_addr_32(servo_id, XCONF.ServoConf.CURR_POS)
|
|
430
|
+
if ret[0] == XCONF.UxbusState.ERR_CODE:
|
|
431
|
+
_, err_warn = self.get_err_warn_code()
|
|
432
|
+
if _ == 0:
|
|
433
|
+
if servo_id + 10 == err_warn[0]:
|
|
434
|
+
errcodes = ret[1]
|
|
435
|
+
else:
|
|
436
|
+
errcodes = 0
|
|
437
|
+
else:
|
|
438
|
+
code = _
|
|
439
|
+
logger.error('Get controller errwarn: ret={}, errwarn={}'.format(code, err_warn))
|
|
440
|
+
errcodes = ret[1]
|
|
441
|
+
return code, errcodes
|
|
442
|
+
|
|
443
|
+
@xarm_is_connected(_type='set')
|
|
444
|
+
def clean_servo_pvl_err(self, servo_id=None):
|
|
445
|
+
assert servo_id is None or (isinstance(servo_id, int) and servo_id >= 1), \
|
|
446
|
+
'The value of parameter servo_id must be greater than 1 or None.'
|
|
447
|
+
if servo_id is None or servo_id > self.axis:
|
|
448
|
+
count = 7 if servo_id == 8 else self.axis
|
|
449
|
+
ids = range(count)
|
|
450
|
+
else:
|
|
451
|
+
ids = [servo_id - 1]
|
|
452
|
+
_, errcode = self.get_servo_error_code()
|
|
453
|
+
for i in ids:
|
|
454
|
+
if errcode[i] == 0x12:
|
|
455
|
+
self.set_servo_addr_16(i + 1, XCONF.ServoConf.RESET_PVL, 0x0002)
|
|
456
|
+
self.set_servo_addr_16(i + 1, XCONF.ServoConf.RESET_ERR, 1)
|
|
457
|
+
return 0
|
|
458
|
+
|
|
459
|
+
@xarm_is_connected(_type='get')
|
|
460
|
+
def get_servo_all_pids(self, servo_id=None):
|
|
461
|
+
assert servo_id is None or (isinstance(servo_id, int) and servo_id >= 1), \
|
|
462
|
+
'The value of parameter servo_id must be greater than 1 or None.'
|
|
463
|
+
self.clean_error()
|
|
464
|
+
self.clean_warn()
|
|
465
|
+
addrs = [
|
|
466
|
+
XCONF.ServoConf.POS_KP, XCONF.ServoConf.POS_FWDKP, XCONF.ServoConf.POS_PWDTC,
|
|
467
|
+
XCONF.ServoConf.SPD_KP, XCONF.ServoConf.SPD_KI, XCONF.ServoConf.CURR_KP,
|
|
468
|
+
XCONF.ServoConf.CURR_KI, XCONF.ServoConf.SPD_IFILT, XCONF.ServoConf.SPD_OFILT,
|
|
469
|
+
XCONF.ServoConf.CURR_IFILT, XCONF.ServoConf.POS_KD, XCONF.ServoConf.POS_CMDILT,
|
|
470
|
+
XCONF.ServoConf.GET_TEMP, XCONF.ServoConf.OVER_TEMP
|
|
471
|
+
]
|
|
472
|
+
if servo_id is None or servo_id > self.axis:
|
|
473
|
+
count = 7 if servo_id == 8 else self.axis
|
|
474
|
+
pids = [[9999] * len(addrs) for _ in range(count)]
|
|
475
|
+
for i in range(count):
|
|
476
|
+
for j, addr in enumerate(addrs):
|
|
477
|
+
_, data = self.get_servo_addr_16(i + 1, addr)
|
|
478
|
+
if _ == 0:
|
|
479
|
+
pids[i][j] = data
|
|
480
|
+
else:
|
|
481
|
+
pids = [9999] * len(addrs)
|
|
482
|
+
for j, addr in enumerate(addrs):
|
|
483
|
+
_, data = self.get_servo_addr_16(servo_id, addr)
|
|
484
|
+
pids[j] = data
|
|
485
|
+
return 0, pids
|
xarm/x3/studio.py
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Software License Agreement (BSD License)
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2021, UFACTORY, Inc.
|
|
5
|
+
# All rights reserved.
|
|
6
|
+
#
|
|
7
|
+
# Author: Vinman <vinman.wen@ufactory.cc> <vinman.cub@gmail.com>
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
import warnings
|
|
11
|
+
from ..core.utils.log import logger
|
|
12
|
+
from .code import APIState
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
from requests import Session
|
|
16
|
+
except:
|
|
17
|
+
import urllib.request
|
|
18
|
+
|
|
19
|
+
class Session(object):
|
|
20
|
+
class Request:
|
|
21
|
+
def __init__(self, url, data, **kwargs):
|
|
22
|
+
req = urllib.request.Request(url, data.encode('utf-8'))
|
|
23
|
+
self.r = urllib.request.urlopen(req)
|
|
24
|
+
self._data = self.r.read()
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def status_code(self):
|
|
28
|
+
return self.r.code
|
|
29
|
+
|
|
30
|
+
def json(self):
|
|
31
|
+
return json.loads(self._data.decode('utf-8'))
|
|
32
|
+
|
|
33
|
+
def post(self, url, data=None, **kwargs):
|
|
34
|
+
return self.Request(url, data)
|
|
35
|
+
|
|
36
|
+
def close(self):
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class Studio(object):
|
|
41
|
+
def __init__(self, ip, ignore_warnning=False):
|
|
42
|
+
super(Studio, self).__init__()
|
|
43
|
+
if not ignore_warnning:
|
|
44
|
+
warnings.warn("don't use it for now, just for debugging")
|
|
45
|
+
self.__ip = ip
|
|
46
|
+
self.__session = Session()
|
|
47
|
+
|
|
48
|
+
def __del__(self):
|
|
49
|
+
self.__session.close()
|
|
50
|
+
|
|
51
|
+
def run_blockly_app(self, name, **kwargs):
|
|
52
|
+
try:
|
|
53
|
+
self.call_studio_api({}, api_name='Core.command.xarm_set_blockly_init', show_fail_log=False)
|
|
54
|
+
except:
|
|
55
|
+
pass
|
|
56
|
+
kwargs['appName'] = name
|
|
57
|
+
ret = self.call_studio_api(kwargs, api_name='Core.command.run_blockly')
|
|
58
|
+
if ret:
|
|
59
|
+
return ret['code']
|
|
60
|
+
return APIState.API_EXCEPTION
|
|
61
|
+
|
|
62
|
+
def delete_blockly_app(self, name):
|
|
63
|
+
ret = self.call_studio_api({
|
|
64
|
+
'parentPath': name,
|
|
65
|
+
'selectNode': {
|
|
66
|
+
'type': 'file'
|
|
67
|
+
}
|
|
68
|
+
}, api_name='Core.command.app_delete_item')
|
|
69
|
+
if ret:
|
|
70
|
+
return ret['code']
|
|
71
|
+
return APIState.API_EXCEPTION
|
|
72
|
+
|
|
73
|
+
def playback_trajectory(self, filename, times=1, wait=False, double_speed=1):
|
|
74
|
+
ret = self.call_studio_api({
|
|
75
|
+
'filename': filename,
|
|
76
|
+
'times': times,
|
|
77
|
+
'speed': double_speed,
|
|
78
|
+
'wait': wait,
|
|
79
|
+
}, api_name='Core.command.xarm_playback_traj')
|
|
80
|
+
if ret:
|
|
81
|
+
return ret['code']
|
|
82
|
+
return APIState.API_EXCEPTION
|
|
83
|
+
|
|
84
|
+
def delete_trajectory(self, filename):
|
|
85
|
+
ret = self.call_studio_api({
|
|
86
|
+
'filename': filename,
|
|
87
|
+
}, api_name='Core.command.xarm_delete_traj')
|
|
88
|
+
if ret:
|
|
89
|
+
return ret['code']
|
|
90
|
+
return APIState.API_EXCEPTION
|
|
91
|
+
|
|
92
|
+
def set_initial_point(self, point):
|
|
93
|
+
ret = self.call_studio_api({'point': point}, api_name='Core.command.xarm_set_initial_point')
|
|
94
|
+
if ret:
|
|
95
|
+
return ret['code']
|
|
96
|
+
return APIState.API_EXCEPTION
|
|
97
|
+
|
|
98
|
+
def get_initial_point(self):
|
|
99
|
+
ret = self.call_studio_api(api_name='XArm.xarm_initial_point')
|
|
100
|
+
if ret:
|
|
101
|
+
return ret['code'], ret['data']
|
|
102
|
+
return APIState.API_EXCEPTION, [0] * 7
|
|
103
|
+
|
|
104
|
+
def call_sdk_api(self, *args, **kwargs):
|
|
105
|
+
kwargs['api_name'] = 'XArm.xarm.{}'.format(kwargs['api_name'])
|
|
106
|
+
return self.call_studio_api(*args, **kwargs)
|
|
107
|
+
|
|
108
|
+
def call_studio_api(self, *args, **kwargs):
|
|
109
|
+
kwargs['path'] = 'v2/api'
|
|
110
|
+
return self.__call_remote_api(*args, **kwargs)
|
|
111
|
+
|
|
112
|
+
def __call_remote_api(self, *args, **kwargs):
|
|
113
|
+
api_name = kwargs.pop('api_name', None)
|
|
114
|
+
show_fail_log = kwargs.pop('show_fail_log', True)
|
|
115
|
+
path = kwargs.pop('path')
|
|
116
|
+
if self.__ip and api_name:
|
|
117
|
+
r = self.__session.post('http://{}:18333/{}'.format(self.__ip, path), data=json.dumps({
|
|
118
|
+
'cmd': api_name, 'args': args, 'kwargs': kwargs
|
|
119
|
+
}), timeout=(5, None))
|
|
120
|
+
if r.status_code == 200:
|
|
121
|
+
res = r.json()
|
|
122
|
+
if res['code'] != 0:
|
|
123
|
+
if show_fail_log:
|
|
124
|
+
logger.error(res['data'])
|
|
125
|
+
return res
|
|
126
|
+
else:
|
|
127
|
+
if show_fail_log:
|
|
128
|
+
logger.error('request failed, http_status_code={}'.format(r.status_code))
|
|
129
|
+
else:
|
|
130
|
+
if show_fail_log:
|
|
131
|
+
logger.error('ip or api_name is empty, ip={}, api_name={}'.format(self.__ip, api_name))
|
|
132
|
+
|
|
133
|
+
def get_mount_direction(self):
|
|
134
|
+
|
|
135
|
+
ret = self.call_studio_api(api_name='XArm.xarm_mount_degrees')
|
|
136
|
+
if ret:
|
|
137
|
+
return ret['code'], ret['data']
|
|
138
|
+
return APIState.API_EXCEPTION, [0, 0]
|