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.
Files changed (63) hide show
  1. xarm/__init__.py +2 -0
  2. xarm/build_backend.py +17 -0
  3. xarm/core/__init__.py +2 -0
  4. xarm/core/comm/__init__.py +5 -0
  5. xarm/core/comm/base.py +303 -0
  6. xarm/core/comm/serial_port.py +44 -0
  7. xarm/core/comm/socket_port.py +150 -0
  8. xarm/core/comm/uxbus_cmd_protocol.py +100 -0
  9. xarm/core/config/__init__.py +0 -0
  10. xarm/core/config/x_code.py +1427 -0
  11. xarm/core/config/x_config.py +553 -0
  12. xarm/core/utils/__init__.py +3 -0
  13. xarm/core/utils/convert.py +124 -0
  14. xarm/core/utils/crc16.py +76 -0
  15. xarm/core/utils/debug_print.py +21 -0
  16. xarm/core/utils/log.py +98 -0
  17. xarm/core/version.py +1 -0
  18. xarm/core/wrapper/__init__.py +11 -0
  19. xarm/core/wrapper/uxbus_cmd.py +1457 -0
  20. xarm/core/wrapper/uxbus_cmd_ser.py +94 -0
  21. xarm/core/wrapper/uxbus_cmd_tcp.py +305 -0
  22. xarm/tools/__init__.py +0 -0
  23. xarm/tools/blockly/__init__.py +1 -0
  24. xarm/tools/blockly/_blockly_base.py +416 -0
  25. xarm/tools/blockly/_blockly_handler.py +1338 -0
  26. xarm/tools/blockly/_blockly_highlight.py +94 -0
  27. xarm/tools/blockly/_blockly_node.py +61 -0
  28. xarm/tools/blockly/_blockly_tool.py +480 -0
  29. xarm/tools/blockly_tool.py +1864 -0
  30. xarm/tools/gcode.py +90 -0
  31. xarm/tools/list_ports.py +39 -0
  32. xarm/tools/modbus_tcp.py +205 -0
  33. xarm/tools/threads.py +30 -0
  34. xarm/tools/utils.py +36 -0
  35. xarm/version.py +1 -0
  36. xarm/wrapper/__init__.py +1 -0
  37. xarm/wrapper/studio_api.py +34 -0
  38. xarm/wrapper/xarm_api.py +4416 -0
  39. xarm/x3/__init__.py +2 -0
  40. xarm/x3/base.py +2638 -0
  41. xarm/x3/base_board.py +198 -0
  42. xarm/x3/code.py +62 -0
  43. xarm/x3/decorator.py +104 -0
  44. xarm/x3/events.py +166 -0
  45. xarm/x3/ft_sensor.py +264 -0
  46. xarm/x3/gpio.py +457 -0
  47. xarm/x3/grammar_async.py +21 -0
  48. xarm/x3/grammar_coroutine.py +24 -0
  49. xarm/x3/gripper.py +830 -0
  50. xarm/x3/modbus_tcp.py +84 -0
  51. xarm/x3/parse.py +110 -0
  52. xarm/x3/record.py +216 -0
  53. xarm/x3/report.py +204 -0
  54. xarm/x3/robotiq.py +220 -0
  55. xarm/x3/servo.py +485 -0
  56. xarm/x3/studio.py +138 -0
  57. xarm/x3/track.py +424 -0
  58. xarm/x3/utils.py +43 -0
  59. xarm/x3/xarm.py +1928 -0
  60. xarm_python_sdk-1.15.2.dist-info/METADATA +103 -0
  61. xarm_python_sdk-1.15.2.dist-info/RECORD +63 -0
  62. xarm_python_sdk-1.15.2.dist-info/WHEEL +4 -0
  63. xarm_python_sdk-1.15.2.dist-info/licenses/LICENSE +27 -0
