use std::time::Duration;
mod error;
pub use error::IncompleteTransmissionError;
pub use error::ReceiveError;
pub use error::SendError;
mod generated;
pub mod msg {
pub use super::generated::*;
}
pub mod sync_peer;
#[cfg(feature = "tokio")]
pub mod tokio_peer;
#[cfg(feature = "nalgebra")]
mod nalgebra;
impl msg::EgmHeader {
pub fn new(seqno: u32, timestamp_ms: u32, kind: msg::egm_header::MessageType) -> Self {
Self {
seqno: Some(seqno),
tm: Some(timestamp_ms),
mtype: Some(kind as i32),
}
}
pub fn command(seqno: u32, timestamp_ms: u32) -> Self {
Self::new(seqno, timestamp_ms, msg::egm_header::MessageType::MsgtypeCommand)
}
pub fn data(seqno: u32, timestamp_ms: u32) -> Self {
Self::new(seqno, timestamp_ms, msg::egm_header::MessageType::MsgtypeData)
}
pub fn correction(seqno: u32, timestamp_ms: u32) -> Self {
Self::new(seqno, timestamp_ms, msg::egm_header::MessageType::MsgtypeCorrection)
}
pub fn path_correction(seqno: u32, timestamp_ms: u32) -> Self {
Self::new(seqno, timestamp_ms, msg::egm_header::MessageType::MsgtypePathCorrection)
}
}
impl msg::EgmCartesian {
pub fn from_mm(x: f64, y: f64, z: f64) -> Self {
Self { x, y, z }
}
pub fn as_mm(&self) -> [f64; 3] {
[self.x, self.y, self.z]
}
}
impl From<[f64; 3]> for msg::EgmCartesian {
fn from(other: [f64; 3]) -> Self {
let [x, y, z] = other;
Self::from_mm(x, y, z)
}
}
impl From<(f64, f64, f64)> for msg::EgmCartesian {
fn from(other: (f64, f64, f64)) -> Self {
let (x, y, z) = other;
Self::from_mm(x, y, z)
}
}
impl msg::EgmQuaternion {
pub fn from_wxyz(w: f64, x: f64, y: f64, z: f64) -> Self {
Self {
u0: w,
u1: x,
u2: y,
u3: z,
}
}
pub fn as_wxyz(&self) -> [f64; 4] {
[self.u0, self.u1, self.u2, self.u3]
}
}
impl msg::EgmEuler {
pub fn from_xyz_degrees(x: f64, y: f64, z: f64) -> Self {
Self { x, y, z }
}
pub fn as_xyz_degrees(&self) -> [f64; 3] {
[self.x, self.y, self.z]
}
}
impl msg::EgmClock {
pub fn new(sec: u64, usec: u64) -> Self {
Self { sec, usec }
}
pub fn elapsed_since_epoch(&self) -> Duration {
Duration::new(self.sec, (self.usec) as u32 * 1000)
}
}
impl Copy for msg::EgmClock {}
impl std::ops::Add<&Duration> for &msg::EgmClock {
type Output = msg::EgmClock;
fn add(self, right: &Duration) -> Self::Output {
let usec = self.usec + u64::from(right.subsec_micros());
msg::EgmClock {
sec: self.sec + right.as_secs() + usec / 1_000_000,
usec: usec % 1_000_000,
}
}
}
impl std::ops::Add<&msg::EgmClock> for &Duration {
type Output = msg::EgmClock;
fn add(self, right: &msg::EgmClock) -> Self::Output {
right + self
}
}
impl std::ops::Add<Duration> for msg::EgmClock {
type Output = Self;
fn add(self, right: Duration) -> Self::Output {
&self + &right
}
}
impl std::ops::Add<msg::EgmClock> for Duration {
type Output = msg::EgmClock;
fn add(self, right: msg::EgmClock) -> Self::Output {
&self + &right
}
}
impl std::ops::AddAssign<&Duration> for msg::EgmClock {
fn add_assign(&mut self, right: &Duration) {
*self = &*self + right
}
}
impl std::ops::AddAssign<Duration> for msg::EgmClock {
fn add_assign(&mut self, right: Duration) {
*self += &right
}
}
#[cfg(test)]
#[test]
fn test_add_duration() {
use assert2::assert;
use msg::EgmClock;
assert!(EgmClock::new(1, 500_000) + Duration::from_secs(1) == EgmClock::new(2, 500_000));
assert!(EgmClock::new(1, 500_000) + Duration::from_millis(600) == EgmClock::new(2, 100_000));
assert!(&EgmClock::new(1, 500_000) + &Duration::from_secs(1) == EgmClock::new(2, 500_000));
assert!(&EgmClock::new(1, 500_000) + &Duration::from_millis(600) == EgmClock::new(2, 100_000));
assert!(Duration::from_secs(1) + EgmClock::new(1, 500_000) == EgmClock::new(2, 500_000));
assert!(Duration::from_millis(600) + EgmClock::new(1, 500_000) == EgmClock::new(2, 100_000));
assert!(&Duration::from_secs(1) + &EgmClock::new(1, 500_000) == EgmClock::new(2, 500_000));
assert!(&Duration::from_millis(600) + &EgmClock::new(1, 500_000) == EgmClock::new(2, 100_000));
let mut clock = EgmClock::new(10, 999_999);
clock += Duration::from_micros(1);
assert!(clock == EgmClock::new(11, 0));
clock += Duration::from_micros(999_999);
assert!(clock == EgmClock::new(11, 999_999));
clock += Duration::from_micros(2);
assert!(clock == EgmClock::new(12, 1));
}
impl msg::EgmPose {
pub fn new(position: impl Into<msg::EgmCartesian>, orientation: impl Into<msg::EgmQuaternion>) -> Self {
Self {
pos: Some(position.into()),
orient: Some(orientation.into()),
euler: None,
}
}
}
impl msg::EgmCartesianSpeed {
pub fn from_mm_and_degrees(linear: [f64; 3], rotational: [f64; 3]) -> Self {
Self {
value: vec![
linear[0],
linear[1],
linear[2],
rotational[0],
rotational[1],
rotational[2],
],
}
}
}
impl msg::EgmJoints {
pub fn from_degrees(joints: impl Into<Vec<f64>>) -> Self {
Self { joints: joints.into() }
}
}
impl From<Vec<f64>> for msg::EgmJoints {
fn from(other: Vec<f64>) -> Self {
Self::from_degrees(other)
}
}
impl From<&[f64]> for msg::EgmJoints {
fn from(other: &[f64]) -> Self {
Self::from_degrees(other)
}
}
impl From<&[f64; 6]> for msg::EgmJoints {
fn from(other: &[f64; 6]) -> Self {
Self::from_degrees(&other[..])
}
}
impl msg::EgmExternalJoints {
pub fn from_degrees(joints: impl Into<Vec<f64>>) -> Self {
Self { joints: joints.into() }
}
}
impl From<Vec<f64>> for msg::EgmExternalJoints {
fn from(other: Vec<f64>) -> Self {
Self::from_degrees(other)
}
}
impl From<&[f64]> for msg::EgmExternalJoints {
fn from(other: &[f64]) -> Self {
Self::from_degrees(other)
}
}
impl msg::EgmPlanned {
pub fn joints(joints: impl Into<msg::EgmJoints>, time: impl Into<msg::EgmClock>) -> Self {
Self {
time: Some(time.into()),
joints: Some(joints.into()),
cartesian: None,
external_joints: None,
}
}
pub fn pose(pose: impl Into<msg::EgmPose>, time: impl Into<msg::EgmClock>) -> Self {
Self {
time: Some(time.into()),
cartesian: Some(pose.into()),
joints: None,
external_joints: None,
}
}
}
impl msg::EgmPathCorr {
pub fn new(position: impl Into<msg::EgmCartesian>, age_ms: u32) -> Self {
Self {
pos: position.into(),
age: age_ms,
}
}
}
impl msg::EgmSensor {
pub fn joint_target(sequence_number: u32, joints: impl Into<msg::EgmJoints>, time: impl Into<msg::EgmClock>) -> Self {
let time = time.into();
let timestamp_ms = (time.sec.wrapping_mul(1000) + time.usec / 1000) as u32;
Self {
header: Some(msg::EgmHeader::correction(sequence_number, timestamp_ms)),
planned: Some(msg::EgmPlanned::joints(joints, time)),
speed_ref: None,
}
}
pub fn pose_target(sequence_number: u32, pose: impl Into<msg::EgmPose>, time: impl Into<msg::EgmClock>) -> Self {
let time = time.into();
let timestamp_ms = (time.sec.wrapping_mul(1000) + time.usec / 1000) as u32;
Self {
header: Some(msg::EgmHeader::correction(sequence_number, timestamp_ms)),
planned: Some(msg::EgmPlanned::pose(pose, time)),
speed_ref: None,
}
}
}
impl msg::EgmSensorPathCorr {
pub fn new(sequence_number: u32, timestamp_ms: u32, correction: impl Into<msg::EgmCartesian>, age_ms: u32) -> Self {
Self {
header: Some(msg::EgmHeader::path_correction(sequence_number, timestamp_ms)),
path_corr: Some(msg::EgmPathCorr::new(correction, age_ms)),
}
}
}
impl msg::EgmRobot {
pub fn sequence_number(&self) -> Option<u32> {
self.header.as_ref()?.seqno
}
pub fn timestamp_ms(&self) -> Option<u32> {
self.header.as_ref()?.tm
}
pub fn feedback_joints(&self) -> Option<&Vec<f64>> {
Some(&self.feed_back.as_ref()?.joints.as_ref()?.joints)
}
pub fn feedback_pose(&self) -> Option<&msg::EgmPose> {
self.feed_back.as_ref()?.cartesian.as_ref()
}
pub fn feedback_extenal_joints(&self) -> Option<&Vec<f64>> {
Some(&self.feed_back.as_ref()?.external_joints.as_ref()?.joints)
}
pub fn feedback_time(&self) -> Option<msg::EgmClock> {
self.feed_back.as_ref()?.time.clone()
}
pub fn planned_joints(&self) -> Option<&Vec<f64>> {
Some(&self.planned.as_ref()?.joints.as_ref()?.joints)
}
pub fn planned_pose(&self) -> Option<&msg::EgmPose> {
self.planned.as_ref()?.cartesian.as_ref()
}
pub fn planned_extenal_joints(&self) -> Option<&Vec<f64>> {
Some(&self.planned.as_ref()?.external_joints.as_ref()?.joints)
}
pub fn planned_time(&self) -> Option<msg::EgmClock> {
self.planned.as_ref()?.time.clone()
}
pub fn motors_enabled(&self) -> Option<bool> {
use msg::egm_motor_state::MotorStateType;
match self.motor_state.as_ref()?.state() {
MotorStateType::MotorsUndefined => None,
MotorStateType::MotorsOn => Some(true),
MotorStateType::MotorsOff => Some(false),
}
}
pub fn rapid_running(&self) -> Option<bool> {
use msg::egm_rapid_ctrl_exec_state::RapidCtrlExecStateType;
match self.rapid_exec_state.as_ref()?.state() {
RapidCtrlExecStateType::RapidUndefined => None,
RapidCtrlExecStateType::RapidRunning => Some(true),
RapidCtrlExecStateType::RapidStopped => Some(false),
}
}
pub fn test_signals(&self) -> Option<&Vec<f64>> {
Some(&self.test_signals.as_ref()?.signals)
}
pub fn measured_force(&self) -> Option<&Vec<f64>> {
Some(&self.measured_force.as_ref()?.force)
}
}
fn encode_to_vec(msg: &impl prost::Message) -> Result<Vec<u8>, prost::EncodeError> {
let encoded_len = msg.encoded_len();
let mut buffer = Vec::<u8>::with_capacity(encoded_len);
msg.encode(&mut buffer)?;
Ok(buffer)
}
#[cfg(test)]
#[test]
fn test_encode_to_vec() {
use assert2::assert;
use prost::Message;
assert!(encode_to_vec(&true).unwrap().len() == true.encoded_len());
assert!(encode_to_vec(&10).unwrap().len() == 10.encoded_len());
assert!(encode_to_vec(&String::from("aap noot mies")).unwrap().len() == String::from("aap noot mies").encoded_len());
}