Skip to content

Commit f534f14

Browse files
committed
new feature: rplidar_drv::sort_scan (ascendScan in C++)
reform: renamed rplidar_drv::protocol::RplidarProtocol to RplidarHostProtocol improve: eliminated dependency to libudev to avoid cross compile failure on linux
1 parent e4c8df0 commit f534f14

File tree

11 files changed

+154
-40
lines changed

11 files changed

+154
-40
lines changed

README.md

+8
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Please see [Roadmap](https://github.com/cnwzhjs/rplidar.rs/blob/master/docs/Road
1616

1717
## Release Notes
1818

19+
* [v0.5.0](https://github.com/cnwzhjs/rplidar.rs/blob/master/docs/ReleaseNote.v0.5.0.md)
1920
* [v0.4.0](https://github.com/cnwzhjs/rplidar.rs/blob/master/docs/ReleaseNote.v0.4.0.md)
2021
* [v0.3.0](https://github.com/cnwzhjs/rplidar.rs/blob/master/docs/ReleaseNote.v0.3.0.md)
2122
* [v0.2.0](https://github.com/cnwzhjs/rplidar.rs/blob/master/docs/ReleaseNote.v0.2.0.md)
@@ -33,6 +34,13 @@ RPLIDAR SDK supports Windows, macOS and Linux by using Visual Studio 2010 projec
3334

3435
## Quick Start
3536

37+
This crate works with Cargo and is on crates.io. Add it to your `Cargo.toml` like so:
38+
39+
```toml
40+
[dependencies]
41+
rplidar_drv = "0.5.0"
42+
```
43+
3644
To use RPLIDAR Rust SDK is quite simple:
3745

3846
```rust

docs/ReleaseNote.v0.5.0.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Release Note for Slamtec RPLIDAR Public SDK for Rust v0.5.0
2+
3+
* new feature: rplidar_drv::sort_scan (ascendScan in C++)
4+
* reform: renamed rplidar_drv::protocol::RplidarProtocol to RplidarHostProtocol
5+
* improve: eliminated dependency to libudev to avoid cross compile failure on linux

docs/Roadmap.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
| feature - stop | since 0.1.0 |
1616
| feature - grab_scan | since 0.2.0 |
1717
| feature - grab_scan_point | since 0.1.0 |
18-
| feature - sort_scan | No |
18+
| feature - sort_scan | since 0.5.0 |
1919
| protocol - measurement_nodes | since 0.1.0 |
2020
| protocol - capsuled_nodes | since 0.1.0 |
2121
| protocol - ultra_capsuled_nodes | since 0.3.0 |

examples/ultra_simple/Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
[package]
22
name = "ultra_simple"
3-
version = "0.4.0"
3+
version = "0.5.0"
44
authors = ["Tony Huang <[email protected]>"]
55
edition = "2018"
66

77
[dependencies]
88
rplidar_drv = { path = "../../rplidar_drv" }
99
rpos_drv = { path = "../../rpos_drv" }
10-
serialport = "3.1.0"
10+
serialport = { version = "3.1.0", default-features = false, features = [] }
1111
hex-slice = "0.1.4"

examples/ultra_simple/src/main.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ extern crate serialport;
55

66
use hex_slice::AsHex;
77

8-
use rplidar_drv::{Health, RplidarDevice, RplidarProtocol};
8+
use rplidar_drv::{Health, RplidarDevice, RplidarHostProtocol};
99
use rpos_drv::{Channel, ErrorKind};
1010
use serialport::prelude::*;
1111
use std::time::Duration;
@@ -42,8 +42,8 @@ fn main() {
4242
.write_data_terminal_ready(false)
4343
.expect("failed to clear DTR");
4444

45-
let channel = Channel::<RplidarProtocol, serialport::SerialPort>::new(
46-
RplidarProtocol::new(),
45+
let channel = Channel::<RplidarHostProtocol, serialport::SerialPort>::new(
46+
RplidarHostProtocol::new(),
4747
serial_port,
4848
);
4949

rplidar_drv/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "rplidar_drv"
33
description = "Driver for Slamtec RPLIDAR series laser sensors"
4-
version = "0.4.0"
4+
version = "0.5.0"
55
license = "GPLv3"
66
repository = "https://github.com/cnwzhjs/rplidar.rs/rplidar_drv"
77
keywords = ["Slamtec", "Rplidar", "Driver"]

rplidar_drv/src/lib.rs

+6-10
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ mod checksum;
1414
mod cmds;
1515
mod prelude;
1616
mod protocol;
17+
pub mod utils;
1718

1819
pub use self::prelude::*;
1920

@@ -25,7 +26,7 @@ use self::capsuled_parser::parse_capsuled;
2526
use self::ultra_capsuled_parser::parse_ultra_capsuled;
2627
use self::checksum::Checksum;
2728
use self::cmds::*;
28-
pub use self::protocol::RplidarProtocol;
29+
pub use self::protocol::RplidarHostProtocol;
2930
use byteorder::{ByteOrder, LittleEndian};
3031
use rpos_drv::{Channel, Error, ErrorKind, Message, Result};
3132
use std::collections::VecDeque;
@@ -39,7 +40,7 @@ const RPLIDAR_GET_LIDAR_CONF_START_VERSION:u16 = ((1 << 8) | (24)) as u16;
3940
/// Rplidar device driver
4041
#[derive(Debug)]
4142
pub struct RplidarDevice<T: ?Sized> {
42-
channel: Channel<RplidarProtocol, T>,
43+
channel: Channel<RplidarHostProtocol, T>,
4344
cached_measurement_nodes: VecDeque<ScanPoint>,
4445
cached_prev_capsule: CachedPrevCapsule,
4546
}
@@ -93,10 +94,10 @@ where
9394
/// # Example
9495
/// ```compile_fail
9596
/// let mut serial_port = serialport::open(serial_port_name)?;
96-
/// let channel = Channel::new(RplidarProtocol::new(), serial_port);
97+
/// let channel = Channel::new(RplidarHostProtocol::new(), serial_port);
9798
/// let rplidar_device = RplidarDevice::new(channel);
9899
/// ```
99-
pub fn new(channel: Channel<RplidarProtocol, T>) -> RplidarDevice<T> {
100+
pub fn new(channel: Channel<RplidarHostProtocol, T>) -> RplidarDevice<T> {
100101
RplidarDevice {
101102
channel: channel,
102103
cached_measurement_nodes: VecDeque::with_capacity(RPLIDAR_DEFAULT_CACHE_DEPTH),
@@ -112,7 +113,7 @@ where
112113
/// let rplidar_device = RplidarDevice::with_stream(serial_port);
113114
/// ```
114115
pub fn with_stream(stream: Box<T>) -> RplidarDevice<T> {
115-
RplidarDevice::<T>::new(rpos_drv::Channel::new(RplidarProtocol::new(), stream))
116+
RplidarDevice::<T>::new(rpos_drv::Channel::new(RplidarHostProtocol::new(), stream))
116117
}
117118

118119
/// get device info of the RPLIDAR
@@ -708,8 +709,3 @@ fn check_sync_and_checksum_hq(msg: &Message) -> Result<()> {
708709
return Ok(());
709710
}
710711
}
711-
712-
#[cfg(test)]
713-
mod tests {
714-
715-
}

rplidar_drv/src/prelude.rs

+31-7
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,33 @@
11
use std::f32::consts::PI;
22
use super::answers::RPLIDAR_RESP_HQ_FLAG_SYNCBIT;
3+
use std::cmp::Ordering;
34

45
/// Scan point in a particular laser scan
5-
#[derive(Debug, Clone, PartialEq)]
6+
#[derive(Debug, Clone, Eq)]
67
pub struct ScanPoint {
78
pub angle_z_q14: u16,
89
pub dist_mm_q2: u32,
910
pub quality: u8,
1011
pub flag: u8,
1112
}
1213

13-
/// Laser scan
14-
#[derive(Debug, Clone, PartialEq)]
15-
pub struct LaserScan {
16-
pub points: Vec<ScanPoint>,
17-
}
18-
1914
impl ScanPoint {
2015
pub fn angle(&self) -> f32 {
2116
return (self.angle_z_q14 as f32) / 16384f32 / 2f32 * PI;
2217
}
2318

19+
pub fn set_angle(&mut self, angle:f32) {
20+
self.angle_z_q14 = (angle * 16384f32 * 2f32 / PI) as u16;
21+
}
22+
2423
pub fn distance(&self) -> f32 {
2524
return (self.dist_mm_q2 as f32) / 4000f32;
2625
}
2726

27+
pub fn set_distance(&mut self, dist: f32) {
28+
self.dist_mm_q2 = (dist * 4000f32) as u32;
29+
}
30+
2831
pub fn is_sync(&self) -> bool {
2932
return (self.flag & RPLIDAR_RESP_HQ_FLAG_SYNCBIT) == RPLIDAR_RESP_HQ_FLAG_SYNCBIT;
3033
}
@@ -34,6 +37,27 @@ impl ScanPoint {
3437
}
3538
}
3639

40+
impl Ord for ScanPoint {
41+
fn cmp(&self, other: &ScanPoint) -> Ordering {
42+
self.angle_z_q14.cmp(&other.angle_z_q14)
43+
}
44+
}
45+
46+
impl PartialOrd for ScanPoint {
47+
fn partial_cmp(&self, other: &ScanPoint) -> Option<Ordering> {
48+
Some(self.cmp(other))
49+
}
50+
}
51+
52+
impl PartialEq for ScanPoint {
53+
fn eq(&self, other: &ScanPoint) -> bool {
54+
self.angle_z_q14 == other.angle_z_q14
55+
&& self.dist_mm_q2 == other.dist_mm_q2
56+
&& self.quality == other.quality
57+
&& self.flag == other.flag
58+
}
59+
}
60+
3761
pub use std::result::Result;
3862

3963
/// Description of a specific scan mode

rplidar_drv/src/protocol.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,19 @@ enum DecodeStatus {
2424
ReceiveResponse,
2525
}
2626

27-
/// The implementation of RPLIDAR protocol
27+
/// The implementation of RPLIDAR host protocol
2828
#[derive(Debug, Clone, PartialEq)]
29-
pub struct RplidarProtocol {
29+
pub struct RplidarHostProtocol {
3030
status: DecodeStatus,
3131
ans_header: Vec<u8>,
3232
ans_flag: u8,
3333
response_size: usize,
3434
decoding_msg: Message, // decode_buffer: RingByteBuffer
3535
}
3636

37-
impl RplidarProtocol {
38-
pub fn new() -> RplidarProtocol {
39-
RplidarProtocol {
37+
impl RplidarHostProtocol {
38+
pub fn new() -> RplidarHostProtocol {
39+
RplidarHostProtocol {
4040
status: DecodeStatus::WaitSyncByte(0),
4141
ans_header: Vec::new(),
4242
ans_flag: 0,
@@ -141,7 +141,7 @@ impl RplidarProtocol {
141141
}
142142
}
143143

144-
impl ProtocolDecoder for RplidarProtocol {
144+
impl ProtocolDecoder for RplidarHostProtocol {
145145
/// Decode bytes and return consumed bytes and message
146146
fn decode(&mut self, buf: &[u8]) -> Result<(usize, Option<Message>)> {
147147
let mut i = 0;
@@ -177,7 +177,7 @@ impl ProtocolDecoder for RplidarProtocol {
177177
}
178178
}
179179

180-
impl ProtocolEncoder for RplidarProtocol {
180+
impl ProtocolEncoder for RplidarHostProtocol {
181181
/// Encode message into byte array
182182
/// Always encode commands
183183
fn encode(&mut self, msg: &Message, bytes: &mut [u8]) -> Result<usize> {
@@ -260,7 +260,7 @@ mod tests {
260260

261261
#[test]
262262
fn protocol_encode() {
263-
let mut protocol = super::RplidarProtocol::new();
263+
let mut protocol = super::RplidarHostProtocol::new();
264264

265265
assert_eq!(
266266
encode(&mut protocol, &Message::new(0x25))

rplidar_drv/src/utils.rs

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
use super::prelude::{ ScanPoint };
2+
use rpos_drv::{Error, ErrorKind, Result};
3+
use std::f32::consts::PI;
4+
5+
const PI2:f32 = PI * 2f32;
6+
7+
fn find_first_valid_index(scan: &Vec<ScanPoint>) -> Option<usize> {
8+
for i in 0..scan.len() {
9+
if scan[i].is_valid() {
10+
return Some(i);
11+
}
12+
}
13+
14+
return None;
15+
}
16+
17+
fn find_last_valid_index(scan: &Vec<ScanPoint>) -> Option<usize> {
18+
for i in 0..scan.len() {
19+
let id = scan.len() - i - 1;
20+
21+
if scan[i].is_valid() {
22+
return Some(id);
23+
}
24+
}
25+
26+
return None;
27+
}
28+
29+
fn tune_head(scan: &mut Vec<ScanPoint>, inc_origin_angle: f32) -> Result<()> {
30+
if let Some(head_index) = find_first_valid_index(scan) {
31+
let mut i = head_index;
32+
33+
while i != 0 {
34+
i -= 1;
35+
let mut expect_angle = scan[i + 1].angle() - inc_origin_angle;
36+
if expect_angle < 0f32 {
37+
expect_angle = 0f32;
38+
}
39+
scan[i].set_angle(expect_angle);
40+
}
41+
42+
return Ok(());
43+
} else {
44+
return Err(Error::new(ErrorKind::OperationFail, "no valid point"));
45+
}
46+
}
47+
48+
fn tune_tail(scan: &mut Vec<ScanPoint>, inc_origin_angle: f32) -> Result<()> {
49+
if let Some(tail_index) = find_last_valid_index(scan) {
50+
for i in tail_index+1..scan.len() {
51+
let mut expect_angle = scan[i - 1].angle() + inc_origin_angle;
52+
if expect_angle > PI2 {
53+
expect_angle -= PI2;
54+
}
55+
scan[i].set_angle(expect_angle);
56+
}
57+
58+
return Ok(());
59+
} else {
60+
return Err(Error::new(ErrorKind::OperationFail, "no valid point"));
61+
}
62+
}
63+
64+
/// sort scan points
65+
pub fn sort_scan(scan: &mut Vec<ScanPoint>) -> Result<()> {
66+
if scan.len() == 0 {
67+
return Ok(());
68+
}
69+
70+
let inc_origin_angle = PI2 / (scan.len() as f32);
71+
72+
tune_head(scan, inc_origin_angle)?;
73+
tune_tail(scan, inc_origin_angle)?;
74+
75+
let front_angle = scan[0].angle();
76+
for i in 1..scan.len() {
77+
if !scan[i].is_valid() {
78+
let mut expect_angle = front_angle + (i as f32) * inc_origin_angle;
79+
if expect_angle > PI2 {
80+
expect_angle -= PI2;
81+
}
82+
scan[i].set_angle(expect_angle);
83+
}
84+
}
85+
86+
scan.sort();
87+
88+
return Ok(());
89+
}

rpos_drv/src/lib.rs

-8
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,3 @@ mod ring_byte_buffer;
1111
pub use self::prelude::*;
1212
pub use self::channel::*;
1313
pub use self::ring_byte_buffer::RingByteBuffer;
14-
15-
#[cfg(test)]
16-
mod tests {
17-
#[test]
18-
fn it_works() {
19-
assert_eq!(2 + 2, 4);
20-
}
21-
}

0 commit comments

Comments
 (0)