kuavo-humanoid-sdk 1.1.3a1252__py3-none-any.whl → 1.1.5__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.
Potentially problematic release.
This version of kuavo-humanoid-sdk might be problematic. Click here for more details.
- kuavo_humanoid_sdk/__init__.py +2 -0
- kuavo_humanoid_sdk/interfaces/data_types.py +44 -0
- kuavo_humanoid_sdk/kuavo/core/core.py +226 -20
- kuavo_humanoid_sdk/kuavo/core/ros/control.py +447 -13
- kuavo_humanoid_sdk/kuavo/core/ros/state.py +228 -5
- kuavo_humanoid_sdk/kuavo/core/ros/vision.py +13 -252
- kuavo_humanoid_sdk/kuavo/robot.py +108 -6
- kuavo_humanoid_sdk/kuavo/robot_arm.py +53 -7
- kuavo_humanoid_sdk/kuavo/robot_head.py +10 -0
- kuavo_humanoid_sdk/kuavo/robot_state.py +35 -2
- kuavo_humanoid_sdk/kuavo_strategy/__init__.py +2 -0
- kuavo_humanoid_sdk/kuavo_strategy/grasp_box/grasp_box_strategy.py +418 -0
- kuavo_humanoid_sdk/kuavo_strategy/kuavo_strategy.py +63 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_twoArmHandPoseCmd.py +20 -16
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/__init__.py +1 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_setMmCtrlFrame.py +273 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_twoArmHandPoseCmdSrv.py +15 -14
- {kuavo_humanoid_sdk-1.1.3a1252.dist-info → kuavo_humanoid_sdk-1.1.5.dist-info}/METADATA +1 -1
- {kuavo_humanoid_sdk-1.1.3a1252.dist-info → kuavo_humanoid_sdk-1.1.5.dist-info}/RECORD +21 -17
- {kuavo_humanoid_sdk-1.1.3a1252.dist-info → kuavo_humanoid_sdk-1.1.5.dist-info}/WHEEL +0 -0
- {kuavo_humanoid_sdk-1.1.3a1252.dist-info → kuavo_humanoid_sdk-1.1.5.dist-info}/top_level.txt +0 -0
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import roslibpy
|
|
2
|
-
import copy
|
|
3
2
|
import time
|
|
4
3
|
from typing import Tuple
|
|
5
4
|
|
|
@@ -14,12 +13,14 @@ try:
|
|
|
14
13
|
except:
|
|
15
14
|
pass
|
|
16
15
|
|
|
17
|
-
from kuavo_humanoid_sdk.interfaces.data_types import (KuavoImuData, KuavoJointData, KuavoOdometry,
|
|
18
|
-
KuavoArmCtrlMode, EndEffectorState, KuavoDexHandTouchState
|
|
16
|
+
from kuavo_humanoid_sdk.interfaces.data_types import (KuavoImuData, KuavoJointData, KuavoOdometry, KuavoManipulationMpcFrame,
|
|
17
|
+
KuavoArmCtrlMode, EndEffectorState, KuavoDexHandTouchState,
|
|
18
|
+
KuavoManipulationMpcCtrlMode, KuavoManipulationMpcControlFlow)
|
|
19
19
|
from kuavo_humanoid_sdk.kuavo.core.ros.param import make_robot_param, EndEffectorType
|
|
20
20
|
from kuavo_humanoid_sdk.common.logger import SDKLogger
|
|
21
21
|
from kuavo_humanoid_sdk.common.websocket_kuavo_sdk import WebSocketKuavoSDK
|
|
22
|
-
|
|
22
|
+
from kuavo_humanoid_sdk.msg.kuavo_msgs.srv import (changeArmCtrlMode, changeArmCtrlModeRequest,setMmCtrlFrame, setMmCtrlFrameRequest,
|
|
23
|
+
changeTorsoCtrlMode, changeTorsoCtrlModeRequest)
|
|
23
24
|
from collections import deque
|
|
24
25
|
from typing import Tuple, Optional
|
|
25
26
|
|
|
@@ -157,6 +158,11 @@ class KuavoRobotStateCore:
|
|
|
157
158
|
self._arm_ctrl_mode = self._srv_get_arm_ctrl_mode()
|
|
158
159
|
self._initialized = True
|
|
159
160
|
|
|
161
|
+
# 获取manipulation mpc 相关参数
|
|
162
|
+
self._manipulation_mpc_frame = self._srv_get_manipulation_mpc_frame()
|
|
163
|
+
self._manipulation_mpc_ctrl_mode = self._srv_get_manipulation_mpc_ctrl_mode()
|
|
164
|
+
self._manipulation_mpc_control_flow = self._srv_get_manipulation_mpc_control_flow()
|
|
165
|
+
|
|
160
166
|
@property
|
|
161
167
|
def com_height(self)->float:
|
|
162
168
|
# odom.position.z - terrain_height = com_height
|
|
@@ -181,6 +187,27 @@ class KuavoRobotStateCore:
|
|
|
181
187
|
self._arm_ctrl_mode = mode
|
|
182
188
|
return self._arm_ctrl_mode
|
|
183
189
|
|
|
190
|
+
@property
|
|
191
|
+
def manipulation_mpc_ctrl_mode(self)->KuavoManipulationMpcCtrlMode:
|
|
192
|
+
mode = self._srv_get_manipulation_mpc_ctrl_mode()
|
|
193
|
+
if mode is not None:
|
|
194
|
+
self._manipulation_mpc_ctrl_mode = mode
|
|
195
|
+
return self._manipulation_mpc_ctrl_mode
|
|
196
|
+
|
|
197
|
+
@property
|
|
198
|
+
def manipulation_mpc_frame(self)->KuavoManipulationMpcFrame:
|
|
199
|
+
frame = self._srv_get_manipulation_mpc_frame()
|
|
200
|
+
if frame is not None:
|
|
201
|
+
self._manipulation_mpc_frame = frame
|
|
202
|
+
return self._manipulation_mpc_frame
|
|
203
|
+
|
|
204
|
+
@property
|
|
205
|
+
def manipulation_mpc_control_flow(self)->KuavoManipulationMpcControlFlow:
|
|
206
|
+
flow = self._srv_get_manipulation_mpc_control_flow()
|
|
207
|
+
if flow is not None:
|
|
208
|
+
self._manipulation_mpc_control_flow = flow
|
|
209
|
+
return self._manipulation_mpc_control_flow
|
|
210
|
+
|
|
184
211
|
@property
|
|
185
212
|
def eef_state(self)->Tuple[EndEffectorState, EndEffectorState]:
|
|
186
213
|
return self._eef_state
|
|
@@ -387,6 +414,194 @@ class KuavoRobotStateCore:
|
|
|
387
414
|
SDKLogger.error(f"Service call failed: {e}")
|
|
388
415
|
return None
|
|
389
416
|
|
|
417
|
+
def _srv_get_manipulation_mpc_ctrl_mode(self, )->KuavoManipulationMpcCtrlMode:
|
|
418
|
+
try:
|
|
419
|
+
service_name = '/mobile_manipulator_get_mpc_control_mode'
|
|
420
|
+
rospy.wait_for_service(service_name, timeout=2.0)
|
|
421
|
+
get_mode_srv = rospy.ServiceProxy(service_name, changeTorsoCtrlMode)
|
|
422
|
+
|
|
423
|
+
req = changeTorsoCtrlModeRequest()
|
|
424
|
+
|
|
425
|
+
resp = get_mode_srv(req)
|
|
426
|
+
if not resp.result:
|
|
427
|
+
SDKLogger.error(f"Failed to get manipulation mpc control mode: {resp.message}")
|
|
428
|
+
return KuavoManipulationMpcCtrlMode.ERROR
|
|
429
|
+
return KuavoManipulationMpcCtrlMode(resp.mode)
|
|
430
|
+
except rospy.ServiceException as e:
|
|
431
|
+
SDKLogger.error(f"Service call to {service_name} failed: {e}")
|
|
432
|
+
except rospy.ROSException as e: # For timeout from wait_for_service
|
|
433
|
+
SDKLogger.error(f"Failed to connect to service {service_name}: {e}")
|
|
434
|
+
except Exception as e:
|
|
435
|
+
SDKLogger.error(f"Failed to get manipulation mpc control mode: {e}")
|
|
436
|
+
return KuavoManipulationMpcCtrlMode.ERROR
|
|
437
|
+
|
|
438
|
+
def _srv_get_manipulation_mpc_frame(self, )->KuavoManipulationMpcFrame:
|
|
439
|
+
try:
|
|
440
|
+
service_name = '/get_mm_ctrl_frame'
|
|
441
|
+
rospy.wait_for_service(service_name, timeout=2.0)
|
|
442
|
+
get_frame_srv = rospy.ServiceProxy(service_name, setMmCtrlFrame)
|
|
443
|
+
|
|
444
|
+
req = setMmCtrlFrameRequest()
|
|
445
|
+
|
|
446
|
+
resp = get_frame_srv(req)
|
|
447
|
+
if not resp.result:
|
|
448
|
+
SDKLogger.error(f"Failed to get manipulation mpc frame: {resp.message}")
|
|
449
|
+
return KuavoManipulationMpcFrame.ERROR
|
|
450
|
+
return KuavoManipulationMpcFrame(resp.currentFrame)
|
|
451
|
+
except rospy.ServiceException as e:
|
|
452
|
+
SDKLogger.error(f"Service call to {service_name} failed: {e}")
|
|
453
|
+
except rospy.ROSException as e: # For timeout from wait_for_service
|
|
454
|
+
SDKLogger.error(f"Failed to connect to service {service_name}: {e}")
|
|
455
|
+
except Exception as e:
|
|
456
|
+
SDKLogger.error(f"Failed to get manipulation mpc frame: {e}")
|
|
457
|
+
return KuavoManipulationMpcFrame.ERROR
|
|
458
|
+
|
|
459
|
+
def _srv_get_manipulation_mpc_control_flow(self, )->KuavoManipulationMpcControlFlow:
|
|
460
|
+
try:
|
|
461
|
+
service_name = '/get_mm_wbc_arm_trajectory_control'
|
|
462
|
+
rospy.wait_for_service(service_name, timeout=2.0)
|
|
463
|
+
get_mode_srv = rospy.ServiceProxy(service_name, changeArmCtrlMode)
|
|
464
|
+
|
|
465
|
+
req = changeArmCtrlModeRequest()
|
|
466
|
+
|
|
467
|
+
resp = get_mode_srv(req)
|
|
468
|
+
if not resp.result:
|
|
469
|
+
SDKLogger.error(f"Failed to get manipulation mpc wbc arm trajectory control mode: {resp.message}")
|
|
470
|
+
return KuavoManipulationMpcControlFlow.Error
|
|
471
|
+
return KuavoManipulationMpcControlFlow(resp.mode)
|
|
472
|
+
except rospy.ServiceException as e:
|
|
473
|
+
SDKLogger.error(f"Service call to {service_name} failed: {e}")
|
|
474
|
+
except rospy.ROSException as e: # For timeout from wait_for_service
|
|
475
|
+
SDKLogger.error(f"Failed to connect to service {service_name}: {e}")
|
|
476
|
+
except Exception as e:
|
|
477
|
+
SDKLogger.error(f"Failed to get manipulation mpc wbc arm trajectory control mode: {e}")
|
|
478
|
+
return KuavoManipulationMpcControlFlow.Error
|
|
479
|
+
|
|
480
|
+
def _srv_get_manipulation_mpc_ctrl_mode(self, )->KuavoManipulationMpcCtrlMode:
|
|
481
|
+
try:
|
|
482
|
+
service_name = '/mobile_manipulator_get_mpc_control_mode'
|
|
483
|
+
rospy.wait_for_service(service_name, timeout=2.0)
|
|
484
|
+
get_mode_srv = rospy.ServiceProxy(service_name, changeTorsoCtrlMode)
|
|
485
|
+
|
|
486
|
+
req = changeTorsoCtrlModeRequest()
|
|
487
|
+
|
|
488
|
+
resp = get_mode_srv(req)
|
|
489
|
+
if not resp.result:
|
|
490
|
+
SDKLogger.error(f"Failed to get manipulation mpc control mode: {resp.message}")
|
|
491
|
+
return KuavoManipulationMpcCtrlMode.ERROR
|
|
492
|
+
return KuavoManipulationMpcCtrlMode(resp.mode)
|
|
493
|
+
except rospy.ServiceException as e:
|
|
494
|
+
SDKLogger.error(f"Service call to {service_name} failed: {e}")
|
|
495
|
+
except rospy.ROSException as e: # For timeout from wait_for_service
|
|
496
|
+
SDKLogger.error(f"Failed to connect to service {service_name}: {e}")
|
|
497
|
+
except Exception as e:
|
|
498
|
+
SDKLogger.error(f"Failed to get manipulation mpc control mode: {e}")
|
|
499
|
+
return KuavoManipulationMpcCtrlMode.ERROR
|
|
500
|
+
|
|
501
|
+
def _srv_get_manipulation_mpc_frame(self, )->KuavoManipulationMpcFrame:
|
|
502
|
+
try:
|
|
503
|
+
service_name = '/get_mm_ctrl_frame'
|
|
504
|
+
rospy.wait_for_service(service_name, timeout=2.0)
|
|
505
|
+
get_frame_srv = rospy.ServiceProxy(service_name, setMmCtrlFrame)
|
|
506
|
+
|
|
507
|
+
req = setMmCtrlFrameRequest()
|
|
508
|
+
|
|
509
|
+
resp = get_frame_srv(req)
|
|
510
|
+
if not resp.result:
|
|
511
|
+
SDKLogger.error(f"Failed to get manipulation mpc frame: {resp.message}")
|
|
512
|
+
return KuavoManipulationMpcFrame.ERROR
|
|
513
|
+
return KuavoManipulationMpcFrame(resp.currentFrame)
|
|
514
|
+
except rospy.ServiceException as e:
|
|
515
|
+
SDKLogger.error(f"Service call to {service_name} failed: {e}")
|
|
516
|
+
except rospy.ROSException as e: # For timeout from wait_for_service
|
|
517
|
+
SDKLogger.error(f"Failed to connect to service {service_name}: {e}")
|
|
518
|
+
except Exception as e:
|
|
519
|
+
SDKLogger.error(f"Failed to get manipulation mpc frame: {e}")
|
|
520
|
+
return KuavoManipulationMpcFrame.ERROR
|
|
521
|
+
|
|
522
|
+
def _srv_get_manipulation_mpc_control_flow(self, )->KuavoManipulationMpcControlFlow:
|
|
523
|
+
try:
|
|
524
|
+
service_name = '/get_mm_wbc_arm_trajectory_control'
|
|
525
|
+
rospy.wait_for_service(service_name, timeout=2.0)
|
|
526
|
+
get_mode_srv = rospy.ServiceProxy(service_name, changeArmCtrlMode)
|
|
527
|
+
|
|
528
|
+
req = changeArmCtrlModeRequest()
|
|
529
|
+
|
|
530
|
+
resp = get_mode_srv(req)
|
|
531
|
+
if not resp.result:
|
|
532
|
+
SDKLogger.error(f"Failed to get manipulation mpc wbc arm trajectory control mode: {resp.message}")
|
|
533
|
+
return KuavoManipulationMpcControlFlow.Error
|
|
534
|
+
return KuavoManipulationMpcControlFlow(resp.mode)
|
|
535
|
+
except rospy.ServiceException as e:
|
|
536
|
+
SDKLogger.error(f"Service call to {service_name} failed: {e}")
|
|
537
|
+
except rospy.ROSException as e: # For timeout from wait_for_service
|
|
538
|
+
SDKLogger.error(f"Failed to connect to service {service_name}: {e}")
|
|
539
|
+
except Exception as e:
|
|
540
|
+
SDKLogger.error(f"Failed to get manipulation mpc wbc arm trajectory control mode: {e}")
|
|
541
|
+
return KuavoManipulationMpcControlFlow.Error
|
|
542
|
+
|
|
543
|
+
def _srv_get_manipulation_mpc_ctrl_mode(self, )->KuavoManipulationMpcCtrlMode:
|
|
544
|
+
try:
|
|
545
|
+
service_name = '/mobile_manipulator_get_mpc_control_mode'
|
|
546
|
+
rospy.wait_for_service(service_name, timeout=2.0)
|
|
547
|
+
get_mode_srv = rospy.ServiceProxy(service_name, changeTorsoCtrlMode)
|
|
548
|
+
|
|
549
|
+
req = changeTorsoCtrlModeRequest()
|
|
550
|
+
|
|
551
|
+
resp = get_mode_srv(req)
|
|
552
|
+
if not resp.result:
|
|
553
|
+
SDKLogger.error(f"Failed to get manipulation mpc control mode: {resp.message}")
|
|
554
|
+
return KuavoManipulationMpcCtrlMode.ERROR
|
|
555
|
+
return KuavoManipulationMpcCtrlMode(resp.mode)
|
|
556
|
+
except rospy.ServiceException as e:
|
|
557
|
+
SDKLogger.error(f"Service call to {service_name} failed: {e}")
|
|
558
|
+
except rospy.ROSException as e: # For timeout from wait_for_service
|
|
559
|
+
SDKLogger.error(f"Failed to connect to service {service_name}: {e}")
|
|
560
|
+
except Exception as e:
|
|
561
|
+
SDKLogger.error(f"Failed to get manipulation mpc control mode: {e}")
|
|
562
|
+
return KuavoManipulationMpcCtrlMode.ERROR
|
|
563
|
+
|
|
564
|
+
def _srv_get_manipulation_mpc_frame(self, )->KuavoManipulationMpcFrame:
|
|
565
|
+
try:
|
|
566
|
+
service_name = '/get_mm_ctrl_frame'
|
|
567
|
+
rospy.wait_for_service(service_name, timeout=2.0)
|
|
568
|
+
get_frame_srv = rospy.ServiceProxy(service_name, setMmCtrlFrame)
|
|
569
|
+
|
|
570
|
+
req = setMmCtrlFrameRequest()
|
|
571
|
+
|
|
572
|
+
resp = get_frame_srv(req)
|
|
573
|
+
if not resp.result:
|
|
574
|
+
SDKLogger.error(f"Failed to get manipulation mpc frame: {resp.message}")
|
|
575
|
+
return KuavoManipulationMpcFrame.ERROR
|
|
576
|
+
return KuavoManipulationMpcFrame(resp.currentFrame)
|
|
577
|
+
except rospy.ServiceException as e:
|
|
578
|
+
SDKLogger.error(f"Service call to {service_name} failed: {e}")
|
|
579
|
+
except rospy.ROSException as e: # For timeout from wait_for_service
|
|
580
|
+
SDKLogger.error(f"Failed to connect to service {service_name}: {e}")
|
|
581
|
+
except Exception as e:
|
|
582
|
+
SDKLogger.error(f"Failed to get manipulation mpc frame: {e}")
|
|
583
|
+
return KuavoManipulationMpcFrame.ERROR
|
|
584
|
+
|
|
585
|
+
def _srv_get_manipulation_mpc_control_flow(self, )->KuavoManipulationMpcControlFlow:
|
|
586
|
+
try:
|
|
587
|
+
service_name = '/get_mm_wbc_arm_trajectory_control'
|
|
588
|
+
rospy.wait_for_service(service_name, timeout=2.0)
|
|
589
|
+
get_mode_srv = rospy.ServiceProxy(service_name, changeArmCtrlMode)
|
|
590
|
+
|
|
591
|
+
req = changeArmCtrlModeRequest()
|
|
592
|
+
|
|
593
|
+
resp = get_mode_srv(req)
|
|
594
|
+
if not resp.result:
|
|
595
|
+
SDKLogger.error(f"Failed to get manipulation mpc wbc arm trajectory control mode: {resp.message}")
|
|
596
|
+
return KuavoManipulationMpcControlFlow.Error
|
|
597
|
+
return KuavoManipulationMpcControlFlow(resp.mode)
|
|
598
|
+
except rospy.ServiceException as e:
|
|
599
|
+
SDKLogger.error(f"Service call to {service_name} failed: {e}")
|
|
600
|
+
except rospy.ROSException as e: # For timeout from wait_for_service
|
|
601
|
+
SDKLogger.error(f"Failed to connect to service {service_name}: {e}")
|
|
602
|
+
except Exception as e:
|
|
603
|
+
SDKLogger.error(f"Failed to get manipulation mpc wbc arm trajectory control mode: {e}")
|
|
604
|
+
return KuavoManipulationMpcControlFlow.Error
|
|
390
605
|
class KuavoRobotStateCoreWebsocket:
|
|
391
606
|
_instance = None
|
|
392
607
|
|
|
@@ -691,4 +906,12 @@ class KuavoRobotStateCoreWebsocket:
|
|
|
691
906
|
return None
|
|
692
907
|
except Exception as e:
|
|
693
908
|
SDKLogger.error(f"Service call failed: {e}")
|
|
694
|
-
return None
|
|
909
|
+
return None
|
|
910
|
+
|
|
911
|
+
|
|
912
|
+
if __name__ == "__main__":
|
|
913
|
+
state = KuavoRobotStateCore()
|
|
914
|
+
print(state.manipulation_mpc_frame)
|
|
915
|
+
print(state.manipulation_mpc_control_flow)
|
|
916
|
+
print(state.manipulation_mpc_ctrl_mode)
|
|
917
|
+
print(state.arm_control_mode)
|
|
@@ -9,8 +9,6 @@ from typing import Tuple, Optional
|
|
|
9
9
|
from kuavo_humanoid_sdk.kuavo.core.ros.param import make_robot_param, EndEffectorType
|
|
10
10
|
from kuavo_humanoid_sdk.common.logger import SDKLogger
|
|
11
11
|
from kuavo_humanoid_sdk.interfaces.data_types import (AprilTagData)
|
|
12
|
-
import roslibpy
|
|
13
|
-
from kuavo_humanoid_sdk.common.websocket_kuavo_sdk import WebSocketKuavoSDK
|
|
14
12
|
|
|
15
13
|
try:
|
|
16
14
|
import rospy
|
|
@@ -36,16 +34,16 @@ class KuavoRobotVisionCore:
|
|
|
36
34
|
def __init__(self):
|
|
37
35
|
"""Initializes vision system components including TF and AprilTag subscribers."""
|
|
38
36
|
if not hasattr(self, '_initialized'):
|
|
37
|
+
# Initialize TF components
|
|
39
38
|
self.tf_buffer = tf2_ros.Buffer()
|
|
40
39
|
self.tf_listener = tf2_ros.TransformListener(self.tf_buffer)
|
|
41
40
|
self.tf_broadcaster = tf2_ros.TransformBroadcaster()
|
|
42
|
-
|
|
43
|
-
self._apriltag_data_base_sub = rospy.Subscriber('/robot_tag_info', AprilTagDetectionArray, self._apriltag_data_callback_base)
|
|
44
|
-
|
|
41
|
+
|
|
45
42
|
# 添加TF2监听器
|
|
46
43
|
self._tf_buffer = tf2_ros.Buffer()
|
|
47
44
|
self._tf_listener = tf2_ros.TransformListener(self._tf_buffer)
|
|
48
45
|
|
|
46
|
+
# FIRST: Initialize data structures before creating subscribers
|
|
49
47
|
""" data """
|
|
50
48
|
self._apriltag_data_from_camera = AprilTagData(
|
|
51
49
|
id = [],
|
|
@@ -64,6 +62,13 @@ class KuavoRobotVisionCore:
|
|
|
64
62
|
size = [],
|
|
65
63
|
pose = []
|
|
66
64
|
)
|
|
65
|
+
|
|
66
|
+
# THEN: Create subscribers after all data structures are initialized
|
|
67
|
+
self._apriltag_data_camera_sub = rospy.Subscriber('/tag_detections', AprilTagDetectionArray, self._apriltag_data_callback_camera)
|
|
68
|
+
self._apriltag_data_base_sub = rospy.Subscriber('/robot_tag_info', AprilTagDetectionArray, self._apriltag_data_callback_base)
|
|
69
|
+
|
|
70
|
+
# Mark as initialized
|
|
71
|
+
self._initialized = True
|
|
67
72
|
|
|
68
73
|
def _apriltag_data_callback_camera(self, data):
|
|
69
74
|
"""Callback for processing AprilTag detections from camera.
|
|
@@ -149,7 +154,7 @@ class KuavoRobotVisionCore:
|
|
|
149
154
|
|
|
150
155
|
# 如果base数据为空,则不处理
|
|
151
156
|
if not self._apriltag_data_from_base.id:
|
|
152
|
-
SDKLogger.warn("No base tag data, skip transform")
|
|
157
|
+
# SDKLogger.warn("No base tag data, skip transform")
|
|
153
158
|
return
|
|
154
159
|
|
|
155
160
|
try:
|
|
@@ -248,7 +253,7 @@ class KuavoRobotVisionCore:
|
|
|
248
253
|
}
|
|
249
254
|
|
|
250
255
|
if data_source not in data_map:
|
|
251
|
-
SDKLogger.error(f"Invalid data source: {data_source}, must be one of {list(data_map.keys())}")
|
|
256
|
+
# SDKLogger.error(f"Invalid data source: {data_source}, must be one of {list(data_map.keys())}")
|
|
252
257
|
return None
|
|
253
258
|
|
|
254
259
|
data = data_map[data_source]
|
|
@@ -257,253 +262,9 @@ class KuavoRobotVisionCore:
|
|
|
257
262
|
indices = [i for i, tag_id in enumerate(data.id) if tag_id == target_id]
|
|
258
263
|
|
|
259
264
|
if not indices:
|
|
260
|
-
SDKLogger.debug(f"No data found for tag ID {target_id} in {data_source} source")
|
|
261
|
-
return None
|
|
262
|
-
|
|
263
|
-
return {
|
|
264
|
-
"sizes": [data.size[i] for i in indices],
|
|
265
|
-
"poses": [data.pose[i] for i in indices]
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
class KuavoRobotVisionCoreWebsocket:
|
|
269
|
-
_instance = None
|
|
270
|
-
|
|
271
|
-
def __new__(cls, *args, **kwargs):
|
|
272
|
-
if not cls._instance:
|
|
273
|
-
cls._instance = super().__new__(cls)
|
|
274
|
-
return cls._instance
|
|
275
|
-
|
|
276
|
-
def __init__(self):
|
|
277
|
-
if not hasattr(self, '_initialized'):
|
|
278
|
-
try:
|
|
279
|
-
self.websocket = WebSocketKuavoSDK()
|
|
280
|
-
if not self.websocket.client.is_connected:
|
|
281
|
-
SDKLogger.error("Failed to connect to WebSocket server")
|
|
282
|
-
raise ConnectionError("Failed to connect to WebSocket server")
|
|
283
|
-
|
|
284
|
-
# Initialize subscribers for vision-related topics
|
|
285
|
-
self._sub_apriltag_camera = roslibpy.Topic(self.websocket.client, '/tag_detections', 'apriltag_ros/AprilTagDetectionArray')
|
|
286
|
-
self._sub_apriltag_base = roslibpy.Topic(self.websocket.client, '/robot_tag_info', 'apriltag_ros/AprilTagDetectionArray')
|
|
287
|
-
|
|
288
|
-
# Initialize TF-related topics
|
|
289
|
-
self._sub_tf = roslibpy.Topic(self.websocket.client, '/tf', 'tf2_msgs/TFMessage')
|
|
290
|
-
self._sub_tf_static = roslibpy.Topic(self.websocket.client, '/tf_static', 'tf2_msgs/TFMessage')
|
|
291
|
-
|
|
292
|
-
# Subscribe to topics
|
|
293
|
-
self._sub_apriltag_camera.subscribe(self._apriltag_camera_callback)
|
|
294
|
-
self._sub_apriltag_base.subscribe(self._apriltag_base_callback)
|
|
295
|
-
self._sub_tf.subscribe(self._tf_callback)
|
|
296
|
-
self._sub_tf_static.subscribe(self._tf_static_callback)
|
|
297
|
-
|
|
298
|
-
# Initialize data structures
|
|
299
|
-
self._apriltag_data_from_camera = AprilTagData(
|
|
300
|
-
id = [],
|
|
301
|
-
size = [],
|
|
302
|
-
pose = []
|
|
303
|
-
)
|
|
304
|
-
self._apriltag_data_from_base = AprilTagData(
|
|
305
|
-
id = [],
|
|
306
|
-
size = [],
|
|
307
|
-
pose = []
|
|
308
|
-
)
|
|
309
|
-
self._apriltag_data_from_odom = AprilTagData(
|
|
310
|
-
id = [],
|
|
311
|
-
size = [],
|
|
312
|
-
pose = []
|
|
313
|
-
)
|
|
314
|
-
|
|
315
|
-
# TF buffer for storing transforms
|
|
316
|
-
self._tf_buffer = {}
|
|
317
|
-
self._tf_static_buffer = {}
|
|
318
|
-
|
|
319
|
-
self._initialized = True
|
|
320
|
-
except Exception as e:
|
|
321
|
-
SDKLogger.error(f"Failed to initialize KuavoRobotVisionCoreWebsocket: {e}")
|
|
322
|
-
raise
|
|
323
|
-
|
|
324
|
-
def _tf_callback(self, msg):
|
|
325
|
-
"""Callback for TF messages."""
|
|
326
|
-
for transform in msg['transforms']:
|
|
327
|
-
key = (transform['header']['frame_id'], transform['child_frame_id'])
|
|
328
|
-
self._tf_buffer[key] = transform
|
|
329
|
-
|
|
330
|
-
def _tf_static_callback(self, msg):
|
|
331
|
-
"""Callback for static TF messages."""
|
|
332
|
-
for transform in msg['transforms']:
|
|
333
|
-
key = (transform['header']['frame_id'], transform['child_frame_id'])
|
|
334
|
-
self._tf_static_buffer[key] = transform
|
|
335
|
-
|
|
336
|
-
def _get_transform(self, target_frame, source_frame):
|
|
337
|
-
"""Get transform between two frames.
|
|
338
|
-
|
|
339
|
-
Args:
|
|
340
|
-
target_frame (str): Target frame ID
|
|
341
|
-
source_frame (str): Source frame ID
|
|
342
|
-
|
|
343
|
-
Returns:
|
|
344
|
-
dict: Transform data if found, None otherwise
|
|
345
|
-
"""
|
|
346
|
-
# Check both dynamic and static transforms
|
|
347
|
-
key = (source_frame, target_frame)
|
|
348
|
-
if key in self._tf_buffer:
|
|
349
|
-
return self._tf_buffer[key]
|
|
350
|
-
if key in self._tf_static_buffer:
|
|
351
|
-
return self._tf_static_buffer[key]
|
|
352
|
-
return None
|
|
353
|
-
|
|
354
|
-
def _transform_pose(self, pose, transform):
|
|
355
|
-
"""Transform a pose using the given transform.
|
|
356
|
-
|
|
357
|
-
Args:
|
|
358
|
-
pose (dict): Pose to transform
|
|
359
|
-
transform (dict): Transform to apply
|
|
360
|
-
|
|
361
|
-
Returns:
|
|
362
|
-
dict: Transformed pose
|
|
363
|
-
"""
|
|
364
|
-
# Extract transform components
|
|
365
|
-
t = transform['transform']
|
|
366
|
-
translation = t['translation']
|
|
367
|
-
rotation = t['rotation']
|
|
368
|
-
|
|
369
|
-
# Extract pose components
|
|
370
|
-
p = pose['position']
|
|
371
|
-
o = pose['orientation']
|
|
372
|
-
|
|
373
|
-
# TODO: Implement actual pose transformation
|
|
374
|
-
# This is a placeholder - actual implementation would involve
|
|
375
|
-
# proper quaternion and vector math
|
|
376
|
-
transformed_pose = {
|
|
377
|
-
'position': {
|
|
378
|
-
'x': p['x'] + translation['x'],
|
|
379
|
-
'y': p['y'] + translation['y'],
|
|
380
|
-
'z': p['z'] + translation['z']
|
|
381
|
-
},
|
|
382
|
-
'orientation': {
|
|
383
|
-
'x': o['x'],
|
|
384
|
-
'y': o['y'],
|
|
385
|
-
'z': o['z'],
|
|
386
|
-
'w': o['w']
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
return transformed_pose
|
|
391
|
-
|
|
392
|
-
def _apriltag_camera_callback(self, msg):
|
|
393
|
-
"""Callback for AprilTag detections in camera frame."""
|
|
394
|
-
# Clear previous data
|
|
395
|
-
self._apriltag_data_from_camera.id = []
|
|
396
|
-
self._apriltag_data_from_camera.size = []
|
|
397
|
-
self._apriltag_data_from_camera.pose = []
|
|
398
|
-
|
|
399
|
-
# Process each detection
|
|
400
|
-
for detection in msg['detections']:
|
|
401
|
-
# Add ID
|
|
402
|
-
for tag_id in detection['id']:
|
|
403
|
-
self._apriltag_data_from_camera.id.append(tag_id)
|
|
404
|
-
|
|
405
|
-
# Add size
|
|
406
|
-
if detection.get('size') and len(detection['size']) > 0:
|
|
407
|
-
self._apriltag_data_from_camera.size.append(detection['size'][0])
|
|
408
|
-
else:
|
|
409
|
-
self._apriltag_data_from_camera.size.append(0.0)
|
|
410
|
-
|
|
411
|
-
# Add pose
|
|
412
|
-
self._apriltag_data_from_camera.pose.append(detection['pose']['pose']['pose'])
|
|
413
|
-
|
|
414
|
-
def _apriltag_base_callback(self, msg):
|
|
415
|
-
"""Callback for AprilTag detections in base frame."""
|
|
416
|
-
# Clear previous data
|
|
417
|
-
self._apriltag_data_from_base.id = []
|
|
418
|
-
self._apriltag_data_from_base.size = []
|
|
419
|
-
self._apriltag_data_from_base.pose = []
|
|
420
|
-
|
|
421
|
-
# Process each detection
|
|
422
|
-
for detection in msg['detections']:
|
|
423
|
-
# Add ID
|
|
424
|
-
for tag_id in detection['id']:
|
|
425
|
-
self._apriltag_data_from_base.id.append(tag_id)
|
|
426
|
-
|
|
427
|
-
# Add size
|
|
428
|
-
if detection.get('size') and len(detection['size']) > 0:
|
|
429
|
-
self._apriltag_data_from_base.size.append(detection['size'][0])
|
|
430
|
-
else:
|
|
431
|
-
self._apriltag_data_from_base.size.append(0.0)
|
|
432
|
-
|
|
433
|
-
# Add pose
|
|
434
|
-
self._apriltag_data_from_base.pose.append(detection['pose']['pose']['pose'])
|
|
435
|
-
|
|
436
|
-
# Transform base data to odom frame
|
|
437
|
-
self._transform_base_to_odom()
|
|
438
|
-
|
|
439
|
-
def _transform_base_to_odom(self):
|
|
440
|
-
"""Transform AprilTag poses from base_link to odom coordinate frame."""
|
|
441
|
-
# Clear previous odom data
|
|
442
|
-
self._apriltag_data_from_odom.id = []
|
|
443
|
-
self._apriltag_data_from_odom.size = []
|
|
444
|
-
self._apriltag_data_from_odom.pose = []
|
|
445
|
-
|
|
446
|
-
# If no base data, skip transformation
|
|
447
|
-
if not self._apriltag_data_from_base.id:
|
|
448
|
-
SDKLogger.warn("No base tag data, skip transform")
|
|
449
|
-
return
|
|
450
|
-
|
|
451
|
-
# Get transform from base_link to odom
|
|
452
|
-
transform = self._get_transform("odom", "base_link")
|
|
453
|
-
if not transform:
|
|
454
|
-
SDKLogger.warn("Transform from base_link to odom not available")
|
|
455
|
-
return
|
|
456
|
-
|
|
457
|
-
# Copy ID and size information
|
|
458
|
-
self._apriltag_data_from_odom.id = self._apriltag_data_from_base.id.copy()
|
|
459
|
-
self._apriltag_data_from_odom.size = self._apriltag_data_from_base.size.copy()
|
|
460
|
-
|
|
461
|
-
# Transform each pose
|
|
462
|
-
for pose in self._apriltag_data_from_base.pose:
|
|
463
|
-
transformed_pose = self._transform_pose(pose, transform)
|
|
464
|
-
self._apriltag_data_from_odom.pose.append(transformed_pose)
|
|
465
|
-
|
|
466
|
-
@property
|
|
467
|
-
def apriltag_data_from_camera(self):
|
|
468
|
-
return self._apriltag_data_from_camera
|
|
469
|
-
|
|
470
|
-
@property
|
|
471
|
-
def apriltag_data_from_base(self):
|
|
472
|
-
return self._apriltag_data_from_base
|
|
473
|
-
|
|
474
|
-
@property
|
|
475
|
-
def apriltag_data_from_odom(self):
|
|
476
|
-
return self._apriltag_data_from_odom
|
|
477
|
-
|
|
478
|
-
def get_data_by_id(self, tag_id: int, frame: str = "odom"):
|
|
479
|
-
"""Get AprilTag data for a specific tag ID from the specified frame.
|
|
480
|
-
|
|
481
|
-
Args:
|
|
482
|
-
tag_id (int): The ID of the AprilTag to get data for
|
|
483
|
-
frame (str): The frame to get data from ("camera", "base", or "odom")
|
|
484
|
-
|
|
485
|
-
Returns:
|
|
486
|
-
dict: The AprilTag data for the specified ID and frame, or None if not found
|
|
487
|
-
"""
|
|
488
|
-
if frame == "camera":
|
|
489
|
-
data = self._apriltag_data_from_camera
|
|
490
|
-
elif frame == "base":
|
|
491
|
-
data = self._apriltag_data_from_base
|
|
492
|
-
elif frame == "odom":
|
|
493
|
-
data = self._apriltag_data_from_odom
|
|
494
|
-
else:
|
|
495
|
-
SDKLogger.error(f"Invalid frame: {frame}")
|
|
265
|
+
# SDKLogger.debug(f"No data found for tag ID {target_id} in {data_source} source")
|
|
496
266
|
return None
|
|
497
|
-
|
|
498
|
-
if not data or not data.id:
|
|
499
|
-
return None
|
|
500
|
-
|
|
501
|
-
# Find all matching indices
|
|
502
|
-
indices = [i for i, id in enumerate(data.id) if id == tag_id]
|
|
503
267
|
|
|
504
|
-
if not indices:
|
|
505
|
-
return None
|
|
506
|
-
|
|
507
268
|
return {
|
|
508
269
|
"sizes": [data.size[i] for i in indices],
|
|
509
270
|
"poses": [data.pose[i] for i in indices]
|