use openigtlink_rust::error::Result;
use openigtlink_rust::io::{ClientBuilder, SyncIgtlClient};
use openigtlink_rust::protocol::message::IgtlMessage;
use openigtlink_rust::protocol::types::SensorMessage;
use std::env;
use std::thread;
use std::time::{Duration, Instant};
fn main() {
if let Err(e) = run() {
eprintln!("[ERROR] {}", e);
std::process::exit(1);
}
}
fn run() -> Result<()> {
let sensor_type = parse_sensor_type();
let mut client = ClientBuilder::new().tcp("127.0.0.1:18944").sync().build()?;
println!("[INFO] Connected to OpenIGTLink server\n");
match sensor_type.as_str() {
"force" => log_force_sensor(&mut client)?,
"imu" => log_imu_sensor(&mut client)?,
"combined" => log_combined_sensors(&mut client)?,
_ => unreachable!(),
}
println!("\n[INFO] Sensor data logging completed successfully");
Ok(())
}
fn parse_sensor_type() -> String {
let args: Vec<String> = env::args().collect();
if args.len() > 1 {
let sensor_type = args[1].to_lowercase();
if ["force", "imu", "combined"].contains(&sensor_type.as_str()) {
return sensor_type;
}
}
println!("Usage: cargo run --example sensor_logger [force|imu|combined]");
println!("Defaulting to force sensor...\n");
"force".to_string()
}
fn log_force_sensor(client: &mut SyncIgtlClient) -> Result<()> {
println!("=== Force/Torque Sensor Logging ===");
println!("Channels: 6 (Fx, Fy, Fz, Tx, Ty, Tz)");
println!("Sample Rate: 100 Hz");
println!("Duration: 10 seconds");
println!("Unit: Newton (force) + Newton-meter (torque)\n");
let sample_rate: usize = 100;
let duration_sec = 10;
let total_samples = sample_rate * duration_sec;
let sample_interval = Duration::from_millis(1000 / sample_rate as u64);
for sample_num in 0..total_samples {
let start_time = Instant::now();
let sensor_data = read_force_sensor(sample_num);
let sensor = SensorMessage::with_unit(1, 0x0101, sensor_data.clone())?;
let msg = IgtlMessage::new(sensor, "ATI_ForceSensor")?;
client.send(&msg)?;
if sample_num % sample_rate == 0 {
let seconds = sample_num / sample_rate;
println!(
"[{}s] Force: [{:6.2}, {:6.2}, {:6.2}] N Torque: [{:6.3}, {:6.3}, {:6.3}] Nm",
seconds,
sensor_data[0],
sensor_data[1],
sensor_data[2],
sensor_data[3],
sensor_data[4],
sensor_data[5]
);
}
let elapsed = start_time.elapsed();
if elapsed < sample_interval {
thread::sleep(sample_interval - elapsed);
}
}
Ok(())
}
fn log_imu_sensor(client: &mut SyncIgtlClient) -> Result<()> {
println!("=== IMU Sensor Logging ===");
println!("Channels: 6 (Accel X,Y,Z + Gyro X,Y,Z)");
println!("Sample Rate: 100 Hz");
println!("Duration: 10 seconds");
println!("Unit: m/s² (accel) + rad/s (gyro)\n");
let sample_rate: usize = 100;
let duration_sec = 10;
let total_samples = sample_rate * duration_sec;
let sample_interval = Duration::from_millis(1000 / sample_rate as u64);
for sample_num in 0..total_samples {
let start_time = Instant::now();
let sensor_data = read_imu_sensor(sample_num);
let sensor = SensorMessage::with_unit(1, 0x0202, sensor_data.clone())?;
let msg = IgtlMessage::new(sensor, "IMU_9DOF")?;
client.send(&msg)?;
if sample_num % sample_rate == 0 {
let seconds = sample_num / sample_rate;
println!(
"[{}s] Accel: [{:6.2}, {:6.2}, {:6.2}] m/s² Gyro: [{:6.3}, {:6.3}, {:6.3}] rad/s",
seconds,
sensor_data[0],
sensor_data[1],
sensor_data[2],
sensor_data[3],
sensor_data[4],
sensor_data[5]
);
}
let elapsed = start_time.elapsed();
if elapsed < sample_interval {
thread::sleep(sample_interval - elapsed);
}
}
Ok(())
}
fn log_combined_sensors(client: &mut SyncIgtlClient) -> Result<()> {
println!("=== Combined Sensor Array Logging ===");
println!("Channels: 14 (8 force + 6 IMU)");
println!("Sample Rate: 100 Hz");
println!("Duration: 10 seconds\n");
let sample_rate: usize = 100;
let duration_sec = 10;
let total_samples = sample_rate * duration_sec;
let sample_interval = Duration::from_millis(1000 / sample_rate as u64);
for sample_num in 0..total_samples {
let start_time = Instant::now();
let sensor_data = read_combined_sensors(sample_num);
let sensor = SensorMessage::with_unit(1, 0, sensor_data.clone())?;
let msg = IgtlMessage::new(sensor, "SensorArray")?;
client.send(&msg)?;
if sample_num % sample_rate == 0 {
let seconds = sample_num / sample_rate;
println!("[{}s] 14 channels: Force[0-7], IMU[8-13]", seconds);
print!(" Force: ");
for value in sensor_data.iter().take(8) {
print!("{:6.2} ", value);
}
println!();
print!(" IMU: ");
for value in sensor_data.iter().take(14).skip(8) {
print!("{:6.2} ", value);
}
println!();
}
let elapsed = start_time.elapsed();
if elapsed < sample_interval {
thread::sleep(sample_interval - elapsed);
}
}
Ok(())
}
fn read_force_sensor(sample_num: usize) -> Vec<f64> {
let t = sample_num as f64 * 0.01;
vec![
2.5 * (t * 2.0).sin(), -1.2 * (t * 1.5).cos(), 5.8 + 0.5 * (t * 3.0).sin(), 0.15 * (t * 1.0).sin(), -0.08 * (t * 1.2).cos(), 0.22 * (t * 0.8).sin(), ]
}
fn read_imu_sensor(sample_num: usize) -> Vec<f64> {
let t = sample_num as f64 * 0.01;
vec![
0.5 * (t * 2.0).sin(), -0.3 * (t * 1.8).cos(), 9.81 + 0.2 * (t * 2.5).sin(), 0.1 * (t * 1.5).sin(), -0.05 * (t * 1.2).cos(), 0.08 * (t * 2.0).sin(), ]
}
fn read_combined_sensors(sample_num: usize) -> Vec<f64> {
let t = sample_num as f64 * 0.01; let mut data = Vec::with_capacity(14);
for i in 0..8 {
let value = (t * (1.0 + i as f64 * 0.2)).sin() * (1.0 + i as f64 * 0.5);
data.push(value);
}
data.push(0.5 * (t * 2.0).sin());
data.push(-0.3 * (t * 1.8).cos());
data.push(9.81 + 0.2 * (t * 2.5).sin());
data.push(0.1 * (t * 1.5).sin());
data.push(-0.05 * (t * 1.2).cos());
data.push(0.08 * (t * 2.0).sin());
data
}