Paparazzi UAS v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
nav_survey_hybrid.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2023 Gautier Hattenberger <gautier.hattenberger@enac.fr>
3 * Based on OSAM poly survey
4 *
5 * This file is part of paparazzi.
6 *
7 * paparazzi is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
11 *
12 * paparazzi is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with paparazzi; see the file COPYING. If not, see
19 * <http://www.gnu.org/licenses/>.
20 */
21
30
34#include "state.h"
35#include "autopilot.h"
36#include "generated/flight_plan.h"
37
38#ifdef DIGITAL_CAM
40#endif
41
42// turn anticipation
43#ifndef SURVEY_HYBRID_APPROACHING_TIME
44#define SURVEY_HYBRID_APPROACHING_TIME 3.f
45#endif
46
47// maximum number of polygon corners
48#ifndef SURVEY_HYBRID_MAX_POLYGON_SIZE
49#define SURVEY_HYBRID_MAX_POLYGON_SIZE 20
50#endif
51
52// use half sweep at the end of polygon
53#ifndef SURVEY_HYBRID_HALF_SWEEP_ENABLED
54#define SURVEY_HYBRID_HALF_SWEEP_ENABLED true
55#endif
56
57// maximum number of sweep lines (0 for unlimited)
58#ifndef SURVEY_HYBRID_MAX_SWEEP
59#define SURVEY_HYBRID_MAX_SWEEP 0
60#endif
61
62// maximum number of sweep back (0 for unlimited)
63#ifndef SURVEY_HYBRID_MAX_SWEEP_BACK
64#define SURVEY_HYBRID_MAX_SWEEP_BACK 0
65#endif
66
67// entry distance (default, half sweep distance)
68#ifndef SURVEY_HYBRID_ENTRY_DISTANCE
69#define SURVEY_HYBRID_ENTRY_DISTANCE (survey_private.sweep_distance / 2.f)
70#endif
71
72// make a circle at entry point if radius is not 0
73#ifndef SURVEY_HYBRID_ENTRY_CIRCLE
74#define SURVEY_HYBRID_ENTRY_CIRCLE TRUE
75#endif
76
77struct Line {float m; float b; float x;};
79
102
105
106static void nav_survey_hybrid_setup(float orientation, float sweep, float radius, float height);
107
108static void TranslateAndRotateFromWorld(struct EnuCoor_f *p, float Zrot, struct EnuCoor_f *trans);
109static void RotateAndTranslateToWorld(struct EnuCoor_f *p, float Zrot, struct EnuCoor_f *trans);
110static void FindInterceptOfTwoLines(float *x, float *y, struct Line L1, struct Line L2);
111static float EvaluateLineForX(float y, struct Line L);
112static float CrossProductZ(struct EnuCoor_f *p1_start, struct EnuCoor_f *p1_end, struct EnuCoor_f *p2_start, struct EnuCoor_f *p2_end);
113
114#define MaxFloat 1000000000
115#define MinFloat -1000000000
116
117#ifndef LINE_START_FUNCTION
118#define LINE_START_FUNCTION {}
119#endif
120#ifndef LINE_STOP_FUNCTION
121#define LINE_STOP_FUNCTION {}
122#endif
123
124#if USE_MISSION
126
127static bool nav_survey_hybrid_mission_local(uint8_t nb, float *params, enum MissionRunFlag flag)
128{
129 if (flag == MissionInit) {
130 if (nb == 10 || nb == 12) {
131 float orientation = params[0];
132 float sweep = params[1];
133 float radius = params[2];
134 float height = params[3];
135 if (nb == 10) { survey_private.size = 3; }
136 else { survey_private.size = 4; }
137 for (int i = 0; i < survey_private.size; i++) {
138 survey_private.corners[i].x = params[4+2*i];
139 survey_private.corners[i].y = params[5+2*i+1];
140 survey_private.corners[i].z = height;
141 }
143 return nav_survey_hybrid_run();
144 }
145 }
146 else if (flag == MissionRun) {
147 return nav_survey_hybrid_run();
148 }
149 return false; // not a valid case
150}
151
152static bool nav_survey_hybrid_mission_global(uint8_t nb, float *params, enum MissionRunFlag flag)
153{
154 if (flag == MissionInit) {
155 if (nb == 10 || nb == 12) {
156 float orientation = params[0];
157 float sweep = params[1];
158 float radius = params[2];
159 float height = params[3];
160 if (nb == 10) { survey_private.size = 3; }
161 else { survey_private.size = 4; }
162 for (int i = 0; i < survey_private.size; i++) {
163 struct LlaCoor_f lla = {
164 .lat = RadOfDeg(params[4+2*i]),
165 .lon = RadOfDeg(params[4+2*i+1]),
166 .alt = stateGetLlaOrigin_f().alt + height
167 };
168 struct EnuCoor_f corner;
171 }
172 nav_survey_hybrid_setup(orientation, sweep, radius, height);
173 return nav_survey_hybrid_run();
174 }
175 }
176 else if (flag == MissionRun) {
177 return nav_survey_hybrid_run();
178 }
179 return false; // not a valid case
180}
181
182#endif
183
199
202static void nav_survey_hybrid_setup(float orientation, float sweep, float radius, float height)
203{
205 int i = 0;
206 float ys = 0.f;
207 float LeftYInt;
208 float RightYInt;
209 float temp;
210 float XIntercept1 = 0.f;
211 float XIntercept2 = 0.f;
212
213 // cap orientation angle to [-pi; +pi]
214 survey_private.orientation = RadOfDeg(orientation);
217
218 // set auto radius mode if needed
219 if (radius < -0.1f) {
222 } else if (radius > 0.1f) {
223 survey_private.radius = radius;
225 } else {
228 }
229
235
236 // Rotate Corners so sweeps are parellel with x axis
237 for (i = 0; i < survey_private.size; i++) {
238 struct EnuCoor_f zero = { 0 };
240 }
241
242 // Find min x and min y
244 for (i = 1; i < survey_private.size; i++) {
247 }
250 }
251 }
252
253 // Translate Corners all exist in quad #1
254 for (i = 0; i < survey_private.size; i++) {
256 }
257
258 // Find max y
260 for (i = 1; i < survey_private.size; i++) {
263 }
264 }
265
266 // Find polygon edges
267 for (i = 0; i < survey_private.size; i++) {
268 if (i == 0) {
269 if (survey_private.corners[survey_private.size - 1].x == survey_private.corners[i].x) { // Don't divide by zero!
271 } else {
273 }
274 }
275 else if (survey_private.corners[i].x == survey_private.corners[i - 1].x) {
277 } else {
279 }
280
282 }
283
284 // Find Min and Max y for each line
287
288 if (LeftYInt > RightYInt) {
291 } else {
294 }
295
296 for (i = 1; i < survey_private.size - 1; i++) {
299
300 if (LeftYInt > RightYInt) {
303 } else {
306 }
307 }
308
311
312 if (LeftYInt > RightYInt) {
315 } else {
318 }
319
320 // Find amount to increment by every sweep
321 if (survey_private.corners[0].y >= survey_private.max_y / 2.f) {
324 } else {
326 }
327
328 // Find y value of the first sweep
330
331 // Find the edges which intercet the sweep line first
332 for (i = 0; i < survey_private.size; i++) {
336 }
337 }
338
339 // Find point to come from and point to go to
345 } else {
350 }
351
352 // Find the entry point
355 survey_private.entry.z = height;
356
357 // Go into entry state
359
362 survey_private.valid = true;
363}
364
365void nav_survey_hybrid_setup_orientation(uint8_t start_wp, float orientation, uint8_t size, float sweep, float radius, float height)
366{
367 survey_private.valid = false;
369 return; // polygon is too small or too big
370 }
371 for (int i = 0; i < size; i++) {
372 struct EnuCoor_f *wp = waypoint_get_enu_f(start_wp + i);
373 if (wp == NULL) {
374 return; // not a valid waypoint
375 }
376 survey_private.corners[i] = *wp;
377 }
378 survey_private.size = size;
379
380 nav_survey_hybrid_setup(orientation, sweep, radius, height);
381}
382
383void nav_survey_hybrid_setup_towards(uint8_t start_wp, uint8_t second_wp, uint8_t size, float sweep, float radius, float height)
384{
385 survey_private.valid = false;
386 struct EnuCoor_f *start = waypoint_get_enu_f(start_wp);
387 struct EnuCoor_f *second = waypoint_get_enu_f(second_wp);
388 if (start == NULL || second == NULL) {
389 return;
390 }
391
392 float dx = second->x - start->x;
393 float dy = second->y - start->y;
394 float angle = DegOfRad(atan2f(dy, dx));
395 nav_survey_hybrid_setup_orientation(start_wp, angle, size, sweep, radius, height);
396}
397
398//=========================================================================================================================
400{
401 if (!survey_private.valid) {
402 return false; // don't start survey
403 }
404
405 struct EnuCoor_f C;
406 float ys = 0.f;
407 static struct EnuCoor_f LastPoint;
408 int i = 0;
409 bool LastHalfSweep = false;
410 static bool HalfSweep = false;
411 float XIntercept1 = 0.f;
412 float XIntercept2 = 0.f;
413 float DInt1 = 0.f;
414 float DInt2 = 0.f;
415 struct EnuCoor_f zero = { 0 };
416 float qdr = 0.f;
417 float qdr_out = 0.f;
418
419 switch (survey_private.status) {
420 case Entry:
424
426 // align segment at entry point with a circle
431
434 if (CloseRadAngles(qdr, qdr_out) && NavCircleCount() > 0.5f) {
438 }
439 } else {
440 // goto entry point
443
449 }
450 }
451 break;
452 case Sweep:
456
457 // Rotate and Translate Line points into real world
462
463 // follow the line
465
468
469#ifdef DIGITAL_CAM
471 double inteiro;
472 double fract = modf(line_length / dc_distance_interval, &inteiro);
473 if (fract > .5) {
474 //if last shot is more than shot_distance/2 from the corner then take a picture in the corner before go to the next sweep
476 }
477#endif
478
480 // Your out of the Polygon so Sweep Back or Half Sweep
481 if ((LastPoint.y + (survey_private.sweep / 2.f)) <= survey_private.max_y ||
482 (LastPoint.y + (survey_private.sweep / 2.f)) >= 0.f ||
484 // Sweep back
486 }
487 if (LastHalfSweep) {
488 HalfSweep = false;
490 } else {
491 HalfSweep = true;
492 ys = LastPoint.y + (survey_private.sweep / 2.f);
493 }
495 } else { // Normal sweep
496 // Find y value of the first sweep
497 HalfSweep = false;
499 }
500
501 // Find the edges which intercet the sweep line first
502 for (i = 0; i < survey_private.size; i++) {
506 }
507 }
508
509 // Find point to come from and point to go to
512
513 if (DInt1 *DInt2 >= 0) {
514 if (fabsf(DInt2) <= fabsf(DInt1)) {
519 } else {
524 }
525 } else {
526 if ((survey_private.to_wp.x - survey_private.from_wp.x) > 0 && DInt2 > 0) {
531 } else if ((survey_private.to_wp.x - survey_private.from_wp.x) < 0 && DInt2 < 0) {
536 } else {
541 }
542 }
543
544 // Go into Turn state
548
552 // end survey if nb > nb_max and nb_max is not 0
553 // or if nb_back > nb_back_max and nb_back_max is not 0
554 return false;
555 }
556 }
557
558 break;
559 case Turn:
562
563 // Rotate and Translate Line points into real world
568
572 } else {
574 }
575 float dir = (survey_private.sweep < 0.f ? -1.f : 1.f) * fabsf(survey_private.radius);
579 // circle turns
581
584 if (CloseRadAngles(qdr, qdr_out)) {
588 }
589 } else {
590 // use straight lines to reach next point
592
597 }
598 }
599
600 break;
601 case Init:
602 return false;
603 default:
604 return false;
605 }
606
607 return true;
608
609}
610
611//============================================================================================================================================
612/*
613 Translates point so (transX, transY) are (0,0) then rotates the point around z by Zrot
614*/
615void TranslateAndRotateFromWorld(struct EnuCoor_f *p, float Zrot, struct EnuCoor_f *trans)
616{
617 float temp;
618
619 p->x = p->x - trans->x;
620 p->y = p->y - trans->y;
621
622 temp = p->x;
623 p->x = p->x * cosf(Zrot) + p->y * sinf(Zrot);
624 p->y = -temp * sinf(Zrot) + p->y * cosf(Zrot);
625}
626
628void RotateAndTranslateToWorld(struct EnuCoor_f *p, float Zrot, struct EnuCoor_f *trans)
629{
630 float temp = p->x;
631
632 p->x = p->x * cosf(Zrot) - p->y * sinf(Zrot);
633 p->y = temp * sinf(Zrot) + p->y * cosf(Zrot);
634
635 p->x = p->x + trans->x;
636 p->y = p->y + trans->y;
637}
638
639void FindInterceptOfTwoLines(float *x, float *y, struct Line L1, struct Line L2)
640{
641 *x = ((L2.b - L1.b) / (L1.m - L2.m));
642 *y = L1.m * (*x) + L1.b;
643}
644
645
646float EvaluateLineForX(float y, struct Line L)
647{
648 return ((y - L.b) / L.m);
649}
650
652{
653 float d1x = p1_end->x - p1_start->x;
654 float d1y = p1_end->y - p1_start->y;
655 float d2x = p2_end->x - p2_start->x;
656 float d2y = p2_end->y - p2_start->y;
657 return d1x * d2y - d1y * d2x;
658}
659
void dc_send_command(uint8_t cmd)
Send Command To Camera.
Core autopilot interface common to all firmwares.
float dc_distance_interval
AutoShoot photos on distance to last shot in meters.
Definition dc.c:85
Standard Digital Camera Control Interface.
@ DC_SHOOT
Definition dc.h:102
#define FLOAT_VECT2_ZERO(_v)
#define VECT2_COPY(_a, _b)
#define VECT3_COPY(_a, _b)
static struct LtpDef_f * stateGetNedOrigin_f(void)
Get the coordinate NED frame origin (float)
Definition state.h:566
struct LlaCoor_f stateGetLlaOrigin_f(void)
Get the LLA position of the frame origin (float)
Definition state.c:143
static struct EnuCoor_f * stateGetPositionEnu_f(void)
Get position in local ENU coordinates (float).
Definition state.h:848
static float p[2][2]
uint16_t foo
Definition main_demo5.c:58
bool mission_register(mission_custom_cb cb, char *type)
Register a new navigation or action callback function.
mission planner library
MissionRunFlag
@ MissionInit
first exec
@ MissionRun
normal run
struct EnuCoor_f * waypoint_get_enu_f(uint8_t wp_id)
Get ENU coordinates (float)
Definition waypoints.c:387
void nav_init_stage(void)
needs to be implemented by fixedwing and rotorcraft seperately
Definition nav.c:92
#define NavCircleCount()
Definition nav.h:155
#define NavVerticalAltitudeMode(_alt, _pre_climb)
Set the vertical mode to altitude control with the specified altitude setpoint and climb pre-command.
Definition nav.h:191
#define CloseRadAngles(_c1, _c2)
#define SURVEY_HYBRID_MAX_SWEEP_BACK
uint8_t size
size of the polygon
#define SURVEY_HYBRID_APPROACHING_TIME
struct EnuCoor_f to_wp
tmp point in rotated frame
struct EnuCoor_f from_wp
tmp point in rotated frame
float orientation
requested orientation in radians
#define LINE_STOP_FUNCTION
static float CrossProductZ(struct EnuCoor_f *p1_start, struct EnuCoor_f *p1_end, struct EnuCoor_f *p2_start, struct EnuCoor_f *p2_end)
#define SURVEY_HYBRID_ENTRY_DISTANCE
#define SURVEY_HYBRID_MAX_SWEEP
float sweep
oriented sweep distance
static void nav_survey_hybrid_setup(float orientation, float sweep, float radius, float height)
finish preparation of survey based on private structure
static float EvaluateLineForX(float y, struct Line L)
static void RotateAndTranslateToWorld(struct EnuCoor_f *p, float Zrot, struct EnuCoor_f *trans)
Rotates point round z by -Zrot then translates so (0,0) becomes (transX,transY)
struct EnuCoor_f entry
entry point
struct Line edges[SURVEY_HYBRID_MAX_POLYGON_SIZE]
polygon edges
void nav_survey_hybrid_init(void)
Init function.
static void TranslateAndRotateFromWorld(struct EnuCoor_f *p, float Zrot, struct EnuCoor_f *trans)
static struct SurveyHybridPrivate survey_private
struct EnuCoor_f circle
circle center
#define MaxFloat
#define SURVEY_HYBRID_ENTRY_CIRCLE
float radius
turn radius
static void FindInterceptOfTwoLines(float *x, float *y, struct Line L1, struct Line L2)
#define SURVEY_HYBRID_MAX_POLYGON_SIZE
#define LINE_START_FUNCTION
bool circle_turns
turns with circles (or lines between points otherwise)
bool valid
setup is valid
SurveyStatus
@ Entry
@ Sweep
float edge_min_y[SURVEY_HYBRID_MAX_POLYGON_SIZE]
tmp point in rotated frame
bool nav_survey_hybrid_run(void)
Run polygon hybrid survey.
void nav_survey_hybrid_setup_orientation(uint8_t start_wp, float orientation, uint8_t size, float sweep, float radius, float height)
Setup polygon survey.
float sweep_distance
requested sweep distance
#define SURVEY_HYBRID_HALF_SWEEP_ENABLED
struct EnuCoor_f segment_to
end of current segment
void nav_survey_hybrid_setup_towards(uint8_t start_wp, uint8_t second_wp, uint8_t size, float sweep, float radius, float height)
Setup "dynamic" polygon survey with sweep orientation towards a waypoint.
float edge_max_y[SURVEY_HYBRID_MAX_POLYGON_SIZE]
tmp point in rotated frame
enum SurveyStatus status
current state
struct EnuCoor_f corners[SURVEY_HYBRID_MAX_POLYGON_SIZE]
corners location
struct SurveyHybrid survey_hybrid
struct EnuCoor_f segment_from
start of current segment
struct EnuCoor_f smallest_corner
tmp point in rotated frame
uint16_t sweep_back_nb_max
uint16_t sweep_back_nb
uint16_t sweep_nb_max
Paparazzi floating point algebra.
void enu_of_lla_point_f(struct EnuCoor_f *enu, struct LtpDef_f *def, struct LlaCoor_f *lla)
float alt
in meters (normally above WGS84 reference ellipsoid)
float y
in meters
float x
in meters
float lat
in radians
float z
in meters
vector in East North Up coordinates Units: meters
vector in Latitude, Longitude and Altitude
struct RotorcraftNavigation nav
Definition navigation.c:51
Rotorcraft navigation functions.
navigation_approaching nav_approaching
Definition navigation.h:153
navigation_circle nav_circle
Definition navigation.h:154
navigation_goto nav_goto
Definition navigation.h:151
navigation_route nav_route
Definition navigation.h:152
static const float dir[]
API to get/set the generic vehicle states.
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.