Get the example working with a real lidar

This commit is contained in:
Piv
2022-03-30 18:35:19 +10:30
parent 1461814c27
commit bd300269dd
2 changed files with 58 additions and 26 deletions

View File

@@ -0,0 +1,14 @@
use rplidar_rs::Lidar;
use std::time::Duration;
fn main() {
let serial = serialport::new("/dev/cu.usbserial-0001", 115200)
.timeout(Duration::from_secs(10))
.open_native()
.expect("Failed to open serial port, check it's available");
let mut lidar = Lidar::new(serial);
lidar.start_scanning().expect("Failed to start scanning");
for scan in lidar {
println!("{}", scan.len());
}
}

View File

@@ -1,3 +1,4 @@
use core::fmt;
use serialport::ClearBuffer; use serialport::ClearBuffer;
use serialport::SerialPort; use serialport::SerialPort;
use std::io::Error; use std::io::Error;
@@ -26,6 +27,7 @@ const SCAN_TYPE: u8 = 129;
const SET_PWM: u8 = 0xF0; const SET_PWM: u8 = 0xF0;
const MAX_MOTOR_PWM: usize = 1023; const MAX_MOTOR_PWM: usize = 1023;
#[allow(dead_code)]
const DEFAULT_MOTOR_PWM: usize = 660; const DEFAULT_MOTOR_PWM: usize = 660;
const SCAN_SIZE: u8 = 5; const SCAN_SIZE: u8 = 5;
@@ -52,17 +54,31 @@ pub enum RPLidarError {
IncorrectHealthFormat, IncorrectHealthFormat,
ScanError(String), ScanError(String),
IncorrectDescriptorFormat, IncorrectDescriptorFormat,
IOError(Error),
} }
impl From<Error> for RPLidarError { impl From<Error> for RPLidarError {
fn from(_: Error) -> Self { fn from(err: Error) -> Self {
todo!() RPLidarError::IOError(err)
} }
} }
impl From<FromUtf8Error> for RPLidarError { impl From<FromUtf8Error> for RPLidarError {
fn from(_: FromUtf8Error) -> Self { fn from(_: FromUtf8Error) -> Self {
todo!() RPLidarError::IncorrectDescriptorFormat
}
}
impl fmt::Debug for RPLidarError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::FailedToStart => write!(f, "FailedToStart"),
Self::IncorrectInfoFormat => write!(f, "IncorrectInfoFormat"),
Self::IncorrectHealthFormat => write!(f, "IncorrectHealthFormat"),
Self::ScanError(arg0) => f.debug_tuple("ScanError").field(arg0).finish(),
Self::IncorrectDescriptorFormat => write!(f, "IncorrectDescriptorFormat"),
Self::IOError(arg0) => f.debug_tuple("IOError").field(arg0).finish(),
}
} }
} }
@@ -73,7 +89,7 @@ pub struct LidarScan {
pub distance: f64, pub distance: f64,
} }
fn process_scan(raw: Vec<u8>) -> Result<LidarScan, RPLidarError> { fn process_scan(raw: [u8; SCAN_SIZE as usize]) -> Result<LidarScan, RPLidarError> {
let new_scan = raw[0] & 0b1; let new_scan = raw[0] & 0b1;
let inversed_new_scan = (raw[0] >> 1) & 0b1; let inversed_new_scan = (raw[0] >> 1) & 0b1;
let quality = raw[0] >> 2; let quality = raw[0] >> 2;
@@ -89,7 +105,7 @@ fn process_scan(raw: Vec<u8>) -> Result<LidarScan, RPLidarError> {
))); )));
} }
let angle = (((raw[1] as isize) >> 1 + (raw[2] as isize) << 7) as f64) / 64.; let angle = ((((raw[1] as isize) >> 1) + (raw[2] as isize) << 7) as f64) / 64.;
let distance = (((raw[3] as isize) + ((raw[4] as isize) << 8)) as f64) / 4.; let distance = (((raw[3] as isize) + ((raw[4] as isize) << 8)) as f64) / 4.;
Ok(LidarScan { Ok(LidarScan {
@@ -102,8 +118,6 @@ fn process_scan(raw: Vec<u8>) -> Result<LidarScan, RPLidarError> {
pub struct Lidar<T: SerialPort> { pub struct Lidar<T: SerialPort> {
motor_running: bool, motor_running: bool,
// TODO: There's a good chance we'll only be able to get back a dyn serialport, which
// sucks as then this will need to be dyn as well.
serial_port: T, serial_port: T,
is_scanning: bool, is_scanning: bool,
measurements_per_batch: usize, measurements_per_batch: usize,
@@ -131,7 +145,7 @@ impl<T: SerialPort> Lidar<T> {
self.serial_port self.serial_port
.write_data_terminal_ready(true) .write_data_terminal_ready(true)
.expect("Failed to write dtr"); .expect("Failed to write dtr");
self.set_pwm(DEFAULT_MOTOR_PWM); // self.set_pwm(DEFAULT_MOTOR_PWM);
self.motor_running = true; self.motor_running = true;
} }
@@ -169,13 +183,14 @@ impl<T: SerialPort> Lidar<T> {
if data_size != INFO_LEN || !is_single || data_type != INFO_TYPE { if data_size != INFO_LEN || !is_single || data_type != INFO_TYPE {
return Err(RPLidarError::IncorrectInfoFormat); return Err(RPLidarError::IncorrectInfoFormat);
} }
let mut buf = [0; INFO_LEN as usize];
let raw = self.read_response(data_size)?; self.serial_port.read(&mut buf)?;
let raw = buf;
let serial_number = String::from_utf8(Vec::from(&raw[4..]))?; let serial_number = String::from_utf8(Vec::from(&raw[4..]))?;
return Ok((raw[0], (raw[2], raw[1]), raw[3], serial_number)); return Ok((raw[0], (raw[2], raw[1]), raw[3], serial_number));
} }
pub fn get_health(&mut self) -> Result<(HealthStatus, u8), RPLidarError> { pub fn get_health(&mut self) -> Result<(HealthStatus, usize), RPLidarError> {
self.send_command(vec![GET_HEALTH]); self.send_command(vec![GET_HEALTH]);
let (data_size, is_single, data_type) = self.read_descriptor()?; let (data_size, is_single, data_type) = self.read_descriptor()?;
@@ -184,9 +199,11 @@ impl<T: SerialPort> Lidar<T> {
return Err(RPLidarError::IncorrectHealthFormat); return Err(RPLidarError::IncorrectHealthFormat);
} }
let raw = self.read_response(data_size)?; let mut buf = [0; HEALTH_LEN as usize];
self.serial_port.read(&mut buf)?;
let raw = buf;
let status = HealthStatus::from_raw(raw[0]); let status = HealthStatus::from_raw(raw[0]);
let error_code = raw[1] << 8 + raw[2]; let error_code = (raw[1] as usize) << 8 + raw[2];
return Ok((status, error_code)); return Ok((status, error_code));
} }
@@ -208,15 +225,20 @@ impl<T: SerialPort> Lidar<T> {
pub fn receive_measurement_and_clear_buffer( pub fn receive_measurement_and_clear_buffer(
&mut self, &mut self,
max_buffer_measurements: u32, max_buffer_measurements: u32,
) -> Result<Vec<u8>, RPLidarError> { ) -> Result<[u8; SCAN_SIZE as usize], RPLidarError> {
if !self.is_scanning { if !self.is_scanning {
return Err(RPLidarError::ScanError(String::from( return Err(RPLidarError::ScanError(String::from(
"Haven't started scanning", "Haven't started scanning",
))); )));
} }
let raw = self.read_response(SCAN_SIZE)?; let mut buf = [0; SCAN_SIZE as usize];
self.serial_port.read(&mut buf)?;
let raw = buf;
if max_buffer_measurements > 0 { if max_buffer_measurements > 0 {
if self.serial_port.bytes_to_read().unwrap() if self
.serial_port
.bytes_to_read()
.expect("Failed to get bytes to read")
> max_buffer_measurements * SCAN_SIZE as u32 > max_buffer_measurements * SCAN_SIZE as u32
{ {
println!("Too many measurements in the input buffer. Clearing Buffer"); println!("Too many measurements in the input buffer. Clearing Buffer");
@@ -229,7 +251,6 @@ impl<T: SerialPort> Lidar<T> {
} }
fn send_command(&mut self, command: Vec<u8>) { fn send_command(&mut self, command: Vec<u8>) {
// TODO: More performant way to do this? It doesn't really matter as it's just sending a command
let mut vec = vec![SYNC]; let mut vec = vec![SYNC];
vec.extend(command); vec.extend(command);
self.serial_port self.serial_port
@@ -238,7 +259,10 @@ impl<T: SerialPort> Lidar<T> {
} }
fn send_payload_command(&mut self, cmd: u8, payload: Vec<u8>) { fn send_payload_command(&mut self, cmd: u8, payload: Vec<u8>) {
let size: u8 = payload.len().try_into().unwrap(); let size: u8 = payload
.len()
.try_into()
.expect("Failed to convert payload length");
let mut req = vec![SYNC]; let mut req = vec![SYNC];
req.push(cmd); req.push(cmd);
req.push(size); req.push(size);
@@ -254,15 +278,15 @@ impl<T: SerialPort> Lidar<T> {
data.iter() data.iter()
.copied() .copied()
.reduce(|accum, next| accum ^ next) .reduce(|accum, next| accum ^ next)
.unwrap() .expect("Failed to calculate checksum")
.to_owned() .to_owned()
} }
// TODO: Custom error type and unwrap the Option so we just return a result
fn read_descriptor(&mut self) -> Result<(u8, bool, u8), RPLidarError> { fn read_descriptor(&mut self) -> Result<(u8, bool, u8), RPLidarError> {
let mut descriptor: [u8; DESCRIPTOR_LEN] = [0; DESCRIPTOR_LEN]; let mut descriptor: [u8; DESCRIPTOR_LEN] = [0; DESCRIPTOR_LEN];
let ret = self.serial_port.read(&mut descriptor)?; let ret = self.serial_port.read(&mut descriptor)?;
if ret != DESCRIPTOR_LEN || (descriptor[0] != SYNC && descriptor[1] != SYNC2) { if ret != DESCRIPTOR_LEN || (descriptor[0] != SYNC && descriptor[1] != SYNC2) {
eprintln!("Failed to read enough or something");
Err(RPLidarError::IncorrectDescriptorFormat) Err(RPLidarError::IncorrectDescriptorFormat)
} else { } else {
let is_single = descriptor[DESCRIPTOR_LEN - 2] == 0; let is_single = descriptor[DESCRIPTOR_LEN - 2] == 0;
@@ -274,12 +298,6 @@ impl<T: SerialPort> Lidar<T> {
assert!(pwm <= MAX_MOTOR_PWM); assert!(pwm <= MAX_MOTOR_PWM);
self.send_payload_command(SET_PWM, Vec::from(pwm.to_ne_bytes())); self.send_payload_command(SET_PWM, Vec::from(pwm.to_ne_bytes()));
} }
fn read_response(&mut self, data_size: u8) -> Result<Vec<u8>, RPLidarError> {
let mut buf: Vec<u8> = Vec::with_capacity(data_size as usize);
self.serial_port.read(&mut buf)?;
Ok(buf)
}
} }
// Probably want to have separate iterator types like we do in swift for measurements vs scans // Probably want to have separate iterator types like we do in swift for measurements vs scans