dynamixel/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2
3mod lib {
4    #[cfg(feature="std")]
5    pub use std::*;
6    #[cfg(not(feature="std"))]
7    pub use core::*;
8}
9
10#[macro_use]
11extern crate log;
12
13extern crate bit_field;
14
15#[cfg(feature="serialport")]
16extern crate serialport;
17
18
19#[macro_use]
20pub mod protocol1;
21#[macro_use]
22pub mod protocol2;
23pub mod pro;
24pub mod dynamixel;
25
26#[cfg(feature="serialport")]
27mod serial_impl;
28
29/// The generic servo trait
30///
31/// Allow using servos without knowing the exact type.
32pub trait Servo<I: Interface> {
33
34    /// Enable/Disable torque on the servo.
35    fn set_enable_torque(&mut self, interface: &mut I, enable_torque: bool) -> Result<(), ::Error>;
36
37    /// Set the goal position. Some servos will be put into "position control mode" when this method is called.
38    ///
39    /// value is in unit: radians
40    fn set_position(&mut self, interface: &mut I, value: f32) -> Result<(), ::Error>;
41    
42    /// Get the current position.
43    ///
44    /// The result is returned in unit: radians 
45    fn get_position(&mut self, interface: &mut I) -> Result<f32, ::Error>;
46}
47
48
49/// An Error originating from an `Interface`
50#[derive(Debug, PartialEq, Eq, Clone, Copy)]
51pub enum CommunicationError {
52    TimedOut,
53    UnsupportedBaud(BaudRate),
54    Other,
55}
56
57#[derive(Debug, PartialEq, Eq, Clone, Copy)]
58pub enum Error {
59    Unfinished,
60    
61    /// An Error originating from the `Interface`
62    Communication(CommunicationError),
63    Format,
64    Processing,
65}
66
67/// Baud rates the interface should support
68///
69/// May be extended and must not be matched against exhaustively.
70#[derive(Debug, PartialEq, Eq, Clone, Copy)]
71pub enum BaudRate {
72    /// Baud rate of 9600
73    Baud9600,
74    
75    /// Baudaud rate of 19 200
76    Baud19200,
77    
78    /// Baudaud rate of 57 600
79    Baud57600,
80    
81    /// Baudaud rate of 115 200
82    Baud115200,
83    
84    /// Baudaud rate of 200 000
85    Baud200000,
86    
87    /// Baudaud rate of 250 000
88    Baud250000,
89    
90    /// Baudaud rate of 400 000
91    Baud400000,
92    
93    /// Baudaud rate of 500 000
94    Baud500000,
95    
96    /// Baudaud rate of 1 000 000
97    Baud1000000,
98    
99    /// Baudaud rate of 2 000 000
100    Baud2000000,
101    
102    /// Baudaud rate of 3 000 000
103    Baud3000000,
104    
105    /// Baudaud rate of 4 000 000
106    Baud4000000,
107    
108    /// Baudaud rate of 4 500 000
109    Baud4500000,
110    
111    /// Baudaud rate of 10 500 000
112    Baud10500000,       
113}
114
115impl From<BaudRate> for u32 {
116    fn from(b: BaudRate) -> u32 {
117        match b {
118            BaudRate::Baud9600 => 9600,
119            BaudRate::Baud19200 => 19200,
120            BaudRate::Baud57600 => 57600,
121            BaudRate::Baud115200 => 115200,
122            BaudRate::Baud200000 => 200_000,
123            BaudRate::Baud250000 => 250_000,
124            BaudRate::Baud400000 => 400_000,
125            BaudRate::Baud500000 => 500_000,
126            BaudRate::Baud1000000 => 1_000_000,
127            BaudRate::Baud2000000 => 2_000_000,
128            BaudRate::Baud3000000 => 3_000_000,
129            BaudRate::Baud4000000 => 4_000_000,
130            BaudRate::Baud4500000 => 4_500_000,
131            BaudRate::Baud10500000 => 10_500_000,       
132        }
133    }
134}
135
136impl BaudRate {
137    fn variants() -> &'static [Self] {
138        &[BaudRate::Baud9600,
139          BaudRate::Baud19200,
140          BaudRate::Baud57600,
141          BaudRate::Baud115200,
142          BaudRate::Baud200000,
143          BaudRate::Baud250000,
144          BaudRate::Baud400000,
145          BaudRate::Baud500000,
146          BaudRate::Baud1000000,
147          BaudRate::Baud2000000,
148          BaudRate::Baud3000000,
149          BaudRate::Baud4000000,
150          BaudRate::Baud4500000,
151          BaudRate::Baud10500000,
152        ]
153    }
154}
155
156/// The interface for communicating with dynamixel servos.
157pub trait Interface {
158    /// Set the baud rate of the interface
159    ///
160    /// `BaudRate` must not be matched against exhaustively.
161    fn set_baud_rate(&mut self, b: BaudRate) -> Result<(), CommunicationError>;
162
163    /// Flush out the read buffer
164    ///
165    /// Whenever a new transmission is started, old data from the read buffer needs to be flushed out first.
166    fn flush(&mut self);
167    
168    /// A blocking/spinning read with timeout.
169    ///
170    /// This function should either:
171    ///
172    /// - read a number of bytes corresponding to `data.len()` into `data` and return `Ok(())`.
173    /// - return `Err(_)`.
174    ///
175    /// If bytes are not received for a given time, a timeout should occur.
176    /// A timeout is signaled by returning `Err(Error::Timeout)`.
177    /// The time between bytes before a timeout occur should be 100ms or more.
178    /// If the timeout is not implemented, a "dead" servo can cause the code to "freeze".
179    fn read(&mut self, data: &mut [u8]) -> Result<(), CommunicationError>;
180
181    /// A blocking/spinning write.
182    ///
183    /// This function should either:
184    /// 
185    /// - write every byte in `data` and return `Ok(())`.
186    /// - return `Err(_)`.
187    ///
188    /// After a transmission is started the time between two consecutive bytes need to be less than 100ms.
189    /// This is because the dynamixel actuator recognizes a time of more than 100ms between bytes as a communication problem.
190    fn write(&mut self, data: &[u8]) -> Result<(), CommunicationError>;
191}
192
193#[cfg(feature="std")]
194impl From<std::io::Error> for CommunicationError {
195    fn from(e: std::io::Error) -> CommunicationError {
196        match e.kind() {
197            std::io::ErrorKind::TimedOut => CommunicationError::TimedOut,
198            _ => CommunicationError::Other,
199        }
200    }
201}
202
203/// All information needed to connect to a servo
204#[derive(Debug, Clone)]
205pub enum ServoInfo {
206    Protocol1(protocol1::ServoInfo),
207    Protocol2(protocol2::ServoInfo),
208}
209
210/// Enumerate all servos connected to the interface
211///
212/// This functions returns a Vec and thus requires the `std` feature.
213#[cfg(feature="std")]
214pub fn enumerate<I: ::Interface>(interface: &mut I) -> Result<Vec<ServoInfo>, CommunicationError> {
215    let mut servos = Vec::new();
216
217    let servos_protocol1 = protocol1::enumerate(interface)?;
218    let servos_protocol2 = protocol2::enumerate(interface)?;
219
220    servos.append(&mut servos_protocol1.into_iter().map(|x| ServoInfo::Protocol1(x)).collect());
221    servos.append(&mut servos_protocol2.into_iter().map(|x| ServoInfo::Protocol2(x)).collect());
222
223    Ok(servos)
224}
225
226/// Connect genericly to a servo
227///
228/// Only offers basic functionality. If you need more functionality use the connect method of the correct servo type instead.
229/// This functions returns a Boxed trait and this requires the `std` feature.
230#[cfg(feature="std")]
231pub fn connect<I: Interface + 'static>(interface: &mut I, info: ServoInfo) -> Result<Box<Servo<I>>, CommunicationError> {
232    match info {
233        ServoInfo::Protocol1(si) => protocol1::connect(interface, si),
234        ServoInfo::Protocol2(si) => protocol2::connect(interface, si),
235    }
236}
237
238#[cfg(test)]
239mod tests {
240    #[test]
241    fn it_works() {
242        assert_eq!(2 + 2, 4);
243    }
244}