PX4 Firmware
PX4 Autopilot Software http://px4.io
CollisionPreventionTest.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (C) 2019 PX4 Development Team. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * 3. Neither the name PX4 nor the names of its contributors may be
16  * used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  ****************************************************************************/
33 
34 #include <gtest/gtest.h>
35 #include "CollisionPrevention.hpp"
36 
37 // to run: make tests TESTFILTER=CollisionPrevention
39 
40 class CollisionPreventionTest : public ::testing::Test
41 {
42 public:
43  void SetUp() override
44  {
46  }
47 };
48 
50 {
51 public:
53  void paramsChanged() {CollisionPrevention::updateParamsImpl();}
54  obstacle_distance_s &getObstacleMap() {return _obstacle_map_body_frame;}
56  {
57  _addDistanceSensorData(distance_sensor, attitude);
58  }
60  {
61  _addObstacleSensorData(obstacle, attitude);
62  }
63  void test_adaptSetpointDirection(matrix::Vector2f &setpoint_dir, int &setpoint_index,
64  float vehicle_yaw_angle_rad)
65  {
66  _adaptSetpointDirection(setpoint_dir, setpoint_index, vehicle_yaw_angle_rad);
67  }
68  bool test_enterData(int map_index, float sensor_range, float sensor_reading)
69  {
70  return _enterData(map_index, sensor_range, sensor_reading);
71  }
72 };
73 
75 {
76 public:
78 protected:
79  hrt_abstime getTime() override
80  {
81  return mocked_time;
82  }
83 
84  hrt_abstime getElapsedTime(const hrt_abstime *ptr) override
85  {
86  return mocked_time - *ptr;
87  }
88 };
89 
90 TEST_F(CollisionPreventionTest, instantiation) { CollisionPrevention cp(nullptr); }
91 
93 {
94  // GIVEN: a simple setup condition
96 
97  // THEN: the collision prevention should be turned off by default
98  EXPECT_FALSE(cp.is_active());
99 }
100 
102 {
103  // GIVEN: a simple setup condition
105  matrix::Vector2f original_setpoint(10, 0);
106  float max_speed = 3.f;
107  matrix::Vector2f curr_pos(0, 0);
108  matrix::Vector2f curr_vel(2, 0);
109 
110  // AND: a parameter handle
111  param_t param = param_handle(px4::params::CP_DIST);
112 
113  // WHEN: we set the parameter check then apply the setpoint modification
114  float value = 10; // try to keep 10m away from obstacles
115  param_set(param, &value);
116  cp.paramsChanged();
117 
118  matrix::Vector2f modified_setpoint = original_setpoint;
119  cp.modifySetpoint(modified_setpoint, max_speed, curr_pos, curr_vel);
120 
121  // THEN: collision prevention should be enabled and limit the speed to zero
122  EXPECT_TRUE(cp.is_active());
123  EXPECT_FLOAT_EQ(0.f, modified_setpoint.norm());
124 }
125 
126 TEST_F(CollisionPreventionTest, testBehaviorOnWithObstacleMessage)
127 {
128  // GIVEN: a simple setup condition
130  matrix::Vector2f original_setpoint1(10, 0);
131  matrix::Vector2f original_setpoint2(-10, 0);
132  float max_speed = 3;
133  matrix::Vector2f curr_pos(0, 0);
134  matrix::Vector2f curr_vel(2, 0);
136  attitude.timestamp = hrt_absolute_time();
137  attitude.q[0] = 1.0f;
138  attitude.q[1] = 0.0f;
139  attitude.q[2] = 0.0f;
140  attitude.q[3] = 0.0f;
141 
142  // AND: a parameter handle
143  param_t param = param_handle(px4::params::CP_DIST);
144  float value = 10; // try to keep 10m distance
145  param_set(param, &value);
146  cp.paramsChanged();
147 
148  // AND: an obstacle message
149  obstacle_distance_s message;
150  memset(&message, 0xDEAD, sizeof(message));
151  message.frame = message.MAV_FRAME_GLOBAL; //north aligned
152  message.min_distance = 100;
153  message.max_distance = 10000;
154  message.angle_offset = 0;
155  message.timestamp = hrt_absolute_time();
156  int distances_array_size = sizeof(message.distances) / sizeof(message.distances[0]);
157  message.increment = 360 / distances_array_size;
158 
159  for (int i = 0; i < distances_array_size; i++) {
160  if (i < 10) {
161  message.distances[i] = 101;
162 
163  } else {
164  message.distances[i] = 10001;
165  }
166 
167  }
168 
169  // WHEN: we publish the message and set the parameter and then run the setpoint modification
170  orb_advert_t obstacle_distance_pub = orb_advertise(ORB_ID(obstacle_distance), &message);
171  orb_advert_t vehicle_attitude_pub = orb_advertise(ORB_ID(vehicle_attitude), &attitude);
172  orb_publish(ORB_ID(obstacle_distance), obstacle_distance_pub, &message);
173  orb_publish(ORB_ID(vehicle_attitude), vehicle_attitude_pub, &attitude);
174  matrix::Vector2f modified_setpoint1 = original_setpoint1;
175  matrix::Vector2f modified_setpoint2 = original_setpoint2;
176  cp.modifySetpoint(modified_setpoint1, max_speed, curr_pos, curr_vel);
177  cp.modifySetpoint(modified_setpoint2, max_speed, curr_pos, curr_vel);
178  orb_unadvertise(obstacle_distance_pub);
179  orb_unadvertise(vehicle_attitude_pub);
180 
181  // THEN: the internal map should know the obstacle
182  // case 1: the velocity setpoint should be cut down to zero
183  // case 2: the velocity setpoint should stay the same as the input
184  EXPECT_FLOAT_EQ(cp.getObstacleMap().min_distance, 100);
185  EXPECT_FLOAT_EQ(cp.getObstacleMap().max_distance, 10000);
186 
187  EXPECT_FLOAT_EQ(0.f, modified_setpoint1.norm()) << modified_setpoint1(0) << "," << modified_setpoint1(1);
188  EXPECT_FLOAT_EQ(original_setpoint2.norm(), modified_setpoint2.norm());
189 }
190 
191 TEST_F(CollisionPreventionTest, testBehaviorOnWithDistanceMessage)
192 {
193  // GIVEN: a simple setup condition
195  matrix::Vector2f original_setpoint1(10, 0);
196  matrix::Vector2f original_setpoint2(-10, 0);
197  float max_speed = 3;
198  matrix::Vector2f curr_pos(0, 0);
199  matrix::Vector2f curr_vel(2, 0);
201  attitude.timestamp = hrt_absolute_time();
202  attitude.q[0] = 1.0f;
203  attitude.q[1] = 0.0f;
204  attitude.q[2] = 0.0f;
205  attitude.q[3] = 0.0f;
206 
207  // AND: a parameter handle
208  param_t param = param_handle(px4::params::CP_DIST);
209  float value = 10; // try to keep 10m distance
210  param_set(param, &value);
211  cp.paramsChanged();
212 
213  // AND: an obstacle message
214  distance_sensor_s message;
215  message.timestamp = hrt_absolute_time();
216  message.min_distance = 1.f;
217  message.max_distance = 100.f;
218  message.current_distance = 1.1f;
219 
220  message.variance = 0.1f;
221  message.signal_quality = 100;
222  message.type = distance_sensor_s::MAV_DISTANCE_SENSOR_LASER;
223  message.orientation = distance_sensor_s::ROTATION_FORWARD_FACING;
224  message.h_fov = math::radians(50.f);
225  message.v_fov = math::radians(30.f);
226 
227  // WHEN: we publish the message and set the parameter and then run the setpoint modification
228  orb_advert_t distance_sensor_pub = orb_advertise(ORB_ID(distance_sensor), &message);
229  orb_advert_t vehicle_attitude_pub = orb_advertise(ORB_ID(vehicle_attitude), &attitude);
230  orb_publish(ORB_ID(distance_sensor), distance_sensor_pub, &message);
231  orb_publish(ORB_ID(vehicle_attitude), vehicle_attitude_pub, &attitude);
232 
233  //WHEN: We run the setpoint modification
234  matrix::Vector2f modified_setpoint1 = original_setpoint1;
235  matrix::Vector2f modified_setpoint2 = original_setpoint2;
236  cp.modifySetpoint(modified_setpoint1, max_speed, curr_pos, curr_vel);
237  cp.modifySetpoint(modified_setpoint2, max_speed, curr_pos, curr_vel);
238  orb_unadvertise(distance_sensor_pub);
239  orb_unadvertise(vehicle_attitude_pub);
240 
241  // THEN: the internal map should know the obstacle
242  // case 1: the velocity setpoint should be cut down to zero because there is an obstacle
243  // case 2: the velocity setpoint should be cut down to zero because there is no data
244  EXPECT_FLOAT_EQ(cp.getObstacleMap().min_distance, 100);
245  EXPECT_FLOAT_EQ(cp.getObstacleMap().max_distance, 10000);
246 
247  EXPECT_FLOAT_EQ(0.f, modified_setpoint1.norm()) << modified_setpoint1(0) << "," << modified_setpoint1(1);
248  EXPECT_FLOAT_EQ(0.f, modified_setpoint2.norm()) << modified_setpoint2(0) << "," << modified_setpoint2(1);
249 }
250 
251 TEST_F(CollisionPreventionTest, testPurgeOldData)
252 {
253  // GIVEN: a simple setup condition
255  hrt_abstime start_time = hrt_absolute_time();
256  mocked_time = start_time;
257  matrix::Vector2f original_setpoint(10, 0);
258  float max_speed = 3;
259  matrix::Vector2f curr_pos(0, 0);
260  matrix::Vector2f curr_vel(2, 0);
262  attitude.timestamp = start_time;
263  attitude.q[0] = 1.0f;
264  attitude.q[1] = 0.0f;
265  attitude.q[2] = 0.0f;
266  attitude.q[3] = 0.0f;
267 
268  // AND: a parameter handle
269  param_t param = param_handle(px4::params::CP_DIST);
270  float value = 10; // try to keep 10m distance
271  param_set(param, &value);
272  cp.paramsChanged();
273 
274  // AND: an obstacle message
275  obstacle_distance_s message, message_empty;
276  memset(&message, 0xDEAD, sizeof(message));
277  message.frame = message.MAV_FRAME_GLOBAL; //north aligned
278  message.min_distance = 100;
279  message.max_distance = 10000;
280  message.angle_offset = 0;
281  message.timestamp = start_time;
282  int distances_array_size = sizeof(message.distances) / sizeof(message.distances[0]);
283  message.increment = 360 / distances_array_size;
284  message_empty = message;
285 
286  for (int i = 0; i < distances_array_size; i++) {
287  if (i < 10) {
288  message.distances[i] = 10001;
289 
290  } else {
291  message.distances[i] = UINT16_MAX;
292  }
293 
294  message_empty.distances[i] = UINT16_MAX;
295  }
296 
297 
298  // WHEN: we publish the message and set the parameter and then run the setpoint modification
299  orb_advert_t obstacle_distance_pub = orb_advertise(ORB_ID(obstacle_distance), &message);
300  orb_advert_t vehicle_attitude_pub = orb_advertise(ORB_ID(vehicle_attitude), &attitude);
301  orb_publish(ORB_ID(obstacle_distance), obstacle_distance_pub, &message);
302  orb_publish(ORB_ID(vehicle_attitude), vehicle_attitude_pub, &attitude);
303 
304  for (int i = 0; i < 10; i++) {
305 
306  matrix::Vector2f modified_setpoint = original_setpoint;
307  cp.modifySetpoint(modified_setpoint, max_speed, curr_pos, curr_vel);
308 
309  mocked_time = mocked_time + 100000; //advance time by 0.1 seconds
310  message_empty.timestamp = mocked_time;
311  orb_publish(ORB_ID(obstacle_distance), obstacle_distance_pub, &message_empty);
312 
313  if (i < 6) {
314  // THEN: If the data is new enough, the velocity setpoint should stay the same as the input
315  // Note: direction will change slightly due to guidance
316  EXPECT_EQ(original_setpoint.norm(), modified_setpoint.norm());
317 
318  } else {
319  // THEN: If the data is expired, the velocity setpoint should be cut down to zero because there is no data
320  EXPECT_FLOAT_EQ(0.f, modified_setpoint.norm()) << modified_setpoint(0) << "," << modified_setpoint(1);
321  }
322  }
323 
324  orb_unadvertise(obstacle_distance_pub);
325  orb_unadvertise(vehicle_attitude_pub);
326 }
327 
329 {
330  // GIVEN: a simple setup condition
332  hrt_abstime start_time = hrt_absolute_time();
333  mocked_time = start_time;
334  matrix::Vector2f original_setpoint(10, 0);
335  float max_speed = 3;
336  matrix::Vector2f curr_pos(0, 0);
337  matrix::Vector2f curr_vel(2, 0);
339  attitude.timestamp = start_time;
340  attitude.q[0] = 1.0f;
341  attitude.q[1] = 0.0f;
342  attitude.q[2] = 0.0f;
343  attitude.q[3] = 0.0f;
344 
345  // AND: a parameter handle
346  param_t param = param_handle(px4::params::CP_DIST);
347  float value = 10; // try to keep 10m distance
348  param_set(param, &value);
349  cp.paramsChanged();
350 
351  // AND: an obstacle message without any obstacle
352  obstacle_distance_s message;
353  memset(&message, 0xDEAD, sizeof(message));
354  message.frame = message.MAV_FRAME_GLOBAL; //north aligned
355  message.min_distance = 100;
356  message.max_distance = 10000;
357  message.angle_offset = 0;
358  message.timestamp = start_time;
359  int distances_array_size = sizeof(message.distances) / sizeof(message.distances[0]);
360  message.increment = 360 / distances_array_size;
361 
362  for (int i = 0; i < distances_array_size; i++) {
363  message.distances[i] = 9000;
364  }
365 
366 
367  // WHEN: we publish the message and set the parameter and then run the setpoint modification
368  orb_advert_t obstacle_distance_pub = orb_advertise(ORB_ID(obstacle_distance), &message);
369  orb_advert_t vehicle_attitude_pub = orb_advertise(ORB_ID(vehicle_attitude), &attitude);
370  orb_publish(ORB_ID(obstacle_distance), obstacle_distance_pub, &message);
371  orb_publish(ORB_ID(vehicle_attitude), vehicle_attitude_pub, &attitude);
372 
373  for (int i = 0; i < 10; i++) {
374 
375  matrix::Vector2f modified_setpoint = original_setpoint;
376  cp.modifySetpoint(modified_setpoint, max_speed, curr_pos, curr_vel);
377 
378  //advance time by 0.1 seconds but no new message comes in
379  mocked_time = mocked_time + 100000;
380 
381  if (i < 5) {
382  // THEN: If the data is new enough, the velocity setpoint should stay the same as the input
383  // Note: direction will change slightly due to guidance
384  EXPECT_EQ(original_setpoint.norm(), modified_setpoint.norm());
385 
386  } else {
387  // THEN: If the data is expired, the velocity setpoint should be cut down to zero because there is no data
388  EXPECT_FLOAT_EQ(0.f, modified_setpoint.norm()) << modified_setpoint(0) << "," << modified_setpoint(1);
389  }
390  }
391 
392  orb_unadvertise(obstacle_distance_pub);
393  orb_unadvertise(vehicle_attitude_pub);
394 }
395 
397 {
398  // GIVEN: a simple setup condition
400  matrix::Vector2f original_setpoint(10, 0);
401  float max_speed = 3;
402  matrix::Vector2f curr_pos(0, 0);
403  matrix::Vector2f curr_vel(2, 0);
404 
405  // AND: a parameter handle
406  param_t param = param_handle(px4::params::CP_DIST);
407  float value = 5; // try to keep 5m distance
408  param_set(param, &value);
409  cp.paramsChanged();
410 
411  // AND: an obstacle message
412  obstacle_distance_s message;
413  memset(&message, 0xDEAD, sizeof(message));
414  message.min_distance = 100;
415  message.max_distance = 2000;
416  message.timestamp = hrt_absolute_time();
417  message.frame = message.MAV_FRAME_GLOBAL; //north aligned
418  int distances_array_size = sizeof(message.distances) / sizeof(message.distances[0]);
419  message.increment = 360 / distances_array_size;
420 
421  for (int i = 0; i < distances_array_size; i++) {
422  message.distances[i] = 700;
423  }
424 
425  // WHEN: we publish the message and set the parameter and then run the setpoint modification
426  orb_advert_t obstacle_distance_pub = orb_advertise(ORB_ID(obstacle_distance), &message);
427  orb_publish(ORB_ID(obstacle_distance), obstacle_distance_pub, &message);
428  matrix::Vector2f modified_setpoint = original_setpoint;
429  cp.modifySetpoint(modified_setpoint, max_speed, curr_pos, curr_vel);
430  orb_unadvertise(obstacle_distance_pub);
431 
432  // THEN: setpoint should go into the same direction as the stick input
433  EXPECT_FLOAT_EQ(original_setpoint.normalized()(0), modified_setpoint.normalized()(0));
434  EXPECT_FLOAT_EQ(original_setpoint.normalized()(1), modified_setpoint.normalized()(1));
435 }
436 
438 {
439  // GIVEN: a simple setup condition
441  float max_speed = 3;
442  matrix::Vector2f curr_pos(0, 0);
443  matrix::Vector2f curr_vel(2, 0);
444 
445  // AND: a parameter handle
446  param_t param = param_handle(px4::params::CP_DIST);
447  float value = 5; // try to keep 5m distance
448  param_set(param, &value);
449  cp.paramsChanged();
450 
451  // AND: an obstacle message
452  obstacle_distance_s message;
453  memset(&message, 0xDEAD, sizeof(message));
454  message.frame = message.MAV_FRAME_GLOBAL; //north aligned
455  message.min_distance = 100;
456  message.max_distance = 2000;
457  int distances_array_size = sizeof(message.distances) / sizeof(message.distances[0]);
458  message.increment = 360.f / distances_array_size;
459 
460  //fov from 45deg to 225deg
461  for (int i = 0; i < distances_array_size; i++) {
462  float angle = i * message.increment;
463 
464  if (angle > 45.f && angle < 225.f) {
465  message.distances[i] = 700;
466 
467  } else {
468  message.distances[i] = UINT16_MAX;
469  }
470  }
471 
472  // WHEN: we publish the message and modify the setpoint for different demanded setpoints
473  orb_advert_t obstacle_distance_pub = orb_advertise(ORB_ID(obstacle_distance), &message);
474 
475  for (int i = 0; i < distances_array_size; i++) {
476 
477  float angle_deg = (float)i * message.increment;
478  float angle_rad = math::radians(angle_deg);
479  matrix::Vector2f original_setpoint = {10.f * cosf(angle_rad), 10.f * sinf(angle_rad)};
480  matrix::Vector2f modified_setpoint = original_setpoint;
481  message.timestamp = hrt_absolute_time();
482  orb_publish(ORB_ID(obstacle_distance), obstacle_distance_pub, &message);
483  cp.modifySetpoint(modified_setpoint, max_speed, curr_pos, curr_vel);
484 
485  //THEN: if the resulting setpoint demands velocities bigger zero, it must lie inside the FOV
486  float setpoint_length = modified_setpoint.norm();
487 
488  if (setpoint_length > 0.f) {
489  matrix::Vector2f setpoint_dir = modified_setpoint / setpoint_length;
490  float sp_angle_body_frame = atan2(setpoint_dir(1), setpoint_dir(0));
491  float sp_angle_deg = math::degrees(matrix::wrap_2pi(sp_angle_body_frame));
492  EXPECT_GE(sp_angle_deg, 45.f);
493  EXPECT_LE(sp_angle_deg, 225.f);
494  }
495  }
496 
497  orb_unadvertise(obstacle_distance_pub);
498 }
499 
501 {
502  // GIVEN: a simple setup condition with the initial state (no distance data)
504  float max_speed = 3;
505  matrix::Vector2f curr_pos(0, 0);
506  matrix::Vector2f curr_vel(2, 0);
507 
508  // AND: a parameter handle
509  param_t param = param_handle(px4::params::CP_DIST);
510  float value = 5; // try to keep 5m distance
511  param_set(param, &value);
512  cp.paramsChanged();
513 
514  matrix::Vector2f original_setpoint = {-5, 0};
515  matrix::Vector2f modified_setpoint = original_setpoint;
516 
517  //THEN: the modified setpoint should be zero velocity
518  cp.modifySetpoint(modified_setpoint, max_speed, curr_pos, curr_vel);
519  EXPECT_FLOAT_EQ(modified_setpoint.norm(), 0.f);
520 
521  //WHEN: we change the parameter CP_GO_NO_DATA to allow flying ouside the FOV
522  param_t param_allow = param_handle(px4::params::CP_GO_NO_DATA);
523  float value_allow = 1;
524  param_set(param_allow, &value_allow);
525  cp.paramsChanged();
526 
527  //THEN: the modified setpoint should stay the same as the input
528  modified_setpoint = original_setpoint;
529  cp.modifySetpoint(modified_setpoint, max_speed, curr_pos, curr_vel);
530  EXPECT_FLOAT_EQ(modified_setpoint.norm(), original_setpoint.norm());
531 }
532 
534 {
535  // GIVEN: a simple setup condition
537  matrix::Vector2f original_setpoint(10, 0);
538  float max_speed = 3;
539  matrix::Vector2f curr_pos(0, 0);
540  matrix::Vector2f curr_vel(2, 0);
541 
542  // AND: distance set to 5m
543  param_t param = param_handle(px4::params::CP_DIST);
544  float value = 5; // try to keep 5m distance
545  param_set(param, &value);
546  cp.paramsChanged();
547 
548  // AND: an obstacle message
549  obstacle_distance_s message;
550  memset(&message, 0xDEAD, sizeof(message));
551  message.min_distance = 100;
552  message.max_distance = 2000;
553  message.timestamp = hrt_absolute_time();
554  message.frame = message.MAV_FRAME_GLOBAL; //north aligned
555  int distances_array_size = sizeof(message.distances) / sizeof(message.distances[0]);
556  message.increment = 360 / distances_array_size;
557 
558  for (int i = 0; i < distances_array_size; i++) {
559  message.distances[i] = 700;
560  }
561 
562  // AND: we publish the message and set the parameter and then run the setpoint modification
563  orb_advert_t obstacle_distance_pub = orb_advertise(ORB_ID(obstacle_distance), &message);
564  orb_publish(ORB_ID(obstacle_distance), obstacle_distance_pub, &message);
565  matrix::Vector2f modified_setpoint_default_jerk = original_setpoint;
566  cp.modifySetpoint(modified_setpoint_default_jerk, max_speed, curr_pos, curr_vel);
567  orb_unadvertise(obstacle_distance_pub);
568 
569  // AND: we now set max jerk to 0.1
570  param = param_handle(px4::params::MPC_JERK_MAX);
571  value = 0.1; // 0.1 maximum jerk
572  param_set(param, &value);
573  cp.paramsChanged();
574 
575  // WHEN: we run the setpoint modification again
576  matrix::Vector2f modified_setpoint_limited_jerk = original_setpoint;
577  cp.modifySetpoint(modified_setpoint_limited_jerk, max_speed, curr_pos, curr_vel);
578 
579  // THEN: the new setpoint should be much slower than the one with default jerk
580  EXPECT_LT(modified_setpoint_limited_jerk.norm() * 10, modified_setpoint_default_jerk.norm());
581 }
582 
583 TEST_F(CollisionPreventionTest, addDistanceSensorData)
584 {
585  // GIVEN: a vehicle attitude and a distance sensor message
587  cp.getObstacleMap().increment = 10.f;
588  matrix::Quaternion<float> vehicle_attitude(1, 0, 0, 0); //unit transform
589  distance_sensor_s distance_sensor {};
590  distance_sensor.min_distance = 0.2f;
591  distance_sensor.max_distance = 20.f;
592  distance_sensor.current_distance = 5.f;
593 
594  //THEN: at initialization the internal obstacle map should only contain UINT16_MAX
595  uint32_t distances_array_size = sizeof(cp.getObstacleMap().distances) / sizeof(cp.getObstacleMap().distances[0]);
596 
597  for (uint32_t i = 0; i < distances_array_size; i++) {
598  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], UINT16_MAX);
599  }
600 
601  //WHEN: we add distance sensor data to the right
602  distance_sensor.orientation = distance_sensor_s::ROTATION_RIGHT_FACING;
603  distance_sensor.h_fov = math::radians(19.99f);
604  cp.test_addDistanceSensorData(distance_sensor, vehicle_attitude);
605 
606  //THEN: the correct bins in the map should be filled
607  for (uint32_t i = 0; i < distances_array_size; i++) {
608  if (i == 8 || i == 9) {
609  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], 500);
610 
611  } else {
612  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], UINT16_MAX);
613  }
614  }
615 
616  //WHEN: we add additionally distance sensor data to the left
617  distance_sensor.orientation = distance_sensor_s::ROTATION_LEFT_FACING;
618  distance_sensor.h_fov = math::radians(50.f);
619  distance_sensor.current_distance = 8.f;
620  cp.test_addDistanceSensorData(distance_sensor, vehicle_attitude);
621 
622  //THEN: the correct bins in the map should be filled
623  for (uint32_t i = 0; i < distances_array_size; i++) {
624  if (i == 8 || i == 9) {
625  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], 500);
626 
627  } else if (i >= 24 && i <= 29) {
628  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], 800);
629 
630  } else {
631  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], UINT16_MAX);
632  }
633  }
634 
635  //WHEN: we add additionally distance sensor data to the front
636  distance_sensor.orientation = distance_sensor_s::ROTATION_FORWARD_FACING;
637  distance_sensor.h_fov = math::radians(10.1f);
638  distance_sensor.current_distance = 3.f;
639  cp.test_addDistanceSensorData(distance_sensor, vehicle_attitude);
640 
641  //THEN: the correct bins in the map should be filled
642  for (uint32_t i = 0; i < distances_array_size; i++) {
643  if (i == 8 || i == 9) {
644  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], 500);
645 
646  } else if (i >= 24 && i <= 29) {
647  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], 800);
648 
649  } else if (i == 0) {
650  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], 300);
651 
652  } else {
653  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], UINT16_MAX);
654  }
655  }
656 
657 
658 }
659 
660 TEST_F(CollisionPreventionTest, addObstacleSensorData_attitude)
661 {
662  // GIVEN: a vehicle attitude and obstacle distance message
664  cp.getObstacleMap().increment = 10.f;
665  obstacle_distance_s obstacle_msg {};
666  obstacle_msg.frame = obstacle_msg.MAV_FRAME_GLOBAL; //north aligned
667  obstacle_msg.increment = 5.f;
668  obstacle_msg.min_distance = 20;
669  obstacle_msg.max_distance = 2000;
670  obstacle_msg.angle_offset = 0.f;
671 
672  matrix::Quaternion<float> vehicle_attitude1(1, 0, 0, 0); //unit transform
673  matrix::Euler<float> attitude2_euler(0, 0, M_PI / 2.0);
674  matrix::Quaternion<float> vehicle_attitude2(attitude2_euler); //90 deg yaw
675  matrix::Euler<float> attitude3_euler(0, 0, -M_PI / 4.0);
676  matrix::Quaternion<float> vehicle_attitude3(attitude3_euler); // -45 deg yaw
677  matrix::Euler<float> attitude4_euler(0, 0, M_PI);
678  matrix::Quaternion<float> vehicle_attitude4(attitude4_euler); // 180 deg yaw
679 
680  //obstacle at 10-30 deg world frame, distance 5 meters
681  memset(&obstacle_msg.distances[0], UINT16_MAX, sizeof(obstacle_msg.distances));
682 
683  for (int i = 2; i < 6 ; i++) {
684  obstacle_msg.distances[i] = 500;
685  }
686 
687 
688  //THEN: at initialization the internal obstacle map should only contain UINT16_MAX
689  int distances_array_size = sizeof(cp.getObstacleMap().distances) / sizeof(cp.getObstacleMap().distances[0]);
690 
691  for (int i = 0; i < distances_array_size; i++) {
692  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], UINT16_MAX);
693  }
694 
695  //WHEN: we add distance sensor data while vehicle has zero yaw
696  cp.test_addObstacleSensorData(obstacle_msg, vehicle_attitude1);
697 
698  //THEN: the correct bins in the map should be filled
699  for (int i = 0; i < distances_array_size; i++) {
700  if (i == 1 || i == 2) {
701  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], 500);
702 
703  } else {
704  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], UINT16_MAX);
705  }
706 
707  //reset array to UINT16_MAX
708  cp.getObstacleMap().distances[i] = UINT16_MAX;
709  }
710 
711 
712  //WHEN: we add distance sensor data while vehicle yaw 90deg to the right
713  cp.test_addObstacleSensorData(obstacle_msg, vehicle_attitude2);
714 
715  //THEN: the correct bins in the map should be filled
716  for (int i = 0; i < distances_array_size; i++) {
717  if (i == 28 || i == 29) {
718  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], 500);
719 
720  } else {
721  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], UINT16_MAX);
722  }
723 
724  //reset array to UINT16_MAX
725  cp.getObstacleMap().distances[i] = UINT16_MAX;
726  }
727 
728  //WHEN: we add distance sensor data while vehicle yaw 45deg to the left
729  cp.test_addObstacleSensorData(obstacle_msg, vehicle_attitude3);
730 
731  //THEN: the correct bins in the map should be filled
732  for (int i = 0; i < distances_array_size; i++) {
733  if (i == 6 || i == 7) {
734  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], 500);
735 
736  } else {
737  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], UINT16_MAX);
738  }
739 
740  //reset array to UINT16_MAX
741  cp.getObstacleMap().distances[i] = UINT16_MAX;
742  }
743 
744  //WHEN: we add distance sensor data while vehicle yaw 180deg
745  cp.test_addObstacleSensorData(obstacle_msg, vehicle_attitude4);
746 
747  //THEN: the correct bins in the map should be filled
748  for (int i = 0; i < distances_array_size; i++) {
749  if (i == 19 || i == 20) {
750  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], 500);
751 
752  } else {
753  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], UINT16_MAX);
754  }
755 
756  //reset array to UINT16_MAX
757  cp.getObstacleMap().distances[i] = UINT16_MAX;
758  }
759 }
760 
761 TEST_F(CollisionPreventionTest, addObstacleSensorData_bodyframe)
762 {
763  // GIVEN: a vehicle attitude and obstacle distance message
765  cp.getObstacleMap().increment = 10.f;
766  obstacle_distance_s obstacle_msg {};
767  obstacle_msg.frame = obstacle_msg.MAV_FRAME_BODY_FRD; //north aligned
768  obstacle_msg.increment = 5.f;
769  obstacle_msg.min_distance = 20;
770  obstacle_msg.max_distance = 2000;
771  obstacle_msg.angle_offset = 0.f;
772 
773  matrix::Quaternion<float> vehicle_attitude1(1, 0, 0, 0); //unit transform
774  matrix::Euler<float> attitude2_euler(0, 0, M_PI / 2.0);
775  matrix::Quaternion<float> vehicle_attitude2(attitude2_euler); //90 deg yaw
776  matrix::Euler<float> attitude3_euler(0, 0, -M_PI / 4.0);
777  matrix::Quaternion<float> vehicle_attitude3(attitude3_euler); // -45 deg yaw
778  matrix::Euler<float> attitude4_euler(0, 0, M_PI);
779  matrix::Quaternion<float> vehicle_attitude4(attitude4_euler); // 180 deg yaw
780 
781  //obstacle at 10-30 deg body frame, distance 5 meters
782  memset(&obstacle_msg.distances[0], UINT16_MAX, sizeof(obstacle_msg.distances));
783 
784  for (int i = 2; i < 6 ; i++) {
785  obstacle_msg.distances[i] = 500;
786  }
787 
788 
789  //THEN: at initialization the internal obstacle map should only contain UINT16_MAX
790  int distances_array_size = sizeof(cp.getObstacleMap().distances) / sizeof(cp.getObstacleMap().distances[0]);
791 
792  for (int i = 0; i < distances_array_size; i++) {
793  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], UINT16_MAX);
794  }
795 
796  //WHEN: we add obstacle data while vehicle has zero yaw
797  cp.test_addObstacleSensorData(obstacle_msg, vehicle_attitude1);
798 
799  //THEN: the correct bins in the map should be filled
800  for (int i = 0; i < distances_array_size; i++) {
801  if (i == 1 || i == 2) {
802  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], 500);
803 
804  } else {
805  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], UINT16_MAX);
806  }
807 
808  //reset array to UINT16_MAX
809  cp.getObstacleMap().distances[i] = UINT16_MAX;
810  }
811 
812  //WHEN: we add obstacle data while vehicle yaw 90deg to the right
813  cp.test_addObstacleSensorData(obstacle_msg, vehicle_attitude2);
814 
815  //THEN: the correct bins in the map should be filled
816  for (int i = 0; i < distances_array_size; i++) {
817  if (i == 1 || i == 2) {
818  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], 500);
819 
820  } else {
821  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], UINT16_MAX);
822  }
823 
824  //reset array to UINT16_MAX
825  cp.getObstacleMap().distances[i] = UINT16_MAX;
826  }
827 
828  //WHEN: we add obstacle data while vehicle yaw 45deg to the left
829  cp.test_addObstacleSensorData(obstacle_msg, vehicle_attitude3);
830 
831  //THEN: the correct bins in the map should be filled
832  for (int i = 0; i < distances_array_size; i++) {
833  if (i == 1 || i == 2) {
834  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], 500);
835 
836  } else {
837  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], UINT16_MAX);
838  }
839 
840  //reset array to UINT16_MAX
841  cp.getObstacleMap().distances[i] = UINT16_MAX;
842  }
843 
844  //WHEN: we add obstacle data while vehicle yaw 180deg
845  cp.test_addObstacleSensorData(obstacle_msg, vehicle_attitude4);
846 
847  //THEN: the correct bins in the map should be filled
848  for (int i = 0; i < distances_array_size; i++) {
849  if (i == 1 || i == 2) {
850  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], 500);
851 
852  } else {
853  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], UINT16_MAX);
854  }
855 
856  //reset array to UINT16_MAX
857  cp.getObstacleMap().distances[i] = UINT16_MAX;
858  }
859 }
860 
861 
862 TEST_F(CollisionPreventionTest, addObstacleSensorData_resolution_offset)
863 {
864  // GIVEN: a vehicle attitude and obstacle distance message
866  cp.getObstacleMap().increment = 10.f;
867  obstacle_distance_s obstacle_msg {};
868  obstacle_msg.frame = obstacle_msg.MAV_FRAME_GLOBAL; //north aligned
869  obstacle_msg.increment = 6.f;
870  obstacle_msg.min_distance = 20;
871  obstacle_msg.max_distance = 2000;
872  obstacle_msg.angle_offset = 0.f;
873 
874  matrix::Quaternion<float> vehicle_attitude(1, 0, 0, 0); //unit transform
875 
876  //obstacle at 0-30 deg world frame, distance 5 meters
877  memset(&obstacle_msg.distances[0], UINT16_MAX, sizeof(obstacle_msg.distances));
878 
879  for (int i = 0; i < 5 ; i++) {
880  obstacle_msg.distances[i] = 500;
881  }
882 
883  //WHEN: we add distance sensor data
884  cp.test_addObstacleSensorData(obstacle_msg, vehicle_attitude);
885 
886  //THEN: the correct bins in the map should be filled
887  int distances_array_size = sizeof(cp.getObstacleMap().distances) / sizeof(cp.getObstacleMap().distances[0]);
888 
889  for (int i = 0; i < distances_array_size; i++) {
890  if (i >= 0 && i <= 2) {
891  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], 500);
892 
893  } else {
894  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], UINT16_MAX);
895  }
896 
897  //reset array to UINT16_MAX
898  cp.getObstacleMap().distances[i] = UINT16_MAX;
899  }
900 
901  //WHEN: we add distance sensor data with an angle offset
902  obstacle_msg.angle_offset = 30.f;
903  cp.test_addObstacleSensorData(obstacle_msg, vehicle_attitude);
904 
905  //THEN: the correct bins in the map should be filled
906  for (int i = 0; i < distances_array_size; i++) {
907  if (i >= 3 && i <= 5) {
908  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], 500);
909 
910  } else {
911  EXPECT_FLOAT_EQ(cp.getObstacleMap().distances[i], UINT16_MAX);
912  }
913 
914  //reset array to UINT16_MAX
915  cp.getObstacleMap().distances[i] = UINT16_MAX;
916  }
917 }
918 
919 TEST_F(CollisionPreventionTest, adaptSetpointDirection_distinct_minimum)
920 {
921  // GIVEN: a vehicle attitude and obstacle distance message
923  cp.getObstacleMap().increment = 10.f;
924  obstacle_distance_s obstacle_msg {};
925  obstacle_msg.frame = obstacle_msg.MAV_FRAME_GLOBAL; //north aligned
926  obstacle_msg.increment = 10.f;
927  obstacle_msg.min_distance = 20;
928  obstacle_msg.max_distance = 2000;
929  obstacle_msg.angle_offset = 0.f;
930 
931  matrix::Quaternion<float> vehicle_attitude(1, 0, 0, 0); //unit transform
932  float vehicle_yaw_angle_rad = matrix::Eulerf(vehicle_attitude).psi();
933 
934  //obstacle at 0-30 deg world frame, distance 5 meters
935  memset(&obstacle_msg.distances[0], UINT16_MAX, sizeof(obstacle_msg.distances));
936 
937  for (int i = 0; i < 7 ; i++) {
938  obstacle_msg.distances[i] = 500;
939  }
940 
941  obstacle_msg.distances[2] = 1000;
942 
943  //define setpoint
944  matrix::Vector2f setpoint_dir(1, 0);
945  float sp_angle_body_frame = atan2f(setpoint_dir(1), setpoint_dir(0)) - vehicle_yaw_angle_rad;
946  float sp_angle_with_offset_deg = matrix::wrap(math::degrees(sp_angle_body_frame) - cp.getObstacleMap().angle_offset,
947  0.f, 360.f);
948  int sp_index = floor(sp_angle_with_offset_deg / cp.getObstacleMap().increment);
949 
950  //set parameter
951  param_t param = param_handle(px4::params::CP_DIST);
952  float value = 3; // try to keep 10m away from obstacles
953  param_set(param, &value);
954  cp.paramsChanged();
955 
956  //WHEN: we add distance sensor data
957  cp.test_addObstacleSensorData(obstacle_msg, vehicle_attitude);
958  cp.test_adaptSetpointDirection(setpoint_dir, sp_index, vehicle_yaw_angle_rad);
959 
960  //THEN: the setpoint direction should be modified correctly
961  EXPECT_EQ(sp_index, 2);
962  EXPECT_FLOAT_EQ(setpoint_dir(0), 0.93969262);
963  EXPECT_FLOAT_EQ(setpoint_dir(1), 0.34202012);
964 }
965 
966 TEST_F(CollisionPreventionTest, adaptSetpointDirection_flat_minimum)
967 {
968  // GIVEN: a vehicle attitude and obstacle distance message
970  cp.getObstacleMap().increment = 10.f;
971  obstacle_distance_s obstacle_msg {};
972  obstacle_msg.frame = obstacle_msg.MAV_FRAME_GLOBAL; //north aligned
973  obstacle_msg.increment = 10.f;
974  obstacle_msg.min_distance = 20;
975  obstacle_msg.max_distance = 2000;
976  obstacle_msg.angle_offset = 0.f;
977 
978  matrix::Quaternion<float> vehicle_attitude(1, 0, 0, 0); //unit transform
979  float vehicle_yaw_angle_rad = matrix::Eulerf(vehicle_attitude).psi();
980 
981  //obstacle at 0-30 deg world frame, distance 5 meters
982  memset(&obstacle_msg.distances[0], UINT16_MAX, sizeof(obstacle_msg.distances));
983 
984  for (int i = 0; i < 7 ; i++) {
985  obstacle_msg.distances[i] = 500;
986  }
987 
988  obstacle_msg.distances[1] = 1000;
989  obstacle_msg.distances[2] = 1000;
990  obstacle_msg.distances[3] = 1000;
991 
992  //define setpoint
993  matrix::Vector2f setpoint_dir(1, 0);
994  float sp_angle_body_frame = atan2f(setpoint_dir(1), setpoint_dir(0)) - vehicle_yaw_angle_rad;
995  float sp_angle_with_offset_deg = matrix::wrap(math::degrees(sp_angle_body_frame) - cp.getObstacleMap().angle_offset,
996  0.f, 360.f);
997  int sp_index = floor(sp_angle_with_offset_deg / cp.getObstacleMap().increment);
998 
999  //set parameter
1000  param_t param = param_handle(px4::params::CP_DIST);
1001  float value = 3; // try to keep 10m away from obstacles
1002  param_set(param, &value);
1003  cp.paramsChanged();
1004 
1005  //WHEN: we add distance sensor data
1006  cp.test_addObstacleSensorData(obstacle_msg, vehicle_attitude);
1007  cp.test_adaptSetpointDirection(setpoint_dir, sp_index, vehicle_yaw_angle_rad);
1008 
1009  //THEN: the setpoint direction should be modified correctly
1010  EXPECT_EQ(sp_index, 2);
1011  EXPECT_FLOAT_EQ(setpoint_dir(0), 0.93969262);
1012  EXPECT_FLOAT_EQ(setpoint_dir(1), 0.34202012);
1013 }
1014 
1015 TEST_F(CollisionPreventionTest, overlappingSensors)
1016 {
1017  // GIVEN: a simple setup condition
1019  matrix::Vector2f original_setpoint(10, 0);
1020  float max_speed = 3;
1021  matrix::Vector2f curr_pos(0, 0);
1022  matrix::Vector2f curr_vel(2, 0);
1024  attitude.timestamp = hrt_absolute_time();
1025  attitude.q[0] = 1.0f;
1026  attitude.q[1] = 0.0f;
1027  attitude.q[2] = 0.0f;
1028  attitude.q[3] = 0.0f;
1029 
1030  // AND: a parameter handle
1031  param_t param = param_handle(px4::params::CP_DIST);
1032  float value = 10; // try to keep 10m distance
1033  param_set(param, &value);
1034  cp.paramsChanged();
1035 
1036  // AND: an obstacle message for a short range and a long range sensor
1037  obstacle_distance_s short_range_msg, short_range_msg_no_obstacle, long_range_msg;
1038  memset(&short_range_msg, 0xDEAD, sizeof(short_range_msg));
1039  short_range_msg.frame = short_range_msg.MAV_FRAME_GLOBAL; //north aligned
1040  short_range_msg.angle_offset = 0;
1041  short_range_msg.timestamp = hrt_absolute_time();
1042  int distances_array_size = sizeof(short_range_msg.distances) / sizeof(short_range_msg.distances[0]);
1043  short_range_msg.increment = 360 / distances_array_size;
1044  long_range_msg = short_range_msg;
1045  long_range_msg.min_distance = 100;
1046  long_range_msg.max_distance = 1000;
1047  short_range_msg.min_distance = 20;
1048  short_range_msg.max_distance = 200;
1049  short_range_msg_no_obstacle = short_range_msg;
1050 
1051 
1052  for (int i = 0; i < distances_array_size; i++) {
1053  if (i < 10) {
1054  short_range_msg_no_obstacle.distances[i] = 201;
1055  short_range_msg.distances[i] = 150;
1056  long_range_msg.distances[i] = 500;
1057 
1058  } else {
1059  short_range_msg_no_obstacle.distances[i] = UINT16_MAX;
1060  short_range_msg.distances[i] = UINT16_MAX;
1061  long_range_msg.distances[i] = UINT16_MAX;
1062  }
1063  }
1064 
1065 
1066  // CASE 1
1067  //WHEN: we publish the long range sensor message
1068  orb_advert_t obstacle_distance_pub = orb_advertise(ORB_ID(obstacle_distance), &long_range_msg);
1069  orb_advert_t vehicle_attitude_pub = orb_advertise(ORB_ID(vehicle_attitude), &attitude);
1070  orb_publish(ORB_ID(obstacle_distance), obstacle_distance_pub, &long_range_msg);
1071  orb_publish(ORB_ID(vehicle_attitude), vehicle_attitude_pub, &attitude);
1072  matrix::Vector2f modified_setpoint = original_setpoint;
1073  cp.modifySetpoint(modified_setpoint, max_speed, curr_pos, curr_vel);
1074 
1075  // THEN: the internal map data should contain the long range measurement
1076  EXPECT_EQ(500, cp.getObstacleMap().distances[2]);
1077 
1078  // CASE 2
1079  // WHEN: we publish the short range message followed by a long range message
1080  short_range_msg.timestamp = hrt_absolute_time();
1081  orb_publish(ORB_ID(obstacle_distance), obstacle_distance_pub, &short_range_msg);
1082  cp.modifySetpoint(modified_setpoint, max_speed, curr_pos, curr_vel);
1083  long_range_msg.timestamp = hrt_absolute_time();
1084  orb_publish(ORB_ID(obstacle_distance), obstacle_distance_pub, &long_range_msg);
1085  cp.modifySetpoint(modified_setpoint, max_speed, curr_pos, curr_vel);
1086 
1087  // THEN: the internal map data should contain the short range measurement
1088  EXPECT_EQ(150, cp.getObstacleMap().distances[2]);
1089 
1090  // CASE 3
1091  // WHEN: we publish the short range message with values out of range followed by a long range message
1092  short_range_msg_no_obstacle.timestamp = hrt_absolute_time();
1093  orb_publish(ORB_ID(obstacle_distance), obstacle_distance_pub, &short_range_msg_no_obstacle);
1094  cp.modifySetpoint(modified_setpoint, max_speed, curr_pos, curr_vel);
1095  long_range_msg.timestamp = hrt_absolute_time();
1096  orb_publish(ORB_ID(obstacle_distance), obstacle_distance_pub, &long_range_msg);
1097  cp.modifySetpoint(modified_setpoint, max_speed, curr_pos, curr_vel);
1098 
1099  // THEN: the internal map data should contain the short range measurement
1100  EXPECT_EQ(500, cp.getObstacleMap().distances[2]);
1101 
1102  orb_unadvertise(obstacle_distance_pub);
1103  orb_unadvertise(vehicle_attitude_pub);
1104 }
1105 
1107 {
1108  // GIVEN: a simple setup condition
1110  cp.getObstacleMap().increment = 10.f;
1111  matrix::Quaternion<float> vehicle_attitude(1, 0, 0, 0); //unit transform
1112 
1113  //THEN: just after initialization all bins are at UINT16_MAX and any data should be accepted
1114  EXPECT_TRUE(cp.test_enterData(8, 2.f, 1.5f)); //shorter range, reading in range
1115  EXPECT_TRUE(cp.test_enterData(8, 2.f, 3.f)); //shorter range, reading out of range
1116  EXPECT_TRUE(cp.test_enterData(8, 20.f, 1.5f)); //same range, reading in range
1117  EXPECT_TRUE(cp.test_enterData(8, 20.f, 21.f)); //same range, reading out of range
1118  EXPECT_TRUE(cp.test_enterData(8, 30.f, 1.5f)); //longer range, reading in range
1119  EXPECT_TRUE(cp.test_enterData(8, 30.f, 31.f)); //longer range, reading out of range
1120 
1121  //WHEN: we add distance sensor data to the right with a valid reading
1122  distance_sensor_s distance_sensor {};
1123  distance_sensor.min_distance = 0.2f;
1124  distance_sensor.max_distance = 20.f;
1125  distance_sensor.orientation = distance_sensor_s::ROTATION_RIGHT_FACING;
1126  distance_sensor.h_fov = math::radians(19.99f);
1127  distance_sensor.current_distance = 5.f;
1128  cp.test_addDistanceSensorData(distance_sensor, vehicle_attitude);
1129 
1130  //THEN: the internal map should contain the distance sensor readings
1131  EXPECT_EQ(500, cp.getObstacleMap().distances[8]);
1132  EXPECT_EQ(500, cp.getObstacleMap().distances[9]);
1133 
1134  //THEN: bins 8 & 9 contain valid readings
1135  // a valid reading should only be accepted from sensors with shorter or equal range
1136  // a out of range reading should only be accepted from sensors with the same range
1137 
1138  EXPECT_TRUE(cp.test_enterData(8, 2.f, 1.5f)); //shorter range, reading in range
1139  EXPECT_FALSE(cp.test_enterData(8, 2.f, 3.f)); //shorter range, reading out of range
1140  EXPECT_TRUE(cp.test_enterData(8, 20.f, 1.5f)); //same range, reading in range
1141  EXPECT_TRUE(cp.test_enterData(8, 20.f, 21.f)); //same range, reading out of range
1142  EXPECT_FALSE(cp.test_enterData(8, 30.f, 1.5f)); //longer range, reading in range
1143  EXPECT_FALSE(cp.test_enterData(8, 30.f, 31.f)); //longer range, reading out of range
1144 
1145  //WHEN: we add distance sensor data to the right with an out of range reading
1146  distance_sensor.current_distance = 21.f;
1147  cp.test_addDistanceSensorData(distance_sensor, vehicle_attitude);
1148 
1149  //THEN: the internal map should contain the distance sensor readings
1150  EXPECT_EQ(2000, cp.getObstacleMap().distances[8]);
1151  EXPECT_EQ(2000, cp.getObstacleMap().distances[9]);
1152 
1153  //THEN: bins 8 & 9 contain readings out of range
1154  // a reading in range will be accepted in any case
1155  // out of range readings will only be accepted from sensors with bigger or equal range
1156 
1157  EXPECT_TRUE(cp.test_enterData(8, 2.f, 1.5f)); //shorter range, reading in range
1158  EXPECT_FALSE(cp.test_enterData(8, 2.f, 3.f)); //shorter range, reading out of range
1159  EXPECT_TRUE(cp.test_enterData(8, 20.f, 1.5f)); //same range, reading in range
1160  EXPECT_TRUE(cp.test_enterData(8, 20.f, 21.f)); //same range, reading out of range
1161  EXPECT_TRUE(cp.test_enterData(8, 30.f, 1.5f)); //longer range, reading in range
1162  EXPECT_TRUE(cp.test_enterData(8, 30.f, 31.f)); //longer range, reading out of range
1163 }
Type wrap(Type x, Type low, Type high)
Wrap value to stay in range [low, high)
bool is_active()
Returs true if Collision Prevention is running.
__EXPORT int param_set(param_t param, const void *val)
Set the value of a parameter.
Definition: parameters.cpp:814
orb_advert_t orb_advertise(const struct orb_metadata *meta, const void *data)
Definition: uORB.cpp:43
void test_adaptSetpointDirection(matrix::Vector2f &setpoint_dir, int &setpoint_index, float vehicle_yaw_angle_rad)
constexpr T degrees(T radians)
Definition: Limits.hpp:91
Quaternion class.
Definition: Dcm.hpp:24
bool test_enterData(int map_index, float sensor_range, float sensor_reading)
Type wrap_2pi(Type x)
Wrap value in range [0, 2π)
void test_addObstacleSensorData(const obstacle_distance_s &obstacle, const matrix::Quatf &attitude)
Vector normalized() const
Definition: Vector.hpp:103
#define ORB_ID(_name)
Generates a pointer to the uORB metadata structure for a given topic.
Definition: uORB.h:87
constexpr T radians(T degrees)
Definition: Limits.hpp:85
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
Definition: integration.cpp:8
Euler< float > Eulerf
Definition: Euler.hpp:156
hrt_abstime getElapsedTime(const hrt_abstime *ptr) override
Euler angles class.
Definition: AxisAngle.hpp:18
void test_addDistanceSensorData(distance_sensor_s &distance_sensor, const matrix::Quatf &attitude)
__BEGIN_DECLS typedef uint64_t hrt_abstime
Absolute time, in microsecond units.
Definition: drv_hrt.h:58
__BEGIN_DECLS typedef void * orb_advert_t
ORB topic advertiser handle.
Definition: uORB.h:134
int orb_publish(const struct orb_metadata *meta, orb_advert_t handle, const void *data)
Definition: uORB.cpp:70
#define M_PI
Definition: gps_helper.cpp:38
__EXPORT void param_reset_all(void)
Reset all parameters to their default values.
Definition: parameters.cpp:910
int orb_unadvertise(orb_advert_t handle)
Definition: uORB.cpp:65
void modifySetpoint(matrix::Vector2f &original_setpoint, const float max_speed, const matrix::Vector2f &curr_pos, const matrix::Vector2f &curr_vel)
Computes collision free setpoints.
Type norm() const
Definition: Vector.hpp:73
hrt_abstime mocked_time
TEST_F(CollisionPreventionTest, instantiation)
obstacle_distance_s & getObstacleMap()
Dual< Scalar, N > floor(const Dual< Scalar, N > &a)
Definition: Dual.hpp:210
Dual< Scalar, N > atan2(const Dual< Scalar, N > &a, const Dual< Scalar, N > &b)
Definition: Dual.hpp:325
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
uint32_t param_t
Parameter handle.
Definition: param.h:98