Skip to content

Commit

Permalink
Adds Smart Return To Home capability by recording the flight path in …
Browse files Browse the repository at this point in the history
…a memory optimimized format. This means the UAV can return to home by using only known-good flight paths.

The flight graph is stored as a series of delta elements at 1m resolution and a list of nodes. Both lists share the same buffer. Each delta element takes up 2 bytes or sometimes 6 bytes if the delta is large. The path can consist of multiple disconnected segments, in which case the gaps are stored as delta elements with a jump-bit set.

Once in a while or when required the graph is consolidated, which means:
 - Points that lie roughly in a line are replaced by a single line
 - Points that lie close to previously recorded lines are pruned
 - For lines that pass close to each other a node element is created

Furthermore:
 - The graph is recorded at a higher precision closer to home
 - If the graph becomes full, the overall precision is reduced and the whole graph is re-consolidated
 - If the graph becomes full once more, all data is removed except for the shortest path home at that moment. One of these actions is repeated at each subsequent fill-up.

Path finding information is generated/refreshed on demand and stored in the nodes. During return-to-home, the best direction to home is continuously evaluated by using the information stored in the nodes.

The graph recording and path finding is implemented in navigator/tracker.cpp.
The graph based return-to-home is implemented in navigator/smart_rtl.cpp.
  • Loading branch information
samuelsadok authored and dagar committed Aug 30, 2017
1 parent 8a1d8f2 commit 4f19e17
Show file tree
Hide file tree
Showing 38 changed files with 8,033 additions and 55 deletions.
110 changes: 110 additions & 0 deletions Tools/Matlab/lineToLineTest.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
% This script can be used to create test cases for the line-to-line
% distance function in the flight path tracker. We can define deltas and
% start points for two lines and get the shortest delta between the two
% lines, as well as a visualisation of it. Note that all points are
% discretized, so they will usually not lie exactly on the lines.

function linesToLineTest()
% plot different scenarios
delta = plotLines([4; 2; -1], [2; 1; -2], [6; 2; 2], [2; 3; 0])
delta = plotLines([4; 2; -1], [2; 1; -2], [6; 2; 2], [5; 4; 4])
delta = plotLines([4; 2; -1], [2; 2; -2], [4; 1; 1], [5; 4; 4])
delta = plotLines([4; 2; -1], [2; 1; -2], [3; 1; 1], [-1; 2; -2])
delta = plotLines([4; 2; -1], [2; 1; -2], [-2; 3; 2], [-1; 2; -2])
delta = plotLines([4; 2; -1], [2; 1; -2], [-2; 3; 2], [-3; 5; 0])
delta = plotLines([4; 2; -1], [6; 3; -3], [-2; 3; 2], [-3; 5; 0])

delta = plotLines([4; 2; -1], [2; 1; -2], [-2; 3; 2], [-1; 2; -2])
end

% This creates a plot showing the two lines and 5 connections between them:
% - the shortest possible connection
% - the start of line1 projected to line2
% - the end of line1 projected to line2
% - the start of line2 projected to line1
% - the end of line2 projected to line1
% The projected points are constrained such that they don't lie beyond
% the start or end of the other line.
function delta = plotLines(deltaA, endA, deltaB, endB)
COEF1 = 32768;

startA = endA - coefToFloat(COEF1-1) * deltaA;
startB = endB - coefToFloat(COEF1-1) * deltaB;

projectedStartACoef = coefFromFloat(-dot(startA-endB,deltaB) / dot(deltaB,deltaB));
projectedEndACoef = coefFromFloat(-dot(endA-endB,deltaB) / dot(deltaB,deltaB));
projectedStartBCoef = coefFromFloat(-dot(startB-endA,deltaA) / dot(deltaA,deltaA));
projectedEndBCoef = coefFromFloat(-dot(endB-endA,deltaA) / dot(deltaA,deltaA));

normal = [deltaA(2)*deltaB(3)-deltaA(3)*deltaB(2);deltaA(3)*deltaB(1)-deltaA(1)*deltaB(3);deltaA(1)*deltaB(2)-deltaA(2)*deltaB(1)];
projectedDelta = normal*dot(endB-endA,normal)/dot(normal,normal);

