2011-03-19 07:20:11 -03:00
// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-
2010-12-19 12:40:33 -04:00
2011-07-17 07:34:05 -03:00
#if CLI_ENABLED == ENABLED
2010-12-19 12:40:33 -04:00
// Functions called from the setup menu
2012-12-14 00:12:39 -04:00
static int8_t setup_accel_scale (uint8_t argc, const Menu::arg *argv);
static int8_t setup_compass (uint8_t argc, const Menu::arg *argv);
2013-03-02 04:54:18 -04:00
static int8_t setup_compassmot (uint8_t argc, const Menu::arg *argv);
2013-05-31 02:56:08 -03:00
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_optflow (uint8_t argc, const Menu::arg *argv);
static int8_t setup_radio (uint8_t argc, const Menu::arg *argv);
static int8_t setup_range (uint8_t argc, const Menu::arg *argv);
static int8_t setup_factory (uint8_t argc, const Menu::arg *argv);
2013-03-07 04:30:45 -04:00
static int8_t setup_set (uint8_t argc, const Menu::arg *argv);
2013-05-31 02:56:08 -03:00
static int8_t setup_show (uint8_t argc, const Menu::arg *argv);
static int8_t setup_sonar (uint8_t argc, const Menu::arg *argv);
2013-03-07 04:30:45 -04:00
2011-02-19 17:04:05 -04:00
// Command/function table for the setup menu
2010-12-19 12:40:33 -04:00
const struct Menu::command setup_menu_commands[] PROGMEM = {
2012-08-21 23:19:50 -03:00
// command function called
// ======= ===============
{"accel", setup_accel_scale},
{"compass", setup_compass},
2013-03-02 04:54:18 -04:00
{"compassmot", setup_compassmot},
2013-05-31 02:56:08 -03:00
{"erase", setup_erase},
{"modes", setup_flightmodes},
{"optflow", setup_optflow},
{"radio", setup_radio},
{"range", setup_range},
{"reset", setup_factory},
{"set", setup_set},
2013-03-07 04:30:45 -04:00
{"show", setup_show},
2013-05-31 02:56:08 -03:00
{"sonar", setup_sonar},
2010-12-19 12:40:33 -04:00
};
// Create the setup menu object.
MENU(setup_menu, "setup", setup_menu_commands);
// Called from the top-level menu to run the setup menu.
2011-07-17 07:32:00 -03:00
static int8_t
2010-12-19 12:40:33 -04:00
setup_mode(uint8_t argc, const Menu::arg *argv)
{
2012-08-21 23:19:50 -03:00
// Give the user some guidance
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("Setup Mode\n\n\n"));
2012-08-21 23:19:50 -03:00
if(g.rc_1.radio_min >= 1300) {
delay(1000);
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("\n!Warning, radio not configured!"));
2012-08-21 23:19:50 -03:00
delay(1000);
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("\n Type 'radio' now.\n\n"));
2012-08-21 23:19:50 -03:00
}
// Run the setup menu. When the menu exits, we will return to the main menu.
setup_menu.run();
2011-07-17 07:30:21 -03:00
return 0;
2010-12-19 12:40:33 -04:00
}
2012-07-19 02:56:13 -03:00
static int8_t
setup_accel_scale(uint8_t argc, const Menu::arg *argv)
{
2013-01-30 07:48:42 -04:00
float trim_roll, trim_pitch;
2012-11-21 02:08:03 -04:00
cliSerial->println_P(PSTR("Initialising gyros"));
2013-01-13 01:04:04 -04:00
ahrs.init();
2012-11-29 07:56:54 -04:00
ins.init(AP_InertialSensor::COLD_START,
2013-09-19 05:33:21 -03:00
ins_sample_rate);
2012-12-19 18:28:10 -04:00
AP_InertialSensor_UserInteractStream interact(hal.console);
2013-09-19 05:33:21 -03:00
if(ins.calibrate_accel(&interact, trim_roll, trim_pitch)) {
2013-01-30 07:48:42 -04:00
// reset ahrs's trim to suggested values from calibration routine
ahrs.set_trim(Vector3f(trim_roll, trim_pitch, 0));
}
2012-11-05 00:32:38 -04:00
report_ins();
return(0);
2012-07-19 02:56:13 -03:00
}
2010-12-19 12:40:33 -04:00
static int8_t
2011-01-09 22:21:09 -04:00
setup_compass(uint8_t argc, const Menu::arg *argv)
2010-12-19 12:40:33 -04:00
{
2012-08-21 23:19:50 -03:00
if (!strcmp_P(argv[1].str, PSTR("on"))) {
g.compass_enabled.set_and_save(true);
init_compass();
} else if (!strcmp_P(argv[1].str, PSTR("off"))) {
2013-05-31 02:56:08 -03:00
Vector3f mag_offsets(0,0,0);
compass.set_offsets(mag_offsets);
compass.save_offsets();
2012-08-21 23:19:50 -03:00
g.compass_enabled.set_and_save(false);
}else{
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("\nOp:[on,off]\n"));
2012-08-21 23:19:50 -03:00
report_compass();
return 0;
}
g.compass_enabled.save();
report_compass();
return 0;
2010-12-19 12:40:33 -04:00
}
2013-03-02 04:54:18 -04:00
// setup_compassmot - sets compass's motor interference parameters
static int8_t
setup_compassmot(uint8_t argc, const Menu::arg *argv)
{
2013-05-19 10:03:48 -03:00
int8_t comp_type; // throttle or current based compensation
Vector3f compass_base; // compass vector when throttle is zero
Vector3f motor_impact; // impact of motors on compass vector
Vector3f motor_impact_scaled; // impact of motors on compass vector scaled with throttle
Vector3f motor_compensation; // final compensation to be stored to eeprom
float throttle_pct; // throttle as a percentage 0.0 ~ 1.0
float throttle_pct_max = 0.0f; // maximum throttle reached (as a percentage 0~1.0)
float current_amps_max = 0.0f; // maximum current reached
float interference_pct; // interference as a percentage of total mag field (for reporting purposes only)
2013-03-02 04:54:18 -04:00
uint32_t last_run_time;
2013-03-03 10:02:36 -04:00
uint8_t print_counter = 49;
2013-05-19 10:03:48 -03:00
bool updated = false; // have we updated the compensation vector at least once
2013-03-03 10:02:36 -04:00
// default compensation type to use current if possible
2013-10-01 10:34:44 -03:00
if (battery.monitoring() == AP_BATT_MONITOR_VOLTAGE_AND_CURRENT) {
2013-03-03 10:02:36 -04:00
comp_type = AP_COMPASS_MOT_COMP_CURRENT;
}else{
comp_type = AP_COMPASS_MOT_COMP_THROTTLE;
}
2013-05-16 04:32:00 -03:00
// check if radio is calibration
pre_arm_rc_checks();
if(!ap.pre_arm_rc_check) {
2013-09-23 11:30:19 -03:00
cliSerial->print_P(PSTR("radio not calibrated\n"));
2013-05-16 04:32:00 -03:00
return 0;
}
2013-03-02 04:54:18 -04:00
// check compass is enabled
if( !g.compass_enabled ) {
2013-09-23 11:30:19 -03:00
cliSerial->print_P(PSTR("compass disabled\n"));
2013-03-03 10:02:36 -04:00
return 0;
}
2013-03-02 04:54:18 -04:00
// initialise compass
init_compass();
2013-03-03 10:02:36 -04:00
// disable motor compensation
compass.motor_compensation_type(AP_COMPASS_MOT_COMP_DISABLED);
2013-03-02 04:54:18 -04:00
compass.set_motor_compensation(Vector3f(0,0,0));
// print warning that motors will spin
// ask user to raise throttle
// inform how to stop test
2013-09-23 11:30:19 -03:00
cliSerial->print_P(PSTR("This records the impact on the compass of running the motors. Motors will spin!\nHold throttle low, then raise to mid for 5 sec, then quickly back to low.\nPress any key to exit.\n\nmeasuring compass vs "));
2013-03-02 04:54:18 -04:00
2013-03-03 10:02:36 -04:00
// inform what type of compensation we are attempting
if( comp_type == AP_COMPASS_MOT_COMP_CURRENT ) {
cliSerial->print_P(PSTR("CURRENT\n"));
}else{
cliSerial->print_P(PSTR("THROTTLE\n"));
}
2013-03-02 04:54:18 -04:00
2013-03-03 10:02:36 -04:00
// clear out user input
2013-03-02 04:54:18 -04:00
while( cliSerial->available() ) {
cliSerial->read();
}
2013-03-03 10:02:36 -04:00
// disable throttle and battery failsafe
2013-03-02 04:54:18 -04:00
g.failsafe_throttle = FS_THR_DISABLED;
2013-11-16 01:46:57 -04:00
g.failsafe_battery_enabled = FS_BATT_DISABLED;
2013-03-02 04:54:18 -04:00
// read radio
read_radio();
// exit immediately if throttle is not zero
if( g.rc_3.control_in != 0 ) {
2013-09-23 11:30:19 -03:00
cliSerial->print_P(PSTR("throttle not zero\n"));
2013-03-02 04:54:18 -04:00
return 0;
}
// get some initial compass readings
last_run_time = millis();
while( millis() - last_run_time < 2000 ) {
compass.accumulate();
}
compass.read();
// exit immediately if the compass is not healthy
2013-12-09 02:47:22 -04:00
if( !compass.healthy() ) {
2013-09-23 11:30:19 -03:00
cliSerial->print_P(PSTR("check compass\n"));
2013-03-02 04:54:18 -04:00
return 0;
}
// store initial x,y,z compass values
2013-12-08 23:10:14 -04:00
compass_base = compass.get_field();
2013-03-02 04:54:18 -04:00
// initialise motor compensation
motor_compensation = Vector3f(0,0,0);
// clear out any user input
while( cliSerial->available() ) {
cliSerial->read();
}
// enable motors and pass through throttle
2013-05-09 01:30:08 -03:00
init_rc_out();
2013-05-16 04:32:00 -03:00
output_min();
2013-03-02 04:54:18 -04:00
motors.armed(true);
// initialise run time
last_run_time = millis();
// main run while there is no user input and the compass is healthy
2013-12-09 02:47:22 -04:00
while(!cliSerial->available() && compass.healthy()) {
2013-03-02 04:54:18 -04:00
// 50hz loop
if( millis() - last_run_time > 20 ) {
last_run_time = millis();
// read radio input
read_radio();
// pass through throttle to motors
motors.throttle_pass_through();
// read some compass values
compass.read();
2013-03-03 10:02:36 -04:00
// read current
read_battery();
2013-03-02 04:54:18 -04:00
// calculate scaling for throttle
throttle_pct = (float)g.rc_3.control_in / 1000.0f;
2013-05-01 21:26:49 -03:00
throttle_pct = constrain_float(throttle_pct,0.0f,1.0f);
2013-03-02 04:54:18 -04:00
// if throttle is zero, update base x,y,z values
if( throttle_pct == 0.0f ) {
2013-12-08 23:10:14 -04:00
compass_base = compass_base * 0.99f + compass.get_field() * 0.01f;
2013-03-02 04:54:18 -04:00
// causing printing to happen as soon as throttle is lifted
print_counter = 49;
}else{
2013-03-03 10:02:36 -04:00
2013-03-02 04:54:18 -04:00
// calculate diff from compass base and scale with throttle
2013-12-08 23:10:14 -04:00
motor_impact = compass.get_field() - compass_base;
2013-03-02 04:54:18 -04:00
2013-03-03 10:02:36 -04:00
// throttle based compensation
if( comp_type == AP_COMPASS_MOT_COMP_THROTTLE ) {
// scale by throttle
motor_impact_scaled = motor_impact / throttle_pct;
2013-03-02 04:54:18 -04:00
2013-03-03 10:02:36 -04:00
// adjust the motor compensation to negate the impact
motor_compensation = motor_compensation * 0.99f - motor_impact_scaled * 0.01f;
updated = true;
}else{
// current based compensation if more than 3amps being drawn
2013-10-01 10:34:44 -03:00
motor_impact_scaled = motor_impact / battery.current_amps();
2013-03-03 10:02:36 -04:00
// adjust the motor compensation to negate the impact if drawing over 3amps
2013-10-01 10:34:44 -03:00
if( battery.current_amps() >= 3.0f ) {
2013-03-03 10:02:36 -04:00
motor_compensation = motor_compensation * 0.99f - motor_impact_scaled * 0.01f;
updated = true;
}
}
2013-03-02 04:54:18 -04:00
2013-05-19 10:03:48 -03:00
// record maximum throttle and current
throttle_pct_max = max(throttle_pct_max, throttle_pct);
2013-10-01 10:34:44 -03:00
current_amps_max = max(current_amps_max, battery.current_amps());
2013-05-19 10:03:48 -03:00
2013-03-02 04:54:18 -04:00
// display output at 1hz if throttle is above zero
print_counter++;
if(print_counter >= 50) {
print_counter = 0;
2013-09-23 11:30:19 -03:00
display_compassmot_info(motor_impact, motor_compensation);
2013-03-02 04:54:18 -04:00
}
}
}else{
// grab some compass values
compass.accumulate();
}
}
// stop motors
motors.output_min();
motors.armed(false);
// clear out any user input
while( cliSerial->available() ) {
cliSerial->read();
}
2013-03-03 10:02:36 -04:00
// print one more time so the last thing printed matches what appears in the report_compass
2013-09-23 11:30:19 -03:00
display_compassmot_info(motor_impact, motor_compensation);
2013-03-03 10:02:36 -04:00
2013-03-02 04:54:18 -04:00
// set and save motor compensation
2013-03-03 10:02:36 -04:00
if( updated ) {
compass.motor_compensation_type(comp_type);
compass.set_motor_compensation(motor_compensation);
compass.save_motor_compensation();
2013-05-19 10:03:48 -03:00
// calculate and display interference compensation at full throttle as % of total mag field
if (comp_type == AP_COMPASS_MOT_COMP_THROTTLE) {
// interference is impact@fullthrottle / mag field * 100
2013-05-31 00:23:19 -03:00
interference_pct = motor_compensation.length() / (float)COMPASS_MAGFIELD_EXPECTED * 100.0f;
2013-05-19 10:03:48 -03:00
}else{
// interference is impact/amp * (max current seen / max throttle seen) / mag field * 100
2013-06-26 19:29:01 -03:00
interference_pct = motor_compensation.length() * (current_amps_max/throttle_pct_max) / (float)COMPASS_MAGFIELD_EXPECTED * 100.0f;
2013-05-19 10:03:48 -03:00
}
cliSerial->printf_P(PSTR("\nInterference at full throttle is %d%% of mag field\n\n"),(int)interference_pct);
2013-03-03 10:02:36 -04:00
}else{
// compensation vector never updated, report failure
cliSerial->printf_P(PSTR("Failed! Compensation disabled. Did you forget to raise the throttle high enough?"));
compass.motor_compensation_type(AP_COMPASS_MOT_COMP_DISABLED);
}
2013-03-02 04:54:18 -04:00
// display new motor offsets and save
report_compass();
return 0;
}
2013-09-23 11:30:19 -03:00
// display_compassmot_info - displays a status line for compassmot process
static void display_compassmot_info(Vector3f& motor_impact, Vector3f& motor_compensation)
{
// print one more time so the last thing printed matches what appears in the report_compass
2013-10-01 10:34:44 -03:00
cliSerial->printf_P(PSTR("thr:%d cur:%4.2f mot x:%4.1f y:%4.1f z:%4.1f comp x:%4.2f y:%4.2f z:%4.2f\n"),(int)g.rc_3.control_in, (float)battery.current_amps(), (float)motor_impact.x, (float)motor_impact.y, (float)motor_impact.z, (float)motor_compensation.x, (float)motor_compensation.y, (float)motor_compensation.z);
2013-09-23 11:30:19 -03:00
}
2013-03-02 04:54:18 -04:00
2013-05-31 02:56:08 -03:00
static int8_t
setup_erase(uint8_t argc, const Menu::arg *argv)
{
zero_eeprom();
return 0;
}
2011-02-19 17:04:05 -04:00
2013-05-31 02:56:08 -03:00
static int8_t
setup_flightmodes(uint8_t argc, const Menu::arg *argv)
{
uint8_t _switchPosition = 0;
uint8_t _oldSwitchPosition = 0;
int8_t mode = 0;
cliSerial->printf_P(PSTR("\nMode switch to edit, aileron: select modes, rudder: Simple on/off\n"));
print_hit_enter();
while(1) {
delay(20);
read_radio();
_switchPosition = readSwitch();
// look for control switch change
if (_oldSwitchPosition != _switchPosition) {
mode = flight_modes[_switchPosition];
mode = constrain_int16(mode, 0, NUM_MODES-1);
// update the user
print_switch(_switchPosition, mode, BIT_IS_SET(g.simple_modes, _switchPosition));
// Remember switch position
_oldSwitchPosition = _switchPosition;
2012-08-21 23:19:50 -03:00
}
2011-05-29 01:02:01 -03:00
2013-05-31 02:56:08 -03:00
// look for stick input
if (abs(g.rc_1.control_in) > 3000) {
mode++;
if(mode >= NUM_MODES)
mode = 0;
2011-05-29 01:02:01 -03:00
2013-05-31 02:56:08 -03:00
// save new mode
flight_modes[_switchPosition] = mode;
2011-05-29 01:02:01 -03:00
2013-05-31 02:56:08 -03:00
// print new mode
print_switch(_switchPosition, mode, BIT_IS_SET(g.simple_modes, _switchPosition));
delay(500);
}
2011-05-29 01:02:01 -03:00
2013-05-31 02:56:08 -03:00
// look for stick input
if (g.rc_4.control_in > 3000) {
g.simple_modes |= (1<<_switchPosition);
// print new mode
print_switch(_switchPosition, mode, BIT_IS_SET(g.simple_modes, _switchPosition));
delay(500);
}
// look for stick input
if (g.rc_4.control_in < -3000) {
g.simple_modes &= ~(1<<_switchPosition);
// print new mode
print_switch(_switchPosition, mode, BIT_IS_SET(g.simple_modes, _switchPosition));
delay(500);
}
2011-05-29 01:02:01 -03:00
2013-05-31 02:56:08 -03:00
// escape hatch
if(cliSerial->available() > 0) {
for (mode = 0; mode < 6; mode++)
flight_modes[mode].save();
2011-05-29 01:02:01 -03:00
2013-05-31 02:56:08 -03:00
g.simple_modes.save();
print_done();
report_flight_modes();
return (0);
}
}
2011-05-27 01:59:01 -03:00
}
2012-08-21 23:19:50 -03:00
2011-07-21 20:14:53 -03:00
static int8_t
setup_optflow(uint8_t argc, const Menu::arg *argv)
{
2012-11-18 12:16:07 -04:00
#if OPTFLOW == ENABLED
2012-08-21 23:19:50 -03:00
if (!strcmp_P(argv[1].str, PSTR("on"))) {
g.optflow_enabled = true;
init_optflow();
} else if (!strcmp_P(argv[1].str, PSTR("off"))) {
g.optflow_enabled = false;
}else{
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("\nOp:[on, off]\n"));
2012-08-21 23:19:50 -03:00
report_optflow();
return 0;
}
g.optflow_enabled.save();
report_optflow();
2012-11-18 12:16:07 -04:00
#endif // OPTFLOW == ENABLED
2012-08-21 23:19:50 -03:00
return 0;
2011-07-21 20:14:53 -03:00
}
2011-12-23 18:41:18 -04:00
2013-05-31 02:56:08 -03:00
// Perform radio setup.
// Called by the setup menu 'radio' command.
static int8_t
setup_radio(uint8_t argc, const Menu::arg *argv)
{
cliSerial->println_P(PSTR("\n\nRadio Setup:"));
uint8_t i;
for(i = 0; i < 100; i++) {
delay(20);
read_radio();
}
if(g.rc_1.radio_in < 500) {
while(1) {
delay(1000);
// stop here
}
}
g.rc_1.radio_min = g.rc_1.radio_in;
g.rc_2.radio_min = g.rc_2.radio_in;
g.rc_3.radio_min = g.rc_3.radio_in;
g.rc_4.radio_min = g.rc_4.radio_in;
g.rc_5.radio_min = g.rc_5.radio_in;
g.rc_6.radio_min = g.rc_6.radio_in;
g.rc_7.radio_min = g.rc_7.radio_in;
g.rc_8.radio_min = g.rc_8.radio_in;
g.rc_1.radio_max = g.rc_1.radio_in;
g.rc_2.radio_max = g.rc_2.radio_in;
g.rc_3.radio_max = g.rc_3.radio_in;
g.rc_4.radio_max = g.rc_4.radio_in;
g.rc_5.radio_max = g.rc_5.radio_in;
g.rc_6.radio_max = g.rc_6.radio_in;
g.rc_7.radio_max = g.rc_7.radio_in;
g.rc_8.radio_max = g.rc_8.radio_in;
g.rc_1.radio_trim = g.rc_1.radio_in;
g.rc_2.radio_trim = g.rc_2.radio_in;
g.rc_4.radio_trim = g.rc_4.radio_in;
// 3 is not trimed
g.rc_5.radio_trim = 1500;
g.rc_6.radio_trim = 1500;
g.rc_7.radio_trim = 1500;
g.rc_8.radio_trim = 1500;
cliSerial->printf_P(PSTR("\nMove all controls to extremes. Enter to save: "));
while(1) {
delay(20);
// Filters radio input - adjust filters in the radio.pde file
// ----------------------------------------------------------
read_radio();
g.rc_1.update_min_max();
g.rc_2.update_min_max();
g.rc_3.update_min_max();
g.rc_4.update_min_max();
g.rc_5.update_min_max();
g.rc_6.update_min_max();
g.rc_7.update_min_max();
g.rc_8.update_min_max();
if(cliSerial->available() > 0) {
delay(20);
while (cliSerial->read() != -1); /* flush */
g.rc_1.save_eeprom();
g.rc_2.save_eeprom();
g.rc_3.save_eeprom();
g.rc_4.save_eeprom();
g.rc_5.save_eeprom();
g.rc_6.save_eeprom();
g.rc_7.save_eeprom();
g.rc_8.save_eeprom();
print_done();
break;
}
}
report_radio();
return(0);
}
static int8_t
setup_range(uint8_t argc, const Menu::arg *argv)
{
cliSerial->printf_P(PSTR("\nCH 6 Ranges are divided by 1000: [low, high]\n"));
g.radio_tuning_low.set_and_save(argv[1].i);
g.radio_tuning_high.set_and_save(argv[2].i);
report_tuning();
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)
{
int16_t c;
cliSerial->printf_P(PSTR("\n'Y' = factory reset, any other key to abort:\n"));
do {
c = cliSerial->read();
} while (-1 == c);
if (('y' != c) && ('Y' != c))
return(-1);
AP_Param::erase_all();
2013-12-27 21:42:10 -04:00
cliSerial->printf_P(PSTR("\nReboot board"));
2013-05-31 02:56:08 -03:00
delay(1000);
for (;; ) {
}
// note, cannot actually return here
return(0);
}
2013-03-07 04:30:45 -04:00
//Set a parameter to a specified value. It will cast the value to the current type of the
//parameter and make sure it fits in case of INT8 and INT16
static int8_t setup_set(uint8_t argc, const Menu::arg *argv)
{
int8_t value_int8;
int16_t value_int16;
AP_Param *param;
enum ap_var_type p_type;
2011-05-27 01:59:01 -03:00
2013-03-07 04:30:45 -04:00
if(argc!=3)
{
cliSerial->printf_P(PSTR("Invalid command. Usage: set <name> <value>\n"));
return 0;
}
param = AP_Param::find(argv[1].str, &p_type);
if(!param)
{
cliSerial->printf_P(PSTR("Param not found: %s\n"), argv[1].str);
return 0;
}
switch(p_type)
{
case AP_PARAM_INT8:
value_int8 = (int8_t)(argv[2].i);
if(argv[2].i!=value_int8)
{
cliSerial->printf_P(PSTR("Value out of range for type INT8\n"));
return 0;
}
((AP_Int8*)param)->set_and_save(value_int8);
break;
case AP_PARAM_INT16:
value_int16 = (int16_t)(argv[2].i);
if(argv[2].i!=value_int16)
{
cliSerial->printf_P(PSTR("Value out of range for type INT16\n"));
return 0;
}
((AP_Int16*)param)->set_and_save(value_int16);
break;
//int32 and float don't need bounds checking, just use the value provoded by Menu::arg
case AP_PARAM_INT32:
((AP_Int32*)param)->set_and_save(argv[2].i);
break;
case AP_PARAM_FLOAT:
((AP_Float*)param)->set_and_save(argv[2].f);
break;
default:
cliSerial->printf_P(PSTR("Cannot set parameter of type %d.\n"), p_type);
break;
}
return 0;
}
2011-07-30 17:42:54 -03:00
2013-05-31 02:56:08 -03:00
// Print the current configuration.
// Called by the setup menu 'show' command.
static int8_t
setup_show(uint8_t argc, const Menu::arg *argv)
{
AP_Param *param;
ap_var_type type;
//If a parameter name is given as an argument to show, print only that parameter
if(argc>=2)
{
param=AP_Param::find(argv[1].str, &type);
if(!param)
{
cliSerial->printf_P(PSTR("Parameter not found: '%s'\n"), argv[1]);
return 0;
}
AP_Param::show(param, argv[1].str, type, cliSerial);
return 0;
}
// clear the area
print_blanks(8);
report_version();
report_radio();
report_frame();
report_batt_monitor();
report_sonar();
report_flight_modes();
report_ins();
report_compass();
report_optflow();
AP_Param::show_all(cliSerial);
return(0);
}
static int8_t
setup_sonar(uint8_t argc, const Menu::arg *argv)
{
if (!strcmp_P(argv[1].str, PSTR("on"))) {
g.sonar_enabled.set_and_save(true);
} else if (!strcmp_P(argv[1].str, PSTR("off"))) {
g.sonar_enabled.set_and_save(false);
} else if (argc > 1 && (argv[1].i >= 0 && argv[1].i <= 3)) {
g.sonar_enabled.set_and_save(true); // if you set the sonar type, surely you want it on
g.sonar_type.set_and_save(argv[1].i);
}else{
cliSerial->printf_P(PSTR("\nOp:[on, off, 0-3]\n"));
report_sonar();
return 0;
}
report_sonar();
return 0;
}
2011-01-20 03:11:21 -04:00
/***************************************************************************/
2011-02-24 01:56:59 -04:00
// CLI reports
2011-01-20 03:11:21 -04:00
/***************************************************************************/
2011-05-09 12:46:56 -03:00
2011-07-17 07:32:00 -03:00
static void report_batt_monitor()
2011-05-09 12:46:56 -03:00
{
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("\nBatt Mon:\n"));
2012-08-21 23:19:50 -03:00
print_divider();
2013-10-01 10:34:44 -03:00
if (battery.monitoring() == AP_BATT_MONITOR_DISABLED) print_enabled(false);
if (battery.monitoring() == AP_BATT_MONITOR_VOLTAGE_ONLY) cliSerial->printf_P(PSTR("volts"));
if (battery.monitoring() == AP_BATT_MONITOR_VOLTAGE_AND_CURRENT) cliSerial->printf_P(PSTR("volts and cur"));
2012-08-21 23:19:50 -03:00
print_blanks(2);
2011-05-09 12:46:56 -03:00
}
2011-05-14 23:02:09 -03:00
2011-07-17 07:32:00 -03:00
static void report_sonar()
2011-02-20 19:09:28 -04:00
{
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("Sonar\n"));
2012-08-21 23:19:50 -03:00
print_divider();
print_enabled(g.sonar_enabled.get());
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("Type: %d (0=XL, 1=LV, 2=XLL, 3=HRLV)"), (int)g.sonar_type);
2012-08-21 23:19:50 -03:00
print_blanks(2);
2011-01-20 03:11:21 -04:00
}
2011-07-17 07:32:00 -03:00
static void report_frame()
2011-01-20 03:11:21 -04:00
{
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("Frame\n"));
2012-08-21 23:19:50 -03:00
print_divider();
#if FRAME_CONFIG == QUAD_FRAME
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("Quad frame\n"));
2012-08-21 23:19:50 -03:00
#elif FRAME_CONFIG == TRI_FRAME
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("TRI frame\n"));
2012-08-21 23:19:50 -03:00
#elif FRAME_CONFIG == HEXA_FRAME
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("Hexa frame\n"));
2012-08-21 23:19:50 -03:00
#elif FRAME_CONFIG == Y6_FRAME
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("Y6 frame\n"));
2012-08-21 23:19:50 -03:00
#elif FRAME_CONFIG == OCTA_FRAME
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("Octa frame\n"));
2012-08-21 23:19:50 -03:00
#elif FRAME_CONFIG == HELI_FRAME
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("Heli frame\n"));
2012-08-21 23:19:50 -03:00
#endif
print_blanks(2);
2011-01-20 03:11:21 -04:00
}
2011-07-17 07:32:00 -03:00
static void report_radio()
2011-01-20 03:11:21 -04:00
{
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("Radio\n"));
2012-08-21 23:19:50 -03:00
print_divider();
// radio
print_radio_values();
print_blanks(2);
2011-01-20 03:11:21 -04:00
}
2012-11-05 00:32:38 -04:00
static void report_ins()
2011-01-20 03:11:21 -04:00
{
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("INS\n"));
2012-08-21 23:19:50 -03:00
print_divider();
2011-01-20 03:11:21 -04:00
2012-08-21 23:19:50 -03:00
print_gyro_offsets();
2012-11-05 00:32:38 -04:00
print_accel_offsets_and_scaling();
2012-08-21 23:19:50 -03:00
print_blanks(2);
2011-01-20 03:11:21 -04:00
}
2011-07-17 07:32:00 -03:00
static void report_compass()
2011-01-20 03:11:21 -04:00
{
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("Compass\n"));
2012-08-21 23:19:50 -03:00
print_divider();
2011-01-20 03:11:21 -04:00
2012-08-21 23:19:50 -03:00
print_enabled(g.compass_enabled);
2011-02-19 17:04:05 -04:00
2012-08-21 23:19:50 -03:00
// mag declination
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("Mag Dec: %4.4f\n"),
2012-08-21 23:19:50 -03:00
degrees(compass.get_declination()));
2011-02-19 22:03:01 -04:00
2012-08-21 23:19:50 -03:00
Vector3f offsets = compass.get_offsets();
2011-02-17 05:36:33 -04:00
2012-08-21 23:19:50 -03:00
// mag offsets
2013-03-02 04:54:18 -04:00
cliSerial->printf_P(PSTR("Mag off: %4.4f, %4.4f, %4.4f\n"),
2012-08-21 23:19:50 -03:00
offsets.x,
offsets.y,
offsets.z);
2013-03-02 04:54:18 -04:00
// motor compensation
2013-03-03 10:02:36 -04:00
cliSerial->print_P(PSTR("Motor Comp: "));
if( compass.motor_compensation_type() == AP_COMPASS_MOT_COMP_DISABLED ) {
cliSerial->print_P(PSTR("Off\n"));
}else{
if( compass.motor_compensation_type() == AP_COMPASS_MOT_COMP_THROTTLE ) {
cliSerial->print_P(PSTR("Throttle"));
}
if( compass.motor_compensation_type() == AP_COMPASS_MOT_COMP_CURRENT ) {
cliSerial->print_P(PSTR("Current"));
}
Vector3f motor_compensation = compass.get_motor_compensation();
cliSerial->printf_P(PSTR("\nComp Vec: %4.2f, %4.2f, %4.2f\n"),
motor_compensation.x,
motor_compensation.y,
motor_compensation.z);
}
2013-03-02 04:54:18 -04:00
print_blanks(1);
2011-01-20 03:11:21 -04:00
}
2011-07-17 07:32:00 -03:00
static void report_flight_modes()
2011-01-20 03:11:21 -04:00
{
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("Flight modes\n"));
2012-08-21 23:19:50 -03:00
print_divider();
2011-02-19 17:04:05 -04:00
2012-08-21 23:19:50 -03:00
for(int16_t i = 0; i < 6; i++ ) {
2013-04-23 10:05:42 -03:00
print_switch(i, flight_modes[i], BIT_IS_SET(g.simple_modes, i));
2012-08-21 23:19:50 -03:00
}
print_blanks(2);
2011-01-20 03:11:21 -04:00
}
2011-07-21 20:14:53 -03:00
void report_optflow()
{
2012-11-18 12:16:07 -04:00
#if OPTFLOW == ENABLED
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("OptFlow\n"));
2012-08-21 23:19:50 -03:00
print_divider();
2011-07-21 20:14:53 -03:00
2012-08-21 23:19:50 -03:00
print_enabled(g.optflow_enabled);
2011-07-21 20:14:53 -03:00
2012-08-21 23:19:50 -03:00
print_blanks(2);
2012-11-18 12:16:07 -04:00
#endif // OPTFLOW == ENABLED
2011-07-21 20:14:53 -03:00
}
2011-12-23 18:41:18 -04:00
2011-01-20 03:11:21 -04:00
/***************************************************************************/
// CLI utilities
/***************************************************************************/
2011-07-17 07:32:00 -03:00
static void
2011-01-20 03:11:21 -04:00
print_radio_values()
{
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("CH1: %d | %d\n"), (int)g.rc_1.radio_min, (int)g.rc_1.radio_max);
cliSerial->printf_P(PSTR("CH2: %d | %d\n"), (int)g.rc_2.radio_min, (int)g.rc_2.radio_max);
cliSerial->printf_P(PSTR("CH3: %d | %d\n"), (int)g.rc_3.radio_min, (int)g.rc_3.radio_max);
cliSerial->printf_P(PSTR("CH4: %d | %d\n"), (int)g.rc_4.radio_min, (int)g.rc_4.radio_max);
cliSerial->printf_P(PSTR("CH5: %d | %d\n"), (int)g.rc_5.radio_min, (int)g.rc_5.radio_max);
cliSerial->printf_P(PSTR("CH6: %d | %d\n"), (int)g.rc_6.radio_min, (int)g.rc_6.radio_max);
cliSerial->printf_P(PSTR("CH7: %d | %d\n"), (int)g.rc_7.radio_min, (int)g.rc_7.radio_max);
2013-07-12 09:46:03 -03:00
cliSerial->printf_P(PSTR("CH8: %d | %d\n"), (int)g.rc_8.radio_min, (int)g.rc_8.radio_max);
2010-12-19 12:40:33 -04:00
}
2011-07-17 07:32:00 -03:00
static void
2012-12-12 19:46:20 -04:00
print_switch(uint8_t p, uint8_t m, bool b)
2010-12-19 12:40:33 -04:00
{
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("Pos %d:\t"),p);
2013-04-20 02:18:22 -03:00
print_flight_mode(cliSerial, m);
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR(",\t\tSimple: "));
2012-08-21 23:19:50 -03:00
if(b)
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("ON\n"));
2012-08-21 23:19:50 -03:00
else
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("OFF\n"));
2010-12-19 12:40:33 -04:00
}
2011-07-17 07:32:00 -03:00
static void
2010-12-19 12:40:33 -04:00
print_done()
{
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("\nSaved\n"));
2010-12-19 12:40:33 -04:00
}
2011-07-17 07:32:00 -03:00
static void zero_eeprom(void)
2010-12-19 12:40:33 -04:00
{
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("\nErasing EEPROM\n"));
2011-06-16 14:03:26 -03:00
2012-12-13 15:48:01 -04:00
for (uint16_t i = 0; i < EEPROM_MAX_ADDR; i++) {
hal.storage->write_byte(i, 0);
2012-08-21 23:19:50 -03:00
}
2011-06-16 14:03:26 -03:00
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("done\n"));
2010-12-19 12:40:33 -04:00
}
2011-01-20 03:11:21 -04:00
2011-07-17 07:32:00 -03:00
static void
2012-11-05 00:32:38 -04:00
print_accel_offsets_and_scaling(void)
2011-02-18 23:59:58 -04:00
{
2013-08-13 12:23:10 -03:00
const Vector3f &accel_offsets = ins.get_accel_offsets();
const Vector3f &accel_scale = ins.get_accel_scale();
2013-03-04 10:14:14 -04:00
cliSerial->printf_P(PSTR("A_off: %4.2f, %4.2f, %4.2f\nA_scale: %4.2f, %4.2f, %4.2f\n"),
2012-11-05 00:32:38 -04:00
(float)accel_offsets.x, // Pitch
(float)accel_offsets.y, // Roll
(float)accel_offsets.z, // YAW
(float)accel_scale.x, // Pitch
(float)accel_scale.y, // Roll
(float)accel_scale.z); // YAW
2011-02-18 23:59:58 -04:00
}
2011-07-17 07:32:00 -03:00
static void
2011-02-18 23:59:58 -04:00
print_gyro_offsets(void)
{
2013-08-13 12:23:10 -03:00
const Vector3f &gyro_offsets = ins.get_gyro_offsets();
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("G_off: %4.2f, %4.2f, %4.2f\n"),
2012-11-05 00:32:38 -04:00
(float)gyro_offsets.x,
(float)gyro_offsets.y,
(float)gyro_offsets.z);
2011-02-18 23:59:58 -04:00
}
2011-07-17 07:34:05 -03:00
#endif // CLI_ENABLED
static void
2012-08-16 08:04:46 -03:00
print_blanks(int16_t num)
2011-07-17 07:34:05 -03:00
{
2012-08-21 23:19:50 -03:00
while(num > 0) {
num--;
2012-11-21 02:08:03 -04:00
cliSerial->println("");
2012-08-21 23:19:50 -03:00
}
2011-07-17 07:34:05 -03:00
}
static void
print_divider(void)
{
2012-08-21 23:19:50 -03:00
for (int i = 0; i < 40; i++) {
2012-11-21 02:08:03 -04:00
cliSerial->print_P(PSTR("-"));
2012-08-21 23:19:50 -03:00
}
2012-11-21 02:08:03 -04:00
cliSerial->println();
2011-07-17 07:34:05 -03:00
}
2012-11-10 02:02:34 -04:00
static void print_enabled(bool b)
2011-07-17 07:34:05 -03:00
{
2012-08-21 23:19:50 -03:00
if(b)
2012-11-21 02:08:03 -04:00
cliSerial->print_P(PSTR("en"));
2012-08-21 23:19:50 -03:00
else
2012-11-21 02:08:03 -04:00
cliSerial->print_P(PSTR("dis"));
cliSerial->print_P(PSTR("abled\n"));
2011-07-17 07:34:05 -03:00
}
static void
init_esc()
{
2013-01-24 22:34:48 -04:00
// reduce update rate to motors to 50Hz
motors.set_update_rate(50);
2013-05-16 04:32:00 -03:00
// we enable the motors directly here instead of calling output_min because output_min would send a low signal to the ESC and disrupt the calibration process
2012-08-21 23:19:50 -03:00
motors.enable();
motors.armed(true);
while(1) {
read_radio();
delay(100);
2013-08-14 00:07:35 -03:00
AP_Notify::flags.esc_calibration = true;
2012-08-21 23:19:50 -03:00
motors.throttle_pass_through();
}
2011-07-17 07:34:05 -03:00
}
static void report_version()
{
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("FW Ver: %d\n"),(int)g.k_format_version);
2012-08-21 23:19:50 -03:00
print_divider();
print_blanks(2);
2011-07-17 07:34:05 -03:00
}
2011-09-10 19:16:51 -03:00
static void report_tuning()
{
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR("\nTUNE:\n"));
2012-08-21 23:19:50 -03:00
print_divider();
if (g.radio_tuning == 0) {
print_enabled(g.radio_tuning.get());
}else{
float low = (float)g.radio_tuning_low.get() / 1000;
float high = (float)g.radio_tuning_high.get() / 1000;
2012-11-21 02:08:03 -04:00
cliSerial->printf_P(PSTR(" %d, Low:%1.4f, High:%1.4f\n"),(int)g.radio_tuning.get(), low, high);
2012-08-21 23:19:50 -03:00
}
print_blanks(2);
2011-09-10 19:16:51 -03:00
}