FrameTransform

Struct FrameTransform 

Source
pub struct FrameTransform<T: Copy + Debug + Default + Serialize + 'static> {
    pub transform: Transform3D<T>,
    pub parent_frame: FrameIdString,
    pub child_frame: FrameIdString,
}
Expand description

Transform message useable as a payload for CuStampedData. This contains just the transform data without timestamps, as timestamps are handled by CuStampedData

§Example

use cu_transform::{FrameTransform, Transform3D};
use cu29::prelude::*;
use cu29::clock::{CuDuration, Tov};
use cu_transform::transform_payload::StampedFrameTransform;

// Create a transform message
let transform = Transform3D::<f32>::default();
let payload = FrameTransform::new(
    transform,
    "world",
    "robot"
);

let data = StampedFrameTransform::new(Some(payload));

Fields§

§transform: Transform3D<T>

The actual transform

§parent_frame: FrameIdString

Parent frame identifier

§child_frame: FrameIdString

Child frame identifier

Implementations§

Source§

impl<T: Copy + Debug + Default + Serialize + 'static> FrameTransform<T>

Source

pub fn new( transform: Transform3D<T>, parent_frame: impl AsRef<str>, child_frame: impl AsRef<str>, ) -> Self

Create a new transform message

Examples found in repository?
examples/payload_usage.rs (lines 26-30)
6fn main() {
7    println!("Cu Transform - CuMsg Pattern Demo");
8    println!("=================================");
9    println!();
10
11    // Create a transform tree
12    let mut tree = TransformTree::<f32>::new();
13    let clock = RobotClock::default();
14
15    // Create transforms using the new CuMsg pattern
16    println!("Creating transforms with CuMsg...");
17
18    // World to base transform
19    let transform1 = Transform3D::from_matrix([
20        [1.0f32, 0.0, 0.0, 0.0], // Column-major: each inner array is a column
21        [0.0, 1.0, 0.0, 0.0],
22        [0.0, 0.0, 1.0, 0.0],
23        [1.0, 0.0, 0.0, 1.0], // Translation (1, 0, 0)
24    ]);
25
26    let frame_transform = FrameTransform::new(
27        transform1,
28        FrameIdString::from("world").expect("Frame name too long"),
29        FrameIdString::from("base").expect("Frame name too long"),
30    );
31    let mut sft = StampedFrameTransform::new(Some(frame_transform));
32    sft.tov = Tov::Time(CuDuration(1_000_000_000)); // 1 second
33
34    // Add to tree using the new API
35    tree.add_transform(&sft).expect("Failed to add transform");
36    println!("  Added world->base transform at t=1s");
37
38    // Base to arm transform
39    let transform2 = Transform3D::from_matrix([
40        [0.0, 1.0, 0.0, 0.0], // 90-degree rotation around Z
41        [-1.0, 0.0, 0.0, 0.0],
42        [0.0, 0.0, 1.0, 0.0],
43        [0.5, 0.0, 0.0, 1.0], // Translation (0.5, 0, 0)
44    ]);
45
46    let msg2 = FrameTransform::new(
47        transform2,
48        FrameIdString::from("base").expect("Frame name too long"),
49        FrameIdString::from("arm").expect("Frame name too long"),
50    );
51    let mut sft = StampedFrameTransform::new(Some(msg2));
52    sft.tov = Tov::Time(CuDuration(1_000_000_000)); // 1 second
53
54    tree.add_transform(&sft).expect("Failed to add transform");
55    println!("  Added base->arm transform at t=1s");
56
57    // Demonstrate using time ranges for a broadcast
58    println!("\nBroadcasting multiple transforms with time range...");
59
60    // Create multiple transforms at different times
61    let times = [
62        CuDuration(2_000_000_000), // 2 seconds
63        CuDuration(2_100_000_000), // 2.1 seconds
64        CuDuration(2_200_000_000),
65    ];
66
67    for (i, &time) in times.iter().enumerate() {
68        let x_translation = 1.0 + (i as f32) * 0.1;
69        let transform = Transform3D::from_matrix([
70            [1.0, 0.0, 0.0, 0.0],
71            [0.0, 1.0, 0.0, 0.0],
72            [0.0, 0.0, 1.0, 0.0],
73            [x_translation, 0.0, 0.0, 1.0],
74        ]);
75
76        let msg = FrameTransform::new(
77            transform,
78            FrameIdString::from("world").expect("Frame name too long"),
79            FrameIdString::from("base").expect("Frame name too long"),
80        );
81        let mut sft = StampedFrameTransform::new(Some(msg));
82
83        // For a broadcast with multiple transforms, use Range
84        if i == 0 {
85            sft.tov = Tov::Range(cu29::clock::CuTimeRange {
86                start: times[0],
87                end: *times.last().unwrap(),
88            });
89        } else {
90            sft.tov = Tov::Time(time);
91        }
92
93        tree.add_transform(&sft).expect("Failed to add transform");
94    }
95
96    println!("  Added 3 transforms with time range 2.0s - 2.2s");
97
98    // Query the tree
99    println!("\nQuerying transforms...");
100
101    let result = tree.lookup_transform("world", "arm", CuDuration(1_000_000_000), &clock);
102    match result {
103        Ok(transform) => {
104            let mat = transform.to_matrix();
105            println!(
106                "  World->arm at t=1s: translation=({:.2}, {:.2}, {:.2})",
107                mat[3][0], mat[3][1], mat[3][2]
108            );
109        }
110        Err(e) => println!("  Error: {e}"),
111    }
112
113    // Query velocity (requires transforms at multiple times)
114    let velocity = tree.lookup_velocity("world", "base", CuDuration(2_100_000_000), &clock);
115    match velocity {
116        Ok(vel) => {
117            println!(
118                "  World->base velocity at t=2.1s: linear=({:.2}, {:.2}, {:.2}) m/s",
119                vel.linear[0], vel.linear[1], vel.linear[2]
120            );
121        }
122        Err(e) => println!("  Error computing velocity: {e}"),
123    }
124
125    println!("\nKey advantages of CuMsg pattern:");
126    println!("- Integrates with Copper message system");
127    println!("- Timestamps handled by CuMsg metadata (Tov)");
128    println!("- Supports time ranges for broadcasts");
129}
More examples
Hide additional examples
examples/basic_usage.rs (lines 144-148)
9fn main() {
10    // Example using the typed transform approach
11    println!("Cu Transform - New Typed Approach Demo");
12    println!("=====================================");
13
14    // Create a buffer for world -> robot transforms
15    let mut world_to_robot_buffer: TypedTransformBuffer<f32, WorldFrame, RobotFrame, 10> =
16        TypedTransformBuffer::new();
17
18    // Create a transform message
19    let transform = Transform3D::from_matrix([
20        [1.0, 0.0, 0.0, 1.0], // X translation
21        [0.0, 1.0, 0.0, 2.0], // Y translation
22        [0.0, 0.0, 1.0, 0.0],
23        [0.0, 0.0, 0.0, 1.0],
24    ]);
25
26    let world_to_robot_msg = TypedTransform::new(transform, CuDuration(1000));
27
28    println!(
29        "Created transform from {} to {}",
30        world_to_robot_msg.parent_name(),
31        world_to_robot_msg.child_name()
32    );
33    if let Some(t) = world_to_robot_msg.transform() {
34        let mat = t.to_matrix();
35        println!(
36            "  Translation: [{}, {}, {}]",
37            mat[0][3], mat[1][3], mat[2][3]
38        );
39    }
40
41    // Add to buffer
42    world_to_robot_buffer.add_transform(world_to_robot_msg);
43
44    // Create second transform
45    let transform2 = Transform3D::from_matrix([
46        [1.0, 0.0, 0.0, 2.0], // X translation
47        [0.0, 1.0, 0.0, 4.0], // Y translation
48        [0.0, 0.0, 1.0, 0.0],
49        [0.0, 0.0, 0.0, 1.0],
50    ]);
51
52    let world_to_robot_msg2 = TypedTransform::new(transform2, CuDuration(2000));
53    world_to_robot_buffer.add_transform(world_to_robot_msg2);
54
55    // Query the buffer
56    if let Some(latest) = world_to_robot_buffer.get_latest_transform() {
57        println!(
58            "\nLatest transform at time {}:",
59            latest.timestamp().unwrap().as_nanos()
60        );
61        if let Some(t) = latest.transform() {
62            let mat = t.to_matrix();
63            println!(
64                "  Translation: [{}, {}, {}]",
65                mat[0][3], mat[1][3], mat[2][3]
66            );
67        }
68    }
69
70    // Query closest to a specific time
71    if let Some(closest) = world_to_robot_buffer.get_closest_transform(CuDuration(1500)) {
72        println!("\nClosest transform to time 1500:");
73        println!("  Actual time: {}", closest.timestamp().unwrap().as_nanos());
74        if let Some(t) = closest.transform() {
75            let mat = t.to_matrix();
76            println!(
77                "  Translation: [{}, {}, {}]",
78                mat[0][3], mat[1][3], mat[2][3]
79            );
80        }
81    }
82
83    // Demonstrate time range
84    if let Some(range) = world_to_robot_buffer.get_time_range() {
85        println!(
86            "\nTime range: {} to {}",
87            range.start.as_nanos(),
88            range.end.as_nanos()
89        );
90    }
91
92    // Demonstrate velocity computation
93    if let Some(latest) = world_to_robot_buffer.get_latest_transform() {
94        if let Some(closest) = world_to_robot_buffer.get_closest_transform(CuDuration(1000)) {
95            if let Some(velocity) = latest.compute_velocity(closest) {
96                println!("\nVelocity computation:");
97                println!(
98                    "  Linear velocity: [{}, {}, {}]",
99                    velocity.linear[0], velocity.linear[1], velocity.linear[2]
100                );
101            }
102        }
103    }
104
105    // Demonstrate the stringly typed version of the API.
106    println!("\n\nConstant-Size Buffer Demo");
107    println!("===========================================");
108
109    let mut const_buffer: ConstTransformBuffer<f32, 5> = ConstTransformBuffer::new();
110
111    // Add some stamped transforms
112    let stamped_transform = StampedTransform {
113        transform,
114        stamp: CuDuration(1000),
115        parent_frame: "world".try_into().unwrap(),
116        child_frame: "robot".try_into().unwrap(),
117    };
118
119    const_buffer.add_transform(stamped_transform);
120
121    if let Some(latest_stamped) = const_buffer.get_latest_transform() {
122        println!("Latest transform in constant buffer:");
123        println!(
124            "  From: {} to: {}",
125            latest_stamped.parent_frame, latest_stamped.child_frame
126        );
127        println!("  Time: {}", latest_stamped.stamp.as_nanos());
128        let mat = latest_stamped.transform.to_matrix();
129        println!(
130            "  Translation: [{}, {}, {}]",
131            mat[0][3], mat[1][3], mat[2][3]
132        );
133    }
134
135    println!("\nThis buffer is stack-allocated with capacity 5 - no heap allocation!");
136
137    // Demonstrate the StampedFrameTransform pattern with TransformTree
138    println!("\n\nStampedFrameTransform Pattern Demo");
139    println!("================================");
140
141    let mut tree = TransformTree::<f32>::new();
142
143    // Create a CuMsg with TransformMsg
144    let frame_transform = FrameTransform::new(
145        transform,
146        FrameIdString::from("world").expect("Frame name too long"),
147        FrameIdString::from("robot").expect("Frame name too long"),
148    );
149
150    let mut sft = StampedFrameTransform::new(Some(frame_transform));
151    sft.tov = Tov::Time(CuDuration(1_000_000_000)); // 1 second
152
153    // Add using the new API
154    tree.add_transform(&sft).expect("Failed to add transform");
155    println!("Added transform using CuMsg<TransformMsg> pattern");
156
157    // Query the transform
158    let robot_clock = cu29::clock::RobotClock::default();
159    let result = tree.lookup_transform("world", "robot", CuDuration(1_000_000_000), &robot_clock);
160
161    match result {
162        Ok(transform) => {
163            let mat = transform.to_matrix();
164            println!(
165                "Retrieved transform: translation=({:.2}, {:.2}, {:.2})",
166                mat[3][0], mat[3][1], mat[3][2]
167            );
168        }
169        Err(e) => println!("Error: {e}"),
170    }
171}
Source