% Rounding is probably appropriate here, as the precision is not
% critical and it allows for a more efficient implementation.
% In a few cases the final result will differ, but visual inspection
% indicates that this is acceptable.
projectedDelta = round(projectedDelta);

remainder = endB-endA - projectedDelta;

A=[-deltaA deltaB];
lineToLineCoef = (A'*A) \ (A'*remainder);
lineToLineCoef(1) = coefFromFloatUnconstrained(lineToLineCoef(1));
lineToLineCoef(2) = coefFromFloatUnconstrained(lineToLineCoef(2));


close all;
hold on;
axis equal;
plot3([endA(1) startA(1)], [endA(2) startA(2)], [endA(3) startA(3)], 'o-r');
plot3([endB(1) startB(1)], [endB(2) startB(2)], [endB(3) startB(3)], 'x-b');
delta = plotLine(deltaA, endA, deltaB, endB, lineToLineCoef(1), lineToLineCoef(2))';
delta1 = plotLine(deltaA, endA, deltaB, endB, COEF1, projectedStartACoef)';
delta2 = plotLine(deltaA, endA, deltaB, endB, 0, projectedEndACoef)';
delta3 = plotLine(deltaA, endA, deltaB, endB, projectedStartBCoef, COEF1)';
delta4 = plotLine(deltaA, endA, deltaB, endB, projectedEndBCoef, 0)';
legend('line A', 'line B', 'line-to-line', 'start1 to line2', 'end1 to line2', 'start2 to line1', 'end2 to line1');
hold off;

%disp(lineToLineCoef);
if (lineToLineCoef(1) >= 0 && lineToLineCoef(1) < COEF1 && lineToLineCoef(2) >= 0 && lineToLineCoef(2) < COEF1)
return
end

delta = delta1;
if (norm(delta2) < norm(delta))
delta = delta2;
end
if (norm(delta3) < norm(delta))
delta = delta3;
end
if (norm(delta4) < norm(delta))
delta = delta4;
end

end

function coef = coefFromFloatUnconstrained(f)
coef = round(f * 32768);
end

function coef = coefFromFloat(f)
coef = coefFromFloatUnconstrained(f);
if coef < 0
coef = 0;
elseif coef > 32767
coef = 32767;
end
end

function f = coefToFloat(coef)
f = coef / 32768;
end

