libits_client/reception/exchange/
perceived_object.rs

1// Software Name: its-client
2// SPDX-FileCopyrightText: Copyright (c) 2016-2022 Orange
3// SPDX-License-Identifier: MIT License
4//
5// This software is distributed under the MIT license, see LICENSE.txt file for more details.
6//
7// Author: Frédéric GARDES <frederic.gardes@orange.com> et al.
8// Software description: This Intelligent Transportation Systems (ITS) [MQTT](https://mqtt.org/) client based on the [JSon](https://www.json.org) [ETSI](https://www.etsi.org/committee/its) specification transcription provides a ready to connect project for the mobility (connected and autonomous vehicles, road side units, vulnerable road users,...).
9use serde::{Deserialize, Serialize};
10
11#[serde_with::skip_serializing_none]
12#[derive(Default, Debug, Clone, Hash, PartialEq, Serialize, Deserialize)]
13pub struct PerceivedObject {
14    pub object_id: u8,
15    pub time_of_measurement: i16,
16    pub confidence: ObjectConfidence,
17    pub x_distance: i32,
18    pub y_distance: i32,
19    pub z_distance: Option<i32>,
20    pub x_speed: i16,
21    pub y_speed: i16,
22    pub z_speed: Option<i16>,
23    pub object_age: u16,
24    pub object_ref_point: Option<u8>,
25    pub x_acceleration: Option<i16>,
26    pub y_acceleration: Option<i16>,
27    pub z_acceleration: Option<i16>,
28    pub roll_angle: Option<u16>,
29    pub pitch_angle: Option<u16>,
30    pub yaw_angle: Option<u16>,
31    pub roll_rate: Option<i16>,
32    pub pitch_rate: Option<i16>,
33    pub yaw_rate: Option<i16>,
34    pub roll_acceleration: Option<i16>,
35    pub pitch_acceleration: Option<i16>,
36    pub yaw_acceleration: Option<i16>,
37    #[serde(skip_serializing_if = "Vec::is_empty", default)]
38    pub lower_triangular_correlation_matrix_columns: Vec<Vec<i8>>,
39    pub planar_object_dimension_1: Option<u16>,
40    pub planar_object_dimension_2: Option<u16>,
41    pub vertical_object_dimension: Option<u16>,
42    #[serde(skip_serializing_if = "Vec::is_empty", default)]
43    pub sensor_id_list: Vec<u8>,
44    pub dynamic_status: Option<u8>,
45    #[serde(skip_serializing_if = "Vec::is_empty", default)]
46    pub classification: Vec<ObjectClassification>,
47    pub matched_position: Option<MatchedPosition>,
48}
49
50#[serde_with::skip_serializing_none]
51#[derive(Default, Debug, Clone, Hash, PartialEq, Serialize, Deserialize)]
52pub struct ObjectConfidence {
53    pub x_distance: u16,
54    pub y_distance: u16,
55    pub x_speed: u8,
56    pub y_speed: u8,
57    pub object: Option<u8>,
58}
59
60#[serde_with::skip_serializing_none]
61#[derive(Debug, Clone, Hash, PartialEq, Serialize, Deserialize)]
62pub struct ObjectClassification {
63    pub object_class: ObjectClass,
64    pub confidence: u8,
65}
66
67#[serde_with::skip_serializing_none]
68#[derive(Debug, Clone, Hash, PartialEq, Serialize, Deserialize)]
69#[serde(rename_all = "snake_case")]
70pub enum ObjectClass {
71    Vehicle(u8),
72    SingleVru(SingleVruClass),
73    VruGroup(VruGroupClass),
74    Other(u8),
75}
76
77#[serde_with::skip_serializing_none]
78#[derive(Debug, Clone, Hash, PartialEq, Serialize, Deserialize)]
79#[serde(rename_all = "snake_case")]
80pub enum SingleVruClass {
81    Pedestrian(u8),
82    Bicyclist(u8),
83    Motorcyclist(u8),
84    Animal(u8),
85}
86
87#[serde_with::skip_serializing_none]
88#[derive(Default, Debug, Clone, Hash, PartialEq, Serialize, Deserialize)]
89pub struct VruGroupClass {
90    pub group_size: u8,
91    pub group_type: VruGroupType,
92    pub cluster_id: Option<u8>,
93}
94
95#[serde_with::skip_serializing_none]
96#[derive(Default, Debug, Clone, Hash, PartialEq, Serialize, Deserialize)]
97pub struct VruGroupType {
98    pub pedestrian: bool,
99    pub bicyclist: bool,
100    pub motorcyclist: bool,
101    pub animal: bool,
102}
103
104#[serde_with::skip_serializing_none]
105#[derive(Default, Debug, Clone, Hash, PartialEq, Serialize, Deserialize)]
106pub struct MatchedPosition {
107    pub lane_id: u8,
108    pub longitudinal_lane_position: u16,
109}
110
111#[cfg(test)]
112mod test {
113    use crate::reception::exchange::perceived_object::PerceivedObject;
114
115    #[test]
116    fn test_deserialize() {
117        let data = r#"{
118                "object_id": 5,
119                "time_of_measurement": 2,
120                "x_distance": 804,
121                "y_distance": 400,
122                "x_speed": 401,
123                "y_speed": 401,
124                "object_age": 1500,
125                "object_ref_point": 0,
126                "dynamic_status": 0,
127                "classification": [
128                  {
129                    "object_class": {
130                      "single_vru": {
131                        "pedestrian": 1
132                      }
133                    },
134                    "confidence": 40
135                  }
136                ],
137                "confidence": {
138                  "x_distance": 4095,
139                  "y_distance": 4095,
140                  "x_speed": 0,
141                  "y_speed": 0,
142                  "object": 10
143                }
144              }"#;
145
146        match serde_json::from_str::<PerceivedObject>(data) {
147            Ok(po) => {
148                assert_eq!(5, po.object_id);
149            }
150            Err(e) => {
151                panic!("Failed to deserialize PO: '{}'", e);
152            }
153        }
154    }
155
156    #[test]
157    fn test_deserialize_full_po() {
158        let data = r#"{
159            "object_id": 0,
160            "time_of_measurement": 50,
161            "x_distance": 400,
162            "y_distance": 100,
163            "z_distance": 50,
164            "x_speed": 1400,
165            "y_speed": 500,
166            "z_speed": 0,
167            "x_acceleration": -160,
168            "y_acceleration": 0,
169            "z_acceleration": 161,
170            "roll_angle": 0,
171            "pitch_angle": 3600,
172            "yaw_angle": 3601,
173            "roll_rate": -32766,
174            "pitch_rate": 0,
175            "yaw_rate": 32767,
176            "roll_acceleration": -32766,
177            "pitch_acceleration": 0,
178            "yaw_acceleration": 32767,
179            "lower_triangular_correlation_matrix_columns": [
180                [-100, -99, -98],
181                [0, 1, 2],
182                [98, 99, 100]
183            ],
184            "planar_object_dimension_1": 1023,
185            "planar_object_dimension_2": 1023,
186            "vertical_object_dimension": 1023,
187            "object_ref_point": 8,
188            "confidence": {
189                "x_distance": 102,
190                "y_distance": 102,
191                "z_distance": 102,
192                "x_speed": 7,
193                "y_speed": 7,
194                "z_speed": 7,
195                "x_acceleration": 102,
196                "y_acceleration": 102,
197                "z_acceleration": 102,
198                "roll_angle": 127,
199                "pitch_angle": 127,
200                "yaw_angle": 127,
201                "roll_rate": 8,
202                "pitch_rate": 8,
203                "yaw_rate": 8,
204                "roll_acceleration": 8,
205                "pitch_acceleration": 8,
206                "yaw_acceleration": 8,
207                "planar_object_dimension_1": 102,
208                "planar_object_dimension_2": 102,
209                "vertical_object_dimension": 102,
210                "longitudinal_lane_position": 102,
211                "object": 10
212            },
213            "object_age": 1500,
214            "sensor_id_list": [1, 2, 10, 100, 255],
215            "dynamic_status": 2,
216            "classification": [{
217                    "object_class": {
218                        "vehicle": 10
219                    },
220                    "confidence": 101
221                },
222                {
223                    "object_class": {
224                        "single_vru": {
225                            "pedestrian": 2
226                        }
227                    },
228                    "confidence": 25
229                },
230                {
231                    "object_class": {
232                        "vru_group": {
233                            "group_type": {
234                                "pedestrian": true,
235                                "bicyclist": false,
236                                "motorcyclist": false,
237                                "animal": true
238                            },
239                            "group_size": 12,
240                            "cluster_id": 255
241                        }
242                    },
243                    "confidence": 64
244                },
245                {
246                    "object_class": {
247                        "other": 1
248                    },
249                    "confidence": 0
250                }
251            ],
252            "matched_position": {
253                "lane_id": 255,
254                "longitudinal_lane_position": 32767
255            }
256        }"#;
257
258        match serde_json::from_str::<PerceivedObject>(data) {
259            Ok(po) => {
260                assert_eq!(0, po.object_id);
261            }
262            Err(e) => {
263                panic!("Failed to deserialize PO: '{}'", e);
264            }
265        }
266    }
267}