@@ -6,13 +6,13 @@ use std::{
66use ahash:: { HashMap , HashMapExt as _, HashSet , HashSetExt as _} ;
77use anyhow:: { Context as _, bail} ;
88use itertools:: Itertools as _;
9- use urdf_rs:: { Geometry , Joint , Link , Material , Robot , Vec3 , Vec4 } ;
9+ use urdf_rs:: { Geometry , Joint , Link , LinkName , Material , Robot , Vec3 , Vec4 } ;
1010
1111use re_chunk:: { ChunkBuilder , ChunkId , EntityPath , RowId , TimePoint } ;
1212use re_log_types:: { EntityPathPart , StoreId } ;
1313use re_types:: {
1414 AsComponents , Component as _, ComponentDescriptor , SerializedComponentBatch ,
15- archetypes:: { Asset3D , Transform3D } ,
15+ archetypes:: { Asset3D , CoordinateFrame , Transform3D , TransformAxes3D } ,
1616 datatypes:: Vec3D ,
1717 external:: glam,
1818} ;
@@ -282,6 +282,15 @@ fn log_robot(
282282 . map ( |prefix| prefix / EntityPath :: from_single_string ( urdf_tree. name . clone ( ) ) )
283283 . unwrap_or_else ( || EntityPath :: from_single_string ( urdf_tree. name . clone ( ) ) ) ;
284284
285+ // Log the robot's root coordinate frame_id.
286+ send_archetype (
287+ tx,
288+ store_id,
289+ entity_path. clone ( ) ,
290+ timepoint,
291+ & CoordinateFrame :: update_fields ( ) . with_frame_id ( urdf_tree. root . name . clone ( ) ) ,
292+ ) ?;
293+
285294 walk_tree (
286295 & urdf_tree,
287296 tx,
@@ -345,8 +354,8 @@ fn log_joint(
345354 name : _,
346355 joint_type,
347356 origin,
348- parent : _ ,
349- child : _ ,
357+ parent,
358+ child,
350359 axis,
351360 limit,
352361 calibration,
@@ -355,7 +364,24 @@ fn log_joint(
355364 safety_controller,
356365 } = joint;
357366
358- send_transform ( tx, store_id, joint_path. clone ( ) , origin, timepoint) ?;
367+ // A joint's own coordinate frame is that of its parent link.
368+ send_archetype (
369+ tx,
370+ store_id,
371+ joint_path. clone ( ) ,
372+ timepoint,
373+ & CoordinateFrame :: update_fields ( ) . with_frame_id ( parent. link . clone ( ) ) ,
374+ ) ?;
375+ // Send the joint origin, i.e. the default transform from parent link to child link.
376+ send_transform (
377+ tx,
378+ store_id,
379+ joint_path. clone ( ) ,
380+ origin,
381+ timepoint,
382+ Some ( parent) ,
383+ Some ( child) ,
384+ ) ?;
359385
360386 log_debug_format (
361387 tx,
@@ -404,13 +430,23 @@ fn log_joint(
404430 Ok ( ( ) )
405431}
406432
407- fn transform_from_pose ( origin : & urdf_rs:: Pose ) -> Transform3D {
433+ fn transform_from_pose (
434+ origin : & urdf_rs:: Pose ,
435+ parent : Option < & LinkName > ,
436+ child : Option < & LinkName > ,
437+ ) -> Transform3D {
408438 let urdf_rs:: Pose { xyz, rpy } = origin;
409439 let translation = [ xyz[ 0 ] as f32 , xyz[ 1 ] as f32 , xyz[ 2 ] as f32 ] ;
410440 let quaternion = quat_xyzw_from_roll_pitch_yaw ( rpy[ 0 ] as f32 , rpy[ 1 ] as f32 , rpy[ 2 ] as f32 ) ;
411- Transform3D :: update_fields ( )
441+ let transform = Transform3D :: update_fields ( )
412442 . with_translation ( translation)
413- . with_quaternion ( quaternion)
443+ . with_quaternion ( quaternion) ;
444+ if let ( Some ( parent) , Some ( child) ) = ( parent, child) {
445+ return transform
446+ . with_parent_frame ( parent. link . clone ( ) )
447+ . with_child_frame ( child. link . clone ( ) ) ;
448+ }
449+ transform
414450}
415451
416452fn send_transform (
@@ -419,19 +455,29 @@ fn send_transform(
419455 entity_path : EntityPath ,
420456 origin : & urdf_rs:: Pose ,
421457 timepoint : & TimePoint ,
458+ parent : Option < & LinkName > ,
459+ child : Option < & LinkName > ,
422460) -> anyhow:: Result < ( ) > {
423461 let urdf_rs:: Pose { xyz, rpy } = origin;
424462 let is_identity = xyz. 0 == [ 0.0 , 0.0 , 0.0 ] && rpy. 0 == [ 0.0 , 0.0 , 0.0 ] ;
425463
426464 if is_identity {
427465 Ok ( ( ) ) // avoid noise
428466 } else {
467+ // TODO: remove axis log this after debugging
468+ send_archetype (
469+ tx,
470+ store_id,
471+ entity_path. clone ( ) ,
472+ timepoint,
473+ & TransformAxes3D :: update_fields ( ) . with_axis_length ( 0.1 ) ,
474+ ) ?;
429475 send_archetype (
430476 tx,
431477 store_id,
432478 entity_path,
433479 timepoint,
434- & transform_from_pose ( origin) ,
480+ & transform_from_pose ( origin, parent , child ) ,
435481 )
436482 }
437483}
@@ -485,6 +531,19 @@ fn log_link(
485531 timepoint,
486532 ) ?;
487533
534+ // Log coordinate frame ID of the link.
535+ send_archetype (
536+ tx,
537+ store_id,
538+ link_entity. clone ( ) ,
539+ timepoint,
540+ & CoordinateFrame :: update_fields ( ) . with_frame_id ( link. name . clone ( ) ) ,
541+ ) ?;
542+
543+ let link_parent = urdf_tree
544+ . get_parent_of_link ( & link. name )
545+ . map ( |joint| & joint. child ) ;
546+
488547 for ( i, visual) in visual. iter ( ) . enumerate ( ) {
489548 let urdf_rs:: Visual {
490549 name,
@@ -493,7 +552,7 @@ fn log_link(
493552 material,
494553 } = visual;
495554 let name = name. clone ( ) . unwrap_or_else ( || format ! ( "visual_{i}" ) ) ;
496- let vis_entity = link_entity / EntityPathPart :: new ( name) ;
555+ let vis_entity = link_entity / EntityPathPart :: new ( name. clone ( ) ) ;
497556
498557 // Prefer inline defined material properties if present, otherwise fall back to global material.
499558 let material = material. as_ref ( ) . and_then ( |mat| {
@@ -504,7 +563,29 @@ fn log_link(
504563 }
505564 } ) ;
506565
507- send_transform ( tx, store_id, vis_entity. clone ( ) , origin, timepoint) ?;
566+ let link_child = urdf_rs:: LinkName { link : name } ;
567+ // TODO
568+ send_transform (
569+ tx,
570+ store_id,
571+ vis_entity. clone ( ) ,
572+ origin,
573+ timepoint,
574+ link_parent,
575+ Some ( & link_child) ,
576+ ) ?;
577+
578+ if let Some ( parent) = link_parent {
579+ let coordinate_frame =
580+ CoordinateFrame :: update_fields ( ) . with_frame_id ( parent. link . clone ( ) ) ;
581+ send_archetype (
582+ tx,
583+ store_id,
584+ vis_entity. clone ( ) ,
585+ timepoint,
586+ & coordinate_frame,
587+ ) ?;
588+ }
508589
509590 log_geometry (
510591 urdf_tree, tx, store_id, vis_entity, geometry, material, timepoint,
@@ -518,9 +599,30 @@ fn log_link(
518599 geometry,
519600 } = collision;
520601 let name = name. clone ( ) . unwrap_or_else ( || format ! ( "collision_{i}" ) ) ;
521- let collision_entity = link_entity / EntityPathPart :: new ( name) ;
602+ let collision_entity = link_entity / EntityPathPart :: new ( name. clone ( ) ) ;
522603
523- send_transform ( tx, store_id, collision_entity. clone ( ) , origin, timepoint) ?;
604+ let link_child = urdf_rs:: LinkName { link : name } ;
605+ send_transform (
606+ tx,
607+ store_id,
608+ collision_entity. clone ( ) ,
609+ origin,
610+ timepoint,
611+ link_parent,
612+ Some ( & link_child) ,
613+ ) ?;
614+
615+ if let Some ( parent) = link_parent {
616+ let coordinate_frame =
617+ CoordinateFrame :: update_fields ( ) . with_frame_id ( parent. link . clone ( ) ) ;
618+ send_archetype (
619+ tx,
620+ store_id,
621+ collision_entity. clone ( ) ,
622+ timepoint,
623+ & coordinate_frame,
624+ ) ?;
625+ }
524626
525627 log_geometry (
526628 urdf_tree,
0 commit comments