function delta = plotLine(deltaA, endA, deltaB, endB, coefA, coefB)
p1 = round(endA - deltaA * coefToFloat(coefA));
p2 = round(endB - deltaB * coefToFloat(coefB));
delta = p2 - p1;
%disp([sqrt(dot(delta, delta)) (p2 - p1)']); % for debugging
plot3([p1(1) p2(1)], [p1(2) p2(2)], [p1(3) p2(3)], '*--');
end
241 changes: 241 additions & 0 deletions Tools/draw_path.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
#!/bin/sh
#
# Script to draw 2D flight paths. The z-component is always 0.
# The purpose is to test the flight graph tracker by handing it a predesigned path.
#
# Usage: draw_path.sh [file]
# If the file already exists, new points are appended.
# arrow keys: move cursor
# spacebar: add current cursor position to path
# q: quit



# Shows a status message at the end of the screen
function show_status() {
tput cup $(expr $SCREEN_WIDTH-1) 0
echo $1
move_cursor
STATUS_CLEAR="no"
}

# Clears the status message
function clear_status() {
[ "$STATUS_CLEAR" = "no" ] || return 0
tput cup 0 0
tput el && tput el1
move_cursor
STATUS_CLEAR="yes"
}

# Terminates the script
function quit() {
tput rmcup
stty echo
exit 0
}

# Moves the terminal cursor to position ($CURSOR_X, $CURSOR_Y)
function move_cursor() {
#echo "\033[$CURSOR_Y;$CURSOR_X"'f'
#echo -e "\033[$CURSOR_Y;3f"
tput cup $CURSOR_Y $CURSOR_X
}

# Draws a line from the last point to the current cursor position
function go_here() {
draw_line $LAST_POINT_X $LAST_POINT_Y $CURSOR_X $CURSOR_Y
echo "o"
move_cursor
LAST_POINT_X=$CURSOR_X
LAST_POINT_Y=$CURSOR_Y
}

# Adds the current cursor position to the file $FILE
function store_point() {
echo "$CURSOR_X,$CURSOR_Y,0," >> $FILE
}

# Loads all points from the file $FILE
# Each line stores a point in the format "x,y,z".
# Empty lines and lines starting with "/" are ignored.
function load_file() {
while IFS='' read -r line || [[ -n "$line" ]]; do
CURSOR_X=$(echo "$line" | awk -F, "/^[^\/]/{print \$1}")
CURSOR_Y=$(echo "$line" | awk -F, "/^[^\/]/{print \$2}")
#echo "X=$CURSOR_X Y=$CURSOR_Y"
[ "$CURSOR_X" = "" ] || [ "$CURSOR_Y" = "" ] || go_here
done < "$FILE"
}

# Draws a line using the Bresenham algorithm
# usage: draw_line x1 y1 x2 y2
# The point (x1, y1) is not filled.
# The point (x2, y2) is filled and the cursor is placed there.
function draw_line() {
X1=$1
Y1=$2
X2=$3
Y2=$4
LINE_CHAR="\\"

# The algorithm requires that delta-y is smaller than delta-x
SWAP_XY=$(echo "define delta(a, b) {if (a>b) return a-b; return b-a;}; delta($X1,$X2) < delta($Y1,$Y2)" | bc)
[ "$SWAP_XY" = "1" ] && {
TEMP=$X1; X1=$Y1; Y1=$TEMP
TEMP=$X2; X2=$Y2; Y2=$TEMP
}

# Delta-x must be positive
REVERSE_DIR=$(echo "$X1 > $X2" | bc)
[ "$REVERSE_DIR" = "1" ] && {
TEMP=$X1; X1=$X2; X2=$TEMP
TEMP=$Y1; Y1=$Y2; Y2=$TEMP
}

# Now the slope is in [-45°, +45], in positive x-direction. The update update differs for positive and negative slopes.
POS_SLOPE=$(echo "$Y2 > $Y1" | bc)

DELTA_X=$(($X2-$X1))
DELTA_Y=$(($Y2-$Y1))

# init update criterion
if [ "$POS_SLOPE" = "1" ]; then
D=$(echo "$DELTA_Y * ($X1+1) - $DELTA_X * ($Y1+0.5) + $X2 * $Y1 - $X1 * $Y2" | bc)
else
D=$(echo "$DELTA_Y * ($X1+1) - $DELTA_X * ($Y1-0.5) + $X2 * $Y1 - $X1 * $Y2" | bc)
fi

XP=$X1
YP=$Y1

while [ $XP -lt $X2 ]; do
[ "$SWAP_XY" = "0" ] && LINE_CHAR="-" || LINE_CHAR="|"

# Move to next pixel, according to update criterion
XP=$(($XP+1))
if [ "$POS_SLOPE" = "1" ]; then
[ $(echo "$D > 0" | bc) = "1" ] && {
YP=$(($YP+1))
D=$(echo "$D - $DELTA_X" | bc)
LINE_CHAR="\\"
}
D=$(echo "$D + $DELTA_Y" | bc)
else
[ $(echo "$D < 0" | bc) = "1" ] && {
YP=$(($YP-1))
D=$(echo "$D + $DELTA_X" | bc)
LINE_CHAR="/"
}
D=$(echo "$D + $DELTA_Y" | bc)
fi

# Draw pixel
[ "$SWAP_XY" = "0" ] && { CURSOR_X=$XP; CURSOR_Y=$YP; } || { CURSOR_X=$YP; CURSOR_Y=$XP; }
move_cursor;

([ "$REVERSE_DIR" = "1" ] && [ "$XP" = "$X2" ]) || echo "$LINE_CHAR"
done

[ "$REVERSE_DIR" = "1" ] && { [ "$SWAP_XY" = "0" ] && { CURSOR_X=$X1; CURSOR_Y=$Y1; } || { CURSOR_X=$Y1; CURSOR_Y=$X1; } }
move_cursor;
}

# Moves the cursor up if possible
function up() {
[ $CURSOR_Y -gt 0 ] && let CURSOR_Y=$CURSOR_Y-1
move_cursor
}

# Moves the cursor down if possible
function down() {
let CURSOR_Y=$CURSOR_Y+1
[ $CURSOR_Y -lt $SCREEN_HEIGHT ] || let CURSOR_Y=$SCREEN_HEIGHT-1
move_cursor
}

# Moves the cursor left if possible
function left() {
[ $CURSOR_X -gt 0 ] && let CURSOR_X=$CURSOR_X-1
move_cursor
}

# Moves the cursor right if possible
function right() {
let CURSOR_X=$CURSOR_X+1
[ $CURSOR_X -lt $SCREEN_WIDTH ] || let CURSOR_X=$SCREEN_WIDTH-1
move_cursor
}




# Set up globals
SCREEN_WIDTH=$(tput cols)
SCREEN_HEIGHT=$(tput lines)
let CURSOR_X=$SCREEN_WIDTH/2
let CURSOR_Y=$SCREEN_HEIGHT/2
LAST_POINT_X=$CURSOR_X
LAST_POINT_Y=$CURSOR_Y
KEY_SEQUENCE=""
FILE=$1

touch $FILE 2>/dev/null || { echo "could not open file $FILE"; exit 1; }

# Switch to alternate screen
tput smcup
#x=$(tput lines)
#while [ $x -gt 0 ]; do echo ""; let x=$x-1; done;
tput clear
stty -echo
move_cursor

load_file


# draws two crosses
#draw_line 20 3 50 15
#draw_line 20 15 50 3
#draw_line 5 5 20 30
#draw_line 20 5 5 30

# draws the same two crosses (with swapped start end end points)
#draw_line 50 15 20 3
#draw_line 50 3 20 15
#draw_line 20 30 5 5
#draw_line 5 30 20 5


while true; do
IFS=""
read -r -n 1 CHAR

KEY_SEQUENCE=$KEY_SEQUENCE$CHAR
CARRY_SEQUENCE=""

clear_status

case $KEY_SEQUENCE in
$'\033'|$'\033[')
# incomplete escape sequence - read another char
CARRY_SEQUENCE=$KEY_SEQUENCE
#show_status "press q to exit"
;;

'q') quit ;;

