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.

@@ -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
- self._apriltag_data_camera_sub = rospy.Subscriber('/tag_detections', AprilTagDetectionArray, self._apriltag_data_callback_camera)
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]