use crate::generate_servo;
generate_servo!(
XL320, v2,
reg: (model_number, r, 0, u16, None),
reg: (firmware_version, r, 2, u8, None),
reg: (id, rw, 3, u8, None),
reg: (baudrate, rw, 4, u8, None),
reg: (return_delay_time, rw, 5, u8, None),
reg: (cw_angle_limit, rw, 6, u16, None),
reg: (ccw_angle_limit, rw, 8, u16, None),
reg: (control_mode, rw, 11, u8, None),
reg: (temperature_limit, rw, 12, u8, None),
reg: (min_voltage_limit, rw, 13, u8, None),
reg: (max_voltage_limit, rw, 14, u8, None),
reg: (max_torque, rw, 15, u16, None),
reg: (status_return_level, rw, 17, u8, None),
reg: (shutdown, rw, 18, u8, None),
reg: (torque_enable, rw, 24, u8, None),
reg: (led, rw, 25, u8, None),
reg: (d_gain, rw, 27, u8, None),
reg: (i_gain, rw, 28, u8, None),
reg: (p_gain, rw, 29, u8, None),
reg: (goal_position, rw, 30, i16, None),
reg: (moving_speed, rw, 32, u16, None),
reg: (torque_limit, rw, 35, u16, None),
reg: (present_position, r, 37, i16, None),
reg: (present_speed, r, 39, u16, None),
reg: (present_load, r, 41, u16, None),
reg: (present_voltage, r, 45, u8, None),
reg: (present_temperature, r, 46, u8, None),
reg: (registered, r, 47, u8, None),
reg: (moving, r, 49, u8, None),
reg: (hardware_error_status, r, 50, u8, None),
reg: (punch, rw, 51, u16, None),
);
pub fn sync_read_present_position_speed_load(
dph: &crate::DynamixelProtocolHandler,
serial_port: &mut dyn serialport::SerialPort,
ids: &[u8],
) -> crate::Result<Vec<(i16, u16, u16)>> {
let val = dph.sync_read(serial_port, ids, 37, 2 + 2 + 2)?;
let val = val
.iter()
.map(|v| {
(
i16::from_le_bytes(v[0..2].try_into().unwrap()),
u16::from_le_bytes(v[2..4].try_into().unwrap()),
u16::from_le_bytes(v[4..6].try_into().unwrap()),
)
})
.collect();
Ok(val)
}
pub mod conv {
pub fn xl320_pos_to_radians(pos: i16) -> f64 {
(300.0_f64.to_radians() * (pos as f64) / 1024.0) - 150.0_f64.to_radians()
}
pub fn radians_to_xl320_pos(rads: f64) -> i16 {
(1024.0 * (150.0_f64.to_radians() + rads) / 300.0_f64.to_radians()) as i16
}
pub fn xl320_abs_speed_to_rad_per_sec(speed: u16) -> f64 {
let rpm = speed as f64 * 0.111;
rpm * 0.10472
}
pub fn rad_per_sec_to_xl320_abs_speed(speed: f64) -> u16 {
let rpm = speed / 0.10472;
(rpm / 0.111) as u16
}
pub fn xl320_oriented_speed_to_rad_per_sec(speed: u16) -> f64 {
let cw = (speed >> 11) == 1;
let rad_per_sec = xl320_abs_speed_to_rad_per_sec(speed % 1024);
match cw {
true => rad_per_sec,
false => -rad_per_sec,
}
}
pub fn rad_per_sec_to_xl320_oriented_speed(speed: f64) -> u16 {
let raw = rad_per_sec_to_xl320_abs_speed(speed.abs());
match speed < 0.0 {
true => raw,
false => raw + 2048,
}
}
pub fn xl320_load_to_abs_torque(load: u16) -> f64 {
load as f64 / 1023.0 * 100.0
}
pub fn torque_to_xl320_abs_load(torque: f64) -> u16 {
assert!(torque >= 0.0);
assert!(torque <= 100.0);
(torque * 1023.0 / 100.0) as u16
}
pub fn xl320_load_to_oriented_torque(load: u16) -> f64 {
let cw = (load >> 10) == 1;
let torque = xl320_load_to_abs_torque(load % 1024);
match cw {
true => torque,
false => -torque,
}
}
pub fn oriented_torque_to_xl320_load(torque: f64) -> u16 {
let load = torque_to_xl320_abs_load(torque.abs());
match torque < 0.0 {
true => load,
false => load + 1024,
}
}
}
#[cfg(test)]
mod tests {
use super::conv::*;
#[test]
fn position_conversions() {
assert_eq!(radians_to_xl320_pos(0.0), 512);
assert_eq!(radians_to_xl320_pos(-150.0_f64.to_radians()), 0);
assert_eq!(radians_to_xl320_pos(150.0_f64.to_radians()), 1024);
assert_eq!(xl320_pos_to_radians(0), -150.0_f64.to_radians());
assert_eq!(xl320_pos_to_radians(512), 0.0);
assert_eq!(xl320_pos_to_radians(1024), 150.0_f64.to_radians());
}
#[test]
fn abs_speed_conversions() {
assert_eq!(rad_per_sec_to_xl320_abs_speed(0.0), 0);
assert_eq!(rad_per_sec_to_xl320_abs_speed(0.5), 43);
assert_eq!(
rad_per_sec_to_xl320_abs_speed(xl320_abs_speed_to_rad_per_sec(66)),
66
);
}
#[test]
fn speed_conversions() {
assert_eq!(xl320_oriented_speed_to_rad_per_sec(99), -1.15076808);
assert_eq!(xl320_oriented_speed_to_rad_per_sec(2048 + 99), 1.15076808);
assert_eq!(
rad_per_sec_to_xl320_oriented_speed(xl320_oriented_speed_to_rad_per_sec(42)),
42
);
}
#[test]
fn torque_conversions() {
assert_eq!(torque_to_xl320_abs_load(0.0), 0);
assert_eq!(torque_to_xl320_abs_load(50.0), 511);
assert_eq!(torque_to_xl320_abs_load(100.0), 1023);
assert_eq!(xl320_load_to_abs_torque(0), 0.0);
assert!((xl320_load_to_abs_torque(511) - 50.0).abs() < 1e-1);
assert_eq!(xl320_load_to_abs_torque(1023), 100.0);
}
#[test]
fn load_conversions() {
assert!((xl320_load_to_abs_torque(511) - 50.0).abs() < 1e-1);
assert!((xl320_load_to_oriented_torque(1024 + 511) - 50.0).abs() < 1e-1);
assert!(
(xl320_load_to_oriented_torque(oriented_torque_to_xl320_load(25.0)) - 25.0).abs()
< 1e-1
);
}
}