Skip to content

Commit

Permalink
waypoint following
Browse files Browse the repository at this point in the history
  • Loading branch information
bvanderveen committed Nov 11, 2012
1 parent b9f1752 commit 1e4d747
Show file tree
Hide file tree
Showing 10 changed files with 384 additions and 59 deletions.
92 changes: 70 additions & 22 deletions fcs/config.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "config.h"
#include <math.h>
#include <stdlib.h>

void init_config(core_config *config) {
// driver.core.waypoint0.lat = 47.258842;
Expand All @@ -12,40 +13,87 @@ void init_config(core_config *config) {

//driver.core.desiredHeading = 81.15;
//driver.core.desiredHeading = 270;
config->turn_coordinator.rudderController.p = .000000001;
config->turn_coordinator.rudderController.i = .0000000015;
config->turn_coordinator.rudderController.d = 110;
config->turn_coordinator.rudderController.p = 1;
config->turn_coordinator.rudderController.i = 0;
config->turn_coordinator.rudderController.d = .1;

config->heading_setting.aileronController.p = 2;
config->heading_setting.aileronController.i = .00000000001;
config->heading_setting.aileronController.d = 1;

config->heading_setting.aileronController2.p = .1;
config->heading_setting.aileronController2.i = .0;
config->heading_setting.aileronController2.d = .1;

config->pitch_setting.desiredPitch = 0;
config->pitch_setting.desiredPitch = 7;
config->pitch_setting.elevatorController.p = .05;
config->pitch_setting.elevatorController.i = 0;
config->pitch_setting.elevatorController.d = 0;

config->course_setting.current_waypoint_index = 1;
config->course_setting.waypoint_threshold = .00005;
config->course_setting.course_p = 2;
config->course_setting.course_i = .0;
config->course_setting.intercept_angle = 80;
config->course_setting.intercept_gain = 50;
config->course_setting.bank_angle = 65;
config->course_setting.bank_gain = 1;

config->course_setting.waypoint_count = 4;

geopoint *waypoints = (geopoint *)malloc(sizeof(geopoint) * config->course_setting.waypoint_count);

// square
waypoints[0].lat = 47.25;
waypoints[0].lon = 11.32;
waypoints[1].lat = 47.25;
waypoints[1].lon = 11.35;
waypoints[2].lat = 47.26;
waypoints[2].lon = 11.35;
waypoints[3].lat = 47.26;
waypoints[3].lon = 11.32;

// parallelogram
// waypoints[0].lat = 47.26;
// waypoints[0].lon = 11.32;
// waypoints[1].lat = 47.26 - .01;
// waypoints[1].lon = 11.38;
// waypoints[2].lat = 47.20;
// waypoints[2].lon = 11.38 - .01;
// waypoints[3].lat = 47.20 + .01;
// waypoints[3].lon = 11.32 - .01;

//waypoints[1] = { .lat = 47.262344, .lon = 11.363722 }; // east of LOWI
// waypoints[2] = { .lat = 47.254662, .lon = 11.361288 }; // east base leg
// waypoints[3] = { .lat = 47.252052, .lon = 11.330928 }; // west base leg
// *waypoints = {
// { .lat = 47.258297, .lon = 11.324047 }, // west of LOWI
// { .lat = 47.262344, .lon = 11.363722 }, // east of LOWI
// { .lat = 47.254662, .lon = 11.361288 }, // east base leg
// { .lat = 47.252052, .lon = 11.330928 } // west base leg
// };

config->course_setting.waypoints = waypoints;

config->course_setting.aileron_controller.p = 1;
config->course_setting.aileron_controller.i = 0;
config->course_setting.aileron_controller.d = .1;

// config->course_setting.course_controller.p = .1;
// config->course_setting.course_controller.i = 0;
// config->course_setting.course_controller.d = 0;

}

void run_config(core_config *config, core_context *context, float dt) {
if (context->effector_state.throttle < 1)
context->effector_state.throttle += .01;

// some stupid basic mission that is basically to fly figure-eights
static int setHeading = 0;
static float originalHeading;
static float acc = 0;
if (!setHeading++) {
originalHeading = context->sensor_state.heading;
config->heading_setting.desiredHeading = originalHeading;
}
acc += .0000000001 * dt;
config->heading_setting.desiredHeading = originalHeading + 140 * sin(acc);
// static int setHeading = 0;
// static float originalHeading;
// static float acc = 0;
// if (!setHeading++) {
// originalHeading = context->sensor_state.heading;
// config->heading_setting.desiredHeading = originalHeading;
// }
// acc += .0000000001 * dt;
// config->heading_setting.desiredHeading = originalHeading + 140 * sin(acc);

core_pitch_setting_update(context, (void *)&config->pitch_setting, dt);
core_heading_setting_update(context, (void *)&config->heading_setting, dt);
core_course_setting_update(context, (void *)&config->course_setting, dt);
//core_heading_setting_update(context, (void *)&config->heading_setting, dt);
core_turn_coordinator_update(context, (void *)&config->turn_coordinator, dt);
}
2 changes: 2 additions & 0 deletions fcs/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "energy.h"
#include "heading.h"
#include "turn_coordinator.h"
#include "course.h"

#ifndef __FCS_CONFIG
#define __FCS_CONFIG
Expand All @@ -10,6 +11,7 @@ struct core_config {
core_heading_setting heading_setting;
core_pitch_setting pitch_setting;
core_turn_coordinator turn_coordinator;
fcs_course_setting course_setting;
};
typedef struct core_config core_config;

Expand Down
162 changes: 150 additions & 12 deletions fcs/course.c
Original file line number Diff line number Diff line change
@@ -1,37 +1,175 @@
#include "course.h"
#include "math.h"
#include <math.h>
#include <stdio.h>

#define EARTH_RADIUS (6373.0)

// TODO meters or what?
float distance_squared(geopoint p0, geopoint p1) {
return 0;
float course_sigma(fcs_course_setting *setting, float cross_track_error) {
//return atan(setting->intercept_gain * cross_track_error /) / (M_PI/2) * TO_RADIANS(setting->intercept_angle);
float exponent = expf(-1 * setting->intercept_gain * cross_track_error / 2);
return TO_RADIANS(setting->intercept_angle) * ((exponent - 1) / (exponent + 1));
}

void follow_segment(core_context *context, geopoint *p0, geopoint *p1, float dt) {
float course_sigma_derivative(fcs_course_setting *setting, float cross_track_error) {
float exponent = expf(-1 * setting->intercept_gain * cross_track_error / 2);
printf("exponent %f\n", exponent);
float exponent_plus_1 = exponent + 1;
return -1 * setting->intercept_gain * TO_RADIANS(setting->intercept_angle) * exponent / (exponent_plus_1 * exponent_plus_1);
}

float heading_between(geopoint *p0, geopoint *p1) {
// tan(angle) = ∂lat / ∂lon
geopoint r;
difference(p0, p1, &r);
float result = atan(TO_RADIANS(r.lon) / TO_RADIANS(r.lat)) + M_PI;
// if (result > M_PI_2)
// result -= M_2_PI;
// if (result < 0)
// result += M_2_PI;
return result;
}

float course_change(fcs_course_setting *setting, float course_error, float cross_track_error, float dt) {
float sigma = course_sigma(setting, cross_track_error);
float error = sigma - course_error;
printf("course_error %f\n", TO_DEGREES(course_error));
printf("sigma %f\n", TO_DEGREES(sigma));
printf("error %f\n", TO_DEGREES(error));
setting->course_integral += error * dt;
float sigma_derivative = course_sigma_derivative(setting, cross_track_error);
printf("sigma_derivative %f\n", sigma_derivative);
float sin_course_error = sin(course_error);
printf("sin(course_error) %f\n", sin_course_error);

float p = setting->course_p * error;
float i = setting->course_i * setting->course_integral;
float d = sigma_derivative * sin_course_error;

printf("p = %f\n", p);
printf("i = %f\n", i);
printf("d = %f\n", d);

float result = p + i + d;

return result;
}

float course_control_roll(fcs_course_setting *setting, float current_roll, float commanded_roll, float dt) {
float roll_error = commanded_roll - current_roll;
pid_update(&setting->aileron_controller, roll_error, dt);
return setting->aileron_controller.output;
}

float course_bank_angle(fcs_course_setting *setting, float course_change) {
return atan(setting->bank_gain * course_change) / (M_PI / 2)
* TO_RADIANS(setting->bank_angle);
}

float initial_bearing_between(geopoint *p0, geopoint *p1) {
float dlon = TO_RADIANS(p1->lon - p0->lon);
float lat0 = TO_RADIANS(p0->lat);
float lat1 = TO_RADIANS(p1->lat);
return atan2(sin(dlon) * cos(lat1), cos(lat0) * sin(lat1) - sin(lat0) * cos(lat1) * cos(dlon));
}

float haversine_distance_between(geopoint *p0, geopoint *p1) {
float dlat = TO_RADIANS(p0->lat - p1->lat);
float dlon = TO_RADIANS(p1->lon - p0->lon);
float lat0 = TO_RADIANS(p0->lat);
float lat1 = TO_RADIANS(p1->lat);

float sin_dlat_2 = sin(dlat / 2);
float sin_dlon_2 = sin(dlon / 2);

float a = sin_dlat_2 * sin_dlat_2 + sin_dlon_2 * sin_dlon_2 * cos(lat0) * cos(lat1);
return 2 * atan2(sqrt(a), sqrt(1 - a)) * EARTH_RADIUS;
}

float cross_track_distance(geopoint *p0, geopoint *p1, geopoint *r) {
// printf("p0 "); geopoint_print(p0);
// printf("p1 "); geopoint_print(p1);
// printf("r "); geopoint_print(r);
float position_bearing = initial_bearing_between(p0, r);
float waypoint_bearing = initial_bearing_between(p0, p1);
float hav_dist = haversine_distance_between(p0, r);
// printf("position bearing %f, %f\n", position_bearing, TO_DEGREES(position_bearing));
// printf("waypoint bearing %f, %f\n", waypoint_bearing, TO_DEGREES(waypoint_bearing));
// printf("haversine dist %f\n", hav_dist);
return asin(sin(hav_dist / EARTH_RADIUS) * sin(position_bearing - waypoint_bearing)) * EARTH_RADIUS;
}

float heading_error(float h0, float h1) {
float a = h1 - h0;
printf("a %f\n", TO_DEGREES(a));
float result = a + ((a > M_PI) ? -(M_PI * 2) : ((a < -M_PI) ? (M_PI * 2) : 0.0));
printf("result %f\n", TO_DEGREES(result));
return result;
}

void follow_segment_2(core_context *context, fcs_course_setting *setting, geopoint *p0, geopoint *p1, geopoint *r, float dt) {
float current_course = TO_RADIANS(context->sensor_state.heading);

float desired_course = initial_bearing_between(p0, p1);

float course_error = heading_error(current_course, desired_course);

float cross_track_error = cross_track_distance(p0, p1, r);

printf("cross_track_error (km) = %f\n", cross_track_error);
printf("current_course (deg) = %f\n", TO_DEGREES(current_course));
printf("desired_course (deg) = %f\n", TO_DEGREES(desired_course));

float course_signal = course_change(setting, -course_error, cross_track_error, dt);
///* + d_desired_course / dt */;

printf("course_signal (deg) = %f\n", TO_DEGREES(course_signal));

float commanded_bank_angle = course_bank_angle(setting, course_signal);
printf("commanded_bank_angle (deg) = %f\n", TO_DEGREES(commanded_bank_angle));

float current_roll = TO_RADIANS(context->sensor_state.roll);
printf("current bank angle (deg) = %f\n", TO_DEGREES(current_roll));
float aileron_signal = course_control_roll(setting, current_roll, commanded_bank_angle, dt);

context->effector_state.ail = -aileron_signal;
}

void core_course_setting_update(core_context *context, void *course_setting, float dt) {
fcs_course_setting *setting = (fcs_course_setting *)course_setting;

// if course is finished, head back toward first waypoint
if (setting->current_waypoint_index == setting->waypoint_count) {
setting->current_waypoint_index = 0;
}

geopoint current_waypoint = setting->waypoints[setting->current_waypoint_index];
geopoint current_position = { .lat = context->sensor_state.lat, .lon = context->sensor_state.lon };

// if distance to next waypoint less than threshold, set next course
if (distance_squared(current_waypoint, current_position) < setting->waypoint_threshold) {
float waypoint_distance_squared = distance_squared(&current_waypoint, &current_position);

if (waypoint_distance_squared < setting->waypoint_threshold) {
setting->current_waypoint_index++;

// if course is finished, head back toward first waypoint
if (setting->current_waypoint_index == setting->waypoint_count) {
setting->current_waypoint_index = 0;
}

current_waypoint = setting->waypoints[setting->current_waypoint_index];
printf("moving to next waypoint\n");
}

int previous_waypoint_index = setting->current_waypoint_index == 0 ?
(setting->waypoint_count - 1) :
(setting->current_waypoint_index - 1);
(setting->current_waypoint_index - 1);

geopoint previous_waypoint = setting->waypoints[previous_waypoint_index];

printf("waypoint_distance_squared (%f) %f \n", setting->waypoint_threshold, waypoint_distance_squared);
printf("current_waypoint_index %d\n", setting->current_waypoint_index);
printf("previous_waypoint_index %d\n", previous_waypoint_index);

// printf("previous_waypoint "); geopoint_print(&previous_waypoint);
// printf("current_waypoint "); geopoint_print(&current_waypoint);
// printf("current_position "); geopoint_print(&current_position);

// fly course
follow_segment(context, &previous_waypoint, &current_waypoint, dt);
follow_segment_2(context, course_setting, &previous_waypoint, &current_waypoint, &current_position, dt);
}
20 changes: 12 additions & 8 deletions fcs/course.h
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
#include "heading.h"
#include "pid_controller.h"
#include "math.h"

#ifndef __FCS_COURSE
#define __FCS_COURSE

struct geopoint {
float
lat,
lon;
};
typedef struct geopoint geopoint;

struct fcs_course_setting {
int current_waypoint_index;
pid_controller aileron_controller;
float course_integral;

float waypoint_threshold;
float course_p;
float course_i;
float intercept_angle;
float intercept_gain;
float bank_angle;
float bank_gain;
int waypoint_count;
geopoint waypoints[];
geopoint *waypoints;
};
typedef struct fcs_course_setting fcs_course_setting;

Expand Down
30 changes: 15 additions & 15 deletions fcs/heading.c
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
#include "heading.h"

float heading_error(float heading, float desiredHeading) {
float a = desiredHeading - heading;
return a + ((a > 180.0) ? -360.0 : ((a < -180.0) ? 360.0 : 0.0));
}
// float heading_error(float heading, float desiredHeading) {
// float a = desiredHeading - heading;
// return a + ((a > 180.0) ? -360.0 : ((a < -180.0) ? 360.0 : 0.0));
// }

void core_heading_setting_update(core_context *context, void *heading_setting, float dt) {
core_heading_setting *setting = (core_heading_setting *)heading_setting;
// void core_heading_setting_update(core_context *context, void *heading_setting, float dt) {
// core_heading_setting *setting = (core_heading_setting *)heading_setting;

// heading control is a PID cascade controller.
// outer loop takes heading error and commands bank angle
float bearingError = heading_error(context->sensor_state.heading, setting->desiredHeading);
pid_update(&setting->aileronController, bearingError, dt);
// // heading control is a PID cascade controller.
// // outer loop takes heading error and commands bank angle
// float bearingError = heading_error(context->sensor_state.heading, setting->desiredHeading);
// pid_update(&setting->aileronController, bearingError, dt);

// inner loop takes bank angle and commands elevator deflection
float roll_error = -setting->aileronController.output - context->sensor_state.roll;
pid_update(&setting->aileronController2, roll_error, dt);
context->effector_state.ail = -setting->aileronController2.output;
}
// // inner loop takes bank angle and commands aileron deflection
// float roll_error = -setting->aileronController.output - context->sensor_state.roll;
// pid_update(&setting->aileronController2, roll_error, dt);
// context->effector_state.ail = -setting->aileronController2.output;
// }

0 comments on commit 1e4d747

Please sign in to comment.