1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
#![cfg_attr(not(feature = "std"), no_std)]

mod lib {
    #[cfg(feature="std")]
    pub use std::*;
    #[cfg(not(feature="std"))]
    pub use core::*;
}

#[macro_use]
extern crate log;

extern crate bit_field;

#[cfg(feature="serialport")]
extern crate serialport;


#[macro_use]
pub mod protocol1;
#[macro_use]
pub mod protocol2;
pub mod pro;
pub mod dynamixel;

#[cfg(feature="serialport")]
mod serial_impl;

/// The generic servo trait
///
/// Allow using servos without knowing the exact type.
pub trait Servo<I: Interface> {

    /// Enable/Disable torque on the servo.
    fn set_enable_torque(&mut self, interface: &mut I, enable_torque: bool) -> Result<(), ::Error>;

    /// Set the goal position. Some servos will be put into "position control mode" when this method is called.
    ///
    /// value is in unit: radians
    fn set_position(&mut self, interface: &mut I, value: f32) -> Result<(), ::Error>;
    
    /// Get the current position.
    ///
    /// The result is returned in unit: radians 
    fn get_position(&mut self, interface: &mut I) -> Result<f32, ::Error>;
}


/// An Error originating from an `Interface`
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum CommunicationError {
    TimedOut,
    UnsupportedBaud(BaudRate),
    Other,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Error {
    Unfinished,
    
    /// An Error originating from the `Interface`
    Communication(CommunicationError),
    Format,
    Processing,
}

/// Baud rates the interface should support
///
/// May be extended and must not be matched against exhaustively.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum BaudRate {
    /// Baud rate of 9600
    Baud9600,
    
    /// Baudaud rate of 19 200
    Baud19200,
    
    /// Baudaud rate of 57 600
    Baud57600,
    
    /// Baudaud rate of 115 200
    Baud115200,
    
    /// Baudaud rate of 200 000
    Baud200000,
    
    /// Baudaud rate of 250 000
    Baud250000,
    
    /// Baudaud rate of 400 000
    Baud400000,
    
    /// Baudaud rate of 500 000
    Baud500000,
    
    /// Baudaud rate of 1 000 000
    Baud1000000,
    
    /// Baudaud rate of 2 000 000
    Baud2000000,
    
    /// Baudaud rate of 3 000 000
    Baud3000000,
    
    /// Baudaud rate of 4 000 000
    Baud4000000,
    
    /// Baudaud rate of 4 500 000
    Baud4500000,
    
    /// Baudaud rate of 10 500 000
    Baud10500000,       
}

impl From<BaudRate> for u32 {
    fn from(b: BaudRate) -> u32 {
        match b {
            BaudRate::Baud9600 => 9600,
            BaudRate::Baud19200 => 19200,
            BaudRate::Baud57600 => 57600,
            BaudRate::Baud115200 => 115200,
            BaudRate::Baud200000 => 200_000,
            BaudRate::Baud250000 => 250_000,
            BaudRate::Baud400000 => 400_000,
            BaudRate::Baud500000 => 500_000,
            BaudRate::Baud1000000 => 1_000_000,
            BaudRate::Baud2000000 => 2_000_000,
            BaudRate::Baud3000000 => 3_000_000,
            BaudRate::Baud4000000 => 4_000_000,
            BaudRate::Baud4500000 => 4_500_000,
            BaudRate::Baud10500000 => 10_500_000,       
        }
    }
}

impl BaudRate {
    fn variants() -> &'static [Self] {
        &[BaudRate::Baud9600,
          BaudRate::Baud19200,
          BaudRate::Baud57600,
          BaudRate::Baud115200,
          BaudRate::Baud200000,
          BaudRate::Baud250000,
          BaudRate::Baud400000,
          BaudRate::Baud500000,
          BaudRate::Baud1000000,
          BaudRate::Baud2000000,
          BaudRate::Baud3000000,
          BaudRate::Baud4000000,
          BaudRate::Baud4500000,
          BaudRate::Baud10500000,
        ]
    }
}

/// The interface for communicating with dynamixel servos.
pub trait Interface {
    /// Set the baud rate of the interface
    ///
    /// `BaudRate` must not be matched against exhaustively.
    fn set_baud_rate(&mut self, b: BaudRate) -> Result<(), CommunicationError>;

    /// Flush out the read buffer
    ///
    /// Whenever a new transmission is started, old data from the read buffer needs to be flushed out first.
    fn flush(&mut self);
    
    /// A blocking/spinning read with timeout.
    ///
    /// This function should either:
    ///
    /// - read a number of bytes corresponding to `data.len()` into `data` and return `Ok(())`.
    /// - return `Err(_)`.
    ///
    /// If bytes are not received for a given time, a timeout should occur.
    /// A timeout is signaled by returning `Err(Error::Timeout)`.
    /// The time between bytes before a timeout occur should be 100ms or more.
    /// If the timeout is not implemented, a "dead" servo can cause the code to "freeze".
    fn read(&mut self, data: &mut [u8]) -> Result<(), CommunicationError>;

    /// A blocking/spinning write.
    ///
    /// This function should either:
    /// 
    /// - write every byte in `data` and return `Ok(())`.
    /// - return `Err(_)`.
    ///
    /// After a transmission is started the time between two consecutive bytes need to be less than 100ms.
    /// This is because the dynamixel actuator recognizes a time of more than 100ms between bytes as a communication problem.
    fn write(&mut self, data: &[u8]) -> Result<(), CommunicationError>;
}

#[cfg(feature="std")]
impl From<std::io::Error> for CommunicationError {
    fn from(e: std::io::Error) -> CommunicationError {
        match e.kind() {
            std::io::ErrorKind::TimedOut => CommunicationError::TimedOut,
            _ => CommunicationError::Other,
        }
    }
}

/// All information needed to connect to a servo
#[derive(Debug, Clone)]
pub enum ServoInfo {
    Protocol1(protocol1::ServoInfo),
    Protocol2(protocol2::ServoInfo),
}

/// Enumerate all servos connected to the interface
///
/// This functions returns a Vec and thus requires the `std` feature.
#[cfg(feature="std")]
pub fn enumerate<I: ::Interface>(interface: &mut I) -> Result<Vec<ServoInfo>, CommunicationError> {
    let mut servos = Vec::new();

    let servos_protocol1 = protocol1::enumerate(interface)?;
    let servos_protocol2 = protocol2::enumerate(interface)?;

    servos.append(&mut servos_protocol1.into_iter().map(|x| ServoInfo::Protocol1(x)).collect());
    servos.append(&mut servos_protocol2.into_iter().map(|x| ServoInfo::Protocol2(x)).collect());

    Ok(servos)
}

/// Connect genericly to a servo
///
/// Only offers basic functionality. If you need more functionality use the connect method of the correct servo type instead.
/// This functions returns a Boxed trait and this requires the `std` feature.
#[cfg(feature="std")]
pub fn connect<I: Interface + 'static>(interface: &mut I, info: ServoInfo) -> Result<Box<Servo<I>>, CommunicationError> {
    match info {
        ServoInfo::Protocol1(si) => protocol1::connect(interface, si),
        ServoInfo::Protocol2(si) => protocol2::connect(interface, si),
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }
}