Skip to content

Commit

Permalink
tf_capture outputs a toml of current transforms after looking up tran…
Browse files Browse the repository at this point in the history
…sforms from an input toml
  • Loading branch information
lucasw committed Sep 21, 2024
1 parent 8febfe4 commit 6a589be
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 2 deletions.
4 changes: 4 additions & 0 deletions tf_roslibrust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ branch = "subscribe_any"
# path = "../../roslibrust/roslibrust_codegen_macro"
# version="0.10"

[[bin]]
name = "tf_capture"
path = "src/bin/capture.rs"

[[bin]]
name = "tf_tree"
path = "src/bin/tree.rs"
Expand Down
68 changes: 68 additions & 0 deletions tf_roslibrust/src/bin/capture.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use tf_roslibrust::tf_util;
use tf_roslibrust::transforms::tf2_msgs;

/// Load a toml file of a list of parent/child frames and then find all those transforms in
/// a live system and output a new toml listing of their current values
/// tf_capture examples/transforms.toml > current_transforms.toml
#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
use roslibrust::ros1::NodeHandle;

// need to have leading slash on node name and topic to function properly
// so figure out namespace then prefix it to name and topics
let mut ns = String::from("");
let args = std::env::args();
let mut args2 = Vec::new();
{
// get namespace
for arg in args {
if arg.starts_with("__ns:=") {
ns = arg.replace("__ns:=", "");
} else {
args2.push(arg);
}
}
}

let full_node_name = &format!("/{ns}/tf_capture").replace("//", "/");
// println!("{}", format!("full ns and node name: {full_node_name}"));

let config_file = &args2[1];
let tfm = tf_util::get_transforms_from_toml(config_file)?;

let nh = NodeHandle::new(&std::env::var("ROS_MASTER_URI")?, full_node_name)
.await
.unwrap();

print!(
"# {:.3} getting transforms...",
tf_util::stamp_to_f64(tf_util::stamp_now())
);
let listener = tf_roslibrust::TfListener::new(&nh).await;

// let some transforms arrive
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;

let mut new_tfm = tf2_msgs::TFMessage::default();
for old_tfs in &tfm.transforms {
// TODO(lucasw) make a lookup_most_recent_transform and then don't need the None
let res =
listener.lookup_transform(&old_tfs.header.frame_id, &old_tfs.child_frame_id, None);
match res {
Ok(new_tfs) => {
new_tfm.transforms.push(new_tfs);
// TODO(lucasw) compare old values to current values, warn if large
}
Err(err) => {
eprintln!("# {err:?} -> going to use old version for this transform");
new_tfm.transforms.push(old_tfs.clone());
}
}
}

let toml = tf_util::transforms_to_toml(tfm)?;
print!("\n\n{toml}");

Ok(())
}
40 changes: 38 additions & 2 deletions tf_roslibrust/src/tf_util.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use chrono::TimeDelta;
use roslibrust_codegen::Time;
use serde_derive::Deserialize;
use serde_derive::{Deserialize, Serialize};
use std::collections::HashMap;
use std::time::SystemTime;

Expand Down Expand Up @@ -39,7 +39,7 @@ pub fn stamp_to_f64(stamp: Time) -> f64 {
}

/// use for loading from a toml
#[derive(Deserialize, Debug)]
#[derive(Deserialize, Serialize, Debug)]
struct TransformRaw {
frame: String,
child_frame: String,
Expand All @@ -51,6 +51,42 @@ struct TransformRaw {
yaw: Option<f64>,
}

impl TransformRaw {
fn from_transform_stamped(tfs: geometry_msgs::TransformStamped) -> Self {
let rot = tfs.transform.rotation;
let quat = nalgebra::UnitQuaternion::new_normalize(nalgebra::geometry::Quaternion::new(
rot.w, rot.x, rot.y, rot.z,
));
let (roll, pitch, yaw) = quat.euler_angles();

let tr = tfs.transform.translation;
let (x, y, z) = (tr.x, tr.y, tr.z);

Self {
frame: tfs.header.frame_id,
child_frame: tfs.child_frame_id,
x: Some(x),
y: Some(y),
z: Some(z),
roll: Some(roll),
pitch: Some(pitch),
yaw: Some(yaw),
}
}
}

pub fn transforms_to_toml(tfm: tf2_msgs::TFMessage) -> Result<String, anyhow::Error> {
let mut tf_vec = Vec::new();
for tfs in tfm.transforms {
tf_vec.push(TransformRaw::from_transform_stamped(tfs));
}

let mut tf_data = HashMap::new();
tf_data.insert("tf", tf_vec);

Ok(toml::to_string(&tf_data).unwrap())
}

pub fn get_transforms_from_toml(filename: &str) -> Result<tf2_msgs::TFMessage, anyhow::Error> {
let tf_data = {
let contents = match std::fs::read_to_string(filename) {
Expand Down

0 comments on commit 6a589be

Please sign in to comment.