$'\033[A') up ;;
$'\033[B') down ;;
$'\033[C') right ;;
$'\033[D') left ;;

$" ") go_here; store_point ;;

*)
show_status "unknown key"
;;
esac

KEY_SEQUENCE=$CARRY_SEQUENCE
done

1 change: 1 addition & 0 deletions cmake/configs/nuttx_auav-x21_default.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ set(config_module_list
drivers/test_ppm
#lib/rc/rc_tests
modules/commander/commander_tests
modules/navigator/navigator_tests
lib/controllib/controllib_test
modules/mavlink/mavlink_tests
modules/mc_pos_control/mc_pos_control_tests
Expand Down
1 change: 1 addition & 0 deletions cmake/configs/nuttx_mindpx-v2_default.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ set(config_module_list
drivers/sf0x/sf0x_tests
drivers/test_ppm
modules/commander/commander_tests
modules/navigator/navigator_tests
modules/mc_pos_control/mc_pos_control_tests
lib/controllib/controllib_test
modules/mavlink/mavlink_tests
Expand Down
1 change: 1 addition & 0 deletions cmake/configs/nuttx_px4fmu-v2_test.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ set(config_module_list
drivers/test_ppm
#lib/rc/rc_tests
modules/commander/commander_tests
modules/navigator/navigator_tests
modules/mc_pos_control/mc_pos_control_tests
lib/controllib/controllib_test
modules/mavlink/mavlink_tests
Expand Down
1 change: 1 addition & 0 deletions cmake/configs/nuttx_px4fmu-v3_default.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ set(config_module_list
drivers/test_ppm
#lib/rc/rc_tests
modules/commander/commander_tests
modules/navigator/navigator_tests
lib/controllib/controllib_test
modules/mavlink/mavlink_tests
modules/mc_pos_control/mc_pos_control_tests
Expand Down
1 change: 1 addition & 0 deletions cmake/configs/nuttx_px4fmu-v4_default.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ set(config_module_list
drivers/sf0x/sf0x_tests
drivers/test_ppm
modules/commander/commander_tests
modules/navigator/navigator_tests
modules/mc_pos_control/mc_pos_control_tests
lib/controllib/controllib_test
modules/mavlink/mavlink_tests
Expand Down
Loading

0 comments on commit 4f19e17

Please sign in to comment.