xarm-python-sdk 1.15.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- xarm/__init__.py +2 -0
- xarm/build_backend.py +17 -0
- xarm/core/__init__.py +2 -0
- xarm/core/comm/__init__.py +5 -0
- xarm/core/comm/base.py +303 -0
- xarm/core/comm/serial_port.py +44 -0
- xarm/core/comm/socket_port.py +150 -0
- xarm/core/comm/uxbus_cmd_protocol.py +100 -0
- xarm/core/config/__init__.py +0 -0
- xarm/core/config/x_code.py +1427 -0
- xarm/core/config/x_config.py +553 -0
- xarm/core/utils/__init__.py +3 -0
- xarm/core/utils/convert.py +124 -0
- xarm/core/utils/crc16.py +76 -0
- xarm/core/utils/debug_print.py +21 -0
- xarm/core/utils/log.py +98 -0
- xarm/core/version.py +1 -0
- xarm/core/wrapper/__init__.py +11 -0
- xarm/core/wrapper/uxbus_cmd.py +1457 -0
- xarm/core/wrapper/uxbus_cmd_ser.py +94 -0
- xarm/core/wrapper/uxbus_cmd_tcp.py +305 -0
- xarm/tools/__init__.py +0 -0
- xarm/tools/blockly/__init__.py +1 -0
- xarm/tools/blockly/_blockly_base.py +416 -0
- xarm/tools/blockly/_blockly_handler.py +1338 -0
- xarm/tools/blockly/_blockly_highlight.py +94 -0
- xarm/tools/blockly/_blockly_node.py +61 -0
- xarm/tools/blockly/_blockly_tool.py +480 -0
- xarm/tools/blockly_tool.py +1864 -0
- xarm/tools/gcode.py +90 -0
- xarm/tools/list_ports.py +39 -0
- xarm/tools/modbus_tcp.py +205 -0
- xarm/tools/threads.py +30 -0
- xarm/tools/utils.py +36 -0
- xarm/version.py +1 -0
- xarm/wrapper/__init__.py +1 -0
- xarm/wrapper/studio_api.py +34 -0
- xarm/wrapper/xarm_api.py +4416 -0
- xarm/x3/__init__.py +2 -0
- xarm/x3/base.py +2638 -0
- xarm/x3/base_board.py +198 -0
- xarm/x3/code.py +62 -0
- xarm/x3/decorator.py +104 -0
- xarm/x3/events.py +166 -0
- xarm/x3/ft_sensor.py +264 -0
- xarm/x3/gpio.py +457 -0
- xarm/x3/grammar_async.py +21 -0
- xarm/x3/grammar_coroutine.py +24 -0
- xarm/x3/gripper.py +830 -0
- xarm/x3/modbus_tcp.py +84 -0
- xarm/x3/parse.py +110 -0
- xarm/x3/record.py +216 -0
- xarm/x3/report.py +204 -0
- xarm/x3/robotiq.py +220 -0
- xarm/x3/servo.py +485 -0
- xarm/x3/studio.py +138 -0
- xarm/x3/track.py +424 -0
- xarm/x3/utils.py +43 -0
- xarm/x3/xarm.py +1928 -0
- xarm_python_sdk-1.15.2.dist-info/METADATA +103 -0
- xarm_python_sdk-1.15.2.dist-info/RECORD +63 -0
- xarm_python_sdk-1.15.2.dist-info/WHEEL +4 -0
- xarm_python_sdk-1.15.2.dist-info/licenses/LICENSE +27 -0
xarm/x3/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
|