pub fn from_stamped(stamped: &StampedTransform<T>) -> Self

Create from a StampedTransform (for migration)

Trait Implementations§

Source§

impl<T: Clone + Copy + Debug + Default + Serialize + 'static> Clone for FrameTransform<T>

Source§

fn clone(&self) -> FrameTransform<T>

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<T: Debug + Copy + Debug + Default + Serialize + 'static> Debug for FrameTransform<T>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<T> Decode<()> for FrameTransform<T>
where T: Decode<()> + Copy + Debug + Default + Serialize + 'static,

Source§

fn decode<D: Decoder<Context = ()>>( decoder: &mut D, ) -> Result<Self, DecodeError>

Attempt to decode this type with the given Decode.
Source§

impl<T: Default + Copy + Debug + Default + Serialize + 'static> Default for FrameTransform<T>

Source§

fn default() -> FrameTransform<T>

Returns the “default value” for a type. Read more
Source§

impl<'de, T> Deserialize<'de> for FrameTransform<T>
where T: Deserialize<'de> + Copy + Debug + Default + Serialize + 'static,

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl<T> Encode for FrameTransform<T>
where T: Encode + Copy + Debug + Default + Serialize + 'static,

Source§

fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError>

Encode a given type.
Source§

impl<T> Serialize for FrameTransform<T>
where T: Serialize + Copy + Debug + Default + Serialize + 'static,

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

§

impl<T> Freeze for FrameTransform<T>

§

impl<T> RefUnwindSafe for FrameTransform<T>
where T: RefUnwindSafe,

§

impl<T> Send for FrameTransform<T>
where T: Send,

§

impl<T> Sync for FrameTransform<T>
where T: Sync,

§

impl<T> Unpin for FrameTransform<T>
where T: Unpin,

§

impl<T> UnwindSafe for FrameTransform<T>
where T: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> EncodableKey for T
where T: Serialize,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> Serialize for T
where T: Serialize + ?Sized,

Source§

fn erased_serialize(&self, serializer: &mut dyn Serializer) -> Result<(), Error>

Source§

fn do_erased_serialize( &self, serializer: &mut dyn Serializer, ) -> Result<(), ErrorImpl>

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> CuMsgPayload for T
where T: Default + Debug + Clone + Encode + Decode<()> + Serialize,

Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> ErasedDestructor for T
where T: 'static,