xarm/x3/base.py ADDED
@@ -0,0 +1,2638 @@
1
+ #!/usr/bin/env python3
2
+ # Software License Agreement (BSD License)
3
+ #
4
+ # Copyright (c) 2020, UFACTORY, Inc.
5
+ # All rights reserved.
6
+ #
7
+ # Author: Vinman <vinman.wen@ufactory.cc> <vinman.cub@gmail.com>
8
+
9
+ import re
10
+ import sys
11
+ import time
12
+ import math
13
+ import uuid
14
+ import queue
15
+ import struct
16
+ import threading
17
+ from collections.abc import Iterable
18
+ try:
19
+ from multiprocessing.pool import ThreadPool
20
+ except:
21
+ ThreadPool = None
22
+ try:
23
+ import asyncio
24
+
25
+ if sys.version_info.major >= 3 and sys.version_info.minor >= 5:
26
+ from .grammar_async import AsyncObject as BaseObject
27
+ else:
28
+ from .grammar_coroutine import CoroutineObject as BaseObject
29
+ except:
30
+ asyncio = None
31
+ if not hasattr(math, 'inf'):
32
+ setattr(math, 'inf', float('inf'))
33
+ from .events import Events
34
+ from ..core.config.x_config import XCONF
35
+ from ..core.comm import SocketPort
36
+ try:
37
+ from ..core.comm import SerialPort
38
+ except:
39
+ SerialPort = None
40
+ from ..core.wrapper import UxbusCmdSer, UxbusCmdTcp
41
+ from ..core.utils.log import logger, pretty_print
42
+ from ..core.utils import convert
43
+ from ..core.config.x_code import ControllerWarn, ControllerError, ControllerErrorCodeMap, ControllerWarnCodeMap
44
+ from .utils import compare_time, compare_version, filter_invaild_number
45
+ from .decorator import xarm_is_connected, xarm_is_ready, xarm_is_not_simulation_mode, xarm_wait_until_cmdnum_lt_max, xarm_wait_until_not_pause
46
+ from .code import APIState
47
+ from ..tools.threads import ThreadManage
48
+ from ..version import __version__
49
+
50
+ controller_error_keys = ControllerErrorCodeMap.keys()
51
+ controller_warn_keys = ControllerWarnCodeMap.keys()
52
+
53
+ print('SDK_VERSION: {}'.format(__version__))
54
+
55
+
56
+ class Base(BaseObject, Events):
57
+ def __init__(self, port=None, is_radian=False, do_not_open=False, **kwargs):
58
+ if kwargs.get('init', False):
59
+ super(Base, self).__init__()
60
+ self._port = port
61
+ self._debug = kwargs.get('debug', False)
62
+ self._baudrate = kwargs.get('baudrate', XCONF.SerialConf.SERIAL_BAUD)
63
+ self._timeout = kwargs.get('timeout', None)
64
+ self._filters = kwargs.get('filters', None)
65
+ self._enable_heartbeat = kwargs.get('enable_heartbeat', False)
66
+ self._enable_report = kwargs.get('enable_report', True)
67
+ self._report_type = kwargs.get('report_type', 'rich')
68
+ self._forbid_uds = kwargs.get('forbid_uds', False)
69
+
70
+ self._check_tcp_limit = kwargs.get('check_tcp_limit', False)
71
+ self._check_joint_limit = kwargs.get('check_joint_limit', True)
72
+ self._check_cmdnum_limit = kwargs.get('check_cmdnum_limit', True)
73
+ self._check_simulation_mode = kwargs.get('check_simulation_mode', True)
74
+ self._max_cmd_num = kwargs.get('max_cmdnum', 512)
75
+ if not isinstance(self._max_cmd_num, int):
76
+ self._max_cmd_num = 512
77
+ self._max_cmd_num = min(XCONF.MAX_CMD_NUM, self._max_cmd_num)
78
+ self._check_robot_sn = kwargs.get('check_robot_sn', False)
79
+ self._check_is_ready = kwargs.get('check_is_ready', True)
80
+ self._check_is_pause = kwargs.get('check_is_pause', True)
81
+ self._timed_comm = kwargs.get('timed_comm', True)
82
+ self._timed_comm_interval = kwargs.get('timed_comm_interval', 30)
83
+ self._timed_comm_t = None
84
+ self._timed_comm_t_alive = False
85
+
86
+ self._baud_checkset = kwargs.get('baud_checkset', True)
87
+ self._default_bio_baud = kwargs.get('default_bio_baud', 2000000)
88
+ self._default_gripper_baud = kwargs.get('default_gripper_baud', 2000000)
89
+ self._default_robotiq_baud = kwargs.get('default_robotiq_baud', 115200)
90
+ self._default_linear_track_baud = kwargs.get('default_linear_track_baud', 2000000)
91
+
92
+ self._max_callback_thread_count = kwargs.get('max_callback_thread_count', 0)
93
+ self._asyncio_loop = None
94
+ self._asyncio_loop_alive = False
95
+ self._asyncio_loop_thread = None
96
+ self._pool = None
97
+ self._thread_manage = ThreadManage()
98
+
99
+ self._rewrite_modbus_baudrate_method = kwargs.get('rewrite_modbus_baudrate_method', True)
100
+
101
+ self._min_tcp_speed, self._max_tcp_speed = 0.1, 1000 # mm/s
102
+ self._min_tcp_acc, self._max_tcp_acc = 1.0, 50000 # mm/s^2
103
+ self._tcp_jerk = 1000 # mm/s^3
104
+
105
+ # self._min_joint_speed, self._max_joint_speed = 0.01, 4.0 # rad/s
106
+ self._min_joint_speed, self._max_joint_speed = 0.0001, 4.0 # rad/s
107
+ self._min_joint_acc, self._max_joint_acc = 0.01, 20.0 # rad/s^2
108
+ self._joint_jerk = 20.0 # rad/s^3
109
+
110
+ self._rot_jerk = 2.3
111
+ self._max_rot_acc = 2.7
112
+
113
+ self._stream_type = 'serial'
114
+ self._stream = None
115
+ self.arm_cmd = None
116
+ self._stream_503 = None # 透传使用
117
+ self.arm_cmd_503 = None # 透传使用
118
+ self._stream_report = None
119
+ self._report_thread = None
120
+ self._only_report_err_warn_changed = True
121
+
122
+ self._last_position = [201.5, 0, 140.5, 3.1415926, 0, 0] # [x(mm), y(mm), z(mm), roll(rad), pitch(rad), yaw(rad)]
123
+ self._last_angles = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] # [servo_1(rad), servo_2(rad), servo_3(rad), servo_4(rad), servo_5(rad), servo_6(rad), servo_7(rad)]
124
+ self._last_tcp_speed = 100 # mm/s, rad/s
125
+ self._last_tcp_acc = 2000 # mm/s^2, rad/s^2
126
+ self._last_joint_speed = 0.3490658503988659 # 20 °/s
127
+ self._last_joint_acc = 8.726646259971648 # 500 °/s^2
128
+ self._mvtime = 0
129
+
130
+ self._version = None
131
+ self._robot_sn = None
132
+ self._control_box_sn = None
133
+ self._position = [201.5, 0, 140.5, 3.1415926, 0, 0]
134
+ self._pose_aa = [201.5, 0, 140.5, 3.1415926, 0, 0]
135
+ self._angles = [0] * 7
136
+ self._position_offset = [0] * 6
137
+ self._world_offset = [0] * 6
138
+ self._state = 4
139
+ self._mode = 0
140
+ self._joints_torque = [0, 0, 0, 0, 0, 0, 0] # 力矩
141
+ self._tcp_load = [0, [0, 0, 0]] # 负载[重量, 重心], [weight, [x, y, z]]
142
+ self._collision_sensitivity = 0 # 碰撞灵敏度
143
+ self._teach_sensitivity = 0 # 示教灵敏度
144
+ self._error_code = 0
145
+ self._warn_code = 0
146
+ self._servo_codes = [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]
147
+ self._cmd_num = 0
148
+ self._arm_type = XCONF.Robot.Type.XARM7_X4
149
+ self._arm_axis = XCONF.Robot.Axis.XARM7
150
+ axis = kwargs.get('axis', self._arm_axis)
151
+ if axis in [5, 6, 7]:
152
+ self._arm_axis = axis
153
+ arm_type = kwargs.get('type', self._arm_type)
154
+ if arm_type in [3, 5, 6, 7, 8, 11]:
155
+ self._arm_type = arm_type
156
+ self._arm_master_id = 0
157
+ self._arm_slave_id = 0
158
+ self._arm_motor_tid = 0
159
+ self._arm_motor_fid = 0
160
+ self._arm_motor_brake_states = [-1, -1, -1, -1, -1, -1, -1, -1] # [motor-1-brake-state, ..., motor-7-brake, reserved]
161
+ self._arm_motor_enable_states = [-1, -1, -1, -1, -1, -1, -1, -1] # [motor-1-enable-state, ..., motor-7-enable, reserved]
162
+ self._gravity_direction = [0, 0, -1]
163
+
164
+ self._is_ready = False
165
+ self._is_sync = False
166
+ self._is_first_report = True
167
+ self._first_report_over = False
168
+ self._default_is_radian = is_radian
169
+ self._only_check_type = kwargs.get('only_check_type', 0)
170
+
171
+ self._sleep_finish_time = time.monotonic()
172
+ self._is_old_protocol = False
173
+
174
+ self._major_version_number = 0 # 固件主版本号
175
+ self._minor_version_number = 0 # 固件次版本号
176
+ self._revision_version_number = 0 # 固件修正版本号
177
+
178
+ self._temperatures = [0, 0, 0, 0, 0, 0, 0]
179
+ self._voltages = [0, 0, 0, 0, 0, 0, 0]
180
+ self._currents = [0, 0, 0, 0, 0, 0, 0]
181
+
182
+ self._is_set_move = False
183
+ self._pause_cond = threading.Condition()
184
+ self._pause_lock = threading.Lock()
185
+ self._pause_cnts = 0
186
+
187
+ self._realtime_tcp_speed = 0
188
+ self._realtime_joint_speeds = [0, 0, 0, 0, 0, 0, 0]
189
+
190
+ self._count = -1
191
+ self._last_report_time = time.monotonic()
192
+ self._max_report_interval = 0
193
+
194
+ self._cgpio_reset_enable = 0
195
+ self._tgpio_reset_enable = 0
196
+ self._cgpio_states = [0, 0, 256, 65533, 0, 65280, 0, 0, 0.0, 0.0, [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0]]
197
+ self._iden_progress = 0
198
+
199
+ self._ignore_error = False
200
+ self._ignore_state = False
201
+ self.modbus_baud = -1
202
+
203
+ self.gripper_is_enabled = False
204
+ self.gripper_speed = 0
205
+ self.gripper_version_numbers = [-1, -1, -1]
206
+
207
+ self.bio_gripper_is_enabled = False
208
+ self.bio_gripper_speed = 0
209
+ self.bio_gripper_error_code = 0
210
+
211
+ self.robotiq_is_activated = False
212
+
213
+ self._cmd_timeout = XCONF.UxbusConf.SET_TIMEOUT / 1000
214
+
215
+ self._is_collision_detection = 1
216
+ self._collision_tool_type = 0
217
+ self._collision_tool_params = [0, 0, 0, 0, 0, 0]
218
+ self._is_simulation_robot = False
219
+
220
+ self._is_reduced_mode = 0
221
+ self._is_fence_mode = 0
222
+ self._is_report_current = 0 # 针对get_report_tau_or_i的结果
223
+ self._is_approx_motion = 0
224
+ self._is_cart_continuous = 0
225
+
226
+ self._reduced_mode_is_on = 0
227
+ self._reduced_tcp_boundary = [9999, -9999, 9999, -9999, 9999, -9999]
228
+
229
+ self._last_update_err_time = 0
230
+ self._last_update_state_time = 0
231
+ self._last_update_cmdnum_time = 0
232
+
233
+ self._arm_type_is_1300 = False
234
+ self._control_box_type_is_1300 = False
235
+
236
+ self.linear_track_baud = -1
237
+ self.linear_track_speed = 1
238
+ self.linear_track_is_enabled = False
239
+ self._ft_ext_force = [0, 0, 0, 0, 0, 0]
240
+ self._ft_raw_force = [0, 0, 0, 0, 0, 0]
241
+ self._only_check_result = 0
242
+ self._keep_heart = True
243
+
244
+ self._has_motion_cmd = False
245
+ self._need_sync = False
246
+
247
+ self._support_feedback = False
248
+ self._feedback_que = queue.Queue()
249
+ self._feedback_thread = None
250
+ self._fb_key_transid_map = {}
251
+ self._fb_transid_type_map = {}
252
+ self._fb_transid_result_map = {}
253
+
254
+ if not do_not_open:
255
+ self.connect()
256
+
257
+ def _init(self):
258
+ self._last_position = [201.5, 0, 140.5, 3.1415926, 0, 0] # [x(mm), y(mm), z(mm), roll(rad), pitch(rad), yaw(rad)]
259
+ self._last_angles = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] # [servo_1(rad), servo_2(rad), servo_3(rad), servo_4(rad), servo_5(rad), servo_6(rad), servo_7(rad)]
260
+ self._last_tcp_speed = 100 # mm/s, rad/s
261
+ self._last_tcp_acc = 2000 # mm/s^2, rad/s^2
262
+ self._last_joint_speed = 0.3490658503988659 # 20 °/s
263
+ self._last_joint_acc = 8.726646259971648 # 500 °/s^2
264
+ self._mvtime = 0
265
+ self._version = None
266
+ self._robot_sn = None
267
+ self._control_box_sn = None
268
+ self._position = [201.5, 0, 140.5, 3.1415926, 0, 0]
269
+ self._pose_aa = [201.5, 0, 140.5, 3.1415926, 0, 0]
270
+ self._angles = [0] * 7
271
+ self._position_offset = [0] * 6
272
+ self._world_offset = [0] * 6
273
+ self._state = 4
274
+ self._mode = 0
275
+ self._joints_torque = [0, 0, 0, 0, 0, 0, 0] # 力矩
276
+ self._tcp_load = [0, [0, 0, 0]] # 负载[重量, 重心], [weight, [x, y, z]]
277
+ self._collision_sensitivity = 0 # 碰撞灵敏度
278
+ self._teach_sensitivity = 0 # 示教灵敏度
279
+ self._error_code = 0
280
+ self._warn_code = 0
281
+ self._servo_codes = [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]
282
+ self._cmd_num = 0
283
+ self._arm_master_id = 0
284
+ self._arm_slave_id = 0
285
+ self._arm_motor_tid = 0
286
+ self._arm_motor_fid = 0
287
+ self._arm_motor_brake_states = [-1, -1, -1, -1, -1, -1, -1,
288
+ -1] # [motor-1-brake-state, ..., motor-7-brake, reserved]
289
+ self._arm_motor_enable_states = [-1, -1, -1, -1, -1, -1, -1,
290
+ -1] # [motor-1-enable-state, ..., motor-7-enable, reserved]
291
+ self._gravity_direction = [0, 0, -1]
292
+
293
+ self._is_ready = False
294
+ self._is_sync = False
295
+ self._is_first_report = True
296
+ self._first_report_over = False
297
+
298
+ self._sleep_finish_time = time.monotonic()
299
+ self._is_old_protocol = False
300
+
301
+ self._major_version_number = 0 # 固件主版本号
302
+ self._minor_version_number = 0 # 固件次版本号
303
+ self._revision_version_number = 0 # 固件修正版本号
304
+
305
+ self._temperatures = [0, 0, 0, 0, 0, 0, 0]
306
+ self._voltages = [0, 0, 0, 0, 0, 0, 0]
307
+ self._currents = [0, 0, 0, 0, 0, 0, 0]
308
+
309
+ self._is_set_move = False
310
+ self._pause_cond = threading.Condition()
311
+ self._pause_lock = threading.Lock()
312
+ self._pause_cnts = 0
313
+
314
+ self._realtime_tcp_speed = 0
315
+ self._realtime_joint_speeds = [0, 0, 0, 0, 0, 0, 0]
316
+
317
+ self._count = -1
318
+ self._last_report_time = time.monotonic()
319
+ self._max_report_interval = 0
320
+
321
+ self._cgpio_reset_enable = 0
322
+ self._tgpio_reset_enable = 0
323
+ self._cgpio_states = [0, 0, 256, 65533, 0, 65280, 0, 0, 0.0, 0.0, [0, 0, 0, 0, 0, 0, 0, 0],
324
+ [0, 0, 0, 0, 0, 0, 0, 0]]
325
+ self._iden_progress = 0
326
+
327
+ self._ignore_error = False
328
+ self._ignore_state = False
329
+ self.modbus_baud = -1
330
+
331
+ self.gripper_is_enabled = False
332
+ self.gripper_speed = 0
333
+ self.gripper_version_numbers = [-1, -1, -1]
334
+
335
+ self.bio_gripper_is_enabled = False
336
+ self.bio_gripper_speed = 0
337
+ self.bio_gripper_error_code = 0
338
+
339
+ self.robotiq_is_activated = False
340
+
341
+ self._cmd_timeout = XCONF.UxbusConf.SET_TIMEOUT / 1000
342
+
343
+ self._is_collision_detection = 1
344
+ self._collision_tool_type = 0
345
+ self._collision_tool_params = [0, 0, 0, 0, 0, 0]
346
+ self._is_simulation_robot = False
347
+
348
+ self._is_reduced_mode = 0
349
+ self._is_fence_mode = 0
350
+ self._is_report_current = 0 # 针对get_report_tau_or_i的结果
351
+ self._is_approx_motion = 0
352
+ self._is_cart_continuous = 0
353
+
354
+ self._reduced_mode_is_on = 0
355
+ self._reduced_tcp_boundary = [9999, -9999, 9999, -9999, 9999, -9999]
356
+
357
+ self._last_update_err_time = 0
358
+ self._last_update_state_time = 0
359
+ self._last_update_cmdnum_time = 0
360
+
361
+ self._arm_type_is_1300 = False
362
+ self._control_box_type_is_1300 = False
363
+
364
+ self.linear_track_baud = -1
365
+ self.linear_track_speed = 1
366
+ self.linear_track_is_enabled = False
367
+
368
+ self._ft_ext_force = [0, 0, 0, 0, 0, 0]
369
+ self._ft_raw_force = [0, 0, 0, 0, 0, 0]
370
+
371
+ self._has_motion_cmd = False
372
+ self._need_sync = False
373
+ self._only_check_result = 0
374
+ self._keep_heart = True
375
+
376
+ @staticmethod
377
+ def log_api_info(msg, *args, code=0, **kwargs):
378
+ if code == 0:
379
+ logger.info(msg, *args, **kwargs)
380
+ else:
381
+ logger.error(msg, *args, **kwargs)
382
+
383
+ def _check_version(self, is_first=False):
384
+ if is_first:
385
+ self._version = None
386
+ self._robot_sn = None
387
+ self._control_box_sn = None
388
+ try:
389
+ if not self._version:
390
+ self.get_version()
391
+ if is_first:
392
+ fail_cnt = 0
393
+ while not self._version and fail_cnt < 100:
394
+ code, _ = self.get_version()
395
+ fail_cnt += 1 if code != 0 else 0
396
+ if code != 0 or not self._version:
397
+ time.sleep(0.1)
398
+ if not self._version and fail_cnt >= 100:
399
+ logger.error('failed to get version')
400
+ return -2
401
+
402
+ if self._version and isinstance(self._version, str):
403
+ # pattern = re.compile(
404
+ # r'.*(\d+),(\d+),(\S+),(\S+),.*[vV]*(\d+)\.(\d+)\.(\d+)')
405
+ pattern = re.compile(
406
+ r'.*(\d+),(\d+),(.*),(.*),.*[vV]*(\d+)\.(\d+)\.(\d+).*')
407
+ m = re.match(pattern, self._version)
408
+ if m:
409
+ (xarm_axis, xarm_type, xarm_sn, ac_version,
410
+ major_version_number,
411
+ minor_version_number,
412
+ revision_version_number) = m.groups()
413
+ self._arm_axis = int(xarm_axis)
414
+ self._arm_type = int(xarm_type)
415
+ self._major_version_number = int(major_version_number)
416
+ self._minor_version_number = int(minor_version_number)
417
+ self._revision_version_number = int(revision_version_number)
418
+
419
+ self._robot_sn = xarm_sn
420
+ self._control_box_sn = ac_version.strip()
421
+
422
+ self._arm_type_is_1300 = int(xarm_sn[2:6]) >= 1300 if xarm_sn[2:6].isdigit() else False
423
+ self._control_box_type_is_1300 = int(ac_version[2:6]) >= 1300 if ac_version[2:6].isdigit() else False
424
+ else:
425
+ pattern = re.compile(r'.*[vV]*(\d+)\.(\d+)\.(\d+).*')
426
+ m = re.match(pattern, self._version)
427
+ if m:
428
+ (self._major_version_number,
429
+ self._minor_version_number,
430
+ self._revision_version_number) = map(int, m.groups())
431
+ else:
432
+ version_date = '-'.join(self._version.split('-')[-3:])
433
+ self._is_old_protocol = compare_time('2019-02-01', version_date)
434
+ if self._is_old_protocol:
435
+ self._major_version_number = 0
436
+ self._minor_version_number = 0
437
+ self._revision_version_number = 1
438
+ else:
439
+ self._major_version_number = 0
440
+ self._minor_version_number = 1
441
+ self._revision_version_number = 0
442
+ if is_first:
443
+ if self._check_robot_sn:
444
+ count = 2
445
+ self.get_robot_sn()
446
+ while not self._robot_sn and count and self.warn_code == 0:
447
+ self.get_robot_sn()
448
+ self.get_err_warn_code()
449
+ if not self._robot_sn and self.warn_code == 0 and count:
450
+ time.sleep(0.1)
451
+ count -= 1
452
+ if self.warn_code != 0:
453
+ self.clean_warn()
454
+ print('ROBOT_IP: {}, VERSION: v{}, PROTOCOL: {}, DETAIL: {}, TYPE1300: [{:d}, {:d}]'.format(
455
+ self._port,
456
+ '{}.{}.{}'.format(self._major_version_number, self._minor_version_number, self._revision_version_number),
457
+ 'V0' if self._is_old_protocol else 'V1', self._version, self._control_box_type_is_1300, self._arm_type_is_1300
458
+ ))
459
+ return 0
460
+ except Exception as e:
461
+ print('compare_time: {}, {}'.format(self._version, e))
462
+ return -1
463
+
464
+ @property
465
+ def only_check_result(self):
466
+ return self._only_check_result
467
+
468
+ @property
469
+ def realtime_tcp_speed(self):
470
+ return self._realtime_tcp_speed
471
+
472
+ @property
473
+ def realtime_joint_speeds(self):
474
+ return [speed if self._default_is_radian else math.degrees(speed) for speed in self._realtime_joint_speeds]
475
+
476
+ @property
477
+ def version_number(self):
478
+ return self._major_version_number, self._minor_version_number, self._revision_version_number
479
+
480
+ @property
481
+ def connected(self):
482
+ return self._stream is not None and self._stream.connected
483
+
484
+ @property
485
+ def connected_503(self):
486
+ return self._stream_503 is not None and self._stream_503.connected
487
+
488
+ @property
489
+ def reported(self):
490
+ return self._stream_report is not None and self._stream_report.connected
491
+
492
+ @property
493
+ def ready(self):
494
+ return self._is_ready
495
+
496
+ @property
497
+ def default_is_radian(self):
498
+ return self._default_is_radian
499
+
500
+ @property
501
+ def is_simulation_robot(self):
502
+ return self._is_simulation_robot
503
+
504
+ def check_is_simulation_robot(self):
505
+ return self._check_simulation_mode and self.is_simulation_robot
506
+ # return self._check_simulation_mode and self.mode != 4
507
+
508
+ @property
509
+ def is_lite6(self):
510
+ return self.axis == 6 and self.device_type == 9
511
+
512
+ @property
513
+ def is_850(self):
514
+ return self.axis == 6 and self.device_type == 12
515
+
516
+ @property
517
+ def version(self):
518
+ if not self._version:
519
+ self.get_version()
520
+ return self._version
521
+ # return 'v' + '.'.join(map(str, self.version_number))
522
+
523
+ @property
524
+ def sn(self):
525
+ return self._robot_sn
526
+
527
+ @property
528
+ def control_box_sn(self):
529
+ return self._control_box_sn
530
+
531
+ @property
532
+ def position(self):
533
+ if not self._enable_report:
534
+ self.get_position()
535
+ return [math.degrees(self._position[i]) if 2 < i < 6 and not self._default_is_radian
536
+ else self._position[i] for i in range(len(self._position))]
537
+
538
+ @property
539
+ def position_aa(self):
540
+ if not self._enable_report:
541
+ self.get_position_aa()
542
+ return [math.degrees(self._pose_aa[i]) if 2 < i < 6 and not self._default_is_radian
543
+ else self._pose_aa[i] for i in range(len(self._pose_aa))]
544
+
545
+ @property
546
+ def tcp_jerk(self):
547
+ return self._tcp_jerk
548
+
549
+ @property
550
+ def tcp_speed_limit(self):
551
+ return [self._min_tcp_speed, self._max_tcp_speed]
552
+
553
+ @property
554
+ def tcp_acc_limit(self):
555
+ return [self._min_tcp_acc, self._max_tcp_acc]
556
+
557
+ @property
558
+ def last_used_position(self):
559
+ return [math.degrees(self._last_position[i]) if 2 < i < 6 and not self._default_is_radian
560
+ else self._last_position[i] for i in range(len(self._last_position))]
561
+
562
+ @property
563
+ def last_used_tcp_speed(self):
564
+ return self._last_tcp_speed
565
+
566
+ @property
567
+ def last_used_tcp_acc(self):
568
+ return self._last_tcp_acc
569
+
570
+ @property
571
+ def angles(self):
572
+ if not self._enable_report:
573
+ self.get_servo_angle()
574
+ return [angle if self._default_is_radian else math.degrees(angle) for angle in self._angles]
575
+
576
+ @property
577
+ def joint_jerk(self):
578
+ return self._joint_jerk if self._default_is_radian else math.degrees(self._joint_jerk)
579
+
580
+ @property
581
+ def joint_speed_limit(self):
582
+ limit = [self._min_joint_speed, self._max_joint_speed]
583
+ if not self._default_is_radian:
584
+ limit = [math.degrees(i) for i in limit]
585
+ return limit
586
+
587
+ @property
588
+ def joint_acc_limit(self):
589
+ limit = [self._min_joint_acc, self._max_joint_acc]
590
+ if not self._default_is_radian:
591
+ limit = [math.degrees(i) for i in limit]
592
+ return limit
593
+
594
+ @property
595
+ def last_used_angles(self):
596
+ return [angle if self._default_is_radian else math.degrees(angle) for angle in self._last_angles]
597
+
598
+ @property
599
+ def last_used_joint_speed(self):
600
+ return self._last_joint_speed if self._default_is_radian else math.degrees(self._last_joint_speed)
601
+
602
+ @property
603
+ def last_used_joint_acc(self):
604
+ return self._last_joint_acc if self._default_is_radian else math.degrees(self._last_joint_acc)
605
+
606
+ @property
607
+ def position_offset(self):
608
+ return [math.degrees(self._position_offset[i]) if 2 < i < 6 and not self._default_is_radian
609
+ else self._position_offset[i] for i in range(len(self._position_offset))]
610
+
611
+ @property
612
+ def world_offset(self):
613
+ return [math.degrees(self._world_offset[i]) if 2 < i < 6 and not self._default_is_radian
614
+ else self._world_offset[i] for i in range(len(self._world_offset))]
615
+
616
+ @property
617
+ def state(self):
618
+ if not self._enable_report:
619
+ self.get_state()
620
+ return self._state
621
+
622
+ @property
623
+ def mode(self):
624
+ return self._mode
625
+
626
+ @property
627
+ def joints_torque(self):
628
+ return self._joints_torque
629
+
630
+ @property
631
+ def tcp_load(self):
632
+ return self._tcp_load
633
+
634
+ @property
635
+ def collision_sensitivity(self):
636
+ return self._collision_sensitivity
637
+
638
+ @property
639
+ def teach_sensitivity(self):
640
+ return self._teach_sensitivity
641
+
642
+ @property
643
+ def motor_brake_states(self):
644
+ return self._arm_motor_brake_states
645
+
646
+ @property
647
+ def motor_enable_states(self):
648
+ return self._arm_motor_enable_states
649
+
650
+ @property
651
+ def temperatures(self):
652
+ return self._temperatures
653
+
654
+ @property
655
+ def error_code(self):
656
+ if not self._enable_report:
657
+ self.get_err_warn_code()
658
+ return self._error_code
659
+
660
+ @property
661
+ def warn_code(self):
662
+ if not self._enable_report:
663
+ self.get_err_warn_code()
664
+ return self._warn_code
665
+
666
+ @property
667
+ def has_error(self):
668
+ return self.error_code != 0
669
+
670
+ @property
671
+ def has_warn(self):
672
+ return self.warn_code != 0
673
+
674
+ @property
675
+ def has_err_warn(self):
676
+ return self.has_error or self._warn_code != 0 or (self.arm_cmd and self.arm_cmd.has_err_warn)
677
+
678
+ @property
679
+ def cmd_num(self):
680
+ if not self._enable_report:
681
+ self.get_cmdnum()
682
+ return self._cmd_num
683
+
684
+ @property
685
+ def device_type(self):
686
+ return self._arm_type
687
+
688
+ @property
689
+ def axis(self):
690
+ return self._arm_axis
691
+
692
+ @property
693
+ def master_id(self):
694
+ return self._arm_master_id
695
+
696
+ @property
697
+ def slave_id(self):
698
+ return self._arm_slave_id
699
+
700
+ @property
701
+ def motor_tid(self):
702
+ return self._arm_motor_tid
703
+
704
+ @property
705
+ def motor_fid(self):
706
+ return self._arm_motor_fid
707
+
708
+ @property
709
+ def gravity_direction(self):
710
+ return self._gravity_direction
711
+
712
+ @property
713
+ def gpio_reset_config(self):
714
+ return [self._cgpio_reset_enable, self._tgpio_reset_enable]
715
+
716
+ @property
717
+ def count(self):
718
+ return self._count
719
+
720
+ @property
721
+ def servo_codes(self):
722
+ return self._servo_codes
723
+
724
+ @property
725
+ def is_stop(self):
726
+ return self.state >= 4
727
+
728
+ @property
729
+ def voltages(self):
730
+ return self._voltages
731
+
732
+ @property
733
+ def currents(self):
734
+ return self._currents
735
+
736
+ @property
737
+ def cgpio_states(self):
738
+ return self._cgpio_states
739
+
740
+ @property
741
+ def self_collision_params(self):
742
+ return [self._is_collision_detection, self._collision_tool_type, self._collision_tool_params]
743
+
744
+ @property
745
+ def is_reduced_mode(self):
746
+ return self._is_reduced_mode != 0
747
+
748
+ @property
749
+ def is_fence_mode(self):
750
+ return self._is_fence_mode != 0
751
+
752
+ @property
753
+ def is_report_current(self):
754
+ return self._is_report_current != 0 # 针对get_report_tau_or_i的结果
755
+
756
+ @property
757
+ def is_approx_motion(self):
758
+ return self._is_approx_motion != 0
759
+
760
+ @property
761
+ def is_cart_continuous(self):
762
+ return self._is_cart_continuous != 0
763
+
764
+ @property
765
+ def reduced_mode_is_on(self):
766
+ return self._reduced_mode_is_on != 0
767
+
768
+ @property
769
+ def reduced_tcp_boundary(self):
770
+ return self._reduced_tcp_boundary
771
+
772
+ @property
773
+ def ft_ext_force(self):
774
+ return self._ft_ext_force
775
+
776
+ @property
777
+ def ft_raw_force(self):
778
+ return self._ft_raw_force
779
+
780
+ @property
781
+ def support_feedback(self):
782
+ return self._support_feedback
783
+
784
+ def version_is_ge(self, major, minor=0, revision=0):
785
+ if self._version is None:
786
+ self._check_version()
787
+ return self._major_version_number > major or (
788
+ self._major_version_number == major and self._minor_version_number > minor) or (
789
+ self._major_version_number == major and self._minor_version_number == minor and
790
+ self._revision_version_number >= revision)
791
+
792
+ def wait_until_not_pause(self):
793
+ if self._check_is_pause and self.connected and self.state == 3 and self._enable_report:
794
+ with self._pause_cond:
795
+ with self._pause_lock:
796
+ self._pause_cnts += 1
797
+ self._pause_cond.wait()
798
+ with self._pause_lock:
799
+ self._pause_cnts -= 1
800
+
801
+ def wait_until_cmdnum_lt_max(self):
802
+ if not self._check_cmdnum_limit:
803
+ return
804
+ while self.connected and self.cmd_num >= self._max_cmd_num:
805
+ if time.monotonic() - self._last_report_time > 0.4:
806
+ self.get_cmdnum()
807
+ time.sleep(0.05)
808
+
809
+ @property
810
+ def check_xarm_is_ready(self):
811
+ if self._check_is_ready and not self.version_is_ge(1, 5, 20):
812
+ return self.ready
813
+ else:
814
+ # no check if version >= 1.5.20
815
+ return True
816
+
817
+ def _timed_comm_thread(self):
818
+ self._timed_comm_t_alive = True
819
+ cnt = 0
820
+ last_send_time = 0
821
+ while self.connected and self._timed_comm_t_alive:
822
+ curr_time = time.monotonic()
823
+ if not self._keep_heart:
824
+ time.sleep(1)
825
+ continue
826
+ if self.arm_cmd and curr_time - last_send_time > 10 and curr_time - self.arm_cmd.last_comm_time > self._timed_comm_interval:
827
+ try:
828
+ if cnt == 0:
829
+ code, _ = self.get_cmdnum()
830
+ elif cnt == 1:
831
+ code, _ = self.get_state()
832
+ else:
833
+ code, _ = self.get_err_warn_code()
834
+ cnt = (cnt + 1) % 3
835
+ if code >= 0:
836
+ last_send_time = curr_time
837
+ except:
838
+ pass
839
+ time.sleep(0.5)
840
+
841
+ def _clean_thread(self):
842
+ self._thread_manage.join(1)
843
+ if self._pool:
844
+ try:
845
+ self._pool.close()
846
+ self._pool.join()
847
+ except:
848
+ pass
849
+
850
+ def connect_503(self):
851
+ self._stream_503 = SocketPort(self._port, XCONF.SocketConf.TCP_CONTROL_PORT + 1,
852
+ heartbeat=self._enable_heartbeat, buffer_size=XCONF.SocketConf.TCP_CONTROL_BUF_SIZE, forbid_uds=self._forbid_uds)
853
+ if not self.connected_503:
854
+ return -1
855
+ self.arm_cmd_503 = UxbusCmdTcp(self._stream_503, set_feedback_key_tranid=self._set_feedback_key_tranid)
856
+ self.arm_cmd_503.set_debug(self._debug)
857
+ return 0
858
+
859
+ def connect(self, port=None, baudrate=None, timeout=None, axis=None, arm_type=None):
860
+ if self.connected:
861
+ return
862
+ if axis in [5, 6, 7]:
863
+ self._arm_axis = axis
864
+ if arm_type in [3, 5, 6, 7, 8, 9, 11]:
865
+ self._arm_type = arm_type
866
+ self._is_ready = True
867
+ self._port = port if port is not None else self._port
868
+ self._baudrate = baudrate if baudrate is not None else self._baudrate
869
+ self._timeout = timeout if timeout is not None else self._timeout
870
+ if not self._port:
871
+ raise Exception('can not connect to port/ip {}'.format(self._port))
872
+ if self._timed_comm_t is not None:
873
+ try:
874
+ self._timed_comm_t_alive = False
875
+ self._timed_comm_t.join()
876
+ self._timed_comm_t = None
877
+ except:
878
+ pass
879
+ self._is_first_report = True
880
+ self._first_report_over = False
881
+ self._init()
882
+ if isinstance(self._port, (str, bytes)):
883
+ if self._port == 'localhost' or re.match(
884
+ r"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$",
885
+ self._port):
886
+ self._stream = SocketPort(self._port, XCONF.SocketConf.TCP_CONTROL_PORT,
887
+ heartbeat=self._enable_heartbeat,
888
+ buffer_size=XCONF.SocketConf.TCP_CONTROL_BUF_SIZE, forbid_uds=self._forbid_uds, fb_que=self._feedback_que)
889
+ if not self.connected:
890
+ raise Exception('connect socket failed')
891
+
892
+ self._report_error_warn_changed_callback()
893
+ self._feedback_thread = threading.Thread(target=self._feedback_thread_handle, daemon=True)
894
+ self._feedback_thread.start()
895
+
896
+ self.arm_cmd = UxbusCmdTcp(self._stream, set_feedback_key_tranid=self._set_feedback_key_tranid)
897
+ self.arm_cmd.set_protocol_identifier(2)
898
+ self._stream_type = 'socket'
899
+
900
+ try:
901
+ if self._timed_comm:
902
+ self._timed_comm_t = threading.Thread(target=self._timed_comm_thread, daemon=True)
903
+ self._timed_comm_t.start()
904
+ except:
905
+ pass
906
+
907
+ self._stream_report = None
908
+
909
+ try:
910
+ self._connect_report()
911
+ except:
912
+ self._stream_report = None
913
+
914
+ if self._check_version(is_first=True) < 0:
915
+ self.disconnect()
916
+ raise Exception('failed to check version, close')
917
+ self._support_feedback = self.version_is_ge(2, 0, 102)
918
+ self.arm_cmd.set_debug(self._debug)
919
+
920
+ if self._max_callback_thread_count < 0 and asyncio is not None:
921
+ self._asyncio_loop = asyncio.new_event_loop()
922
+ self._asyncio_loop_thread = threading.Thread(target=self._run_asyncio_loop, daemon=True)
923
+ self._thread_manage.append(self._asyncio_loop_thread)
924
+ self._asyncio_loop_thread.start()
925
+ elif self._max_callback_thread_count > 0 and ThreadPool is not None:
926
+ self._pool = ThreadPool(self._max_callback_thread_count)
927
+
928
+ if self._stream.connected and self._enable_report:
929
+ self._report_thread = threading.Thread(target=self._report_thread_handle, daemon=True)
930
+ self._report_thread.start()
931
+ self._thread_manage.append(self._report_thread)
932
+
933
+ self._report_connect_changed_callback()
934
+ else:
935
+ if SerialPort is None:
936
+ raise Exception('serial module is not found, if you want to connect to xArm with serial, please `pip install pyserial>=3.4`')
937
+ self._stream = SerialPort(self._port)
938
+ if not self.connected:
939
+ raise Exception('connect serial failed')
940
+ self._report_error_warn_changed_callback()
941
+
942
+ self.arm_cmd = UxbusCmdSer(self._stream)
943
+ self._stream_type = 'serial'
944
+
945
+ if self._max_callback_thread_count < 0 and asyncio is not None:
946
+ self._asyncio_loop = asyncio.new_event_loop()
947
+ self._asyncio_loop_thread = threading.Thread(target=self._run_asyncio_loop, daemon=True)
948
+ self._thread_manage.append(self._asyncio_loop_thread)
949
+ self._asyncio_loop_thread.start()
950
+ elif self._max_callback_thread_count > 0 and ThreadPool is not None:
951
+ self._pool = ThreadPool(self._max_callback_thread_count)
952
+
953
+ if self._enable_report:
954
+ self._report_thread = threading.Thread(target=self._auto_get_report_thread, daemon=True)
955
+ self._report_thread.start()
956
+ self._report_connect_changed_callback(True, True)
957
+ self._thread_manage.append(self._report_thread)
958
+ else:
959
+ self._report_connect_changed_callback(True, False)
960
+ self._check_version(is_first=True)
961
+ self.arm_cmd.set_debug(self._debug)
962
+ self.set_timeout(self._cmd_timeout)
963
+ if self._rewrite_modbus_baudrate_method:
964
+ setattr(self.arm_cmd, 'set_modbus_baudrate_old', self.arm_cmd.set_modbus_baudrate)
965
+ setattr(self.arm_cmd, 'set_modbus_baudrate', self._core_set_modbus_baudrate)
966
+
967
+ if asyncio:
968
+ def _run_asyncio_loop(self):
969
+ # @asyncio.coroutine
970
+ # def _asyncio_loop():
971
+ # logger.debug('asyncio thread start ...')
972
+ # while self.connected:
973
+ # yield from asyncio.sleep(0.001)
974
+ # logger.debug('asyncio thread exit ...')
975
+
976
+ try:
977
+ asyncio.set_event_loop(self._asyncio_loop)
978
+ self._asyncio_loop_alive = True
979
+ # self._asyncio_loop.run_until_complete(_asyncio_loop())
980
+ self._asyncio_loop.run_until_complete(self._asyncio_loop_func())
981
+ except Exception as e:
982
+ pass
983
+
984
+ self._asyncio_loop_alive = False
985
+
986
+ # @staticmethod
987
+ # @asyncio.coroutine
988
+ # def _async_run_callback(callback, msg):
989
+ # yield from callback(msg)
990
+
991
+ def _run_callback(self, callback, msg, name='', enable_callback_thread=True):
992
+ try:
993
+ if self._asyncio_loop_alive and enable_callback_thread:
994
+ coroutine = self._async_run_callback(callback, msg)
995
+ asyncio.run_coroutine_threadsafe(coroutine, self._asyncio_loop)
996
+ elif self._pool is not None and enable_callback_thread:
997
+ self._pool.apply_async(callback, args=(msg,))
998
+ else:
999
+ callback(msg)
1000
+ except Exception as e:
1001
+ logger.error('run {} callback exception: {}'.format(name, e))
1002
+
1003
+ def _core_set_modbus_baudrate(self, baudrate, use_old=False):
1004
+ """
1005
+ 此函数是用于覆盖core.set_modbus_baudrate方法,主要用于兼容旧代码
1006
+ 新代码建议直接使用set_tgpio_modbus_baudrate此接口
1007
+ :param baudrate:
1008
+ :param use_old:
1009
+ 为True时调用原来的core.set_modbus_baudrate方法
1010
+ 为False时使用新的set_tgpio_modbus_baudrate
1011
+ :return [code, ...]
1012
+ """
1013
+ if not use_old:
1014
+ ret = self.set_tgpio_modbus_baudrate(baudrate)
1015
+ return [ret, self.modbus_baud]
1016
+ else:
1017
+ return self.arm_cmd.set_modbus_baudrate_old(baudrate)
1018
+
1019
+ def disconnect(self):
1020
+ try:
1021
+ self._stream.close()
1022
+ except:
1023
+ pass
1024
+ if self._stream_503:
1025
+ try:
1026
+ self._stream_503.close()
1027
+ except:
1028
+ pass
1029
+ if self._stream_report:
1030
+ try:
1031
+ self._stream_report.close()
1032
+ except:
1033
+ pass
1034
+ self._is_ready = False
1035
+ try:
1036
+ self._stream.join()
1037
+ except:
1038
+ pass
1039
+ if self._stream_report:
1040
+ try:
1041
+ self._stream_report.join()
1042
+ except:
1043
+ pass
1044
+ self._report_connect_changed_callback(False, False)
1045
+ with self._pause_cond:
1046
+ self._pause_cond.notifyAll()
1047
+ self._clean_thread()
1048
+
1049
+ def set_timeout(self, timeout):
1050
+ self._cmd_timeout = timeout
1051
+ if self.arm_cmd is not None:
1052
+ self._cmd_timeout = self.arm_cmd.set_timeout(self._cmd_timeout)
1053
+ return self._cmd_timeout
1054
+
1055
+ def set_baud_checkset_enable(self, enable):
1056
+ self._baud_checkset = enable
1057
+ return 0
1058
+
1059
+ def set_checkset_default_baud(self, type_, baud):
1060
+ if type_ == 1:
1061
+ self._default_gripper_baud = baud
1062
+ elif type_ == 2:
1063
+ self._default_bio_baud = baud
1064
+ elif type_ == 3:
1065
+ self._default_robotiq_baud = baud
1066
+ elif type_ == 4:
1067
+ self._default_linear_track_baud = baud
1068
+ else:
1069
+ return APIState.API_EXCEPTION
1070
+ return 0
1071
+
1072
+ def get_checkset_default_baud(self, type_):
1073
+ if type_ == 1:
1074
+ return 0, self._default_gripper_baud
1075
+ elif type_ == 2:
1076
+ return 0, self._default_bio_baud
1077
+ elif type_ == 3:
1078
+ return 0, self._default_robotiq_baud
1079
+ elif type_ == 4:
1080
+ return 0, self._default_linear_track_baud
1081
+ return APIState.API_EXCEPTION, 0
1082
+
1083
+ def _connect_report(self):
1084
+ if self._enable_report:
1085
+ if self._stream_report:
1086
+ try:
1087
+ self._stream_report.close()
1088
+ except:
1089
+ pass
1090
+ time.sleep(2)
1091
+ if self._report_type == 'real':
1092
+ self._stream_report = SocketPort(
1093
+ self._port, XCONF.SocketConf.TCP_REPORT_REAL_PORT,
1094
+ buffer_size=1024 if not self._is_old_protocol else 87,
1095
+ forbid_uds=self._forbid_uds)
1096
+ elif self._report_type == 'normal':
1097
+ self._stream_report = SocketPort(
1098
+ self._port, XCONF.SocketConf.TCP_REPORT_NORM_PORT,
1099
+ buffer_size=XCONF.SocketConf.TCP_REPORT_NORMAL_BUF_SIZE if not self._is_old_protocol else 87,
1100
+ forbid_uds=self._forbid_uds)
1101
+ else:
1102
+ self._stream_report = SocketPort(
1103
+ self._port, XCONF.SocketConf.TCP_REPORT_RICH_PORT,
1104
+ buffer_size=1024 if not self._is_old_protocol else 187,
1105
+ forbid_uds=self._forbid_uds)
1106
+
1107
+ def __report_callback(self, report_id, item, name=''):
1108
+ if report_id in self._report_callbacks.keys():
1109
+ for callback in self._report_callbacks[report_id]:
1110
+ self._run_callback(callback, item, name=name)
1111
+
1112
+ def _report_connect_changed_callback(self, main_connected=None, report_connected=None):
1113
+ if self.REPORT_CONNECT_CHANGED_ID in self._report_callbacks.keys():
1114
+ for callback in self._report_callbacks[self.REPORT_CONNECT_CHANGED_ID]:
1115
+ self._run_callback(callback, {
1116
+ 'connected': self._stream and self._stream.connected if main_connected is None else main_connected,
1117
+ 'reported': self._stream_report and self._stream_report.connected if report_connected is None else report_connected,
1118
+ }, name='connect_changed')
1119
+
1120
+ def _report_state_changed_callback(self):
1121
+ if self._ignore_state:
1122
+ return
1123
+ self.__report_callback(self.REPORT_STATE_CHANGED_ID, {'state': self._state}, name='state_changed')
1124
+
1125
+ def _report_mode_changed_callback(self):
1126
+ self.__report_callback(self.REPORT_MODE_CHANGED_ID, {'mode': self._mode}, name='mode_changed')
1127
+
1128
+ def _report_mtable_mtbrake_changed_callback(self):
1129
+ self.__report_callback(self.REPORT_MTABLE_MTBRAKE_CHANGED_ID, {
1130
+ 'mtable': [bool(i) for i in self._arm_motor_enable_states],
1131
+ 'mtbrake': [bool(i) for i in self._arm_motor_brake_states]
1132
+ }, name='(mtable/mtbrake)_changed')
1133
+
1134
+ def _report_error_warn_changed_callback(self):
1135
+ if self._ignore_error:
1136
+ return
1137
+ self.__report_callback(self.REPORT_ERROR_WARN_CHANGED_ID, {
1138
+ 'warn_code': self._warn_code,
1139
+ 'error_code': self._error_code,
1140
+ }, name='(error/warn)_changed')
1141
+
1142
+ def _report_cmdnum_changed_callback(self):
1143
+ self.__report_callback(self.REPORT_CMDNUM_CHANGED_ID, {
1144
+ 'cmdnum': self._cmd_num
1145
+ }, name='cmdnum_changed')
1146
+
1147
+ def _report_temperature_changed_callback(self):
1148
+ self.__report_callback(self.REPORT_TEMPERATURE_CHANGED_ID, {
1149
+ 'temperatures': self.temperatures
1150
+ }, name='temperature_changed')
1151
+
1152
+ def _report_count_changed_callback(self):
1153
+ self.__report_callback(self.REPORT_COUNT_CHANGED_ID, {'count': self._count}, name='count_changed')
1154
+
1155
+ def _report_iden_progress_changed_callback(self):
1156
+ self.__report_callback(self.REPORT_IDEN_PROGRESS_CHANGED_ID, {'progress': self._iden_progress}, name='iden_progress_changed')
1157
+
1158
+ def _report_location_callback(self):
1159
+ if self.REPORT_LOCATION_ID in self._report_callbacks.keys():
1160
+ for item in self._report_callbacks[self.REPORT_LOCATION_ID]:
1161
+ callback = item['callback']
1162
+ ret = {}
1163
+ if item['cartesian']:
1164
+ ret['cartesian'] = self.position.copy()
1165
+ if item['joints']:
1166
+ ret['joints'] = self.angles.copy()
1167
+ self._run_callback(callback, ret, name='location')
1168
+
1169
+ def _report_callback(self):
1170
+ if self.REPORT_ID in self._report_callbacks.keys():
1171
+ for item in self._report_callbacks[self.REPORT_ID]:
1172
+ callback = item['callback']
1173
+ ret = {}
1174
+ if item['cartesian']:
1175
+ ret['cartesian'] = self.position.copy()
1176
+ if item['joints']:
1177
+ ret['joints'] = self.angles.copy()
1178
+ if item['error_code']:
1179
+ ret['error_code'] = self._error_code
1180
+ if item['warn_code']:
1181
+ ret['warn_code'] = self._warn_code
1182
+ if item['state']:
1183
+ ret['state'] = self._state
1184
+ if item['mtable']:
1185
+ mtable = [bool(i) for i in self._arm_motor_enable_states]
1186
+ ret['mtable'] = mtable.copy()
1187
+ if item['mtbrake']:
1188
+ mtbrake = [bool(i) for i in self._arm_motor_brake_states]
1189
+ ret['mtbrake'] = mtbrake.copy()
1190
+ if item['cmdnum']:
1191
+ ret['cmdnum'] = self._cmd_num
1192
+ self._run_callback(callback, ret, name='report')
1193
+
1194
+ def _report_thread_handle(self):
1195
+ main_socket_connected = self.connected
1196
+ report_socket_connected = self.reported
1197
+ protocol_identifier = 2
1198
+ last_send_time = 0
1199
+ max_reconnect_cnts = 10
1200
+ connect_failed_cnt = 0
1201
+
1202
+ while self.connected:
1203
+ try:
1204
+ curr_time = time.monotonic()
1205
+ if self._keep_heart:
1206
+ if protocol_identifier != 3 and self.version_is_ge(1, 8, 6) and self.arm_cmd.set_protocol_identifier(3) == 0:
1207
+ protocol_identifier = 3
1208
+ if protocol_identifier == 3 and curr_time - last_send_time > 10 and curr_time - self.arm_cmd.last_comm_time > 30:
1209
+ code, _ = self.get_state()
1210
+ # print('send heartbeat, code={}'.format(code))
1211
+ if code >= 0:
1212
+ last_send_time = curr_time
1213
+ if curr_time - self.arm_cmd.last_comm_time > 90:
1214
+ logger.error('client timeout over 90s, disconnect')
1215
+ break
1216
+ if not self.reported:
1217
+ # self.get_err_warn_code()
1218
+ if report_socket_connected:
1219
+ report_socket_connected = False
1220
+ self._report_connect_changed_callback(main_socket_connected, report_socket_connected)
1221
+ self._connect_report()
1222
+ if not self.reported:
1223
+ connect_failed_cnt += 1
1224
+ if self.connected and (connect_failed_cnt <= max_reconnect_cnts or protocol_identifier == 3):
1225
+ time.sleep(2)
1226
+ elif not self.connected or protocol_identifier == 2:
1227
+ logger.error('report thread is break, connected={}, failed_cnts={}'.format(self.connected, connect_failed_cnt))
1228
+ break
1229
+ continue
1230
+ else:
1231
+ connect_failed_cnt = 0
1232
+ connect_failed_cnt = 0
1233
+ if not report_socket_connected:
1234
+ report_socket_connected = True
1235
+ self._report_connect_changed_callback(main_socket_connected, report_socket_connected)
1236
+ recv_data = self._stream_report.read(1)
1237
+ if recv_data != -1:
1238
+ size = convert.bytes_to_u32(recv_data)
1239
+ if self._is_old_protocol and size > 256:
1240
+ self._is_old_protocol = False
1241
+ self._handle_report_data(recv_data)
1242
+ # else:
1243
+ # if self.connected:
1244
+ # code, err_warn = self.get_err_warn_code()
1245
+ # if code == -1 or code == 3:
1246
+ # break
1247
+ # if not self.connected:
1248
+ # break
1249
+ except Exception as e:
1250
+ logger.error(e)
1251
+ # if self.connected:
1252
+ # code, _ = self.get_err_warn_code()
1253
+ # if code == -1 or code == 3:
1254
+ # break
1255
+ if not self.connected:
1256
+ break
1257
+ if not self._stream_report or not self._stream_report.connected:
1258
+ self._connect_report()
1259
+ time.sleep(0.001)
1260
+ if self._pause_cnts > 0:
1261
+ with self._pause_cond:
1262
+ self._pause_cond.notifyAll()
1263
+ self.disconnect()
1264
+
1265
+ def _handle_report_data(self, data):
1266
+ def __handle_report_normal_old(rx_data):
1267
+ report_time = time.monotonic()
1268
+ interval = report_time - self._last_report_time
1269
+ self._max_report_interval = max(self._max_report_interval, interval)
1270
+ self._last_report_time = report_time
1271
+ # print('length:', convert.bytes_to_u32(rx_data[0:4]))
1272
+ state, mtbrake, mtable, error_code, warn_code = rx_data[4:9]
1273
+ angles = convert.bytes_to_fp32s(rx_data[9:7 * 4 + 9], 7)
1274
+ pose = convert.bytes_to_fp32s(rx_data[37:6 * 4 + 37], 6)
1275
+ cmd_num = convert.bytes_to_u16(rx_data[61:63])
1276
+ pose_offset = convert.bytes_to_fp32s(rx_data[63:6 * 4 + 63], 6)
1277
+
1278
+ if error_code != self._error_code or warn_code != self._warn_code:
1279
+ if error_code != self._error_code:
1280
+ self._error_code = error_code
1281
+ if self._error_code != 0:
1282
+ pretty_print('Error, code: {}'.format(self._error_code), color='red')
1283
+ else:
1284
+ pretty_print('Error had clean', color='blue')
1285
+ if warn_code != self._warn_code:
1286
+ self._warn_code = warn_code
1287
+ if self._warn_code != 0:
1288
+ pretty_print('Warn, code: {}'.format(self._warn_code), color='yellow')
1289
+ else:
1290
+ pretty_print('Warnning had clean', color='blue')
1291
+ self._report_error_warn_changed_callback()
1292
+ logger.info('OnReport -> err={}, warn={}, state={}, cmdnum={}, mtbrake={}, mtable={}'.format(
1293
+ error_code, warn_code, state, cmd_num, mtbrake, mtable
1294
+ ))
1295
+ elif not self._only_report_err_warn_changed:
1296
+ self._report_error_warn_changed_callback()
1297
+
1298
+ if cmd_num != self._cmd_num:
1299
+ self._cmd_num = cmd_num
1300
+ self._report_cmdnum_changed_callback()
1301
+
1302
+ if state != self._state:
1303
+ self._state = state
1304
+ self._report_state_changed_callback()
1305
+
1306
+ mtbrake = [mtbrake & 0x01, mtbrake >> 1 & 0x01, mtbrake >> 2 & 0x01, mtbrake >> 3 & 0x01,
1307
+ mtbrake >> 4 & 0x01, mtbrake >> 5 & 0x01, mtbrake >> 6 & 0x01, mtbrake >> 7 & 0x01]
1308
+ mtable = [mtable & 0x01, mtable >> 1 & 0x01, mtable >> 2 & 0x01, mtable >> 3 & 0x01,
1309
+ mtable >> 4 & 0x01, mtable >> 5 & 0x01, mtable >> 6 & 0x01, mtable >> 7 & 0x01]
1310
+
1311
+ if mtbrake != self._arm_motor_brake_states or mtable != self._arm_motor_enable_states:
1312
+ self._arm_motor_enable_states = mtable
1313
+ self._arm_motor_brake_states = mtbrake
1314
+ self._report_mtable_mtbrake_changed_callback()
1315
+
1316
+ if not self._is_first_report:
1317
+ if state in [4, 5] or not all([bool(item[0] & item[1]) for item in zip(mtbrake, mtable)][:self.axis]):
1318
+ # if self._is_ready:
1319
+ # pretty_print('[report], xArm is not ready to move', color='red')
1320
+ self._is_ready = False
1321
+ else:
1322
+ # if not self._is_ready:
1323
+ # pretty_print('[report], xArm is ready to move', color='green')
1324
+ self._is_ready = True
1325
+ else:
1326
+ self._is_ready = False
1327
+ self._is_first_report = False
1328
+ if not self._is_ready:
1329
+ self._sleep_finish_time = 0
1330
+
1331
+ reset_tgpio_params = False
1332
+ reset_linear_track_params = False
1333
+ if 0 < error_code <= 17:
1334
+ reset_tgpio_params = True
1335
+ reset_linear_track_params = True
1336
+ elif error_code in [19, 28]:
1337
+ reset_tgpio_params = True
1338
+ elif error_code == 111:
1339
+ reset_linear_track_params = True
1340
+ if reset_tgpio_params:
1341
+ self.modbus_baud = -1
1342
+ self.robotiq_is_activated = False
1343
+ self.gripper_is_enabled = False
1344
+ self.bio_gripper_is_enabled = False
1345
+ self.bio_gripper_speed = 0
1346
+ self.gripper_is_enabled = False
1347
+ self.gripper_speed = 0
1348
+ self.gripper_version_numbers = [-1, -1, -1]
1349
+ if reset_linear_track_params:
1350
+ self.linear_track_baud = -1
1351
+ self.linear_track_is_enabled = False
1352
+ self.linear_track_speed = 1
1353
+
1354
+ # if error_code in [1, 10, 11, 12, 13, 14, 15, 16, 17, 19, 28]:
1355
+ # self.modbus_baud = -1
1356
+ # self.robotiq_is_activated = False
1357
+ # self.gripper_is_enabled = False
1358
+ # self.bio_gripper_is_enabled = False
1359
+ # self.bio_gripper_speed = 0
1360
+ # self.gripper_is_enabled = False
1361
+ # self.gripper_speed = 0
1362
+ # self.gripper_version_numbers = [-1, -1, -1]
1363
+ # self.linear_track_is_enabled = False
1364
+ # self.linear_track_speed = 0
1365
+
1366
+ self._error_code = error_code
1367
+ self._warn_code = warn_code
1368
+ self.arm_cmd.has_err_warn = error_code != 0 or warn_code != 0
1369
+ _state = self._state
1370
+ self._state = state
1371
+ if self.state != 3 and (_state == 3 or self._pause_cnts > 0):
1372
+ with self._pause_cond:
1373
+ self._pause_cond.notifyAll()
1374
+ self._cmd_num = cmd_num
1375
+ self._arm_motor_brake_states = mtbrake
1376
+ self._arm_motor_enable_states = mtable
1377
+
1378
+ update_time = time.monotonic()
1379
+ self._last_update_cmdnum_time = update_time
1380
+ self._last_update_state_time = update_time
1381
+ self._last_update_err_time = update_time
1382
+
1383
+ for i in range(len(pose)):
1384
+ pose[i] = filter_invaild_number(pose[i], 3 if i < 3 else 6, default=self._position[i])
1385
+ for i in range(len(angles)):
1386
+ angles[i] = filter_invaild_number(angles[i], 6, default=self._angles[i])
1387
+ for i in range(len(pose_offset)):
1388
+ pose_offset[i] = filter_invaild_number(pose_offset[i], 3 if i < 3 else 6, default=self._position_offset[i])
1389
+
1390
+ if not (0 < self._error_code <= 17):
1391
+ self._position = pose
1392
+ if not (0 < self._error_code <= 17):
1393
+ self._angles = angles
1394
+ if not (0 < self._error_code <= 17):
1395
+ self._position_offset = pose_offset
1396
+
1397
+ self._report_location_callback()
1398
+
1399
+ self._report_callback()
1400
+ if not self._is_sync and self._error_code == 0 and self._state not in [4, 5, 6]:
1401
+ self._sync()
1402
+ self._is_sync = True
1403
+
1404
+ def __handle_report_rich_old(rx_data):
1405
+ __handle_report_normal_old(rx_data)
1406
+ (self._arm_type,
1407
+ arm_axis,
1408
+ self._arm_master_id,
1409
+ self._arm_slave_id,
1410
+ self._arm_motor_tid,
1411
+ self._arm_motor_fid) = rx_data[87:93]
1412
+
1413
+ if 7 >= arm_axis >= 5:
1414
+ self._arm_axis = arm_axis
1415
+ if self._arm_type == 5:
1416
+ self._arm_axis = 5
1417
+ elif self._arm_type == 6:
1418
+ self._arm_axis = 6
1419
+ elif self._arm_type == 3:
1420
+ self._arm_axis = 7
1421
+
1422
+ ver_msg = rx_data[93:122]
1423
+ # self._version = str(ver_msg, 'utf-8')
1424
+
1425
+ trs_msg = convert.bytes_to_fp32s(rx_data[123:143], 5)
1426
+ # trs_msg = [i[0] for i in trs_msg]
1427
+ (self._tcp_jerk,
1428
+ self._min_tcp_acc,
1429
+ self._max_tcp_acc,
1430
+ self._min_tcp_speed,
1431
+ self._max_tcp_speed) = trs_msg
1432
+ # print('tcp_jerk: {}, min_acc: {}, max_acc: {}, min_speed: {}, max_speed: {}'.format(
1433
+ # self._tcp_jerk, self._min_tcp_acc, self._max_tcp_acc, self._min_tcp_speed, self._max_tcp_speed
1434
+ # ))
1435
+
1436
+ p2p_msg = convert.bytes_to_fp32s(rx_data[143:163], 5)
1437
+ # p2p_msg = [i[0] for i in p2p_msg]
1438
+ (self._joint_jerk,
1439
+ self._min_joint_acc,
1440
+ self._max_joint_acc,
1441
+ self._min_joint_speed,
1442
+ self._max_joint_speed) = p2p_msg
1443
+ # print('joint_jerk: {}, min_acc: {}, max_acc: {}, min_speed: {}, max_speed: {}'.format(
1444
+ # self._joint_jerk, self._min_joint_acc, self._max_joint_acc,
1445
+ # self._min_joint_speed, self._max_joint_speed
1446
+ # ))
1447
+
1448
+ rot_msg = convert.bytes_to_fp32s(rx_data[163:171], 2)
1449
+ # rot_msg = [i[0] for i in rot_msg]
1450
+ self._rot_jerk, self._max_rot_acc = rot_msg
1451
+ # print('rot_jerk: {}, mac_acc: {}'.format(self._rot_jerk, self._max_rot_acc))
1452
+
1453
+ sv3_msg = convert.bytes_to_u16s(rx_data[171:187], 8)
1454
+ self._first_report_over = True
1455
+
1456
+ def __handle_report_real(rx_data):
1457
+ state, mode = rx_data[4] & 0x0F, rx_data[4] >> 4
1458
+ cmd_num = convert.bytes_to_u16(rx_data[5:7])
1459
+ angles = convert.bytes_to_fp32s(rx_data[7:7 * 4 + 7], 7)
1460
+ pose = convert.bytes_to_fp32s(rx_data[35:6 * 4 + 35], 6)
1461
+ torque = convert.bytes_to_fp32s(rx_data[59:7 * 4 + 59], 7)
1462
+ if cmd_num != self._cmd_num:
1463
+ self._cmd_num = cmd_num
1464
+ self._report_cmdnum_changed_callback()
1465
+ if state != self._state:
1466
+ self._state = state
1467
+ self._report_state_changed_callback()
1468
+ if state in [4, 5]:
1469
+ self._is_ready = False
1470
+ else:
1471
+ self._is_ready = True
1472
+
1473
+ if mode != self._mode:
1474
+ self._mode = mode
1475
+ self._report_mode_changed_callback()
1476
+ for i in range(len(pose)):
1477
+ pose[i] = filter_invaild_number(pose[i], 3 if i < 3 else 6, default=self._position[i])
1478
+ for i in range(len(angles)):
1479
+ angles[i] = filter_invaild_number(angles[i], 6, default=self._angles[i])
1480
+
1481
+ if not (0 < self._error_code <= 17):
1482
+ self._position = pose
1483
+ if not (0 < self._error_code <= 17):
1484
+ self._angles = angles
1485
+ self._joints_torque = torque
1486
+
1487
+ self._report_location_callback()
1488
+
1489
+ self._report_callback()
1490
+ if not self._is_sync and self._state not in [4, 5]:
1491
+ self._sync()
1492
+ self._is_sync = True
1493
+ length = len(rx_data)
1494
+ if length >= 135:
1495
+ # FT_SENSOR
1496
+ self._ft_ext_force = convert.bytes_to_fp32s(rx_data[87:111], 6)
1497
+ self._ft_raw_force = convert.bytes_to_fp32s(rx_data[111:135], 6)
1498
+
1499
+ def __handle_report_normal(rx_data):
1500
+ report_time = time.monotonic()
1501
+ interval = report_time - self._last_report_time
1502
+ self._max_report_interval = max(self._max_report_interval, interval)
1503
+ self._last_report_time = report_time
1504
+ # print('length:', convert.bytes_to_u32(rx_data[0:4]), len(rx_data))
1505
+ state, mode = rx_data[4] & 0x0F, rx_data[4] >> 4
1506
+ # if state != self._state or mode != self._mode:
1507
+ # print('mode: {}, state={}, time={}'.format(mode, state, time.monotonic()))
1508
+ cmd_num = convert.bytes_to_u16(rx_data[5:7])
1509
+ angles = convert.bytes_to_fp32s(rx_data[7:7 * 4 + 7], 7)
1510
+ pose = convert.bytes_to_fp32s(rx_data[35:6 * 4 + 35], 6)
1511
+ torque = convert.bytes_to_fp32s(rx_data[59:7 * 4 + 59], 7)
1512
+ mtbrake, mtable, error_code, warn_code = rx_data[87:91]
1513
+ pose_offset = convert.bytes_to_fp32s(rx_data[91:6 * 4 + 91], 6)
1514
+ tcp_load = convert.bytes_to_fp32s(rx_data[115:4 * 4 + 115], 4)
1515
+ collis_sens, teach_sens = rx_data[131:133]
1516
+ # if (collis_sens not in list(range(6)) or teach_sens not in list(range(6))) \
1517
+ # and ((error_code != 0 and error_code not in controller_error_keys) or (warn_code != 0 and warn_code not in controller_warn_keys)):
1518
+ # self._stream_report.close()
1519
+ # logger.warn('ReportDataException: data={}'.format(rx_data))
1520
+ # return
1521
+ length = convert.bytes_to_u32(rx_data[0:4])
1522
+ data_len = len(rx_data)
1523
+ if (length != data_len and (length != 233 or data_len != 245)) or collis_sens not in list(range(6)) or teach_sens not in list(range(6)) \
1524
+ or mode not in list(range(12)) or state not in list(range(10)):
1525
+ self._stream_report.close()
1526
+ logger.warn('ReportDataException: length={}, data_len={}, '
1527
+ 'state={}, mode={}, collis_sens={}, teach_sens={}, '
1528
+ 'error_code={}, warn_code={}'.format(
1529
+ length, data_len,
1530
+ state, mode, collis_sens, teach_sens, error_code, warn_code
1531
+ ))
1532
+ return
1533
+ self._gravity_direction = convert.bytes_to_fp32s(rx_data[133:3*4 + 133], 3)
1534
+
1535
+ reset_tgpio_params = False
1536
+ reset_linear_track_params = False
1537
+ if 0 < error_code <= 17:
1538
+ reset_tgpio_params = True
1539
+ reset_linear_track_params = True
1540
+ elif error_code in [19, 28]:
1541
+ reset_tgpio_params = True
1542
+ elif error_code == 111:
1543
+ reset_linear_track_params = True
1544
+ if reset_tgpio_params:
1545
+ self.modbus_baud = -1
1546
+ self.robotiq_is_activated = False
1547
+ self.gripper_is_enabled = False
1548
+ self.bio_gripper_is_enabled = False
1549
+ self.bio_gripper_speed = 0
1550
+ self.gripper_is_enabled = False
1551
+ self.gripper_speed = 0
1552
+ self.gripper_version_numbers = [-1, -1, -1]
1553
+ if reset_linear_track_params:
1554
+ self.linear_track_baud = -1
1555
+ self.linear_track_is_enabled = False
1556
+ self.linear_track_speed = 0
1557
+
1558
+ # if error_code in [1, 10, 11, 12, 13, 14, 15, 16, 17, 19, 28]:
1559
+ # self.modbus_baud = -1
1560
+ # self.robotiq_is_activated = False
1561
+ # self.gripper_is_enabled = False
1562
+ # self.bio_gripper_is_enabled = False
1563
+ # self.bio_gripper_speed = -1
1564
+ # self.gripper_speed = -1
1565
+ # self.gripper_version_numbers = [-1, -1, -1]
1566
+ # self.linear_track_is_enabled = False
1567
+ # self.linear_track_speed = -1
1568
+
1569
+ # print('torque: {}'.format(torque))
1570
+ # print('tcp_load: {}'.format(tcp_load))
1571
+ # print('collis_sens: {}, teach_sens: {}'.format(collis_sens, teach_sens))
1572
+
1573
+ if error_code != self._error_code or warn_code != self._warn_code:
1574
+ if error_code != self._error_code:
1575
+ self._error_code = error_code
1576
+ if self._error_code != 0:
1577
+ pretty_print('ControllerError, code: {}'.format(self._error_code), color='red')
1578
+ else:
1579
+ pretty_print('ControllerError had clean', color='blue')
1580
+ if warn_code != self._warn_code:
1581
+ self._warn_code = warn_code
1582
+ if self._warn_code != 0:
1583
+ pretty_print('ControllerWarning, code: {}'.format(self._warn_code), color='yellow')
1584
+ else:
1585
+ pretty_print('ControllerWarning had clean', color='blue')
1586
+ self._report_error_warn_changed_callback()
1587
+ logger.info('OnReport -> err={}, warn={}, state={}, cmdnum={}, mtbrake={}, mtable={}, mode={}'.format(
1588
+ error_code, warn_code, state, cmd_num, mtbrake, mtable, mode
1589
+ ))
1590
+ elif not self._only_report_err_warn_changed:
1591
+ self._report_error_warn_changed_callback()
1592
+
1593
+ if cmd_num != self._cmd_num:
1594
+ self._cmd_num = cmd_num
1595
+ self._report_cmdnum_changed_callback()
1596
+
1597
+ if state != self._state:
1598
+ if not self._has_motion_cmd and self._state in [0, 1] and state not in [0, 1]:
1599
+ self._need_sync = True
1600
+ if self._state in [0, 1] and state not in [0, 1]:
1601
+ self._has_motion_cmd = False
1602
+ # print('old_state: {}, new_state: {}, has_motion_cmd={}, need_sync: {}'.format(self._state, state, self._has_motion_cmd, self._need_sync))
1603
+ self._state = state
1604
+ self._report_state_changed_callback()
1605
+ if mode != self._mode:
1606
+ self._mode = mode
1607
+ self._report_mode_changed_callback()
1608
+
1609
+ mtbrake = [mtbrake & 0x01, mtbrake >> 1 & 0x01, mtbrake >> 2 & 0x01, mtbrake >> 3 & 0x01,
1610
+ mtbrake >> 4 & 0x01, mtbrake >> 5 & 0x01, mtbrake >> 6 & 0x01, mtbrake >> 7 & 0x01]
1611
+ mtable = [mtable & 0x01, mtable >> 1 & 0x01, mtable >> 2 & 0x01, mtable >> 3 & 0x01,
1612
+ mtable >> 4 & 0x01, mtable >> 5 & 0x01, mtable >> 6 & 0x01, mtable >> 7 & 0x01]
1613
+
1614
+ if mtbrake != self._arm_motor_brake_states or mtable != self._arm_motor_enable_states:
1615
+ self._arm_motor_enable_states = mtable
1616
+ self._arm_motor_brake_states = mtbrake
1617
+ self._report_mtable_mtbrake_changed_callback()
1618
+
1619
+ if not self._is_first_report:
1620
+ if state in [4, 5] or not all([bool(item[0] & item[1]) for item in zip(mtbrake, mtable)][:self.axis]):
1621
+ # if self._is_ready:
1622
+ # pretty_print('[report], xArm is not ready to move', color='red')
1623
+ self._is_ready = False
1624
+ else:
1625
+ # if not self._is_ready:
1626
+ # pretty_print('[report], xArm is ready to move', color='green')
1627
+ self._is_ready = True
1628
+ else:
1629
+ self._is_ready = False
1630
+ self._is_first_report = False
1631
+ if not self._is_ready:
1632
+ self._sleep_finish_time = 0
1633
+
1634
+ self._error_code = error_code
1635
+ self._warn_code = warn_code
1636
+ self.arm_cmd.has_err_warn = error_code != 0 or warn_code != 0
1637
+ _state = self._state
1638
+ self._state = state
1639
+ if self.state != 3 and (_state == 3 or self._pause_cnts > 0):
1640
+ with self._pause_cond:
1641
+ self._pause_cond.notifyAll()
1642
+ self._mode = mode
1643
+ self._cmd_num = cmd_num
1644
+
1645
+ update_time = time.monotonic()
1646
+ self._last_update_cmdnum_time = update_time
1647
+ self._last_update_state_time = update_time
1648
+ self._last_update_err_time = update_time
1649
+
1650
+ self._arm_motor_brake_states = mtbrake
1651
+ self._arm_motor_enable_states = mtable
1652
+ self._joints_torque = torque
1653
+ if compare_version(self.version_number, (0, 2, 0)):
1654
+ self._tcp_load = [float('{:.3f}'.format(tcp_load[0])), [float('{:.3f}'.format(i)) for i in tcp_load[1:]]]
1655
+ else:
1656
+ self._tcp_load = [float('{:.3f}'.format(tcp_load[0])), [float('{:.3f}'.format(i * 1000)) for i in tcp_load[1:]]]
1657
+ self._collision_sensitivity = collis_sens
1658
+ self._teach_sensitivity = teach_sens
1659
+
1660
+ for i in range(len(pose)):
1661
+ pose[i] = filter_invaild_number(pose[i], 3 if i < 3 else 6, default=self._position[i])
1662
+ for i in range(len(angles)):
1663
+ angles[i] = filter_invaild_number(angles[i], 6, default=self._angles[i])
1664
+ for i in range(len(pose_offset)):
1665
+ pose_offset[i] = filter_invaild_number(pose_offset[i], 3 if i < 3 else 6, default=self._position_offset[i])
1666
+
1667
+ if not (0 < self._error_code <= 17):
1668
+ self._position = pose
1669
+ if not (0 < self._error_code <= 17):
1670
+ self._angles = angles
1671
+ if not (0 < self._error_code <= 17):
1672
+ self._position_offset = pose_offset
1673
+
1674
+ self._report_location_callback()
1675
+
1676
+ self._report_callback()
1677
+ if not self._is_sync and self._error_code == 0 and self._state not in [4, 5]:
1678
+ self._sync()
1679
+ self._is_sync = True
1680
+ elif self._need_sync:
1681
+ self._need_sync = False
1682
+ self._sync()
1683
+
1684
+ def __handle_report_rich(rx_data):
1685
+ # print('interval={}, max_interval={}'.format(interval, self._max_report_interval))
1686
+ __handle_report_normal(rx_data)
1687
+ (self._arm_type,
1688
+ arm_axis,
1689
+ self._arm_master_id,
1690
+ self._arm_slave_id,
1691
+ self._arm_motor_tid,
1692
+ self._arm_motor_fid) = rx_data[145:151]
1693
+
1694
+ if 7 >= arm_axis >= 5:
1695
+ self._arm_axis = arm_axis
1696
+
1697
+ # self._version = str(rx_data[151:180], 'utf-8')
1698
+
1699
+ trs_msg = convert.bytes_to_fp32s(rx_data[181:201], 5)
1700
+ # trs_msg = [i[0] for i in trs_msg]
1701
+ (self._tcp_jerk,
1702
+ self._min_tcp_acc,
1703
+ self._max_tcp_acc,
1704
+ self._min_tcp_speed,
1705
+ self._max_tcp_speed) = trs_msg
1706
+ # print('tcp_jerk: {}, min_acc: {}, max_acc: {}, min_speed: {}, max_speed: {}'.format(
1707
+ # self._tcp_jerk, self._min_tcp_acc, self._max_tcp_acc, self._min_tcp_speed, self._max_tcp_speed
1708
+ # ))
1709
+
1710
+ p2p_msg = convert.bytes_to_fp32s(rx_data[201:221], 5)
1711
+ # p2p_msg = [i[0] for i in p2p_msg]
1712
+ (self._joint_jerk,
1713
+ self._min_joint_acc,
1714
+ self._max_joint_acc,
1715
+ self._min_joint_speed,
1716
+ self._max_joint_speed) = p2p_msg
1717
+ # print('joint_jerk: {}, min_acc: {}, max_acc: {}, min_speed: {}, max_speed: {}'.format(
1718
+ # self._joint_jerk, self._min_joint_acc, self._max_joint_acc,
1719
+ # self._min_joint_speed, self._max_joint_speed
1720
+ # ))
1721
+
1722
+ rot_msg = convert.bytes_to_fp32s(rx_data[221:229], 2)
1723
+ # rot_msg = [i[0] for i in rot_msg]
1724
+ self._rot_jerk, self._max_rot_acc = rot_msg
1725
+ # print('rot_jerk: {}, mac_acc: {}'.format(self._rot_jerk, self._max_rot_acc))
1726
+
1727
+ servo_codes = [val for val in rx_data[229:245]]
1728
+ for i in range(self.axis):
1729
+ if self._servo_codes[i][0] != servo_codes[i * 2] or self._servo_codes[i][1] != servo_codes[i * 2 + 1]:
1730
+ print('servo_error_code, servo_id={}, status={}, code={}'.format(i + 1, servo_codes[i * 2], servo_codes[i * 2 + 1]))
1731
+ self._servo_codes[i][0] = servo_codes[i * 2]
1732
+ self._servo_codes[i][1] = servo_codes[i * 2 + 1]
1733
+
1734
+ self._first_report_over = True
1735
+
1736
+ # length = convert.bytes_to_u32(rx_data[0:4])
1737
+ length = len(rx_data)
1738
+ if length >= 252:
1739
+ temperatures = list(struct.unpack('>7b', struct.pack('>7B', *rx_data[245:252])))
1740
+ # temperatures = list(map(int, rx_data[245:252]))
1741
+ if temperatures != self.temperatures:
1742
+ self._temperatures = temperatures
1743
+ self._report_temperature_changed_callback()
1744
+ if length >= 284:
1745
+ speeds = convert.bytes_to_fp32s(rx_data[252:8 * 4 + 252], 8)
1746
+ self._realtime_tcp_speed = speeds[0]
1747
+ self._realtime_joint_speeds = speeds[1:]
1748
+ # print(speeds[0], speeds[1:])
1749
+ if length >= 288:
1750
+ count = convert.bytes_to_u32(rx_data[284:288])
1751
+ # print(count, rx_data[284:288])
1752
+ if self._count != -1 and count != self._count:
1753
+ self._count = count
1754
+ self._report_count_changed_callback()
1755
+ self._count = count
1756
+ if length >= 312:
1757
+ world_offset = convert.bytes_to_fp32s(rx_data[288:6 * 4 + 288], 6)
1758
+ for i in range(len(world_offset)):
1759
+ if i < 3:
1760
+ world_offset[i] = float('{:.3f}'.format(world_offset[i]))
1761
+ else:
1762
+ world_offset[i] = float('{:.6f}'.format(world_offset[i]))
1763
+ if math.inf not in world_offset and -math.inf not in world_offset and not (10 <= self._error_code <= 17):
1764
+ self._world_offset = world_offset
1765
+ if length >= 314:
1766
+ self._cgpio_reset_enable, self._tgpio_reset_enable = rx_data[312:314]
1767
+ if length >= 417:
1768
+ self._is_simulation_robot = bool(rx_data[314])
1769
+ self._is_collision_detection, self._collision_tool_type = rx_data[315:317]
1770
+ self._collision_tool_params = convert.bytes_to_fp32s(rx_data[317:341], 6)
1771
+
1772
+ voltages = convert.bytes_to_u16s(rx_data[341:355], 7)
1773
+ voltages = list(map(lambda x: x / 100, voltages))
1774
+ self._voltages = voltages
1775
+
1776
+ currents = convert.bytes_to_fp32s(rx_data[355:383], 7)
1777
+ self._currents = currents
1778
+
1779
+ cgpio_states = []
1780
+ cgpio_states.extend(rx_data[383:385])
1781
+ cgpio_states.extend(convert.bytes_to_u16s(rx_data[385:401], 8))
1782
+ cgpio_states[6:10] = list(map(lambda x: x / 4095.0 * 10.0, cgpio_states[6:10]))
1783
+ cgpio_states.append(list(map(int, rx_data[401:409])))
1784
+ cgpio_states.append(list(map(int, rx_data[409:417])))
1785
+ if self._control_box_type_is_1300 and length >= 433:
1786
+ cgpio_states[-2].extend(list(map(int, rx_data[417:425])))
1787
+ cgpio_states[-1].extend(list(map(int, rx_data[425:433])))
1788
+ self._cgpio_states = cgpio_states
1789
+ if length >= 481:
1790
+ # FT_SENSOR
1791
+ self._ft_ext_force = convert.bytes_to_fp32s(rx_data[433:457], 6)
1792
+ self._ft_raw_force = convert.bytes_to_fp32s(rx_data[457:481], 6)
1793
+ if length >= 482:
1794
+ iden_progress = rx_data[481]
1795
+ if iden_progress != self._iden_progress:
1796
+ self._iden_progress = iden_progress
1797
+ self._report_iden_progress_changed_callback()
1798
+ if length >= 494:
1799
+ pose_aa = convert.bytes_to_fp32s(rx_data[482:494], 3)
1800
+ for i in range(len(pose_aa)):
1801
+ pose_aa[i] = filter_invaild_number(pose_aa[i], 6, default=self._pose_aa[i])
1802
+ self._pose_aa = self._position[:3] + pose_aa
1803
+ if length >= 495:
1804
+ self._is_reduced_mode = rx_data[494] & 0x01
1805
+ self._is_fence_mode = (rx_data[494] >> 1) & 0x01
1806
+ self._is_report_current = (rx_data[494] >> 2) & 0x01 # 针对get_report_tau_or_i的结果
1807
+ self._is_approx_motion = (rx_data[494] >> 3) & 0x01
1808
+ self._is_cart_continuous = (rx_data[494] >> 4) & 0x01
1809
+ if length >= 496:
1810
+ self._reduced_mode_is_on = rx_data[495]
1811
+ self._reduced_tcp_boundary = convert.bytes_to_16s(rx_data[496:508], 6)
1812
+
1813
+ try:
1814
+ if self._report_type == 'real':
1815
+ __handle_report_real(data)
1816
+ elif self._report_type == 'rich':
1817
+ if self._is_old_protocol:
1818
+ __handle_report_rich_old(data)
1819
+ else:
1820
+ __handle_report_rich(data)
1821
+ else:
1822
+ if self._is_old_protocol:
1823
+ __handle_report_normal_old(data)
1824
+ else:
1825
+ __handle_report_normal(data)
1826
+ except Exception as e:
1827
+ logger.error(e)
1828
+
1829
+ def _auto_get_report_thread(self):
1830
+ logger.debug('get report thread start')
1831
+ while self.connected:
1832
+ try:
1833
+ cmd_num = self._cmd_num
1834
+ state = self._state
1835
+ error_code = self._error_code
1836
+ warn_code = self._warn_code
1837
+
1838
+ self.get_cmdnum()
1839
+ time.sleep(0.01)
1840
+ self.get_state()
1841
+ time.sleep(0.01)
1842
+ self.get_err_warn_code()
1843
+ time.sleep(0.01)
1844
+ self.get_servo_angle()
1845
+ time.sleep(0.01)
1846
+ self.get_position()
1847
+
1848
+ if self.state != 3 and (state == 3 or self._pause_cnts > 0):
1849
+ with self._pause_cond:
1850
+ self._pause_cond.notifyAll()
1851
+ if cmd_num != self._cmd_num:
1852
+ self._report_cmdnum_changed_callback()
1853
+ if state != self._state:
1854
+ self._report_state_changed_callback()
1855
+ if state in [4, 5]:
1856
+ # if self._is_ready:
1857
+ # pretty_print('[report], xArm is not ready to move', color='red')
1858
+ self._sleep_finish_time = 0
1859
+ self._is_ready = False
1860
+ else:
1861
+ # if not self._is_ready:
1862
+ # pretty_print('[report], xArm is ready to move', color='green')
1863
+ self._is_ready = True
1864
+ if error_code != self._error_code or warn_code != self._warn_code:
1865
+ self._report_error_warn_changed_callback()
1866
+ elif not self._only_report_err_warn_changed and (self._error_code != 0 or self._warn_code != 0):
1867
+ self._report_error_warn_changed_callback()
1868
+
1869
+ self._report_location_callback()
1870
+ self._report_callback()
1871
+
1872
+ if self._cmd_num >= self._max_cmd_num:
1873
+ time.sleep(1)
1874
+ self._first_report_over = True
1875
+ time.sleep(0.1)
1876
+ except:
1877
+ pass
1878
+ self.disconnect()
1879
+ logger.debug('get report thread stopped')
1880
+
1881
+ def _sync_tcp(self, index=None):
1882
+ if not self._stream_report or not self._stream_report.connected:
1883
+ self.get_position()
1884
+ self.get_servo_angle()
1885
+ self._last_angles = self._angles.copy()
1886
+ if index is None:
1887
+ self._last_position = self._position.copy()
1888
+ elif isinstance(index, int) and 0 <= index < 6:
1889
+ self._last_position[index] = self._position[index]
1890
+ # print('=============sync_tcp: index={}'.format(index))
1891
+
1892
+ def _sync_joints(self, index=None):
1893
+ if not self._stream_report or not self._stream_report.connected:
1894
+ self.get_position()
1895
+ self.get_servo_angle()
1896
+ self._last_position = self._position.copy()
1897
+ if index is None:
1898
+ self._last_angles = self._angles.copy()
1899
+ elif isinstance(index, int) and 0 <= index < 7:
1900
+ self._last_angles[index] = self._angles[index]
1901
+ # print('=============sync_joint: index={}'.format(index))
1902
+
1903
+ def _sync(self):
1904
+ if not self._stream_report or not self._stream_report.connected:
1905
+ self.get_position()
1906
+ self.get_servo_angle()
1907
+ self._last_position = self._position.copy()
1908
+ self._last_angles = self._angles.copy()
1909
+ # print('=============sync_all')
1910
+
1911
+ def _set_params(self, **kwargs):
1912
+ is_radian = kwargs.get('is_radian', self._default_is_radian)
1913
+ if 'X' in kwargs and isinstance(kwargs['X'], (int, float)):
1914
+ self._last_position[0] = kwargs.get('X')
1915
+ if 'Y' in kwargs and isinstance(kwargs['Y'], (int, float)):
1916
+ self._last_position[1] = kwargs.get('Y')
1917
+ if 'Z' in kwargs and isinstance(kwargs['Z'], (int, float)):
1918
+ self._last_position[2] = kwargs.get('Z')
1919
+ if 'A' in kwargs and isinstance(kwargs['A'], (int, float)):
1920
+ self._last_position[3] = kwargs.get('A') if is_radian else math.radians(kwargs.get('A'))
1921
+ if 'B' in kwargs and isinstance(kwargs['B'], (int, float)):
1922
+ self._last_position[4] = kwargs.get('B') if is_radian else math.radians(kwargs.get('B'))
1923
+ if 'C' in kwargs and isinstance(kwargs['C'], (int, float)):
1924
+ self._last_position[5] = kwargs.get('C') if is_radian else math.radians(kwargs.get('C'))
1925
+ # if 'R' in kwargs and isinstance(kwargs['R'], (int, float)):
1926
+ # self._last_position[6] = kwargs.get('R')
1927
+ if 'I' in kwargs and isinstance(kwargs['I'], (int, float)):
1928
+ self._last_angles[0] = kwargs.get('I') if is_radian else math.radians(kwargs.get('I'))
1929
+ if 'J' in kwargs and isinstance(kwargs['J'], (int, float)):
1930
+ self._last_angles[1] = kwargs.get('J') if is_radian else math.radians(kwargs.get('J'))
1931
+ if 'K' in kwargs and isinstance(kwargs['K'], (int, float)):
1932
+ self._last_angles[2] = kwargs.get('K') if is_radian else math.radians(kwargs.get('K'))
1933
+ if 'L' in kwargs and isinstance(kwargs['L'], (int, float)):
1934
+ self._last_angles[3] = kwargs.get('L') if is_radian else math.radians(kwargs.get('L'))
1935
+ if 'M' in kwargs and isinstance(kwargs['M'], (int, float)):
1936
+ self._last_angles[4] = kwargs.get('M') if is_radian else math.radians(kwargs.get('M'))
1937
+ if 'N' in kwargs and isinstance(kwargs['N'], (int, float)):
1938
+ self._last_angles[5] = kwargs.get('N') if is_radian else math.radians(kwargs.get('N'))
1939
+ if 'O' in kwargs and isinstance(kwargs['O'], (int, float)):
1940
+ self._last_angles[6] = kwargs.get('O') if is_radian else math.radians(kwargs.get('O'))
1941
+
1942
+ if 'F' in kwargs and isinstance(kwargs['F'], (int, float)):
1943
+ self._last_tcp_speed = kwargs.get('F')
1944
+ self._last_tcp_speed = min(max(self._last_tcp_speed, self._min_tcp_speed), self._max_tcp_speed)
1945
+ if 'Q' in kwargs and isinstance(kwargs['Q'], (int, float)):
1946
+ self._last_tcp_acc = kwargs.get('Q')
1947
+ self._last_tcp_acc = min(max(self._last_tcp_acc, self._min_tcp_acc), self._max_tcp_acc)
1948
+ if 'F2' in kwargs and isinstance(kwargs['F2'], (int, float)):
1949
+ self._last_joint_speed = kwargs.get('F2')
1950
+ if not is_radian:
1951
+ self._last_joint_speed = math.radians(self._last_joint_speed)
1952
+ self._last_joint_speed = min(max(self._last_joint_speed, self._min_joint_speed), self._max_joint_speed)
1953
+ if 'Q2' in kwargs and isinstance(kwargs['Q2'], (int, float)):
1954
+ self._last_joint_acc = kwargs.get('Q2')
1955
+ if not is_radian:
1956
+ self._last_joint_acc = math.radians(self._last_joint_acc)
1957
+ self._last_joint_acc = min(max(self._last_joint_acc, self._min_joint_acc), self._max_joint_acc)
1958
+ if 'T' in kwargs and isinstance(kwargs['T'], (int, float)):
1959
+ self._mvtime = kwargs.get('T')
1960
+ if 'LIMIT_VELO' in kwargs and isinstance(kwargs['LIMIT_VELO'], (list, tuple)) \
1961
+ and len(kwargs['LIMIT_VELO']) == 2 and isinstance(kwargs['LIMIT_VELO'][0], (int, float)) \
1962
+ and isinstance(kwargs['LIMIT_VELO'][1], (int, float)) \
1963
+ and kwargs['LIMIT_VELO'][0] <= kwargs['LIMIT_VELO'][1]:
1964
+ self._min_tcp_speed, self._max_tcp_speed = kwargs.get('LIMIT_VELO')
1965
+ if 'LIMIT_ACC' in kwargs and isinstance(kwargs['LIMIT_ACC'], (list, tuple)) \
1966
+ and len(kwargs['LIMIT_ACC']) == 2 and isinstance(kwargs['LIMIT_ACC'][0], (int, float)) \
1967
+ and isinstance(kwargs['LIMIT_ACC'][1], (int, float)) \
1968
+ and kwargs['LIMIT_ACC'][0] <= kwargs['LIMIT_ACC'][1]:
1969
+ self._min_tcp_acc, self._max_tcp_acc = kwargs.get('LIMIT_ACC')
1970
+
1971
+ def _get_params(self, is_radian=None):
1972
+ is_radian = self._default_is_radian if is_radian is None else is_radian
1973
+ if is_radian:
1974
+ return {
1975
+ 'lastPosition': self._last_position,
1976
+ 'lastAngles': self._last_angles,
1977
+ 'mvvelo': self._last_tcp_speed,
1978
+ 'mvacc': self._last_tcp_acc,
1979
+ 'tcpJerk': self._tcp_jerk,
1980
+ 'jointJerk': self._joint_jerk,
1981
+ 'angle_mvvelo': self._last_joint_speed,
1982
+ 'angle_mvacc': self._last_joint_acc,
1983
+ 'mvtime': self._mvtime,
1984
+ 'LIMIT_VELO': [self._min_tcp_speed, self._max_tcp_speed],
1985
+ 'LIMIT_ACC': [self._min_tcp_acc, self._max_tcp_acc],
1986
+ 'LIMIT_ANGLE_VELO': [self._min_joint_speed, self._max_joint_speed],
1987
+ 'LIMIT_ANGLE_ACC': [self._min_joint_acc, self._max_joint_acc],
1988
+ }
1989
+ else:
1990
+ return {
1991
+ 'lastPosition': [math.degrees(self._last_position[i]) if 2 < i < 6 else self._last_position[i] for i in range(len(self._last_position))],
1992
+ 'lastAngles': [math.degrees(angle) for angle in self._last_angles],
1993
+ 'mvvelo': round(self._last_tcp_speed),
1994
+ 'mvacc': round(self._last_tcp_acc),
1995
+ 'tcpJerk': round(self._tcp_jerk),
1996
+ 'jointJerk': round(math.degrees(self._joint_jerk)),
1997
+ 'angle_mvvelo': round(math.degrees(self._last_joint_speed)),
1998
+ 'angle_mvacc': round(math.degrees(self._last_joint_acc)),
1999
+ 'mvtime': self._mvtime,
2000
+ 'LIMIT_VELO': list(map(round, [self._min_tcp_speed, self._max_tcp_speed])),
2001
+ 'LIMIT_ACC': list(map(round, [self._min_tcp_acc, self._max_tcp_acc])),
2002
+ 'LIMIT_ANGLE_VELO': list(map(round, [math.degrees(self._min_joint_speed), math.degrees(self._max_joint_speed)])),
2003
+ 'LIMIT_ANGLE_ACC': list(map(round, [math.degrees(self._min_joint_acc), math.degrees(self._max_joint_acc)])),
2004
+ }
2005
+
2006
+ def _check_code(self, code, is_move_cmd=False, mode=-1):
2007
+ if is_move_cmd:
2008
+ if code in [0, XCONF.UxbusState.WAR_CODE]:
2009
+ if self.arm_cmd.state_is_ready:
2010
+ if mode >= 0 and mode != self.mode:
2011
+ logger.warn('The mode may be incorrect, just as a reminder, mode: {} ({})'.format(mode, self.mode))
2012
+ return 0
2013
+ # return 0 if mode < 0 or mode == self.mode else APIState.MODE_IS_NOT_CORRECT
2014
+ else:
2015
+ return XCONF.UxbusState.STATE_NOT_READY
2016
+ else:
2017
+ return code
2018
+ # return 0 if code in [0, XCONF.UxbusState.WAR_CODE] and self.arm_cmd.state_is_ready else XCONF.UxbusState.STATE_NOT_READY if not self.arm_cmd.state_is_ready else code
2019
+ else:
2020
+ return 0 if code in [0, XCONF.UxbusState.ERR_CODE, XCONF.UxbusState.WAR_CODE, XCONF.UxbusState.STATE_NOT_READY] else code
2021
+
2022
+ def _check_mode_is_correct(self, mode, timeout=1):
2023
+ if self._enable_report and self._stream_type == 'socket':
2024
+ cnt = int(10 * timeout)
2025
+ while cnt > 0 and self.mode != mode:
2026
+ time.sleep(0.1)
2027
+ cnt -= 1
2028
+ if self.mode != mode:
2029
+ return False
2030
+ return True
2031
+
2032
+ @xarm_is_connected(_type='get')
2033
+ def get_version(self):
2034
+ ret = self.arm_cmd.get_version()
2035
+ ret[0] = self._check_code(ret[0])
2036
+ if ret[0] == 0:
2037
+ version = ''.join(list(map(chr, ret[1:])))
2038
+ self._version = version[:version.find('\0')]
2039
+ return ret[0], self._version
2040
+
2041
+ @xarm_is_connected(_type='get')
2042
+ def get_robot_sn(self):
2043
+ ret = self.arm_cmd.get_robot_sn()
2044
+ ret[0] = self._check_code(ret[0])
2045
+ if ret[0] == 0:
2046
+ robot_sn = ''.join(list(map(chr, ret[1:])))
2047
+ split_inx = robot_sn.find('\0')
2048
+ self._robot_sn = robot_sn[:split_inx]
2049
+ control_box_sn = robot_sn[split_inx+1:]
2050
+ self._control_box_sn = control_box_sn[:control_box_sn.find('\0')].strip()
2051
+ self._arm_type_is_1300 = int(self._robot_sn[2:6]) >= 1300 if self._robot_sn[2:6].isdigit() else False
2052
+ self._control_box_type_is_1300 = int(self._control_box_sn[2:6]) >= 1300 if self._control_box_sn[2:6].isdigit() else False
2053
+ return ret[0], self._robot_sn
2054
+
2055
+ @xarm_is_connected(_type='get')
2056
+ def check_verification(self):
2057
+ ret = self.arm_cmd.check_verification()
2058
+ ret[0] = self._check_code(ret[0])
2059
+ return ret[0], ret[1]
2060
+
2061
+ @xarm_is_connected(_type='get')
2062
+ def get_position(self, is_radian=None):
2063
+ is_radian = self._default_is_radian if is_radian is None else is_radian
2064
+ ret = self.arm_cmd.get_tcp_pose()
2065
+ ret[0] = self._check_code(ret[0])
2066
+ if ret[0] == 0 and len(ret) > 6:
2067
+ self._position = [filter_invaild_number(ret[i], 6, default=self._position[i-1]) for i in range(1, 7)]
2068
+ return ret[0], [float(
2069
+ '{:.6f}'.format(math.degrees(self._position[i]) if 2 < i < 6 and not is_radian else self._position[i])) for
2070
+ i in range(len(self._position))]
2071
+
2072
+ @xarm_is_connected(_type='get')
2073
+ def get_servo_angle(self, servo_id=None, is_radian=None, is_real=False):
2074
+ is_radian = self._default_is_radian if is_radian is None else is_radian
2075
+ if is_real and self.version_is_ge(1, 9, 110):
2076
+ ret = self.arm_cmd.get_joint_states(num=1)
2077
+ else:
2078
+ ret = self.arm_cmd.get_joint_pos()
2079
+ ret[0] = self._check_code(ret[0])
2080
+ if ret[0] == 0 and len(ret) > 7:
2081
+ self._angles = [filter_invaild_number(ret[i], 6, default=self._angles[i-1]) for i in range(1, 8)]
2082
+ if servo_id is None or servo_id == 8 or len(self._angles) < servo_id:
2083
+ return ret[0], list(
2084
+ map(lambda x: float('{:.6f}'.format(x if is_radian else math.degrees(x))), self._angles))
2085
+ else:
2086
+ return ret[0], float(
2087
+ '{:.6f}'.format(self._angles[servo_id - 1] if is_radian else math.degrees(self._angles[servo_id - 1])))
2088
+
2089
+ @xarm_is_connected(_type='get')
2090
+ def get_joint_states(self, is_radian=None, num=3):
2091
+ is_radian = self._default_is_radian if is_radian is None else is_radian
2092
+ ret = self.arm_cmd.get_joint_states(num=num)
2093
+ ret[0] = self._check_code(ret[0])
2094
+ positon = ret[1:8]
2095
+ result = [positon]
2096
+ if num >= 2:
2097
+ velocity = ret[8:15]
2098
+ result.append(velocity)
2099
+ if num >= 3:
2100
+ effort = ret[15:22]
2101
+ result.append(effort)
2102
+ if ret[0] == 0:
2103
+ if not is_radian:
2104
+ for i in range(7):
2105
+ positon[i] = math.degrees(positon[i])
2106
+ if num >= 2:
2107
+ velocity[i] = math.degrees(velocity[i])
2108
+ return ret[0], result
2109
+
2110
+ @xarm_is_connected(_type='get')
2111
+ def get_position_aa(self, is_radian=None):
2112
+ is_radian = self._default_is_radian if is_radian is None else is_radian
2113
+ ret = self.arm_cmd.get_position_aa()
2114
+ ret[0] = self._check_code(ret[0])
2115
+ if ret[0] == 0 and len(ret) > 6:
2116
+ self._pose_aa = [filter_invaild_number(ret[i], 6, default=self._pose_aa[i - 1]) for i in range(1, 7)]
2117
+ return ret[0], [float(
2118
+ '{:.6f}'.format(math.degrees(self._pose_aa[i]) if 2 < i < 6 and not is_radian else self._pose_aa[i]))
2119
+ for i in range(len(self._pose_aa))]
2120
+
2121
+ @xarm_is_connected(_type='get')
2122
+ def get_pose_offset(self, pose1, pose2, orient_type_in=0, orient_type_out=0, is_radian=None):
2123
+ is_radian = self._default_is_radian if is_radian is None else is_radian
2124
+ _pose1 = [pose1[i] if i <= 2 or is_radian else math.radians(pose1[i]) for i in range(6)]
2125
+ _pose2 = [pose2[i] if i <= 2 or is_radian else math.radians(pose2[i]) for i in range(6)]
2126
+ ret = self.arm_cmd.get_pose_offset(_pose1, _pose2, orient_type_in, orient_type_out)
2127
+ ret[0] = self._check_code(ret[0])
2128
+ if ret[0] == 0 and len(ret) > 6:
2129
+ pose = [float('{:.6f}'.format(ret[i] if i <= 3 or is_radian else math.degrees(ret[i]))) for i in
2130
+ range(1, 7)]
2131
+ return ret[0], pose
2132
+ return ret[0], ret[1:7]
2133
+
2134
+ def get_is_moving(self):
2135
+ self.get_state()
2136
+ return self._state == 1
2137
+
2138
+ @xarm_is_connected(_type='get')
2139
+ def get_state(self):
2140
+ ret = self.arm_cmd.get_state()
2141
+ ret[0] = self._check_code(ret[0])
2142
+ if ret[0] == 0:
2143
+ # if ret[1] != self._state:
2144
+ # self._state = ret[1]
2145
+ # self._report_state_changed_callback()
2146
+ self._state = ret[1]
2147
+ self._last_update_state_time = time.monotonic()
2148
+ return ret[0], ret[1] if ret[0] == 0 else self._state
2149
+
2150
+ @xarm_is_connected(_type='set')
2151
+ def set_state(self, state=0):
2152
+ _state = self._state
2153
+ ret = self.arm_cmd.set_state(state)
2154
+ ret[0] = self._check_code(ret[0])
2155
+ if state == 4 and ret[0] == 0:
2156
+ # self._last_position[:6] = self.position
2157
+ # self._last_angles = self.angles
2158
+ self._sleep_finish_time = 0
2159
+ # self._is_sync = False
2160
+ self.get_state()
2161
+ if _state != self._state:
2162
+ self._report_state_changed_callback()
2163
+ if self.state != 3 and (_state == 3 or self._pause_cnts > 0):
2164
+ with self._pause_cond:
2165
+ self._pause_cond.notifyAll()
2166
+ if self._state in [4, 5]:
2167
+ self._sleep_finish_time = 0
2168
+ if self._is_ready:
2169
+ pretty_print('[set_state], xArm is not ready to move', color='red')
2170
+ self._is_ready = False
2171
+ else:
2172
+ if not self._is_ready:
2173
+ pretty_print('[set_state], xArm is ready to move', color='green')
2174
+ self._is_ready = True
2175
+ self.log_api_info('API -> set_state({}) -> code={}, state={}'.format(state, ret[0], self._state), code=ret[0])
2176
+ return ret[0]
2177
+
2178
+ @xarm_is_connected(_type='set')
2179
+ def set_mode(self, mode=0, detection_param=0):
2180
+ if self.version_is_ge(1, 10, 0):
2181
+ detection_param = detection_param if detection_param >= 0 else 0
2182
+ else:
2183
+ detection_param = -1
2184
+ ret = self.arm_cmd.set_mode(mode, detection_param=detection_param)
2185
+ ret[0] = self._check_code(ret[0])
2186
+ self.log_api_info('API -> set_mode({}) -> code={}'.format(mode, ret[0]), code=ret[0])
2187
+ return ret[0]
2188
+
2189
+ @xarm_is_connected(_type='get')
2190
+ def get_cmdnum(self):
2191
+ ret = self.arm_cmd.get_cmdnum()
2192
+ ret[0] = self._check_code(ret[0])
2193
+ if ret[0] == 0:
2194
+ if ret[1] != self._cmd_num:
2195
+ self._report_cmdnum_changed_callback()
2196
+ self._cmd_num = ret[1]
2197
+ self._last_update_cmdnum_time = time.monotonic()
2198
+ return ret[0], self._cmd_num
2199
+
2200
+ @xarm_is_connected(_type='get')
2201
+ def get_err_warn_code(self, show=False, lang='en'):
2202
+ ret = self.arm_cmd.get_err_code()
2203
+ lang = lang if lang == 'cn' else 'en'
2204
+ ret[0] = self._check_code(ret[0])
2205
+ if ret[0] == 0:
2206
+ # if ret[1] != self._error_code or ret[2] != self._warn_code:
2207
+ # self._error_code, self._warn_code = ret[1:3]
2208
+ # self._report_error_warn_changed_callback()
2209
+
2210
+ self._error_code, self._warn_code = ret[1:3]
2211
+ self._last_update_err_time = time.monotonic()
2212
+ if show:
2213
+ pretty_print('************* {}, {}: {} **************'.format(
2214
+ '获取控制器错误警告码' if lang == 'cn' else 'GetErrorWarnCode',
2215
+ '状态' if lang == 'cn' else 'Status',
2216
+ ret[0]), color='light_blue')
2217
+ controller_error = ControllerError(self._error_code, status=0)
2218
+ controller_warn = ControllerWarn(self._warn_code, status=0)
2219
+ pretty_print('* {}: {}, {}: {}'.format(
2220
+ '错误码' if lang == 'cn' else 'ErrorCode',
2221
+ controller_error.code,
2222
+ '信息' if lang == 'cn' else 'Info',
2223
+ controller_error.title[lang]),
2224
+ color='red' if self._error_code != 0 else 'white')
2225
+ pretty_print('* {}: {}, {}: {}'.format(
2226
+ '警告码' if lang == 'cn' else 'WarnCode',
2227
+ controller_warn.code,
2228
+ '信息' if lang == 'cn' else 'Info',
2229
+ controller_warn.title[lang]),
2230
+ color='yellow' if self._warn_code != 0 else 'white')
2231
+ pretty_print('*' * 50, color='light_blue')
2232
+ return ret[0], ret[1:3] if ret[0] == 0 else [self._error_code, self._warn_code]
2233
+
2234
+ @xarm_is_connected(_type='set')
2235
+ def clean_error(self):
2236
+ ret = self.arm_cmd.clean_err()
2237
+ self.get_state()
2238
+ if self._state in [4, 5]:
2239
+ self._sleep_finish_time = 0
2240
+ if self._is_ready:
2241
+ pretty_print('[clean_error], xArm is not ready to move', color='red')
2242
+ self._is_ready = False
2243
+ else:
2244
+ if not self._is_ready:
2245
+ pretty_print('[clean_error], xArm is ready to move', color='green')
2246
+ self._is_ready = True
2247
+ self.log_api_info('API -> clean_error -> code={}'.format(ret[0]), code=ret[0])
2248
+ return ret[0]
2249
+
2250
+ @xarm_is_connected(_type='set')
2251
+ def clean_warn(self):
2252
+ ret = self.arm_cmd.clean_war()
2253
+ self.log_api_info('API -> clean_warn -> code={}'.format(ret[0]), code=ret[0])
2254
+ return ret[0]
2255
+
2256
+ @xarm_is_connected(_type='set')
2257
+ @xarm_is_not_simulation_mode(ret=0)
2258
+ def motion_enable(self, enable=True, servo_id=None):
2259
+ assert servo_id is None or (isinstance(servo_id, int) and 1 <= servo_id <= 8)
2260
+ if servo_id is None or servo_id == 8:
2261
+ ret = self.arm_cmd.motion_en(8, int(enable))
2262
+ else:
2263
+ ret = self.arm_cmd.motion_en(servo_id, int(enable))
2264
+ ret[0] = self._check_code(ret[0])
2265
+ if ret[0] == 0:
2266
+ self._is_ready = bool(enable)
2267
+ self.get_state()
2268
+ if self._state in [4, 5]:
2269
+ self._sleep_finish_time = 0
2270
+ if self._is_ready:
2271
+ pretty_print('[motion_enable], xArm is not ready to move', color='red')
2272
+ self._is_ready = False
2273
+ else:
2274
+ if not self._is_ready:
2275
+ pretty_print('[motion_enable], xArm is ready to move', color='green')
2276
+ self._is_ready = True
2277
+ self.log_api_info('API -> motion_enable -> code={}'.format(ret[0]), code=ret[0])
2278
+ return ret[0]
2279
+
2280
+ def _gen_feedback_key(self, wait, **kwargs):
2281
+ feedback_key = kwargs.get('feedback_key', '') if self._support_feedback and not wait else ''
2282
+ studio_wait = bool(feedback_key)
2283
+ feedback_key = str(uuid.uuid1()) if wait and self._support_feedback else feedback_key
2284
+ # feedback_key = str(uuid.uuid1()) if wait and self._support_feedback else ''
2285
+ self._fb_key_transid_map[feedback_key if feedback_key else 'no_use'] = -1
2286
+ return feedback_key, studio_wait
2287
+
2288
+ def _get_feedback_transid(self, feedback_key, studio_wait=False, is_pop=True):
2289
+ return (self._fb_key_transid_map.pop(feedback_key, -1) if is_pop else self._fb_key_transid_map.get(feedback_key, -1)) if not studio_wait else -1
2290
+
2291
+ def _set_feedback_key_tranid(self, feedback_key, trans_id, feedback_type=0):
2292
+ self._fb_key_transid_map[feedback_key] = trans_id
2293
+ self._fb_transid_type_map[trans_id] = feedback_type
2294
+ self._fb_transid_result_map.pop(trans_id, -1)
2295
+
2296
+ def _wait_feedback(self, timeout=None, trans_id=-1, ignore_log=False):
2297
+ if timeout is not None:
2298
+ expired = time.monotonic() + timeout + (self._sleep_finish_time if self._sleep_finish_time > time.monotonic() else 0)
2299
+ else:
2300
+ expired = 0
2301
+ state5_cnt = 0
2302
+ while timeout is None or time.monotonic() < expired:
2303
+ if not self.connected:
2304
+ self._fb_transid_result_map.clear()
2305
+ if not ignore_log:
2306
+ self.log_api_info('wait_feedback, xarm is disconnect', code=APIState.NOT_CONNECTED)
2307
+ return APIState.NOT_CONNECTED, -1
2308
+ if self.error_code != 0:
2309
+ self._fb_transid_result_map.clear()
2310
+ if not ignore_log:
2311
+ self.log_api_info('wait_feedback, xarm has error, error={}'.format(self.error_code), code=APIState.HAS_ERROR)
2312
+ return APIState.HAS_ERROR, -1
2313
+ code, state = self.get_state()
2314
+ if code != 0:
2315
+ return code, -1
2316
+ if state >= 4:
2317
+ self._sleep_finish_time = 0
2318
+ if state == 5:
2319
+ state5_cnt += 1
2320
+ if state != 5 or state5_cnt >= 20:
2321
+ self._fb_transid_result_map.clear()
2322
+ if not ignore_log:
2323
+ self.log_api_info('wait_feedback, xarm is stop, state={}'.format(state), code=APIState.EMERGENCY_STOP)
2324
+ return APIState.EMERGENCY_STOP, -1
2325
+ else:
2326
+ state5_cnt = 0
2327
+ if trans_id in self._fb_transid_result_map:
2328
+ return 0, self._fb_transid_result_map.pop(trans_id, -1)
2329
+ time.sleep(0.05)
2330
+ return APIState.WAIT_FINISH_TIMEOUT, -1
2331
+
2332
+ def wait_move(self, timeout=None, trans_id=-1, set_cnt=2):
2333
+ if self._support_feedback and trans_id > 0:
2334
+ return self._wait_feedback(timeout, trans_id)[0]
2335
+ if timeout is not None:
2336
+ expired = time.monotonic() + timeout + (self._sleep_finish_time if self._sleep_finish_time > time.monotonic() else 0)
2337
+ else:
2338
+ expired = 0
2339
+ _, state = self.get_state()
2340
+ cnt = 0
2341
+ state5_cnt = 0
2342
+ max_cnt = set_cnt if _ == 0 and state == 1 else 10
2343
+ while timeout is None or time.monotonic() < expired:
2344
+ if not self.connected:
2345
+ self.log_api_info('wait_move, xarm is disconnect', code=APIState.NOT_CONNECTED)
2346
+ return APIState.NOT_CONNECTED
2347
+ if self.error_code != 0:
2348
+ self.log_api_info('wait_move, xarm has error, error={}'.format(self.error_code), code=APIState.HAS_ERROR)
2349
+ return APIState.HAS_ERROR
2350
+ if self.mode != 0 and self.mode != 11:
2351
+ return 0
2352
+ code, state = self.get_state()
2353
+ if code != 0:
2354
+ return code
2355
+ if state >= 4:
2356
+ self._sleep_finish_time = 0
2357
+ if state == 5:
2358
+ state5_cnt += 1
2359
+ if state != 5 or state5_cnt >= 20:
2360
+ self.log_api_info('wait_move, xarm is stop, state={}'.format(state), code=APIState.EMERGENCY_STOP)
2361
+ return APIState.EMERGENCY_STOP
2362
+ else:
2363
+ state5_cnt = 0
2364
+ if time.monotonic() < self._sleep_finish_time or state == 3:
2365
+ cnt = 0
2366
+ max_cnt = 2 if state == 3 else max_cnt
2367
+ time.sleep(0.05)
2368
+ continue
2369
+ if state == 0 or state == 1:
2370
+ cnt = 0
2371
+ max_cnt = set_cnt
2372
+ time.sleep(0.05)
2373
+ continue
2374
+ else:
2375
+ cnt += 1
2376
+ if cnt >= max_cnt:
2377
+ return 0
2378
+ time.sleep(0.05)
2379
+ return APIState.WAIT_FINISH_TIMEOUT
2380
+
2381
+ @xarm_is_connected(_type='set')
2382
+ def _check_modbus_code(self, ret, length=2, only_check_code=False, host_id=XCONF.TGPIO_HOST_ID):
2383
+ code = ret[0]
2384
+ if self._check_code(code) == 0:
2385
+ if not only_check_code:
2386
+ if len(ret) < length:
2387
+ return APIState.MODBUS_ERR_LENG
2388
+ if ret[1] != host_id:
2389
+ return APIState.HOST_ID_ERR
2390
+ if code != 0:
2391
+ if host_id == XCONF.TGPIO_HOST_ID:
2392
+ if self.error_code != 19 and self.error_code != 28:
2393
+ self.get_err_warn_code()
2394
+ if self.error_code != 19 and self.error_code != 28:
2395
+ code = 0
2396
+ else:
2397
+ if self.error_code != 100 + host_id:
2398
+ self.get_err_warn_code()
2399
+ if self.error_code != 100 + host_id:
2400
+ code = 0
2401
+ return code
2402
+
2403
+ @xarm_is_connected(_type='set')
2404
+ def checkset_modbus_baud(self, baudrate, check=True, host_id=XCONF.TGPIO_HOST_ID):
2405
+ if check and (not self._baud_checkset or baudrate <= 0):
2406
+ return 0
2407
+ if check and ((host_id == XCONF.TGPIO_HOST_ID and self.modbus_baud == baudrate) or (host_id == XCONF.LINEER_TRACK_HOST_ID and self.linear_track_baud == baudrate)):
2408
+ return 0
2409
+ if baudrate not in self.arm_cmd.BAUDRATES:
2410
+ return APIState.MODBUS_BAUD_NOT_SUPPORT
2411
+ ret, cur_baud_inx = self._get_modbus_baudrate_inx(host_id=host_id)
2412
+ if ret == 0:
2413
+ baud_inx = self.arm_cmd.BAUDRATES.index(baudrate)
2414
+ if cur_baud_inx != baud_inx:
2415
+ try:
2416
+ self._ignore_error = True
2417
+ self._ignore_state = True if self.state not in [4, 5] else False
2418
+ state = self.state
2419
+ # self.arm_cmd.tgpio_addr_w16(XCONF.ServoConf.MODBUS_BAUDRATE, baud_inx)
2420
+ self.arm_cmd.tgpio_addr_w16(0x1A0B, baud_inx, bid=host_id)
2421
+ time.sleep(0.3)
2422
+ if host_id != XCONF.LINEER_TRACK_HOST_ID:
2423
+ self.arm_cmd.tgpio_addr_w16(XCONF.ServoConf.SOFT_REBOOT, 1, bid=host_id)
2424
+ if host_id == XCONF.TGPIO_HOST_ID:
2425
+ if self.error_code != 19 and self.error_code != 28:
2426
+ self.get_err_warn_code()
2427
+ if self.error_code == 19 or self.error_code == 28:
2428
+ self.clean_error()
2429
+ if self._ignore_state:
2430
+ self.set_state(state if state >= 3 else 0)
2431
+ time.sleep(1)
2432
+ else:
2433
+ if self.error_code != 100 + host_id:
2434
+ self.get_err_warn_code()
2435
+ if self.error_code == 100 + host_id:
2436
+ self.clean_error()
2437
+ if self._ignore_state:
2438
+ self.set_state(state if state >= 3 else 0)
2439
+ time.sleep(1)
2440
+ except Exception as e:
2441
+ self._ignore_error = False
2442
+ self._ignore_state = False
2443
+ logger.error('checkset_modbus_baud error: {}'.format(e))
2444
+ return APIState.API_EXCEPTION
2445
+ self._ignore_error = False
2446
+ self._ignore_state = False
2447
+ ret, cur_baud_inx = self._get_modbus_baudrate_inx(host_id=host_id)
2448
+ self.log_api_info('API -> checkset_modbus_baud -> code={}, baud_inx={}'.format(ret, cur_baud_inx), code=ret)
2449
+ # if ret == 0 and cur_baud_inx < len(self.arm_cmd.BAUDRATES):
2450
+ # self.modbus_baud = self.arm_cmd.BAUDRATES[cur_baud_inx]
2451
+ if host_id == XCONF.TGPIO_HOST_ID:
2452
+ return 0 if self.modbus_baud == baudrate else APIState.MODBUS_BAUD_NOT_CORRECT
2453
+ elif host_id == XCONF.LINEER_TRACK_HOST_ID:
2454
+ return 0 if self.linear_track_baud == baudrate else APIState.MODBUS_BAUD_NOT_CORRECT
2455
+ else:
2456
+ if ret == 0 and 0 <= cur_baud_inx < len(self.arm_cmd.BAUDRATES):
2457
+ return 0 if self.arm_cmd.BAUDRATES[cur_baud_inx] == baudrate else APIState.MODBUS_BAUD_NOT_CORRECT
2458
+ return APIState.MODBUS_BAUD_NOT_CORRECT
2459
+
2460
+ @xarm_is_connected(_type='get')
2461
+ def _get_modbus_baudrate_inx(self, host_id=XCONF.TGPIO_HOST_ID):
2462
+ ret = self.arm_cmd.tgpio_addr_r16(XCONF.ServoConf.MODBUS_BAUDRATE & 0x0FFF, bid=host_id)
2463
+ if ret[0] in [XCONF.UxbusState.ERR_CODE, XCONF.UxbusState.WAR_CODE]:
2464
+ if host_id == XCONF.TGPIO_HOST_ID:
2465
+ if self.error_code != 19 and self.error_code != 28:
2466
+ self.get_err_warn_code()
2467
+ if self.error_code != 19 and self.error_code != 28:
2468
+ ret[0] = 0
2469
+ else:
2470
+ if self.error_code != 100 + host_id:
2471
+ self.get_err_warn_code()
2472
+ if self.error_code != 100 + host_id:
2473
+ ret[0] = 0
2474
+ if ret[0] == 0 and 0 <= ret[1] < len(self.arm_cmd.BAUDRATES):
2475
+ if host_id == XCONF.TGPIO_HOST_ID:
2476
+ self.modbus_baud = self.arm_cmd.BAUDRATES[ret[1]]
2477
+ elif host_id == XCONF.LINEER_TRACK_HOST_ID:
2478
+ self.linear_track_baud = self.arm_cmd.BAUDRATES[ret[1]]
2479
+ return ret[0], ret[1]
2480
+
2481
+ @xarm_is_connected(_type='set')
2482
+ def set_tgpio_modbus_timeout(self, timeout, is_transparent_transmission=False, **kwargs):
2483
+ ret = self.arm_cmd.set_modbus_timeout(timeout, is_transparent_transmission=kwargs.get('is_tt', is_transparent_transmission))
2484
+ self.log_api_info('API -> set_tgpio_modbus_timeout -> code={}'.format(ret[0]), code=ret[0])
2485
+ return ret[0]
2486
+
2487
+ @xarm_is_connected(_type='set')
2488
+ def set_tgpio_modbus_baudrate(self, baud):
2489
+ code = self.checkset_modbus_baud(baud, check=False)
2490
+ self.log_api_info('API -> set_tgpio_modbus_baudrate -> code={}'.format(code), code=code)
2491
+ return code
2492
+
2493
+ @xarm_is_connected(_type='get')
2494
+ def get_tgpio_modbus_baudrate(self):
2495
+ code, baud_inx = self._get_modbus_baudrate_inx()
2496
+ # if code == 0 and baud_inx < len(self.arm_cmd.BAUDRATES):
2497
+ # self.modbus_baud = self.arm_cmd.BAUDRATES[baud_inx]
2498
+ return code, self.modbus_baud
2499
+
2500
+ @xarm_is_connected(_type='set')
2501
+ def set_control_modbus_baudrate(self, baud):
2502
+ code = self.checkset_modbus_baud(baud, check=False, host_id=XCONF.LINEER_TRACK_HOST_ID)
2503
+ self.log_api_info('API -> set_control_modbus_baudrate -> code={}'.format(code), code=code)
2504
+ return code
2505
+
2506
+ def getset_tgpio_modbus_data(self, datas, min_res_len=0, ignore_log=False, host_id=XCONF.TGPIO_HOST_ID, is_transparent_transmission=False, use_503_port=False, **kwargs):
2507
+ if not self.connected:
2508
+ return APIState.NOT_CONNECTED, []
2509
+ is_tt = kwargs.get('is_tt', is_transparent_transmission)
2510
+ if is_tt:
2511
+ if use_503_port:
2512
+ if not self.connected_503 and self.connect_503() != 0:
2513
+ return APIState.NOT_CONNECTED, []
2514
+ ret = self.arm_cmd_503.tgpio_set_modbus(datas, len(datas), host_id=host_id, is_transparent_transmission=True)
2515
+ else:
2516
+ ret = self.arm_cmd.tgpio_set_modbus(datas, len(datas), host_id=host_id, is_transparent_transmission=True)
2517
+ else:
2518
+ ret = self.arm_cmd.tgpio_set_modbus(datas, len(datas), host_id=host_id)
2519
+ ret[0] = self._check_modbus_code(ret, min_res_len + 2, host_id=host_id)
2520
+ if not ignore_log:
2521
+ self.log_api_info('API -> getset_tgpio_modbus_data -> code={}, response={}'.format(ret[0], ret[2:]), code=ret[0])
2522
+ return ret[0], ret[2:]
2523
+
2524
+ @xarm_is_connected(_type='set')
2525
+ def set_simulation_robot(self, on_off):
2526
+ ret = self.arm_cmd.set_simulation_robot(on_off)
2527
+ ret[0] = self._check_code(ret[0])
2528
+ self.log_api_info('API -> set_simulation_robot({}) -> code={}'.format(on_off, ret[0]), code=ret[0])
2529
+ return ret[0]
2530
+
2531
+ @xarm_wait_until_not_pause
2532
+ @xarm_wait_until_cmdnum_lt_max
2533
+ @xarm_is_ready(_type='set')
2534
+ def set_tcp_load(self, weight, center_of_gravity, wait=False, **kwargs):
2535
+ if compare_version(self.version_number, (0, 2, 0)):
2536
+ _center_of_gravity = center_of_gravity
2537
+ else:
2538
+ _center_of_gravity = [item / 1000.0 for item in center_of_gravity]
2539
+ feedback_key, studio_wait = self._gen_feedback_key(wait, **kwargs)
2540
+ ret = self.arm_cmd.set_tcp_load(weight, _center_of_gravity, feedback_key=feedback_key)
2541
+ trans_id = self._get_feedback_transid(feedback_key, studio_wait)
2542
+ ret[0] = self._check_code(ret[0], is_move_cmd=True)
2543
+ self.log_api_info('API -> set_tcp_load -> code={}, weight={}, center={}'.format(ret[0], weight, _center_of_gravity), code=ret[0])
2544
+ if wait and ret[0] == 0:
2545
+ return self.wait_move(None, trans_id=trans_id)
2546
+ return ret[0]
2547
+
2548
+ def set_only_check_type(self, only_check_type):
2549
+ self._only_check_type = only_check_type if only_check_type in [0, 1, 2, 3] else 0
2550
+
2551
+ def get_dh_params(self):
2552
+ ret = self.arm_cmd.get_dh_params()
2553
+ ret[0] = self._check_code(ret[0])
2554
+ return ret[0], ret[1:]
2555
+
2556
+ def set_dh_params(self, dh_params, flag=0):
2557
+ if len(dh_params) < 28:
2558
+ dh_params.extend([0] * (28 - len(dh_params)))
2559
+ ret = self.arm_cmd.set_dh_params(dh_params, flag)
2560
+ ret[0] = self._check_code(ret[0])
2561
+ return ret[0]
2562
+
2563
+ def _feedback_thread_handle(self):
2564
+ while self.connected:
2565
+ try:
2566
+ data = self._feedback_que.get(timeout=1)
2567
+ except:
2568
+ continue
2569
+ self._feedback_callback(data)
2570
+
2571
+ def _feedback_callback(self, data):
2572
+ trans_id = convert.bytes_to_u16(data[0:2])
2573
+ feedback_type = self._fb_transid_type_map.pop(trans_id, -1)
2574
+ if feedback_type != -1:
2575
+ self._fb_transid_result_map[trans_id] = data[12] # feedback_code
2576
+ if feedback_type & data[8] == 0:
2577
+ return
2578
+ self.__report_callback(self.FEEDBACK_ID, data, name='feedback')
2579
+
2580
+ def set_feedback_type(self, feedback_type):
2581
+ if not self._support_feedback:
2582
+ return APIState.CMD_NOT_EXIST
2583
+ ret = self.arm_cmd.set_feedback_type(feedback_type)
2584
+ ret[0] = self._check_code(ret[0])
2585
+ return ret[0]
2586
+
2587
+ def set_common_param(self, param_type, param_val):
2588
+ ret = self.arm_cmd.set_common_param(param_type, param_val)
2589
+ ret[0] = self._check_code(ret[0])
2590
+ return ret[0]
2591
+
2592
+ def get_common_param(self, param_type, return_val=True):
2593
+ ret = self.arm_cmd.get_common_param(param_type)
2594
+ ret[0] = self._check_code(ret[0])
2595
+ return ret[0], ret[1] if return_val else ret[1:]
2596
+
2597
+ def get_common_info(self, param_type, return_val=True):
2598
+ ret = self.arm_cmd.get_common_info(param_type)
2599
+ ret[0] = self._check_code(ret[0])
2600
+ return ret[0], ret[1] if return_val else ret[1:]
2601
+
2602
+ def get_traj_speeding(self, rate):
2603
+ ret = self.arm_cmd.get_traj_speeding(rate)
2604
+ ret[0] = self._check_code(ret[0])
2605
+ return ret[0], ret[1:]
2606
+
2607
+ def set_ft_collision_detection(self, on_off):
2608
+ return self.set_common_param(11, int(on_off))
2609
+
2610
+ def set_ft_collision_rebound(self, on_off):
2611
+ return self.set_common_param(13, int(on_off))
2612
+
2613
+ def set_ft_collision_threshold(self, thresholds):
2614
+ assert isinstance(thresholds, Iterable) and len(thresholds) >= 6
2615
+ return self.set_common_param(12, thresholds)
2616
+
2617
+ def set_ft_collision_reb_distance(self, distances, is_radian=None):
2618
+ assert isinstance(distances, Iterable) and len(distances) >= 6
2619
+ is_radian = self._default_is_radian if is_radian is None else is_radian
2620
+ if not is_radian:
2621
+ distances[3:6] = list(map(lambda x: float('{}'.format(math.radians(x))), distances[3:6]))
2622
+ return self.set_common_param(14, distances)
2623
+
2624
+ def get_ft_collision_detection(self):
2625
+ return self.get_common_param(11)
2626
+
2627
+ def get_ft_collision_rebound(self):
2628
+ return self.get_common_param(13)
2629
+
2630
+ def get_ft_collision_threshold(self):
2631
+ return self.get_common_param(12)
2632
+
2633
+ def get_ft_collision_reb_distance(self, is_radian=None):
2634
+ ret = self.get_common_param(14)
2635
+ is_radian = self._default_is_radian if is_radian is None else is_radian
2636
+ if ret[0] == 0 and not is_radian:
2637
+ ret[1][3:6] = list(map(lambda x: float('{:.6f}'.format(math.degrees(x))), ret[1][3:6]))
2638
+ return ret