mirror of https://github.com/ArduPilot/ardupilot
1008 lines
22 KiB
Plaintext
1008 lines
22 KiB
Plaintext
// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: t -*-
|
|
|
|
// Functions called from the setup menu
|
|
static int8_t setup_radio (uint8_t argc, const Menu::arg *argv);
|
|
static int8_t setup_motors (uint8_t argc, const Menu::arg *argv);
|
|
static int8_t setup_accel (uint8_t argc, const Menu::arg *argv);
|
|
static int8_t setup_factory (uint8_t argc, const Menu::arg *argv);
|
|
static int8_t setup_erase (uint8_t argc, const Menu::arg *argv);
|
|
static int8_t setup_flightmodes (uint8_t argc, const Menu::arg *argv);
|
|
static int8_t setup_pid (uint8_t argc, const Menu::arg *argv);
|
|
static int8_t setup_frame (uint8_t argc, const Menu::arg *argv);
|
|
static int8_t setup_current (uint8_t argc, const Menu::arg *argv);
|
|
static int8_t setup_compass (uint8_t argc, const Menu::arg *argv);
|
|
static int8_t setup_mag_offset (uint8_t argc, const Menu::arg *argv);
|
|
static int8_t setup_declination (uint8_t argc, const Menu::arg *argv);
|
|
static int8_t setup_show (uint8_t argc, const Menu::arg *argv);
|
|
|
|
// Command/function table for the setup menu
|
|
const struct Menu::command setup_menu_commands[] PROGMEM = {
|
|
// command function called
|
|
// ======= ===============
|
|
{"erase", setup_erase},
|
|
{"reset", setup_factory},
|
|
{"pid", setup_pid},
|
|
{"radio", setup_radio},
|
|
{"motors", setup_motors},
|
|
{"level", setup_accel},
|
|
{"modes", setup_flightmodes},
|
|
{"frame", setup_frame},
|
|
{"current", setup_current},
|
|
{"compass", setup_compass},
|
|
{"mag_offset", setup_mag_offset},
|
|
{"declination", setup_declination},
|
|
{"show", setup_show}
|
|
};
|
|
|
|
// Create the setup menu object.
|
|
MENU(setup_menu, "setup", setup_menu_commands);
|
|
|
|
// Called from the top-level menu to run the setup menu.
|
|
int8_t
|
|
setup_mode(uint8_t argc, const Menu::arg *argv)
|
|
{
|
|
// Give the user some guidance
|
|
Serial.printf_P(PSTR("Setup Mode\n"
|
|
"\n"
|
|
"IMPORTANT: if you have not previously set this system up, use the\n"
|
|
"'reset' command to initialize the EEPROM to sensible default values\n"
|
|
"and then the 'radio' command to configure for your radio.\n"
|
|
"\n"));
|
|
|
|
// Run the setup menu. When the menu exits, we will return to the main menu.
|
|
setup_menu.run();
|
|
}
|
|
|
|
// Print the current configuration.
|
|
// Called by the setup menu 'show' command.
|
|
static int8_t
|
|
setup_show(uint8_t argc, const Menu::arg *argv)
|
|
{
|
|
uint8_t i;
|
|
// clear the area
|
|
print_blanks(8);
|
|
|
|
report_radio();
|
|
report_frame();
|
|
report_current();
|
|
report_gains();
|
|
report_xtrack();
|
|
report_throttle();
|
|
report_flight_modes();
|
|
report_imu();
|
|
report_compass();
|
|
return(0);
|
|
}
|
|
|
|
// Initialise the EEPROM to 'factory' settings (mostly defined in APM_Config.h or via defaults).
|
|
// Called by the setup menu 'factoryreset' command.
|
|
static int8_t
|
|
setup_factory(uint8_t argc, const Menu::arg *argv)
|
|
{
|
|
|
|
uint8_t i;
|
|
int c;
|
|
|
|
Serial.printf_P(PSTR("\nType 'Y' and hit Enter to perform factory reset, any other key to abort:\n"));
|
|
|
|
do {
|
|
c = Serial.read();
|
|
} while (-1 == c);
|
|
|
|
if (('y' != c) && ('Y' != c))
|
|
return(-1);
|
|
|
|
//zero_eeprom();
|
|
default_gains();
|
|
|
|
|
|
// setup default values
|
|
default_waypoint_info();
|
|
default_nav();
|
|
default_alt_hold();
|
|
default_frame();
|
|
default_flight_modes();
|
|
default_throttle();
|
|
default_logs();
|
|
default_current();
|
|
print_done();
|
|
|
|
// finish
|
|
// ------
|
|
return(0);
|
|
}
|
|
|
|
// Perform radio setup.
|
|
// Called by the setup menu 'radio' command.
|
|
static int8_t
|
|
setup_radio(uint8_t argc, const Menu::arg *argv)
|
|
{
|
|
Serial.println("\n\nRadio Setup:");
|
|
uint8_t i;
|
|
|
|
for(i = 0; i < 100;i++){
|
|
delay(20);
|
|
read_radio();
|
|
}
|
|
|
|
if(rc_1.radio_in < 500){
|
|
while(1){
|
|
Serial.printf_P(PSTR("\nNo radio; Check connectors."));
|
|
delay(1000);
|
|
// stop here
|
|
}
|
|
}
|
|
|
|
rc_1.radio_min = rc_1.radio_in;
|
|
rc_2.radio_min = rc_2.radio_in;
|
|
rc_3.radio_min = rc_3.radio_in;
|
|
rc_4.radio_min = rc_4.radio_in;
|
|
rc_5.radio_min = rc_5.radio_in;
|
|
rc_6.radio_min = rc_6.radio_in;
|
|
rc_7.radio_min = rc_7.radio_in;
|
|
rc_8.radio_min = rc_8.radio_in;
|
|
|
|
rc_1.radio_max = rc_1.radio_in;
|
|
rc_2.radio_max = rc_2.radio_in;
|
|
rc_3.radio_max = rc_3.radio_in;
|
|
rc_4.radio_max = rc_4.radio_in;
|
|
rc_5.radio_max = rc_5.radio_in;
|
|
rc_6.radio_max = rc_6.radio_in;
|
|
rc_7.radio_max = rc_7.radio_in;
|
|
rc_8.radio_max = rc_8.radio_in;
|
|
|
|
rc_1.radio_trim = rc_1.radio_in;
|
|
rc_2.radio_trim = rc_2.radio_in;
|
|
rc_4.radio_trim = rc_4.radio_in;
|
|
// 3 is not trimed
|
|
rc_5.radio_trim = 1500;
|
|
rc_6.radio_trim = 1500;
|
|
rc_7.radio_trim = 1500;
|
|
rc_8.radio_trim = 1500;
|
|
|
|
|
|
Serial.printf_P(PSTR("\nMove all controls to each extreme. Hit Enter to save: "));
|
|
while(1){
|
|
|
|
delay(20);
|
|
// Filters radio input - adjust filters in the radio.pde file
|
|
// ----------------------------------------------------------
|
|
read_radio();
|
|
|
|
rc_1.update_min_max();
|
|
rc_2.update_min_max();
|
|
rc_3.update_min_max();
|
|
rc_4.update_min_max();
|
|
rc_5.update_min_max();
|
|
rc_6.update_min_max();
|
|
rc_7.update_min_max();
|
|
rc_8.update_min_max();
|
|
|
|
if(Serial.available() > 0){
|
|
//rc_3.radio_max += 250;
|
|
Serial.flush();
|
|
|
|
save_EEPROM_radio();
|
|
//delay(100);
|
|
// double checking
|
|
//read_EEPROM_radio();
|
|
//print_radio_values();
|
|
print_done();
|
|
break;
|
|
}
|
|
}
|
|
report_radio();
|
|
return(0);
|
|
}
|
|
|
|
static int8_t
|
|
setup_motors(uint8_t argc, const Menu::arg *argv)
|
|
{
|
|
report_frame();
|
|
|
|
init_rc_in();
|
|
|
|
// read the radio to set trims
|
|
// ---------------------------
|
|
trim_radio();
|
|
|
|
print_hit_enter();
|
|
delay(1000);
|
|
|
|
|
|
int out_min = rc_3.radio_min + 70;
|
|
|
|
|
|
|
|
while(1){
|
|
delay(20);
|
|
read_radio();
|
|
motor_out[CH_1] = rc_3.radio_min;
|
|
motor_out[CH_2] = rc_3.radio_min;
|
|
motor_out[CH_3] = rc_3.radio_min;
|
|
motor_out[CH_4] = rc_3.radio_min;
|
|
|
|
|
|
|
|
if(frame_type == PLUS_FRAME){
|
|
if(rc_1.control_in > 0){
|
|
motor_out[CH_1] = out_min;
|
|
Serial.println("0");
|
|
|
|
}else if(rc_1.control_in < 0){
|
|
motor_out[CH_2] = out_min;
|
|
Serial.println("1");
|
|
}
|
|
|
|
if(rc_2.control_in > 0){
|
|
motor_out[CH_4] = out_min;
|
|
Serial.println("3");
|
|
|
|
}else if(rc_2.control_in < 0){
|
|
motor_out[CH_3] = out_min;
|
|
Serial.println("2");
|
|
}
|
|
|
|
}else if(frame_type == X_FRAME){
|
|
|
|
// lower right
|
|
if((rc_1.control_in > 0) && (rc_2.control_in > 0)){
|
|
motor_out[CH_4] = out_min;
|
|
Serial.println("3");
|
|
// lower left
|
|
}else if((rc_1.control_in < 0) && (rc_2.control_in > 0)){
|
|
motor_out[CH_2] = out_min;
|
|
Serial.println("1");
|
|
|
|
// upper left
|
|
}else if((rc_1.control_in < 0) && (rc_2.control_in < 0)){
|
|
motor_out[CH_3] = out_min;
|
|
Serial.println("2");
|
|
|
|
// upper right
|
|
}else if((rc_1.control_in > 0) && (rc_2.control_in < 0)){
|
|
motor_out[CH_1] = out_min;
|
|
Serial.println("0");
|
|
}
|
|
|
|
}else if(frame_type == TRI_FRAME){
|
|
|
|
if(rc_1.control_in > 0){
|
|
motor_out[CH_1] = out_min;
|
|
|
|
}else if(rc_1.control_in < 0){
|
|
motor_out[CH_2] = out_min;
|
|
}
|
|
|
|
if(rc_2.control_in > 0){
|
|
motor_out[CH_4] = out_min;
|
|
}
|
|
|
|
if(rc_4.control_in > 0){
|
|
rc_4.servo_out = 2000;
|
|
|
|
}else if(rc_4.control_in < 0){
|
|
rc_4.servo_out = -2000;
|
|
}
|
|
|
|
rc_4.calc_pwm();
|
|
motor_out[CH_3] = rc_4.radio_out;
|
|
}
|
|
|
|
if(rc_3.control_in > 0){
|
|
APM_RC.OutputCh(CH_1, rc_3.radio_in);
|
|
APM_RC.OutputCh(CH_2, rc_3.radio_in);
|
|
APM_RC.OutputCh(CH_3, rc_3.radio_in);
|
|
if(frame_type != TRI_FRAME)
|
|
APM_RC.OutputCh(CH_4, rc_3.radio_in);
|
|
}else{
|
|
APM_RC.OutputCh(CH_1, motor_out[CH_1]);
|
|
APM_RC.OutputCh(CH_2, motor_out[CH_2]);
|
|
APM_RC.OutputCh(CH_3, motor_out[CH_3]);
|
|
APM_RC.OutputCh(CH_4, motor_out[CH_4]);
|
|
}
|
|
|
|
if(Serial.available() > 0){
|
|
return (0);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int8_t
|
|
setup_accel(uint8_t argc, const Menu::arg *argv)
|
|
{
|
|
Serial.printf_P(PSTR("\nHold ArduCopter completely still and level.\n"));
|
|
|
|
imu.init_accel();
|
|
imu.print_accel_offsets();
|
|
|
|
report_imu();
|
|
return(0);
|
|
}
|
|
|
|
static int8_t
|
|
setup_pid(uint8_t argc, const Menu::arg *argv)
|
|
{
|
|
if (!strcmp_P(argv[1].str, PSTR("default"))) {
|
|
default_gains();
|
|
|
|
}else if (!strcmp_P(argv[1].str, PSTR("s_kp"))) {
|
|
pid_stabilize_roll.kP(argv[2].f);
|
|
pid_stabilize_pitch.kP(argv[2].f);
|
|
save_EEPROM_PID();
|
|
|
|
}else if (!strcmp_P(argv[1].str, PSTR("s_kd"))) {
|
|
stabilize_dampener = argv[2].f;
|
|
save_EEPROM_PID();
|
|
|
|
}else if (!strcmp_P(argv[1].str, PSTR("y_kp"))) {
|
|
pid_yaw.kP(argv[2].f);
|
|
save_EEPROM_PID();
|
|
|
|
}else if (!strcmp_P(argv[1].str, PSTR("s_kd"))) {
|
|
pid_yaw.kD(argv[2].f);
|
|
save_EEPROM_PID();
|
|
|
|
}else if (!strcmp_P(argv[1].str, PSTR("t_kp"))) {
|
|
pid_baro_throttle.kP(argv[2].f);
|
|
save_EEPROM_PID();
|
|
|
|
}else if (!strcmp_P(argv[1].str, PSTR("t_kd"))) {
|
|
pid_baro_throttle.kD(argv[2].f);
|
|
save_EEPROM_PID();
|
|
}else{
|
|
default_gains();
|
|
}
|
|
|
|
|
|
report_gains();
|
|
}
|
|
|
|
static int8_t
|
|
setup_flightmodes(uint8_t argc, const Menu::arg *argv)
|
|
{
|
|
byte switchPosition, oldSwitchPosition, mode;
|
|
|
|
Serial.printf_P(PSTR("\nMove RC toggle switch to each position to edit, move aileron stick to select modes."));
|
|
print_hit_enter();
|
|
trim_radio();
|
|
|
|
while(1){
|
|
delay(20);
|
|
read_radio();
|
|
switchPosition = readSwitch();
|
|
|
|
|
|
// look for control switch change
|
|
if (oldSwitchPosition != switchPosition){
|
|
|
|
mode = flight_modes[switchPosition];
|
|
mode = constrain(mode, 0, NUM_MODES-1);
|
|
|
|
// update the user
|
|
print_switch(switchPosition, mode);
|
|
|
|
// Remember switch position
|
|
oldSwitchPosition = switchPosition;
|
|
}
|
|
|
|
// look for stick input
|
|
if (radio_input_switch() == true){
|
|
mode++;
|
|
if(mode >= NUM_MODES)
|
|
mode = 0;
|
|
|
|
// save new mode
|
|
flight_modes[switchPosition] = mode;
|
|
|
|
// print new mode
|
|
print_switch(switchPosition, mode);
|
|
}
|
|
|
|
// escape hatch
|
|
if(Serial.available() > 0){
|
|
save_EEPROM_flight_modes();
|
|
print_done();
|
|
report_flight_modes();
|
|
return (0);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int8_t
|
|
setup_declination(uint8_t argc, const Menu::arg *argv)
|
|
{
|
|
mag_declination = argv[1].f;
|
|
save_EEPROM_mag_declination();
|
|
report_compass();
|
|
}
|
|
|
|
static int8_t
|
|
setup_erase(uint8_t argc, const Menu::arg *argv)
|
|
{
|
|
zero_eeprom();
|
|
return 0;
|
|
}
|
|
|
|
static int8_t
|
|
setup_compass(uint8_t argc, const Menu::arg *argv)
|
|
{
|
|
if (!strcmp_P(argv[1].str, PSTR("on"))) {
|
|
compass_enabled = true;
|
|
init_compass();
|
|
|
|
} else if (!strcmp_P(argv[1].str, PSTR("off"))) {
|
|
compass_enabled = false;
|
|
|
|
} else {
|
|
Serial.printf_P(PSTR("\nOptions:[on,off]\n"));
|
|
report_compass();
|
|
return 0;
|
|
}
|
|
|
|
save_EEPROM_mag();
|
|
report_compass();
|
|
return 0;
|
|
}
|
|
|
|
static int8_t
|
|
setup_frame(uint8_t argc, const Menu::arg *argv)
|
|
{
|
|
if (!strcmp_P(argv[1].str, PSTR("+"))) {
|
|
frame_type = PLUS_FRAME;
|
|
|
|
} else if (!strcmp_P(argv[1].str, PSTR("x"))) {
|
|
frame_type = X_FRAME;
|
|
|
|
} else if (!strcmp_P(argv[1].str, PSTR("tri"))) {
|
|
frame_type = TRI_FRAME;
|
|
|
|
} else if (!strcmp_P(argv[1].str, PSTR("hexa"))) {
|
|
frame_type = HEXA_FRAME;
|
|
|
|
} else {
|
|
Serial.printf_P(PSTR("\nOptions:[+, x, tri, hexa]\n"));
|
|
report_frame();
|
|
return 0;
|
|
}
|
|
|
|
save_EEPROM_frame();
|
|
report_frame();
|
|
return 0;
|
|
}
|
|
|
|
static int8_t
|
|
setup_current(uint8_t argc, const Menu::arg *argv)
|
|
{
|
|
if (!strcmp_P(argv[1].str, PSTR("on"))) {
|
|
current_enabled = true;
|
|
save_EEPROM_mag();
|
|
|
|
} else if (!strcmp_P(argv[1].str, PSTR("off"))) {
|
|
current_enabled = false;
|
|
save_EEPROM_mag();
|
|
|
|
} else if(argv[1].i > 10){
|
|
milliamp_hours = argv[1].i;
|
|
|
|
} else {
|
|
Serial.printf_P(PSTR("\nOptions:[on, off, mAh]\n"));
|
|
report_current();
|
|
return 0;
|
|
}
|
|
|
|
save_EEPROM_current();
|
|
report_current();
|
|
return 0;
|
|
}
|
|
|
|
static int8_t
|
|
setup_mag_offset(uint8_t argc, const Menu::arg *argv)
|
|
{
|
|
Serial.printf_P(PSTR("\nRotate/Pitch/Roll your ArduCopter until the offset variables stop changing.\n"));
|
|
print_hit_enter();
|
|
Serial.printf_P(PSTR("Starting in 3 secs.\n"));
|
|
delay(3000);
|
|
|
|
|
|
compass.init(); // Initialization
|
|
compass.set_orientation(MAGORIENTATION); // set compass's orientation on aircraft
|
|
compass.set_offsets(0, 0, 0); // set offsets to account for surrounding interference
|
|
compass.set_declination(ToRad(DECLINATION)); // set local difference between magnetic north and true north
|
|
//int counter = 0;
|
|
float _min[3], _max[3], _offset[3];
|
|
|
|
while(1){
|
|
static float min[3], _max[3], offset[3];
|
|
if (millis() - fast_loopTimer > 100) {
|
|
delta_ms_fast_loop = millis() - fast_loopTimer;
|
|
fast_loopTimer = millis();
|
|
G_Dt = (float)delta_ms_fast_loop / 1000.f;
|
|
|
|
|
|
compass.read();
|
|
compass.calculate(0, 0); // roll = 0, pitch = 0 for this example
|
|
|
|
// capture min
|
|
if(compass.mag_x < _min[0]) _min[0] = compass.mag_x;
|
|
if(compass.mag_y < _min[1]) _min[1] = compass.mag_y;
|
|
if(compass.mag_z < _min[2]) _min[2] = compass.mag_z;
|
|
|
|
// capture max
|
|
if(compass.mag_x > _max[0]) _max[0] = compass.mag_x;
|
|
if(compass.mag_y > _max[1]) _max[1] = compass.mag_y;
|
|
if(compass.mag_z > _max[2]) _max[2] = compass.mag_z;
|
|
|
|
// calculate offsets
|
|
offset[0] = -(_max[0] + _min[0]) / 2;
|
|
offset[1] = -(_max[1] + _min[1]) / 2;
|
|
offset[2] = -(_max[2] + _min[2]) / 2;
|
|
|
|
// display all to user
|
|
Serial.printf_P(PSTR("Heading: "));
|
|
Serial.print(ToDeg(compass.heading));
|
|
Serial.print(" \t(");
|
|
Serial.print(compass.mag_x);
|
|
Serial.print(",");
|
|
Serial.print(compass.mag_y);
|
|
Serial.print(",");
|
|
Serial.print(compass.mag_z);
|
|
Serial.print(")\t offsets(");
|
|
Serial.print(offset[0]);
|
|
Serial.print(",");
|
|
Serial.print(offset[1]);
|
|
Serial.print(",");
|
|
Serial.print(offset[2]);
|
|
Serial.println(")");
|
|
|
|
if(Serial.available() > 0){
|
|
|
|
mag_offset_x = offset[0];
|
|
mag_offset_y = offset[1];
|
|
mag_offset_z = offset[2];
|
|
|
|
save_EEPROM_mag_offset();
|
|
|
|
// set offsets to account for surrounding interference
|
|
compass.set_offsets(mag_offset_x, mag_offset_y, mag_offset_z);
|
|
|
|
report_compass();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************/
|
|
// CLI utilities
|
|
/***************************************************************************/
|
|
|
|
void default_waypoint_info()
|
|
{
|
|
wp_radius = 4; //TODO: Replace this quick fix with a real way to define wp_radius
|
|
loiter_radius = 30; //TODO: Replace this quick fix with a real way to define loiter_radius
|
|
save_EEPROM_waypoint_info();
|
|
}
|
|
|
|
|
|
void
|
|
default_nav()
|
|
{
|
|
// nav control
|
|
x_track_gain = XTRACK_GAIN * 100;
|
|
x_track_angle = XTRACK_ENTRY_ANGLE * 100;
|
|
pitch_max = PITCH_MAX * 100;
|
|
save_EEPROM_nav();
|
|
}
|
|
|
|
void
|
|
default_alt_hold()
|
|
{
|
|
alt_to_hold = -1;
|
|
save_EEPROM_alt_RTL();
|
|
}
|
|
|
|
void
|
|
default_frame()
|
|
{
|
|
frame_type = PLUS_FRAME;
|
|
save_EEPROM_frame();
|
|
}
|
|
|
|
void
|
|
default_current()
|
|
{
|
|
milliamp_hours = 2000;
|
|
current_enabled = false;
|
|
save_EEPROM_current();
|
|
}
|
|
|
|
void
|
|
default_flight_modes()
|
|
{
|
|
flight_modes[0] = FLIGHT_MODE_1;
|
|
flight_modes[1] = FLIGHT_MODE_2;
|
|
flight_modes[2] = FLIGHT_MODE_3;
|
|
flight_modes[3] = FLIGHT_MODE_4;
|
|
flight_modes[4] = FLIGHT_MODE_5;
|
|
flight_modes[5] = FLIGHT_MODE_6;
|
|
save_EEPROM_flight_modes();
|
|
}
|
|
|
|
void
|
|
default_throttle()
|
|
{
|
|
throttle_min = THROTTLE_MIN;
|
|
throttle_max = THROTTLE_MAX;
|
|
throttle_cruise = THROTTLE_CRUISE;
|
|
throttle_failsafe_enabled = THROTTLE_FAILSAFE;
|
|
throttle_failsafe_action = THROTTLE_FAILSAFE_ACTION;
|
|
throttle_failsafe_value = THROTTLE_FS_VALUE;
|
|
save_EEPROM_throttle();
|
|
}
|
|
|
|
void default_logs()
|
|
{
|
|
|
|
// convenience macro for testing LOG_* and setting LOGBIT_*
|
|
#define LOGBIT(_s) (LOG_ ## _s ? LOGBIT_ ## _s : 0)
|
|
log_bitmask =
|
|
LOGBIT(ATTITUDE_FAST) |
|
|
LOGBIT(ATTITUDE_MED) |
|
|
LOGBIT(GPS) |
|
|
LOGBIT(PM) |
|
|
LOGBIT(CTUN) |
|
|
LOGBIT(NTUN) |
|
|
LOGBIT(MODE) |
|
|
LOGBIT(RAW) |
|
|
LOGBIT(CMD) |
|
|
LOGBIT(CURRENT);
|
|
#undef LOGBIT
|
|
|
|
save_EEPROM_logs();
|
|
}
|
|
|
|
|
|
void
|
|
default_gains()
|
|
{
|
|
// acro, angular rate
|
|
pid_acro_rate_roll.kP(ACRO_RATE_ROLL_P);
|
|
pid_acro_rate_roll.kI(ACRO_RATE_ROLL_I);
|
|
pid_acro_rate_roll.kD(0);
|
|
pid_acro_rate_roll.imax(ACRO_RATE_ROLL_IMAX * 100);
|
|
|
|
pid_acro_rate_pitch.kP(ACRO_RATE_PITCH_P);
|
|
pid_acro_rate_pitch.kI(ACRO_RATE_PITCH_I);
|
|
pid_acro_rate_pitch.kD(0);
|
|
pid_acro_rate_pitch.imax(ACRO_RATE_PITCH_IMAX * 100);
|
|
|
|
pid_acro_rate_yaw.kP(ACRO_RATE_YAW_P);
|
|
pid_acro_rate_yaw.kI(ACRO_RATE_YAW_I);
|
|
pid_acro_rate_yaw.kD(0);
|
|
pid_acro_rate_yaw.imax(ACRO_RATE_YAW_IMAX * 100);
|
|
|
|
|
|
// stabilize, angle error
|
|
pid_stabilize_roll.kP(STABILIZE_ROLL_P);
|
|
pid_stabilize_roll.kI(STABILIZE_ROLL_I);
|
|
pid_stabilize_roll.kD(0);
|
|
pid_stabilize_roll.imax(STABILIZE_ROLL_IMAX * 100);
|
|
|
|
pid_stabilize_pitch.kP(STABILIZE_PITCH_P);
|
|
pid_stabilize_pitch.kI(STABILIZE_PITCH_I);
|
|
pid_stabilize_pitch.kD(0);
|
|
pid_stabilize_pitch.imax(STABILIZE_PITCH_IMAX * 100);
|
|
|
|
// YAW hold
|
|
pid_yaw.kP(YAW_P);
|
|
pid_yaw.kI(YAW_I);
|
|
pid_yaw.kD(0);
|
|
pid_yaw.imax(YAW_IMAX * 100);
|
|
|
|
|
|
// custom dampeners
|
|
// roll pitch
|
|
stabilize_dampener = STABILIZE_DAMPENER;
|
|
|
|
//yaw
|
|
hold_yaw_dampener = HOLD_YAW_DAMPENER;
|
|
|
|
|
|
// navigation
|
|
pid_nav_lat.kP(NAV_P);
|
|
pid_nav_lat.kI(NAV_I);
|
|
pid_nav_lat.kD(NAV_D);
|
|
pid_nav_lat.imax(NAV_IMAX);
|
|
|
|
pid_nav_lon.kP(NAV_P);
|
|
pid_nav_lon.kI(NAV_I);
|
|
pid_nav_lon.kD(NAV_D);
|
|
pid_nav_lon.imax(NAV_IMAX);
|
|
|
|
pid_baro_throttle.kP(THROTTLE_BARO_P);
|
|
pid_baro_throttle.kI(THROTTLE_BARO_I);
|
|
pid_baro_throttle.kD(THROTTLE_BARO_D);
|
|
pid_baro_throttle.imax(THROTTLE_BARO_IMAX);
|
|
|
|
pid_sonar_throttle.kP(THROTTLE_SONAR_P);
|
|
pid_sonar_throttle.kI(THROTTLE_SONAR_I);
|
|
pid_sonar_throttle.kD(THROTTLE_SONAR_D);
|
|
pid_sonar_throttle.imax(THROTTLE_SONAR_IMAX);
|
|
|
|
save_EEPROM_PID();
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
// CLI utilities
|
|
/***************************************************************************/
|
|
|
|
void report_current()
|
|
{
|
|
print_blanks(2);
|
|
read_EEPROM_current();
|
|
Serial.printf_P(PSTR("Current Sensor\n"));
|
|
print_divider();
|
|
print_enabled(current_enabled);
|
|
|
|
Serial.printf_P(PSTR("mah: %d"),milliamp_hours);
|
|
print_blanks(1);
|
|
}
|
|
|
|
|
|
void report_frame()
|
|
{
|
|
print_blanks(2);
|
|
read_EEPROM_frame();
|
|
Serial.printf_P(PSTR("Frame\n"));
|
|
print_divider();
|
|
|
|
|
|
if(frame_type == X_FRAME)
|
|
Serial.printf_P(PSTR("X "));
|
|
else if(frame_type == PLUS_FRAME)
|
|
Serial.printf_P(PSTR("Plus "));
|
|
else if(frame_type == TRI_FRAME)
|
|
Serial.printf_P(PSTR("TRI "));
|
|
else if(frame_type == HEXA_FRAME)
|
|
Serial.printf_P(PSTR("HEXA "));
|
|
|
|
Serial.printf_P(PSTR("frame (%d)"), (int)frame_type);
|
|
print_blanks(1);
|
|
}
|
|
|
|
void report_radio()
|
|
{
|
|
print_blanks(2);
|
|
Serial.printf_P(PSTR("Radio\n"));
|
|
print_divider();
|
|
// radio
|
|
read_EEPROM_radio();
|
|
print_radio_values();
|
|
print_blanks(1);
|
|
}
|
|
|
|
void report_gains()
|
|
{
|
|
print_blanks(2);
|
|
Serial.printf_P(PSTR("Gains\n"));
|
|
print_divider();
|
|
|
|
read_EEPROM_PID();
|
|
// Acro
|
|
Serial.printf_P(PSTR("Acro:\nroll:\n"));
|
|
print_PID(&pid_acro_rate_roll);
|
|
Serial.printf_P(PSTR("pitch:\n"));
|
|
print_PID(&pid_acro_rate_pitch);
|
|
Serial.printf_P(PSTR("yaw:\n"));
|
|
print_PID(&pid_acro_rate_yaw);
|
|
|
|
// Stabilize
|
|
Serial.printf_P(PSTR("\nStabilize:\nroll:\n"));
|
|
print_PID(&pid_stabilize_roll);
|
|
Serial.printf_P(PSTR("pitch:\n"));
|
|
print_PID(&pid_stabilize_pitch);
|
|
Serial.printf_P(PSTR("yaw:\n"));
|
|
print_PID(&pid_yaw);
|
|
|
|
Serial.printf_P(PSTR("Stabilize dampener: %4.3f\n"), stabilize_dampener);
|
|
Serial.printf_P(PSTR("Yaw Dampener: %4.3f\n\n"), hold_yaw_dampener);
|
|
|
|
// Nav
|
|
Serial.printf_P(PSTR("Nav:\nlat:\n"));
|
|
print_PID(&pid_nav_lat);
|
|
Serial.printf_P(PSTR("long:\n"));
|
|
print_PID(&pid_nav_lon);
|
|
Serial.printf_P(PSTR("baro throttle:\n"));
|
|
print_PID(&pid_baro_throttle);
|
|
Serial.printf_P(PSTR("sonar throttle:\n"));
|
|
print_PID(&pid_sonar_throttle);
|
|
print_blanks(1);
|
|
}
|
|
|
|
void report_xtrack()
|
|
{
|
|
print_blanks(2);
|
|
Serial.printf_P(PSTR("Crosstrack\n"));
|
|
print_divider();
|
|
// radio
|
|
read_EEPROM_nav();
|
|
Serial.printf_P(PSTR("XTRACK: %4.2f\n"
|
|
"XTRACK angle: %d\n"
|
|
"PITCH_MAX: %ld"),
|
|
x_track_gain,
|
|
x_track_angle,
|
|
pitch_max);
|
|
print_blanks(1);
|
|
}
|
|
|
|
void report_throttle()
|
|
{
|
|
print_blanks(2);
|
|
Serial.printf_P(PSTR("Throttle\n"));
|
|
print_divider();
|
|
|
|
read_EEPROM_throttle();
|
|
Serial.printf_P(PSTR("min: %d\n"
|
|
"max: %d\n"
|
|
"cruise: %d\n"
|
|
"failsafe_enabled: %d\n"
|
|
"failsafe_value: %d"),
|
|
throttle_min,
|
|
throttle_max,
|
|
throttle_cruise,
|
|
throttle_failsafe_enabled,
|
|
throttle_failsafe_value);
|
|
print_blanks(1);
|
|
}
|
|
|
|
void report_imu()
|
|
{
|
|
print_blanks(2);
|
|
Serial.printf_P(PSTR("IMU\n"));
|
|
print_divider();
|
|
|
|
imu.print_gyro_offsets();
|
|
imu.print_accel_offsets();
|
|
print_blanks(1);
|
|
}
|
|
|
|
void report_compass()
|
|
{
|
|
print_blanks(2);
|
|
Serial.printf_P(PSTR("Compass\n"));
|
|
print_divider();
|
|
|
|
read_EEPROM_compass();
|
|
read_EEPROM_compass_declination();
|
|
read_EEPROM_compass_offset();
|
|
|
|
print_enabled(compass_enabled);
|
|
|
|
// mag declination
|
|
Serial.printf_P(PSTR("Mag Delination: %4.4f\n"),
|
|
mag_declination);
|
|
|
|
// mag offsets
|
|
Serial.printf_P(PSTR("Mag offsets: %4.4f, %4.4f, %4.4f"),
|
|
mag_offset_x,
|
|
mag_offset_y,
|
|
mag_offset_z);
|
|
print_blanks(1);
|
|
}
|
|
|
|
|
|
void report_flight_modes()
|
|
{
|
|
print_blanks(2);
|
|
Serial.printf_P(PSTR("Flight modes\n"));
|
|
print_divider();
|
|
read_EEPROM_flight_modes();
|
|
|
|
for(int i = 0; i < 6; i++ ){
|
|
print_switch(i, flight_modes[i]);
|
|
}
|
|
print_blanks(1);
|
|
}
|
|
|
|
/***************************************************************************/
|
|
// CLI utilities
|
|
/***************************************************************************/
|
|
|
|
void
|
|
print_PID(PID * pid)
|
|
{
|
|
Serial.printf_P(PSTR("P: %4.3f, I:%4.3f, D:%4.3f, IMAX:%ld\n"), pid->kP(), pid->kI(), pid->kD(), (long)pid->imax());
|
|
}
|
|
|
|
void
|
|
print_radio_values()
|
|
{
|
|
Serial.printf_P(PSTR("CH1: %d | %d\n"), rc_1.radio_min, rc_1.radio_max);
|
|
Serial.printf_P(PSTR("CH2: %d | %d\n"), rc_2.radio_min, rc_2.radio_max);
|
|
Serial.printf_P(PSTR("CH3: %d | %d\n"), rc_3.radio_min, rc_3.radio_max);
|
|
Serial.printf_P(PSTR("CH4: %d | %d\n"), rc_4.radio_min, rc_4.radio_max);
|
|
Serial.printf_P(PSTR("CH5: %d | %d\n"), rc_5.radio_min, rc_5.radio_max);
|
|
Serial.printf_P(PSTR("CH6: %d | %d\n"), rc_6.radio_min, rc_6.radio_max);
|
|
Serial.printf_P(PSTR("CH7: %d | %d\n"), rc_7.radio_min, rc_7.radio_max);
|
|
Serial.printf_P(PSTR("CH8: %d | %d\n"), rc_8.radio_min, rc_8.radio_max);
|
|
}
|
|
|
|
void
|
|
print_switch(byte p, byte m)
|
|
{
|
|
Serial.printf_P(PSTR("Pos %d: "),p);
|
|
Serial.println(flight_mode_strings[m]);
|
|
}
|
|
|
|
void
|
|
print_done()
|
|
{
|
|
Serial.printf_P(PSTR("\nSaved Settings\n\n"));
|
|
}
|
|
|
|
void
|
|
print_blanks(int num)
|
|
{
|
|
while(num > 0){
|
|
num--;
|
|
Serial.println("");
|
|
}
|
|
}
|
|
|
|
void
|
|
print_divider(void)
|
|
{
|
|
for (int i = 0; i < 40; i++) {
|
|
Serial.print("-");
|
|
}
|
|
Serial.println("");
|
|
}
|
|
|
|
|
|
// for reading in vales for mode switch
|
|
boolean
|
|
radio_input_switch(void)
|
|
{
|
|
static byte bouncer;
|
|
|
|
if (abs(rc_1.radio_in - rc_1.radio_trim) > 200)
|
|
bouncer = 10;
|
|
|
|
if (bouncer > 0)
|
|
bouncer--;
|
|
|
|
if (bouncer == 1){
|
|
return true;
|
|
}else{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
void zero_eeprom(void)
|
|
{
|
|
byte b;
|
|
Serial.printf_P(PSTR("\nErasing EEPROM\n"));
|
|
for (int i = 0; i < EEPROM_MAX_ADDR; i++) {
|
|
eeprom_write_byte((uint8_t *) i, b);
|
|
}
|
|
Serial.printf_P(PSTR("done\n"));
|
|
}
|
|
|
|
|
|
void print_enabled(boolean b)
|
|
{
|
|
if(b)
|
|
Serial.printf_P(PSTR("en"));
|
|
else
|
|
Serial.printf_P(PSTR("dis"));
|
|
Serial.printf_P(PSTR("abled\n"));
|
|
}
|
|
|
|
|
|
|