use crate::command::PositionCommand;
use crate::query::QueryResult;
use crate::transport::args::TransportArgs;
use crate::transport::async_transport::AsyncRouter;
use crate::transport::singleton::get_singleton_transport;
use crate::transport::transaction::Request;
use crate::Controller;
use clap::Parser;
use std::time::{Duration, Instant};
#[derive(Parser)]
#[command(about = "Command multiple servos with auto-discovery")]
struct Args {
#[arg(long)]
r#async: bool,
#[command(flatten)]
transport: TransportArgs,
}
fn run_blocking(args: &Args) -> Result<(), crate::Error> {
let transport = get_singleton_transport(Some(&args.transport.clone().into()))?;
let mut transport = transport.lock().unwrap();
let devices = transport.discover(0, 0)?;
if devices.is_empty() {
println!("No devices found!");
return Ok(());
}
println!("Discovered {} device(s):", devices.len());
for device in &devices {
println!(" CAN ID: {}", device.can_id);
}
println!();
let servo_ids: Vec<u8> = devices.iter().map(|d| d.can_id).collect();
let servos: Vec<Controller> = servo_ids.iter().map(|&id| Controller::new(id)).collect();
let mut stop_requests: Vec<_> = servos
.iter()
.map(|s| Request::new(s.make_stop(false).into_frame()))
.collect();
transport.cycle(&mut stop_requests)?;
let start = Instant::now();
loop {
let now = start.elapsed().as_secs_f32();
let mut requests: Vec<_> = servos
.iter()
.enumerate()
.map(|(i, servo)| {
let velocity = 0.1 * (now + i as f32).sin();
Request::new(
servo
.make_position_command(
&PositionCommand::new().position(f32::NAN).velocity(velocity),
true, )
.into_frame(),
)
})
.collect();
transport.cycle(&mut requests)?;
let output: Vec<String> = requests
.iter()
.flat_map(|req| req.responses.peek())
.map(|frame| {
let result = QueryResult::parse(&frame);
format!(
"({:04X} {:.4} {:.4})",
frame.arbitration_id, result.position, result.velocity
)
})
.collect();
println!("{}", output.join(", "));
std::thread::sleep(Duration::from_millis(20));
}
}
#[tokio::main]
async fn run_async(args: &Args) -> Result<(), crate::Error> {
let opts = args.transport.clone().into();
let mut transport = AsyncRouter::with_options(&opts).await?;
let devices = transport.discover(0, 0).await?;
if devices.is_empty() {
println!("No devices found!");
return Ok(());
}
println!("Discovered {} device(s):", devices.len());
for device in &devices {
println!(" CAN ID: {}", device.can_id);
}
println!();
let servo_ids: Vec<u8> = devices.iter().map(|d| d.can_id).collect();
let servos: Vec<Controller> = servo_ids.iter().map(|&id| Controller::new(id)).collect();
let mut stop_requests: Vec<_> = servos
.iter()
.map(|s| Request::new(s.make_stop(false).into_frame()))
.collect();
transport.cycle(&mut stop_requests).await?;
let start = Instant::now();
loop {
let now = start.elapsed().as_secs_f32();
let mut requests: Vec<_> = servos
.iter()
.enumerate()
.map(|(i, servo)| {
let velocity = 0.1 * (now + i as f32).sin();
Request::new(
servo
.make_position_command(
&PositionCommand::new().position(f32::NAN).velocity(velocity),
true, )
.into_frame(),
)
})
.collect();
transport.cycle(&mut requests).await?;
let output: Vec<String> = requests
.iter()
.flat_map(|req| req.responses.peek())
.map(|frame| {
let result = QueryResult::parse(&frame);
format!(
"({:04X} {:.4} {:.4})",
frame.arbitration_id, result.position, result.velocity
)
})
.collect();
println!("{}", output.join(", "));
tokio::time::sleep(Duration::from_millis(20)).await;
}
}
pub fn run(register_transports: impl FnOnce()) -> Result<(), crate::Error> {
let args = Args::parse();
register_transports();
if args.r#async {
run_async(&args)
} else {
run_blocking(&args)
}
}