Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

High-Level flight: plan shortest rotation to reach the desired yaw #1101

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions src/modules/interface/math3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,35 @@ SOFTWARE.
static inline float fsqr(float x) { return x * x; }
static inline float radians(float degrees) { return (M_PI_F / 180.0f) * degrees; }
static inline float degrees(float radians) { return (180.0f / M_PI_F) * radians; }

// Normalize radians to be in range [-pi,pi]
// See https://stackoverflow.com/questions/4633177/c-how-to-wrap-a-float-to-the-interval-pi-pi
static inline float normalize_radians(float radians)
{
// Copy the sign of the value in radians to the value of pi.
float signed_pi = copysignf(M_PI_F, radians);
// Set the value of difference to the appropriate signed value between pi and -pi.
radians = fmodf(radians + signed_pi, 2 * M_PI_F) - signed_pi;
return radians;
}

// modulo operation that uses the floored definition (as in Python), rather than
// the truncated definition used for the % operator in C
// See https://en.wikipedia.org/wiki/Modulo_operation
static inline float fmodf_floored(float x, float n)
{
return x - floorf(x / n) * n;
}

// compute shortest signed angle between two given angles (in range [-pi, pi])
// See https://stackoverflow.com/questions/1878907/how-can-i-find-the-difference-between-two-angles
static inline float shortest_signed_angle_radians(float start, float goal)
{
float diff = goal - start;
float signed_diff = fmodf_floored(diff + M_PI_F, 2 * M_PI_F) - M_PI_F;
return signed_diff;
}

static inline float clamp(float value, float min, float max) {
if (value < min) return min;
if (value > max) return max;
Expand Down
16 changes: 13 additions & 3 deletions src/modules/src/planner.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,14 @@ static void plan_takeoff_or_landing(struct planner *p, struct vec curr_pos, floa
struct vec hover_pos = curr_pos;
hover_pos.z = hover_height;

// compute the shortest possible rotation towards 0
hover_yaw = normalize_radians(hover_yaw);
curr_yaw = normalize_radians(curr_yaw);
float goal_yaw = curr_yaw + shortest_signed_angle_radians(curr_yaw, hover_yaw);

piecewise_plan_7th_order_no_jerk(&p->planned_trajectory, duration,
curr_pos, curr_yaw, vzero(), 0, vzero(),
hover_pos, hover_yaw, vzero(), 0, vzero());
hover_pos, goal_yaw, vzero(), 0, vzero());
}

// ----------------- //
Expand Down Expand Up @@ -178,9 +183,14 @@ int plan_go_to_from(struct planner *p, const struct traj_eval *curr_eval, bool r
hover_yaw += curr_eval->yaw;
}

// compute the shortest possible rotation towards 0
float curr_yaw = normalize_radians(curr_eval->yaw);
hover_yaw = normalize_radians(hover_yaw);
float goal_yaw = curr_yaw + shortest_signed_angle_radians(curr_yaw, hover_yaw);

piecewise_plan_7th_order_no_jerk(&p->planned_trajectory, duration,
curr_eval->pos, curr_eval->yaw, curr_eval->vel, curr_eval->omega.z, curr_eval->acc,
hover_pos, hover_yaw, vzero(), 0, vzero());
curr_eval->pos, curr_yaw, curr_eval->vel, curr_eval->omega.z, curr_eval->acc,
hover_pos, goal_yaw, vzero(), 0, vzero());

p->reversed = false;
p->state = TRAJECTORY_STATE_FLYING;
Expand Down
24 changes: 24 additions & 0 deletions test_python/test_math3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,27 @@ def test_that_vec_is_converted_to_numpy_array():
# Assert
expected = np.array([1, 2, 3])
assert np.allclose(expected, actual)


def test_normalize_radians():
# Fixture
angles = [-100, -5, 0, np.pi + 0.1, -np.pi - 0.1, 100]

for angle in angles:
# Test
actual = cffirmware.normalize_radians(angle)
# Assert
expected = np.arctan2(np.sin(angle), np.cos(angle))
assert np.allclose(expected, actual)


def test_shortest_signed_angle_radians():
# Fixture
angle_pairs = [(-np.pi/2, np.pi), (np.pi/2, np.pi), (np.pi, -np.pi/3)]

for start, goal in angle_pairs:
# Test
actual = cffirmware.shortest_signed_angle_radians(start, goal)
# Assert
expected = np.arctan2(np.sin(goal - start), np.cos(goal - start))
assert np.allclose(expected, actual)