use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Twist {
pub timestamp: u64,
pub linear: [f32; 3],
pub angular: [f32; 3],
}
impl Twist {
pub fn new(linear_x: f32, linear_y: f32, linear_z: f32, angular_x: f32, angular_y: f32, angular_z: f32) -> Self {
Self {
timestamp: crate::prelude::now_micros(),
linear: [linear_x, linear_y, linear_z],
angular: [angular_x, angular_y, angular_z],
}
}
pub fn new_2d(linear_x: f32, angular_z: f32) -> Self {
Self::new(linear_x, 0.0, 0.0, 0.0, 0.0, angular_z)
}
pub fn stop() -> Self {
Self::new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
}
pub fn forward(speed: f32) -> Self {
Self::new_2d(speed, 0.0)
}
pub fn backward(speed: f32) -> Self {
Self::new_2d(-speed, 0.0)
}
pub fn rotate(angular_z: f32) -> Self {
Self::new_2d(0.0, angular_z)
}
pub fn linear_speed(&self) -> f32 {
let l = self.linear;
(l[0] * l[0] + l[1] * l[1] + l[2] * l[2]).sqrt()
}
pub fn angular_speed(&self) -> f32 {
let a = self.angular;
(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]).sqrt()
}
pub fn clamp(&mut self, max_linear: f32, max_angular: f32) {
let linear_mag = self.linear_speed();
if linear_mag > max_linear {
let scale = max_linear / linear_mag;
self.linear = [self.linear[0] * scale, self.linear[1] * scale, self.linear[2] * scale];
}
let angular_mag = self.angular_speed();
if angular_mag > max_angular {
let scale = max_angular / angular_mag;
self.angular = [
self.angular[0] * scale,
self.angular[1] * scale,
self.angular[2] * scale,
];
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JointState {
pub timestamp: u64,
pub names: Vec<String>,
pub positions: Vec<f32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub velocities: Option<Vec<f32>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub efforts: Option<Vec<f32>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GripperCommand {
pub timestamp: u64,
pub position: f32,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_effort: Option<f32>,
}
impl JointState {
pub fn new() -> Self {
Self {
timestamp: crate::prelude::now_micros(),
names: Vec::new(),
positions: Vec::new(),
velocities: None,
efforts: None,
}
}
pub fn with_positions(names: Vec<String>, positions: Vec<f32>) -> Self {
Self {
timestamp: crate::prelude::now_micros(),
names,
positions,
velocities: None,
efforts: None,
}
}
pub fn get_position(&self, name: &str) -> Option<f32> {
self.names
.iter()
.position(|n| n == name)
.and_then(|i| self.positions.get(i).copied())
}
pub fn is_valid(&self) -> bool {
let num = self.names.len();
if self.positions.len() != num {
return false;
}
if let Some(ref v) = self.velocities {
if v.len() != num {
return false;
}
}
if let Some(ref e) = self.efforts {
if e.len() != num {
return false;
}
}
true
}
}
impl Default for JointState {
fn default() -> Self {
Self::new()
}
}
impl GripperCommand {
pub fn open() -> Self {
Self {
timestamp: crate::prelude::now_micros(),
position: 1.0,
max_effort: None,
}
}
pub fn close() -> Self {
Self {
timestamp: crate::prelude::now_micros(),
position: 0.0,
max_effort: None,
}
}
pub fn new(position: f32, max_effort: Option<f32>) -> Self {
Self {
timestamp: crate::prelude::now_micros(),
position: position.clamp(0.0, 1.0),
max_effort,
}
}
pub fn is_open(&self) -> bool {
self.position > 0.9
}
pub fn is_closed(&self) -> bool {
self.position < 0.1
}
pub fn percent_open(&self) -> f32 {
self.position * 100.0
}
}