velodyne_lidar/packet/
data.rs

1use crate::{
2    consts::{AZIMUTH_COUNT_PER_REV, BLOCKS_PER_PACKET, CHANNELS_PER_BLOCK, FIRING_PERIOD},
3    types::{
4        channel_array::ChannelArrayDRef,
5        firing_block::{FiringBlockD16, FiringBlockD32, FiringBlockS16, FiringBlockS32},
6        firing_xyz::{FiringXyzD16, FiringXyzD32, FiringXyzS16, FiringXyzS32},
7        format::{Format, FormatKind},
8    },
9    utils::AngleExt as _,
10    Config16, Config32,
11};
12use eyre::{ensure, Result};
13use itertools::{chain, izip, Itertools as _};
14use measurements::Angle;
15use std::{f64::consts::PI, iter, mem, time::Duration};
16
17/// Represents the block index in range from 0 to 31, or from 32 to 63.
18#[repr(u16)]
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
20pub enum BlockIdentifier {
21    Block0To31 = 0xeeff,
22    Block32To63 = 0xddff,
23}
24
25/// Represents the way the sensor measures the laser signal.
26#[repr(u8)]
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
28pub enum ReturnMode {
29    Strongest = 0x37,
30    Last = 0x38,
31    Dual = 0x39,
32}
33
34impl ReturnMode {
35    pub fn is_single(&self) -> bool {
36        [ReturnMode::Strongest, ReturnMode::Last].contains(self)
37    }
38
39    pub fn is_dual(&self) -> bool {
40        *self == Self::Dual
41    }
42}
43
44/// Represents the hardware model.
45#[repr(u8)]
46#[derive(
47    Debug, Clone, Copy, PartialEq, Eq, Hash, strum::AsRefStr, strum::Display, strum::EnumString,
48)]
49pub enum ProductID {
50    HDL32E = 0x21,
51    VLP16 = 0x22,
52    PuckLite = 0x23,
53    PuckHiRes = 0x24,
54    VLP32C = 0x28,
55    Velarray = 0x31,
56    VLS128 = 0xa1,
57}
58
59impl ProductID {
60    pub fn num_lines(&self) -> usize {
61        match self {
62            Self::HDL32E => 16,
63            Self::VLP16 => 16,
64            Self::PuckLite => 16,
65            Self::PuckHiRes => 16,
66            Self::VLP32C => 32,
67            Self::Velarray => todo!(),
68            Self::VLS128 => 128,
69        }
70    }
71}
72
73/// Represents a point of measurement.
74#[repr(C, packed)]
75#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
76pub struct Channel {
77    /// The raw distance of laser return.
78    pub distance: u16,
79    /// The intensity of laser return.
80    pub intensity: u8,
81}
82
83/// Represents a sequence of measurements with meta data.
84#[repr(C, packed)]
85#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
86pub struct Block {
87    /// Represents the block that the firing belongs to.
88    pub block_identifier: BlockIdentifier,
89    /// Encoder count of rotation motor ranging from 0 to 36000 (inclusive).
90    pub azimuth_count: u16,
91    /// Array of channels.
92    pub channels: [Channel; CHANNELS_PER_BLOCK],
93}
94
95impl Block {
96    pub fn azimuth_radians(&self) -> f64 {
97        2.0 * PI * self.azimuth_count as f64 / (AZIMUTH_COUNT_PER_REV - 1) as f64
98    }
99
100    pub fn azimuth_degrees(&self) -> f64 {
101        360.0 * self.azimuth_count as f64 / (AZIMUTH_COUNT_PER_REV - 1) as f64
102    }
103
104    pub fn azimuth(&self) -> Angle {
105        Angle::from_radians(self.azimuth_radians())
106    }
107}
108
109/// Represents a data packet from Velodyne sensor.
110#[repr(C, packed)]
111#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
112pub struct DataPacket {
113    /// Sensor data.
114    pub blocks: [Block; BLOCKS_PER_PACKET],
115    /// Timestamp in microseconds.
116    pub toh: u32,
117    /// Indicates single return mode or dual return mode.
118    pub return_mode: ReturnMode,
119    /// Sensor model.
120    pub product_id: ProductID,
121}
122
123impl DataPacket {
124    /// Construct packet from binary buffer.
125    pub fn from_bytes(buffer: [u8; mem::size_of::<Self>()]) -> Self {
126        unsafe { mem::transmute::<_, Self>(buffer) }
127    }
128
129    /// Construct packet from slice of bytes. Fail if the slice size is not correct.
130    pub fn from_slice(buffer: &[u8]) -> Result<&Self> {
131        ensure!(
132            buffer.len() == mem::size_of::<Self>(),
133            "Requre the slice length to be {}, but get {}",
134            mem::size_of::<Self>(),
135            buffer.len(),
136        );
137        let packet = unsafe { &*(buffer.as_ptr() as *const Self) };
138        Ok(packet)
139    }
140
141    pub fn toh(&self) -> Duration {
142        Duration::from_micros(self.toh as u64)
143    }
144
145    pub fn try_format(&self) -> Option<Format> {
146        Format::try_from_model(self.product_id, self.return_mode)
147    }
148
149    pub fn format(&self) -> Format {
150        Format::from_model(self.product_id, self.return_mode)
151    }
152
153    pub fn firing_block_iter(
154        &self,
155    ) -> FormatKind<
156        impl Iterator<Item = FiringBlockS16<'_>> + Clone,
157        impl Iterator<Item = FiringBlockS32<'_>> + Clone,
158        impl Iterator<Item = FiringBlockD16<'_>> + Clone,
159        impl Iterator<Item = FiringBlockD32<'_>> + Clone,
160    > {
161        use Format::*;
162        use FormatKind as F;
163
164        match self.format() {
165            Single16 => F::from_s16(self.firing_block_iter_s16()),
166            Dual16 => F::from_d16(self.firing_block_iter_d16()),
167            Single32 => F::from_s32(self.firing_block_iter_s32()),
168            Dual32 => F::from_d32(self.firing_block_iter_d32()),
169        }
170    }
171
172    pub fn firing_block_iter_s16(
173        &self,
174    ) -> impl Iterator<Item = FiringBlockS16<'_>> + Clone + Sync + Send {
175        let block_period = FIRING_PERIOD.mul_f64(2.0);
176        let tohs = iter::successors(Some(self.toh()), move |prev| Some(*prev + block_period));
177        let firing_azimuths = {
178            let block_azimuths: Vec<_> = self.blocks.iter().map(|block| block.azimuth()).collect();
179            let block_azimuth_diffs: Vec<_> = block_azimuths
180                .iter()
181                .cloned()
182                .tuple_windows()
183                .map(|(curr, next)| (next - curr).wrap_to_2pi())
184                .collect();
185            let last_block_azimuth_diff = *block_azimuth_diffs.last().unwrap();
186
187            izip!(
188                block_azimuths,
189                chain!(block_azimuth_diffs, [last_block_azimuth_diff])
190            )
191            .map(|(block_azimuth, block_azimuth_diff)| {
192                let mid_azimuth = block_azimuth + block_azimuth_diff / 2.0;
193                let last_azimuth = block_azimuth + block_azimuth_diff;
194                [block_azimuth..mid_azimuth, mid_azimuth..last_azimuth]
195            })
196        };
197
198        izip!(tohs, firing_azimuths, &self.blocks).flat_map(
199            move |(block_toh, [former_azimuth, latter_azimuth], block)| {
200                let former_toh = block_toh;
201                let latter_toh = former_toh + FIRING_PERIOD;
202
203                let (former_channels, latter_channels) = block.channels.split_at(16);
204
205                let former = FiringBlockS16 {
206                    toh: former_toh,
207                    azimuth_range: former_azimuth,
208                    block,
209                    channels: former_channels
210                        .try_into()
211                        .unwrap_or_else(|_| unreachable!()),
212                };
213                let latter = FiringBlockS16 {
214                    toh: latter_toh,
215                    azimuth_range: latter_azimuth,
216                    block,
217                    channels: latter_channels
218                        .try_into()
219                        .unwrap_or_else(|_| unreachable!()),
220                };
221
222                [former, latter]
223            },
224        )
225    }
226
227    pub fn firing_block_iter_d16(
228        &self,
229    ) -> impl Iterator<Item = FiringBlockD16<'_>> + Clone + Sync + Send {
230        let block_period = FIRING_PERIOD.mul_f64(2.0);
231        let tohs = iter::successors(Some(self.toh()), move |prev| Some(*prev + block_period));
232        let firing_azimuths = {
233            let block_azimuths: Vec<_> = self
234                .blocks
235                .iter()
236                .step_by(2)
237                .map(|block| block.azimuth())
238                .collect();
239            let block_azimuth_diffs: Vec<_> = block_azimuths
240                .iter()
241                .cloned()
242                .tuple_windows()
243                .map(|(curr, next)| (next - curr).wrap_to_2pi())
244                .collect();
245            let last_block_azimuth_diff = *block_azimuth_diffs.last().unwrap();
246
247            izip!(
248                block_azimuths,
249                chain!(block_azimuth_diffs, [last_block_azimuth_diff])
250            )
251            .map(|(block_azimuth, block_azimuth_diff)| {
252                let mid_azimuth = block_azimuth + block_azimuth_diff / 2.0;
253                let last_azimuth = block_azimuth + block_azimuth_diff;
254                [block_azimuth..mid_azimuth, mid_azimuth..last_azimuth]
255            })
256        };
257
258        izip!(tohs, firing_azimuths, self.blocks.chunks(2)).flat_map(
259            |(block_toh, [former_azimuth, latter_azimuth], block_pair)| {
260                let [block_strongest, block_last] = match block_pair {
261                    [first, second] => [first, second],
262                    _ => unreachable!(),
263                };
264
265                let former_toh = block_toh;
266                let latter_toh = former_toh + FIRING_PERIOD;
267
268                let (former_strongest, latter_strongest) = block_strongest.channels.split_at(16);
269                let (former_last, latter_last) = block_last.channels.split_at(16);
270
271                [
272                    FiringBlockD16 {
273                        toh: former_toh,
274                        azimuth_range: former_azimuth,
275                        block_strongest,
276                        block_last,
277                        channels: ChannelArrayDRef {
278                            strongest: former_strongest
279                                .try_into()
280                                .unwrap_or_else(|_| unreachable!()),
281                            last: former_last.try_into().unwrap_or_else(|_| unreachable!()),
282                        },
283                    },
284                    FiringBlockD16 {
285                        toh: latter_toh,
286                        azimuth_range: latter_azimuth,
287                        block_strongest,
288                        block_last,
289                        channels: ChannelArrayDRef {
290                            strongest: latter_strongest
291                                .try_into()
292                                .unwrap_or_else(|_| unreachable!()),
293                            last: latter_last.try_into().unwrap_or_else(|_| unreachable!()),
294                        },
295                    },
296                ]
297            },
298        )
299    }
300
301    pub fn firing_block_iter_s32(
302        &self,
303    ) -> impl Iterator<Item = FiringBlockS32<'_>> + Clone + Sync + Send {
304        let tohs = iter::successors(Some(self.toh()), move |prev| Some(*prev + FIRING_PERIOD));
305        let azimuths = {
306            let block_azimuths: Vec<_> = self.blocks.iter().map(|block| block.azimuth()).collect();
307            let block_azimuth_diffs: Vec<_> = block_azimuths
308                .iter()
309                .cloned()
310                .tuple_windows()
311                .map(|(curr, next)| (next - curr).wrap_to_2pi())
312                .collect();
313            let last_block_azimuth_diff = *block_azimuth_diffs.last().unwrap();
314
315            izip!(
316                block_azimuths,
317                chain!(block_azimuth_diffs, [last_block_azimuth_diff])
318            )
319            .map(|(former_azimuth, azimuth_diff)| {
320                let latter_azimuth = former_azimuth + azimuth_diff;
321                former_azimuth..latter_azimuth
322            })
323        };
324
325        izip!(tohs, azimuths, &self.blocks).map(move |(block_toh, azimuth_range, block)| {
326            let former_toh = block_toh;
327            let latter_toh = former_toh + FIRING_PERIOD;
328
329            FiringBlockS32 {
330                toh: latter_toh,
331                azimuth_range,
332                block,
333                channels: &block.channels,
334            }
335        })
336    }
337
338    pub fn firing_block_iter_d32(
339        &self,
340    ) -> impl Iterator<Item = FiringBlockD32<'_>> + Clone + Sync + Send {
341        let tohs = iter::successors(Some(self.toh()), move |prev| Some(*prev + FIRING_PERIOD));
342        let azimuths = {
343            let azimuths: Vec<_> = self
344                .blocks
345                .iter()
346                .step_by(2)
347                .map(|block| block.azimuth())
348                .collect();
349            let azimuth_diffs: Vec<_> = azimuths
350                .iter()
351                .cloned()
352                .tuple_windows()
353                .map(|(curr, next)| (next - curr).wrap_to_2pi())
354                .collect();
355            let last_azimuth_diff = *azimuth_diffs.last().unwrap();
356
357            izip!(azimuths, chain!(azimuth_diffs, [last_azimuth_diff])).map(
358                |(former_azimuth, azimuth_diff)| {
359                    let latter_azimuth = former_azimuth + azimuth_diff;
360                    former_azimuth..latter_azimuth
361                },
362            )
363        };
364
365        izip!(tohs, azimuths, self.blocks.chunks(2)).map(
366            move |(block_toh, azimuth_range, chunk)| {
367                let [block_strongest, block_last] = match chunk {
368                    [first, second] => [first, second],
369                    _ => unreachable!(),
370                };
371
372                FiringBlockD32 {
373                    toh: block_toh,
374                    azimuth_range,
375                    block_strongest,
376                    block_last,
377                    channels: ChannelArrayDRef {
378                        strongest: &block_strongest.channels,
379                        last: &block_last.channels,
380                    },
381                }
382            },
383        )
384    }
385
386    pub fn firing_xyz_iter_s16<'a>(
387        &'a self,
388        beams: &'a Config16,
389    ) -> impl Iterator<Item = FiringXyzS16> + Clone + Sync + Send + 'a {
390        self.firing_block_iter_s16()
391            .map(|firing| firing.to_firing_xyz(beams))
392    }
393
394    pub fn firing_xyz_iter_s32<'a>(
395        &'a self,
396        beams: &'a Config32,
397    ) -> impl Iterator<Item = FiringXyzS32> + Clone + Sync + Send + 'a {
398        self.firing_block_iter_s32()
399            .map(|firing| firing.to_firing_xyz(beams))
400    }
401
402    pub fn firing_xyz_iter_d16<'a>(
403        &'a self,
404        beams: &'a Config16,
405    ) -> impl Iterator<Item = FiringXyzD16> + Clone + Sync + Send + 'a {
406        self.firing_block_iter_d16()
407            .map(|firing| firing.to_firing_xyz(beams))
408    }
409
410    pub fn firing_xyz_iter_d32<'a>(
411        &'a self,
412        beams: &'a Config32,
413    ) -> impl Iterator<Item = FiringXyzD32> + Clone + Sync + Send + 'a {
414        self.firing_block_iter_d32()
415            .map(|firing| firing.to_firing_xyz(beams))
416    }
417}