// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: t -*- /* This GCS protocol sends text-based information over the GCS port */ #if GCS_PROTOCOL == GCS_PROTOCOL_DEBUGTERMINAL #define ERR(a) ((DEBUGTERMINAL_VERBOSE)>0?(PSTR(a)):(0)) void GCS_DEBUGTERMINAL::update() { byte numc, i, c; numc = _port->available(); for (i=0;iread(); processgcsinput(c); } } void GCS_DEBUGTERMINAL::processgcsinput(char c) { if (c==8) { //Received a backspace character; move the buffer index backwards if (bufferidx > 0) bufferidx--; } else if (c==10) { //Received a linefeed; do nothing } else if (c==13) { //Received a carriage return; process command gcsinputbuffer[bufferidx] = 0; run_debugt_command(gcsinputbuffer); bufferidx = 0; } else { gcsinputbuffer[bufferidx++] = c; if (bufferidx >= sizeof(gcsinputbuffer)) bufferidx = 0; } } void GCS_DEBUGTERMINAL::run_debugt_command(char *buf) { BetterStream *port = _port; //*********** Ignore comments *********** if (strmatch(buf, PSTR("//"))) { //*********** Process 'show' commands *********** } else if (strmatch(buf, PSTR("show "))) { if (strmatch(buf+5, PSTR("heartbeat"))) report_heartbeat = 1; else if (strmatch(buf+5, PSTR("attitude"))) report_attitude = 1; else if (strmatch(buf+5, PSTR("location"))) report_location = 1; else if (strmatch(buf+5, PSTR("command"))) report_command = 1; else if (strmatch(buf+5, PSTR("cpuload"))) report_cpu_load = 1; else if (strmatch(buf+5, PSTR("severity"))) report_severity = atoi(buf+14); else print_error(ERR("USAGE: show {heartbeat|attitude|location|command|severity }")); //*********** Process 'hide' commands *********** } else if (strmatch(buf, PSTR("hide "))) { if (strmatch(buf+5, PSTR("heartbeat"))) report_heartbeat = 0; else if (strmatch(buf+5, PSTR("attitude"))) report_attitude = 0; else if (strmatch(buf+5, PSTR("location"))) report_location = 0; else if (strmatch(buf+5, PSTR("command"))) report_command = 0; else if (strmatch(buf+5, PSTR("cpuload"))) report_cpu_load = 0; else if (strmatch(buf+5, PSTR("all"))) { report_heartbeat = 0; report_attitude = 0; report_location = 0; report_command = 0; report_cpu_load = 0; } else print_error(ERR("USAGE: hide {heartbeat|attitude|location|command|all}")); //*********** Process 'copy' command *********** } else if (strmatch(buf, PSTR("copy "))) { //------- copy cmd ------- if (strmatch(buf+5, PSTR("cmd "))) { unsigned char i = 9, index1, index2; while (buf[i] != 0) { i++; if (buf[i] == ' ') break; } if (buf[i] == ' ') { buf[i] = 0; index1 = atoi(buf+9); index2 = atoi(buf+i+1); Location temp = get_wp_with_index(index1); set_wp_with_index(temp, index2); port->print_P(PSTR("Copied command index ")); port->print(index1,DEC); port->print_P(PSTR(" to ")); port->println(index2,DEC); } else { print_error(ERR("USAGE: copy cmd ")); } } //*********** Process 'echo' command *********** } else if (strmatch(buf, PSTR("echo "))) { port->println(buf+5); //*********** Process 'groundstart' command *********** } else if (strmatch(buf, PSTR("groundstart"))) { startup_ground(); //*********** Process 'inithome' command *********** } else if (strmatch(buf, PSTR("inithome"))) { init_home(); port->println_P(PSTR("Home set.")); //------- k -? ------- } else if (strmatch(buf, PSTR("k -?"))) { print_error(ERR("USAGE: {print|set} {k{p|i|d}|imax} {servoroll|servopitch|servorudder|navroll|navpitchasp|navpitchalt|throttlete|throttlealt}")); print_error(ERR("USAGE: {print|set} kff {pitchcomp|ruddermix|pitchtothrottle}")); //*********** Process 'print' commands *********** } else if (strmatch(buf, PSTR("print "))) { //------- print airspeedtrim ------- if (strmatch(buf+6, PSTR("airspeedtrim"))) { port->printf_P("Trim airspeed = %f\n", (float)get(PARAM_TRIM_AIRSPEED)/100); //------- print airspeednudge ------- } else if (strmatch(buf+6, PSTR("airspeednudge"))) { port->printf_P("Airspeed nudge = %f\n", (float)airspeed_nudge/100); //------- print altitude ------- } else if (strmatch(buf+6, PSTR("altitude"))) { recalc_climb_rate(); port->printf_P(PSTR("Altitude:\n" " Pressure: %.2fm\n" " GPS: %.2fm\n" " Mix ratio: %.3f\n" " Mix: %.2fm\n" " Above home: %.1fm\n" " Climb rate: %.2fm/s\n"), (float)press_alt / 100, (float)gps.altitude / 100, get(PARAM_ALT_MIX), (((1.0 - get(PARAM_ALT_MIX)) * gps.altitude) + (get(PARAM_ALT_MIX) * press_alt)) / 100, (float)get_altitude_above_home()/100, (float)climb_rate/100); //------- print attitude ------- } else if (strmatch(buf+6, PSTR("attitude"))) { print_attitude(); //------- print commands[ -] ------- } else if (strmatch(buf+6, PSTR("commands"))) { unsigned char dash, index1, index2; for (dash=14; dashprint_P(PSTR("EEPROM read: ")); for (i=0; i<6; i++) { port->print_P(PSTR("Ch ")); port->print(i,DEC); port->print_P(PSTR(" = ")); port->print(get(uint8_param_t(PARAM_FLIGHT_MODE_1+i)),DEC); port->print_P(PSTR(", ")); } port->println(" "); //------- print holdalt ------- } else if (strmatch(buf+6, PSTR("holdalt"))) { port->print_P(PSTR("Altitude above home set to ")); port->println(get(PARAM_ALT_HOLD_HOME),2); //------- print imax {servoroll|servopitch|servorudder|navroll|navpitchasp|navpitchalt|throttlete|throttlealt} ------- } else if (strmatch(buf+6, PSTR("imax "))) { int i; unsigned char j; if (get_pid_offset_name(buf+11, &i, &j)) { port->print_P(PSTR("Integrator maximum for ")); port->print(buf+9); port->print_P(PSTR(" = ")); port->println(pid_index[i]->imax(),DEC); } else print_gain_keyword_error(); //------- print kp {servoroll|servopitch|servorudder|navroll|navpitchasp|navpitchalt|throttlete|throttlealt} ------- } else if (strmatch(buf+6, PSTR("kp "))) { int i; unsigned char j; if (get_pid_offset_name(buf+9, &i, &j)) { port->print_P(PSTR("P gain for ")); port->print(buf+9); port->print_P(PSTR(" = ")); port->println(pid_index[i]->kP(),DEC); } else print_gain_keyword_error(); //------- print ki {servoroll|servopitch|servorudder|navroll|navpitchasp|navpitchalt|throttlete|throttlealt} ------- } else if (strmatch(buf+6, PSTR("ki "))) { int i; unsigned char j; if (get_pid_offset_name(buf+9, &i, &j)) { port->print_P(PSTR("I gain for ")); port->print(buf+9); port->print_P(PSTR(" = ")); port->println(pid_index[i]->kI(),DEC); } else print_gain_keyword_error(); //------- print kd {servoroll|servopitch|servorudder|navroll|navpitchasp|navpitchalt|throttlete|throttlealt} ------- } else if (strmatch(buf+6, PSTR("kd "))) { int i; unsigned char j; if (get_pid_offset_name(buf+9, &i, &j)) { port->print_P(PSTR("D gain for ")); port->print(buf+9); port->print_P(PSTR(" = ")); port->println(pid_index[i]->kD(),DEC); } else print_gain_keyword_error(); //------- print kff {pitchcomp|ruddermix|pitchtothrottle} ------- } else if (strmatch(buf+6, PSTR("kff "))) { if (strmatch(buf+10, PSTR("pitchcomp"))) { port->print_P(PSTR("FF gain for pitchcomp = ")); port->println(get(PARAM_KFF_PTCHCOMP),DEC); } else if (strmatch(buf+10, PSTR("ruddermix"))) { port->print_P(PSTR("FF gain for ruddermix = ")); port->println(get(PARAM_KFF_RDDRMIX),DEC); } else if (strmatch(buf+10, PSTR("pitchtothrottle"))) { port->print_P(PSTR("FF gain for pitchtothrottle = ")); port->println(get(PARAM_KFF_PTCH2THR),DEC); /*} else if (strmatch(buf+10, PSTR("throttletopitch"))) { port->print_P(PSTR("FF gain for throttletopitch = ")); port->println(kff[CASE_T_TO_P],DEC);*/ } else print_gain_keyword_error(); //------- print location ------- } else if (strmatch(buf+6, PSTR("location"))) { print_position(); //------- print navrolllimit ------- } else if (strmatch(buf+6, PSTR("navrolllimit"))) { port->print_P(PSTR("Nav roll limit = ")); port->println((float)get(PARAM_LIM_ROLL)/100,2); //------- print navsettings ------- } else if (strmatch(buf+6, PSTR("navsettings"))) { port->printf_P(PSTR("Navigation settings:\n" #if AIRSPEED_SENSOR == ENABLED " Cruise airspeed: %.2f\n" #else " Cruise throttle: %d\n" #endif " Hold altitude above home: %ld\n" " Loiter radius: %d\n" " Waypoint radius: %d\n"), #if AIRSPEED_SENSOR == ENABLED (float)get(PARAM_TRIM_AIRSPEED) / 100, #else get(PARAM_TRIM_THROTTLE), #endif get(PARAM_ALT_HOLD_HOME), get(PARAM_LOITER_RADIUS), get(PARAM_WP_RADIUS)); //------- print pitchmax ------- } else if (strmatch(buf+6, PSTR("pitchmax"))) { port->print_P(PSTR("Maximum pitch = ")); port->println((float)get(PARAM_LIM_PITCH_MAX)/100,2); //------- print pitchmin ------- } else if (strmatch(buf+6, PSTR("pitchmin"))) { port->print_P(PSTR("Minimum pitch = ")); port->println((float)get(PARAM_LIM_PITCH_MIN)/100,2); //------- print pitchtarget ------- } else if (strmatch(buf+6, PSTR("pitchtarget"))) { port->print_P(PSTR("Target pitch = ")); port->println((float)get(PARAM_TRIM_PITCH)/100,2); #if HIL_MODE != HIL_MODE_ATTITUDE //------- print pressure ------- } else if (strmatch(buf+6, PSTR("pressure"))) { port->println_P(PSTR("BMP085 pressure sensor:")); port->print_P(PSTR(" Temperature: ")); port->println(pitot.Temp,DEC); port->print_P(PSTR(" Pressure: ")); port->println(pitot.Press,DEC); #endif //------- print rlocation home ------- } else if (strmatch(buf+6, PSTR("rlocation home"))) { print_rlocation(&home); //------- print rlocation ------- //(implication is "relative to next waypoint") } else if (strmatch(buf+6, PSTR("rlocation"))) { print_rlocation(&next_WP); //------- print speed ------- } else if (strmatch(buf+6, PSTR("speed"))) { port->println_P(PSTR("Speed:")); port->print_P(PSTR(" Ground: ")); port->println((float)gps.ground_speed/100.0,2); #if AIRSPEED_SENSOR == ENABLED port->print_P(PSTR(" Air: ")); port->println((float)airspeed/100.0,2); port->print_P(PSTR(" Cruise: ")); port->println((float)get(PARAM_TRIM_AIRSPEED)/100.0,2); #endif //------- print throttlecruise ------- } else if (strmatch(buf+6, PSTR("throttlecruise"))) { port->print_P(PSTR("Throttle cruise = ")); port->print(get(PARAM_TRIM_THROTTLE),DEC); port->println_P(PSTR("%")); //------- print throttlemax ------- } else if (strmatch(buf+6, PSTR("throttlemax"))) { port->print_P(PSTR("Throttle max = ")); port->print(get(PARAM_THR_MAX),DEC); port->println_P(PSTR("%")); //------- print throttlemin ------- } else if (strmatch(buf+6, PSTR("throttlemin"))) { port->print_P(PSTR("Throttle min = ")); port->print(get(PARAM_THR_MIN),DEC); port->println_P(PSTR("%")); //------- print tuning ------- } else if (strmatch(buf+6, PSTR("tuning"))) { print_tuning(); } else print_error(ERR("USAGE: print {altitude|attitude|commands|ctrlmode|curwaypts|flightmodes|k -?|kp|ki|kd|kff|location|navsettings|pressure|rlocation [home]|speed|tuning|}")); //*********** Process 'reset' commands *********** } else if (strmatch(buf, PSTR("reset "))) { //------- reset commands ------- if (strmatch(buf+6, PSTR("commands"))) { reload_commands(); port->println_P(PSTR("Commands reloaded.")); } else print_error(ERR("USAGE: reset commands")); //*********** Process 'rtl' command *********** } else if (strmatch(buf, PSTR("rtl"))) { return_to_launch(); port->println_P(PSTR("Returning to launch...")); //*********** Process 'set' commands *********** } else if (strmatch(buf, PSTR("set "))) { //------- set cmd ------- if (strmatch(buf+4, PSTR("cmd "))) { process_set_cmd(buf+8, bufferidx-8); //------- set cmdcount ------- } else if (strmatch(buf+4, PSTR("cmdcount "))) { set(PARAM_WP_TOTAL, atoi(buf+13)); port->print_P(PSTR("PARAM_WP_TOTAL = ")); port->println(get(PARAM_WP_TOTAL),DEC); //------- set cmdindex ------- } else if (strmatch(buf+4, PSTR("cmdindex "))) { set(PARAM_WP_INDEX, atoi(buf+13)); decrement_WP_index(); next_command = get_wp_with_index(get(PARAM_WP_INDEX)+1); port->print_P(PSTR("Command set to index ")); port->print(get(PARAM_WP_INDEX),DEC); if (next_command.id >= 0x10 && next_command.id <= 0x1F) { //TODO: create a function the defines what type of command each command ID is command_must_index = 0; port->println_P(PSTR(" (must)")); } else if (next_command.id >= 0x20 && next_command.id <= 0x2F) { command_may_index = 0; port->println_P(PSTR(" (may)")); } else port->println_P(PSTR(" (now)")); next_command.id = CMD_BLANK; if (get(PARAM_WP_INDEX) > get(PARAM_WP_TOTAL)) { set(PARAM_WP_TOTAL, get(PARAM_WP_INDEX)); port->print_P(PSTR(" The total number of commands is now ")); port->println(get(PARAM_WP_TOTAL),DEC); } next_WP = current_loc; update_commands(); //------- set cruise ------- } else if (strmatch(buf+4, PSTR("cruise "))) { unsigned char j = 4+7; #if AIRSPEED_SENSOR == 1 port->print_P(PSTR("airspeed_cruise changed from ")); port->print((float)get(PARAM_TRIM_AIRSPEED)/100,2); port->print_P(PSTR(" to ")); set(PARAM_TRIM_AIRSPEED, (int)(readfloat(buf, &j)/100000)); set(PARAM_TRIM_AIRSPEED, constrain(get(PARAM_TRIM_AIRSPEED),0,9000)); //TODO: constrain minimum as stall speed, maximum as Vne port->println(((float)get(PARAM_TRIM_AIRSPEED))/100,2); #else port->print_P(PSTR("throttle_cruise changed from ")); port->print(get(PARAM_TRIM_THROTTLE),DEC); port->print_P(PSTR(" to ")); set(PARAM_TRIM_THROTTLE, constrain((int)(readfloat(buf, &j)/10000000),0,200)); port->println(get(PARAM_TRIM_THROTTLE),DEC); #endif //save_user_configs(); //------- set holdalt ------- } else if (strmatch(buf+4, PSTR("holdalt "))) { int tempalt = atoi(buf+12)*100; set(PARAM_ALT_HOLD_HOME, (float)tempalt); //save_alt_to_hold((int32_t)tempalt); port->println_P(PSTR("Hold altitude above home set.")); //------- set imax {servoroll|servopitch|servorudder|navroll|navpitchasp|navpitchalt|throttlete|throttlealt} ------- } else if (strmatch(buf+4, PSTR("imax "))) { int i; unsigned char j = 0; if (get_pid_offset_name(buf+9, &i, &j)) { buf[9+j] = 0; port->print_P(PSTR("Integrator maximum for ")); port->print(buf+9); port->print_P(PSTR(" changed from ")); port->print(pid_index[i]->imax(),DEC); port->print_P(PSTR(" to ")); pid_index[i]->imax((float)atoi(buf+j)); pid_index[i]->save_gains(); port->println(pid_index[i]->imax(),DEC); } else print_error(ERR("ERROR: Did not recognize keyword; type set k -? for more information")); //------- set kp {servoroll|servopitch|servorudder|navroll|navpitchasp|navpitchalt|throttlete|throttlealt} ------- } else if (strmatch(buf+4, PSTR("kp "))) { int i; unsigned char j = 0; if (get_pid_offset_name(buf+7, &i, &j)) { buf[7+j] = 0; port->print_P(PSTR("P gain for ")); port->print(buf+7); port->print_P(PSTR(" changed from ")); port->print(pid_index[i]->kP(),DEC); port->print_P(PSTR(" to ")); j += 7+1; pid_index[i]->kP(((float)readfloat(buf, &j))/10000000); pid_index[i]->save_gains(); port->println(pid_index[i]->kP(),DEC); } else print_gain_keyword_error(); //------- set ki {servoroll|servopitch|servorudder|navroll|navpitchasp|navpitchalt|throttlete|throttlealt} ------- } else if (strmatch(buf+4, PSTR("ki "))) { int i; unsigned char j = 0; if (get_pid_offset_name(buf+7, &i, &j)) { buf[7+j] = 0; port->print_P(PSTR("I gain for ")); port->print(buf+7); port->print_P(PSTR(" changed from ")); port->print(pid_index[i]->kI(),DEC); port->print_P(PSTR(" to ")); j += 7+1; pid_index[i]->kI(((float)readfloat(buf, &j))/10000000); pid_index[i]->save_gains(); port->println(pid_index[i]->kI(),DEC); } else print_gain_keyword_error(); //------- set kd {servoroll|servopitch|servorudder|navroll|navpitchasp|navpitchalt|throttlete|throttlealt} ------- } else if (strmatch(buf+4, PSTR("kd "))) { int i; unsigned char j = 0; if (get_pid_offset_name(buf+7, &i, &j)) { buf[7+j] = 0; port->print_P(PSTR("D gain for ")); port->print(buf+7); port->print_P(PSTR(" changed from ")); port->print(pid_index[i]->kD(),DEC); port->print_P(PSTR(" to ")); j += 7+1; pid_index[i]->kD(((float)readfloat(buf, &j))/10000000); pid_index[i]->save_gains(); port->println(pid_index[i]->kD(),DEC); } else print_gain_keyword_error(); //------- set kff {pitchcomp|ruddermix|pitchtothrottle} ------- } else if (strmatch(buf+4, PSTR("kff "))) { unsigned char j = 0; if (strmatch(buf+8, PSTR("pitchcomp"))) { buf[8+9] = 0; port->print_P(PSTR("FF gain for ")); port->print(buf+8); port->print_P(PSTR(" changed from ")); port->print(get(PARAM_KFF_PTCHCOMP),DEC); port->print_P(PSTR(" to ")); j = 8+9+1; set(PARAM_KFF_PTCHCOMP, ((float)readfloat(buf, &j))/10000000); port->println(get(PARAM_KFF_PTCHCOMP),DEC); } else if (strmatch(buf+8, PSTR("ruddermix"))) { buf[8+9] = 0; port->print_P(PSTR("FF gain for ")); port->print(buf+8); port->print_P(PSTR(" changed from ")); port->print(get(PARAM_KFF_RDDRMIX),DEC); port->print_P(PSTR(" to ")); j = 8+9+1; set(PARAM_KFF_RDDRMIX, ((float)readfloat(buf, &j))/10000000); port->println(get(PARAM_KFF_RDDRMIX),DEC); } else if (strmatch(buf+8, PSTR("pitchtothrottle"))) { buf[8+15] = 0; port->print_P(PSTR("FF gain for ")); port->print(buf+8); port->print_P(PSTR(" changed from ")); port->print(get(PARAM_KFF_PTCH2THR),DEC); port->print_P(PSTR(" to ")); j = 8+15+1; set(PARAM_KFF_PTCH2THR, ((float)readfloat(buf, &j))/10000000); port->println(get(PARAM_KFF_PTCH2THR),DEC); /*} else if (strmatch(buf+8, PSTR("throttletopitch"))) { buf[8+15] = 0; port->print_P(PSTR("FF gain for ")); port->print(buf+8); port->print_P(PSTR(" changed from ")); port->print(kff[CASE_T_TO_P],DEC); port->print_P(PSTR(" to ")); j = 8+15+1; kff[CASE_T_TO_P] = ((float)readfloat(buf, &j))/10000000; port->println(kff[CASE_T_TO_P],DEC);*/ } else print_gain_keyword_error(); //------- set loiterradius ------- } else if (strmatch(buf+4, PSTR("loiterradius "))) { set(PARAM_LOITER_RADIUS, atoi(buf+17)); port->print_P(PSTR("Set loiter radius to ")); port->print(get(PARAM_LOITER_RADIUS),DEC); port->println_P(PSTR(" meters")); //------- set navrolllimit ------- } else if (strmatch(buf+4, PSTR("navrolllimit "))) { unsigned char j = 17; port->print_P(PSTR("Nav roll limit changed from ")); port->print((float)get(PARAM_LIM_ROLL)/100,2); port->print_P(PSTR(" to ")); set(PARAM_LIM_ROLL, readfloat(buf, &j)/100000); port->println((float)get(PARAM_LIM_ROLL)/100,2); //------- set pitchmax ------- } else if (strmatch(buf+4, PSTR("pitchmax "))) { unsigned char j = 13; port->print_P(PSTR("Maximum pitch changed from ")); port->print((float)get(PARAM_LIM_PITCH_MAX)/100,2); port->print_P(PSTR(" to ")); set(PARAM_LIM_PITCH_MAX, readfloat(buf, &j)/100000); port->println((float)get(PARAM_LIM_PITCH_MAX)/100,2); //------- set pitchmin ------- } else if (strmatch(buf+4, PSTR("pitchmin "))) { unsigned char j = 13; port->print_P(PSTR("Minimum pitch changed from ")); port->print((float)get(PARAM_LIM_PITCH_MIN)/100,2); port->print_P(PSTR(" to ")); set(PARAM_LIM_PITCH_MIN, readfloat(buf, &j)/100000); port->println((float)get(PARAM_LIM_PITCH_MIN)/100,2); //------- set pitchtarget ------- } else if (strmatch(buf+4, PSTR("pitchtarget "))) { unsigned char j = 16; port->print_P(PSTR("Pitch target changed from ")); port->print((float)get(PARAM_TRIM_PITCH)/100,2); port->print_P(PSTR(" to ")); set(PARAM_TRIM_PITCH, readfloat(buf, &j)/100000); port->println((float)get(PARAM_TRIM_PITCH)/100,2); //------- set rcin ------- } else if (strmatch(buf+4, PSTR("rcin"))) { unsigned char index = buf[8]-'1'; if (index < 8) { radio_in[index] = atoi(buf+9); } else print_error(ERR("USAGE: set rcin ")); //------- set rcout ------- } else if (strmatch(buf+4, PSTR("rcout"))) { unsigned char index = buf[9]-'1'; if (index < 8) { radio_out[index] = atoi(buf+10); APM_RC.OutputCh(index, radio_out[index]); } else print_error(ERR("USAGE: set rcout ")); //------- set relay ------- } else if (strmatch(buf+4, PSTR("relay "))) { unsigned char newvalue = atoi(buf+10); if (newvalue == 0) { relay_off(); port->println_P(PSTR("Relay turned off")); } else if (newvalue == 1) { relay_on(); port->println_P(PSTR("Relay turned on")); } else { relay_toggle(); port->println_P(PSTR("Relay toggled")); } //------- set throttlecruise ------- } else if (strmatch(buf+4, PSTR("throttlecruise "))) { port->print_P(PSTR("Throttle cruise changed from ")); port->print(get(PARAM_TRIM_THROTTLE),DEC); port->print_P(PSTR("% to ")); set(PARAM_TRIM_THROTTLE,atoi(buf+19)); port->print(get(PARAM_TRIM_THROTTLE),DEC); port->println_P(PSTR("%")); //------- set throttlefailsafe ------- } else if (strmatch(buf+4, PSTR("throttlefailsafe "))) { set(PARAM_THR_FAILSAFE, atoi(buf+21)); /*if (get(PARAM_THROTTLE_FS) == 0) throttle_FS_enabled = 0; else throttle_FS_enabled = 1;*/ //save_user_configs(); port->println_P(PSTR("Throttle failsafe adjusted.")); //------- set throttlefailsafeaction ------- } else if (strmatch(buf+4, PSTR("throttlefailsafeaction "))) { set(PARAM_THR_FS_ACTION, atoi(buf+27)); //save_user_configs(); //------- set throttlemax ------- } else if (strmatch(buf+4, PSTR("throttlemax "))) { port->print_P(PSTR("Throttle max changed from ")); port->print(get(PARAM_THR_MAX),DEC); port->print_P(PSTR("% to ")); set(PARAM_THR_MAX, atoi(buf+16)); port->print(get(PARAM_THR_MAX),DEC); port->println_P(PSTR("%")); //save_user_configs(); //------- set throttlemin ------- } else if (strmatch(buf+4, PSTR("throttlemin "))) { port->print_P(PSTR("Throttle min changed from ")); port->print(get(PARAM_THR_MIN),DEC); port->print_P(PSTR("% to ")); set(PARAM_THR_MIN, atoi(buf+16)); port->print(get(PARAM_THR_MIN),DEC); port->println_P(PSTR("%")); //save_user_configs(); //------- set wpradius ------- } else if (strmatch(buf+4, PSTR("wpradius "))) { set(PARAM_WP_RADIUS, atoi(buf+13)); port->print_P(PSTR("Set waypoint radius to ")); port->print(get(PARAM_WP_RADIUS),DEC); port->println_P(PSTR(" meters")); //------- set xtrackentryangle ------- } else if (strmatch(buf+4, PSTR("xtrackentryangle "))) { unsigned char j = 21; set(PARAM_XTRACK_ANGLE, readfloat(buf, &j)/100000); port->print_P(PSTR("Crosstrack entry angle set to ")); port->println((float)get(PARAM_XTRACK_ANGLE)/100,2); //------- set xtrackgain ------- } else if (strmatch(buf+4, PSTR("xtrackgain "))) { unsigned char j = 15; set(PARAM_XTRACK_GAIN, ((float)readfloat(buf, &j))/10000000); port->print_P(PSTR("Crosstrack gain set to ")); port->println(get(PARAM_XTRACK_GAIN),2); } else print_error(ERR("USAGE: set {cmd|cmdcount|cmdindex|cruise|holdalt|kp|ki|kd|kff|loiterradius|rcin|rcout|wpradius}")); //*********** Process 'status' commands *********** } else if (strmatch(buf, PSTR("status "))) { //------- status altitude ------- if (strmatch(buf+7, PSTR("altitude"))) { port->printf_P(PSTR("Altitude:\n" " altitude_error = %.2fm\n" " target_altitude = %.2fm\n" " next_WP.alt = %.2fm\n" " wp_distance = %ldm\n" " wp_totalDistance = %ldm\n" " offset_altitude = %.2fm\n"), (float)altitude_error/100, (float)target_altitude/100, (float)next_WP.alt/100, wp_distance, wp_totalDistance, (float)offset_altitude/100); //------- status climb ------- } else if (strmatch(buf+7, PSTR("climb"))) { print_climb_debug_info(); //------- status control ------- } else if (strmatch(buf+7, PSTR("control"))) { port->printf_P(PSTR("Control status:\n" " Roll: nav= %.2f, servo_out= %.2f\n" // XXX float? " Pitch: nav= %.2f, servo_out= %.2f\n" // XXX float? " Throttle: nav= %d, servo_out= %d\n"), (float)nav_roll / 100, (float)servo_out[CH_ROLL] / 100, (float)nav_pitch / 100, (float)servo_out[CH_PITCH] / 100, get(PARAM_TRIM_THROTTLE), servo_out[CH_THROTTLE]); //------- status gps ------- } else if (strmatch(buf+7, PSTR("gps"))) { port->printf_P(PSTR("GPS status:\n" " Fix: %S (%d)\n" " Satellites: %d\n" " Fix count: %d\n"), (gps.fix ? PSTR("Valid") : PSTR("INVALID")), (int)gps.fix, (int)gps.num_sats, gps_fix_count); //------- status landing ------- } else if (strmatch(buf+7, PSTR("landing"))) { port->printf_P(PSTR("Landing status:" " land_complete = %d\n" " landing_pitch = %d\n" " nav_pitch = %ld\n" " airspeed_cruise = %d\n" " throttle_cruise = %d\n" " hold_course = %ld\n" " nav_bearing = %ld\n" " bearing_error = %ld\n"), (int)land_complete, landing_pitch, nav_pitch, get(PARAM_TRIM_AIRSPEED), get(PARAM_TRIM_THROTTLE), hold_course, nav_bearing, bearing_error); //------- status loiter ------- } else if (strmatch(buf+7, PSTR("loiter"))) { port->printf_P(PSTR("Loiter status:" " Loiter radius: %d\n" " Progress: %d/%d\n" // XXX original had non-ASCII units char " Time: %ldms/%dms\n"), get(PARAM_LOITER_RADIUS), loiter_sum, loiter_total, loiter_time, loiter_time_max); //------- status navigation ------- } else if (strmatch(buf+7, PSTR("navigation"))) { port->printf_P(PSTR("Navigation status:\n" " From <%.6f, %.6f, %.1f>: "), (float)prev_WP.lat/10000000.0, (float)prev_WP.lng/10000000.0, (float)prev_WP.alt/100.0); print_rlocation(&prev_WP); port->printf_P(PSTR(" At <%.6f, %.6f, %.1f>\n"), (float)current_loc.lat/10000000.0, (float)current_loc.lng/10000000.0, (float)current_loc.alt/100.0); port->printf_P(PSTR(" To <%.6f, %.6f, %.1f>: "), (float)next_WP.lat/10000000.0, (float)next_WP.lng/10000000.0, (float)next_WP.alt/100.0); print_rlocation(&next_WP); port->printf_P(PSTR(" Distance: %.1f%% %ldm / %ldm; %.1f vertically\n"), 100.0*(float)(wp_totalDistance-wp_distance)/(float)wp_totalDistance, wp_totalDistance-wp_distance, wp_totalDistance, (float)altitude_error/100.0); port->printf_P(PSTR(" Nav bearing: %.2f; error = %.2f\n"), (float)nav_bearing/100.0, (float)bearing_error/100.0); port->printf_P(PSTR(" Ground course: %.1f (current), %.1f (target)\n"), (float)gps.ground_course/100.0, (float)target_bearing/100.0); if (hold_course >= 0) { port->print_P(PSTR(" HOLD COURSE: ")); port->println(hold_course/100.0,2); } //------- status navpitch ------- } else if (strmatch(buf+7, PSTR("navpitch"))) { #if AIRSPEED_SENSOR == ENABLED port->printf_P(PSTR(">>> nav_pitch = PID[airspeed_error (%.2f) = airspeed_cruise (%.2f) - airspeed (%.2f)]\n"), (float)airspeed_error / 100, (float)get(PARAM_TRIM_AIRSPEED) / 100, (float)airspeed / 100); #else port->printf_P(PSTR(">>> nav_pitch = PID[altitude_error (%ld) = target_altitude (%ld) - current_loc.alt (%ld)]\n"), altitude_error, target_altitude, current_loc.alt); #endif port->printf_P(PSTR("nav_pitch (%.2f) - pitch_sensor (%.2f) + pitch_comp (%.2f) = %.2f\n"), (float)nav_pitch / 100, (float)dcm.pitch_sensor / 100, fabs(dcm.roll_sensor * get(PARAM_KFF_PTCHCOMP)) / 100, (float)(nav_pitch-dcm.pitch_sensor + fabs(dcm.roll_sensor * get(PARAM_KFF_PTCHCOMP))) / 100); port->printf_P(PSTR("servo_out[CH_PITCH] (%.2f) = PID[nav_pitch + pitch_comp - pitch_sensor]"), (float)servo_out[CH_PITCH] / 100); //------- status navroll ------- } else if (strmatch(buf+7, PSTR("navroll"))) { print_rlocation(&next_WP); port->printf_P(PSTR("bearing_error (%ld) = nav_bearing (%ld) - yaw_sensor (%ld)\n" "nav_roll (%ld) - roll_sensor (%ld) = %ld\n" "servo_out[CH_ROLL] = %d\n"), bearing_error, nav_bearing, dcm.yaw_sensor, nav_roll, dcm.roll_sensor, nav_roll - dcm.roll_sensor, servo_out[CH_ROLL]); //------- status pid {servoroll|servopitch|servorudder|navroll|navpitchasp|navpitchalt|throttlete|throttlealt} ------- } else if (strmatch(buf+7, PSTR("pid "))) { int i; unsigned char j; if (get_pid_offset_name(buf+11, &i, &j)) { port->print(buf+11); port->print_P(PSTR(": ")); display_PID = i; //The next time a PID calculation is performed on this channel, the print_PID routine in this GCS will be called } else print_error(ERR("ERROR: Did not recognize keyword")); //------- status rcinputch ------- } else if (strmatch(buf+7, PSTR("rcinputch"))) { unsigned char i; port->println_P(PSTR("RC hardware input:")); for (i=0; i<8; i++) { port->print_P(PSTR(" Ch")); port->print(i+1,DEC); port->print_P(PSTR(": ")); port->println(APM_RC.InputCh(i)); } //------- status rcin ------- } else if (strmatch(buf+7, PSTR("rcin"))) { unsigned char i; port->println_P(PSTR("RC software input:")); for (i=0; i<8; i++) { port->print_P(PSTR(" Ch")); port->print(i+1,DEC); port->print_P(PSTR(": ")); port->println(radio_in[i]); } //------- status rcout ------- } else if (strmatch(buf+7, PSTR("rcout"))) { unsigned char i; port->println_P(PSTR("RC software output:")); for (i=0; i<8; i++) { port->print_P(PSTR(" Ch")); port->print(i+1,DEC); port->print_P(PSTR(": ")); port->println(radio_out[i]); } //------- status rcpwm ------- } else if (strmatch(buf+7, PSTR("rcpwm"))) { unsigned char i; port->println_P(PSTR("RC hardware output:")); for (i=0; i<8; i++) { port->print_P(PSTR(" Ch")); port->print(i+1,DEC); port->print_P(PSTR(": ")); port->println(readOutputCh(i)); } //------- status rctrim ------- } else if (strmatch(buf+7, PSTR("rctrim"))) { unsigned char i; port->println_P(PSTR("RC trim:")); for (i=0; i<8; i++) { port->print_P(PSTR(" Ch")); port->print(i+1,DEC); port->print_P(PSTR(": ")); port->println(radio_trim(i)); } port->print_P(PSTR(" elevon1_trim = ")); port->println(elevon1_trim,DEC); port->print_P(PSTR(" elevon2_trim = ")); port->println(elevon2_trim,DEC); //------- status rc ------- } else if (strmatch(buf+7, PSTR("rc"))) { unsigned char i; port->println_P(PSTR("RC:\tCh\tHWin\tSWtrim\tSWin\tServo\tSWout\tHWout\t")); for (i=0; i<8; i++) { // XXX might benefit from field widths, since some terminals tab badly port->printf_P(PSTR("\t%u\t%u\t%u\t%u\t%.2f\t%d\t%d\n"), (unsigned int)(i + 1), APM_RC.InputCh(i), radio_trim(i), radio_in[i], (float)servo_out[i] / 100, radio_out[i], readOutputCh(i)); } //------- status system ------- } else if (strmatch(buf+7, PSTR("system"))) { port->printf_P(PSTR("System status:" " Ground start: %S (%d)\n" " Home: %SSET (%d)\n"), (ground_start ? PSTR("YES") : PSTR("NO")), (int)ground_start, (home_is_set ? PSTR("") : PSTR("NOT ")), (int)home_is_set); //------- status takeoff ------- /*} else if (strmatch(buf+7, PSTR("takeoff"))) { port->println_P(PSTR("Takeoff status:")); port->print_P(PSTR(" takeoff in progress: ")); if (takeoff_in_progress) port->println_P(PSTR("YES")); else { port->print_P(PSTR("NO; trigger = ")); port->print(toss_trigger,DEC); port->print_P(PSTR(", current = ")); Vector3f temp = ardupilotDCM.get_accels(); port->println(abs(temp.y),1); } port->printf_P(PSTR(" takeoff_pitch = %.2f\n" " scaler = %.3f\n" " nav_pitch = %.2f\n" " throttle = %d\n" " hold_course = %.2f\n" " nav_bearing = %ld\n" " bearing_error = %ld\n" " current_loc.alt = %ld\n" " home.alt + takeoff_altitude = %ld"), (float)takeoff_pitch / 100, (float)airspeed / (float)airspeed_cruise, (float)nav_pitch / 100, servo_out[CH_THROTTLE], (float)hold_course / 100, nav_bearing, bearing_error, current_loc.alt, home.alt + takeoff_altitude);*/ //------- status telemetry ------- } else if (strmatch(buf+7, PSTR("telemetry"))) { port->printf_P(PSTR("Telemetry status:\n" " %S heartbeat\n" " %S location\n" " %S attitude\n" " %S command\n" " Severity report level %d\n"), (report_heartbeat ? PSTR("Show") : PSTR("Hide")), (report_location ? PSTR("Show") : PSTR("Hide")), (report_attitude ? PSTR("Show") : PSTR("Hide")), (report_command ? PSTR("Show") : PSTR("Hide")), (int)report_severity); //------- status throttle ------- } else if (strmatch(buf+7, PSTR("throttle"))) { #if AIRSPEED_SENSOR == ENABLED port->printf_P(PSTR(">>> airspeed_energy_error (%ld) = 0.5 * (airspeed_cruise (%.2f)^2 - airspeed (%.2f)^2)\n" "energy_error (%ld) = airspeed_energy_error (%ld) + altitude_error*0.098 (%ld)\n" "servo_out[CH_THROTTLE] (%d) = PID[energy_error]\n"), airspeed_energy_error, (float)get(PARAM_TRIM_AIRSPEED) / 100, (float)airspeed / 100, energy_error, airspeed_energy_error, (long)((float)altitude_error * 0.098), servo_out[CH_THROTTLE]); #else port->printf_P(PSTR("altitude_error (%ld) = target_altitude (%ld) - current_loc.alt (%ld)\n" "servo_out[CH_THROTTLE] (%d) = PID[altitude_error]\n"), altitude_error, target_altitude, current_loc.alt, servo_out[CH_THROTTLE]); #endif //------- status waypoints ------- } else if (strmatch(buf+7, PSTR("waypoints"))) { port->printf_P(PSTR("Waypoints status:\n" " Distance: %ld/%ld\n" " Index: %d/%d\n" " Next: %d\n"), wp_distance, wp_totalDistance, (int)get(PARAM_WP_INDEX), (int)get(PARAM_WP_TOTAL), (int)next_wp_index); } else if (strmatch(buf+7, PSTR("james"))) { port->println_P(PSTR("James is a monkey")); } else { print_error(ERR("USAGE: status {control|gps|landing|loiter|mixing|navigation|navpitch|navroll|rc|rcinputch|rcin|rcout|rcpwm|rctrim|system|takeoff|telemetry|throttle|waypoints}")); } } else { print_error(ERR("USAGE: {echo |groundstart|inithome|show|hide|print|status|set|reset|rtl}")); print_error(ERR("Type -? for specific usage guidance")); } } /* strmatch compares two strings and returns 1 if they match and 0 if they don't s2 must be stored in program memory (via PSTR) rather than RAM (like standard strings) s1 must be at least as long as s2 for a valid match if s1 is longer than s2, then only the beginning of s1 (the length of s2) must match s2 for a valid match */ int GCS_DEBUGTERMINAL::strmatch(char* s1, const char* s2) { int i = 0; char c1 = s1[0], c2 = pgm_read_byte(s2); while (c1 != 0 && c2 != 0) { if (c1 < c2) return 0; if (c1 > c2) return 0; i++; c1 = s1[i]; c2 = pgm_read_byte(s2+i); } if (c2==0) return 1; else return 0; } /* readfloat parses a string written as a float starting at the offset in *i and updates *i as it parses numbers are multiplied by 10,000,000 and decimals beyond 7 places are discarded parsing is terminated with either a space or a null, other characters are ignored */ long GCS_DEBUGTERMINAL::readfloat(char* s, unsigned char* i) { long result = 0, multiplier = 0; char c, neg = 0; for (;;(*i)++) { c = s[*i]; if (c == ' ') break; else if (c == 0) break; else if (c == '-') neg = 1-neg; else if (c == '.') { result *= 10000000; multiplier = 1000000; } else if (c >= '0' && c <= '9') { if (multiplier == 0) result = (result*10) + c-'0'; else { result += (c-'0')*multiplier; multiplier /= 10; } } } if (multiplier == 0) result *= 10000000; if (neg) return -result; else return result; } /* process_set_cmd processing the parameters of a 'set cmd' command and takes the appropriate action *buffer is the buffer containing the parameters of the command; it should start after the space after 'set cmd' bufferlen is the length of the buffer; the routine will stop looking for parameters after the offset index reaches this value */ #define SETPARAM_NONE (0) #define SETPARAM_ID (1) #define SETPARAM_P1 (2) #define SETPARAM_LAT (3) #define SETPARAM_LNG (4) #define SETPARAM_ALT (5) #define SETPARAM_P2 (6) #define SETPARAM_P3 (7) #define SETPARAM_P4 (8) void GCS_DEBUGTERMINAL::process_set_cmd(char *buffer, int bufferlen) { BetterStream *port = _port; unsigned char i, j, err=1, setparam=SETPARAM_NONE; unsigned char cmdindex=0, p1=0, cmdid; long lat, lng, alt; Location temp; //Parse the command index for (i=0; i= '0' && buffer[i] <= '9') cmdindex = (cmdindex*10) + buffer[i]-'0'; else break; if (buffer[i] == ' ') { //Find the end of the command-type string i++; for (j=i; j SETPARAM_NONE) { //Process new parameter value i = j+1; if (setparam == SETPARAM_ALT || setparam == SETPARAM_LAT || setparam == SETPARAM_LNG) { lat = readfloat(buffer, &i); } else { unsigned char k; for (k=i; i= '0' && buffer[k] <= '9')) break; buffer[k] = 0; lat = atol(buffer+i); i = k; } temp = get_wp_with_index(cmdindex); if (setparam == SETPARAM_ID) temp.id = lat; else if (setparam == SETPARAM_P1) temp.p1 = lat; else if (setparam == SETPARAM_ALT) temp.alt = lat/100000; else if (setparam == SETPARAM_LAT) temp.lat = lat; else if (setparam == SETPARAM_LNG) temp.lng = lat; else if (setparam == SETPARAM_P2) temp.alt = lat; else if (setparam == SETPARAM_P3) temp.lat = lat; else if (setparam == SETPARAM_P4) temp.lng = lat; cmdid = temp.id; p1 = temp.p1; lat = temp.lat; lng = temp.lng; alt = temp.alt; err = 0; } else { //Process param 1 for (i=j+1; i= '0' && buffer[i] <= '9') p1 = (p1*10) + buffer[i]-'0'; else break; } if (buffer[i] == ' ') { //Process altitude i++; if (strmatch(buffer+i, PSTR("here"))) { lat = gps.latitude; lng = gps.longitude; alt = get_altitude_above_home(); //GPS.altitude; err = 0; } else { alt = readfloat(buffer, &i)/100000; if (buffer[i] == ' ') { //Process latitude i++; lat = readfloat(buffer, &i); if (strmatch(buffer+i, PSTR("here"))) { lat = gps.latitude; lng = gps.longitude; err = 0; } else { if (buffer[i] == ' ') { //Process longitude i++; lng = readfloat(buffer, &i); //TODO: add other command special cases here if (cmdid == CMD_LAND_OPTIONS) { temp.p1 = p1; temp.alt = alt; temp.lat = lat / 10000000; temp.lng = lng / 10000000; } err = 0; } else print_error(ERR("Error processing set cmd: Could not find longitude parameter")); } } else print_error(ERR("Error processing set cmd: Could not find latitude parameter")); } } else print_error(ERR("Error processing set cmd: Could not find altitude parameter")); } } else print_error(ERR("Error processing set cmd: Could not find command type")); } else print_error(ERR("Error processing set cmd: Could not find command index")); if (err == 0) { temp.id = cmdid; temp.p1 = p1; temp.lat = lat; temp.lng = lng; temp.alt = alt; if (cmdindex >= get(PARAM_WP_TOTAL)) { set(PARAM_WP_TOTAL, cmdindex+1); } set_wp_with_index(temp, cmdindex); port->printf_P(PSTR("Set command %d to %d with p1=%d, lat=%ld, lng=%ld, alt=%ld\n"), (int)cmdindex, (int)temp.id, (int)temp.p1, temp.lat, temp.lng, temp.alt); } } /* get_pid_offset_name matches a string expressed in *buffer with a pid keyword and returns the k-array gain offset in *offset, and the length of that string expression in *length. If a good keyword match is found, 1 is returned; 0 otherwise */ int GCS_DEBUGTERMINAL::get_pid_offset_name(char *buffer, int *offset, unsigned char *length) { if (strmatch(buffer, PSTR("servoroll"))) { *length += 9; *offset = CASE_SERVO_ROLL; } else if (strmatch(buffer, PSTR("servopitch"))) { *length += 10; *offset = CASE_SERVO_PITCH; } else if (strmatch(buffer, PSTR("servorudder"))) { *length += 11; *offset = CASE_SERVO_RUDDER; } else if (strmatch(buffer, PSTR("navroll"))) { *length += 7; *offset = CASE_NAV_ROLL; } else if (strmatch(buffer, PSTR("navpitchasp"))) { *length += 11; *offset = CASE_NAV_PITCH_ASP; } else if (strmatch(buffer, PSTR("navpitchalt"))) { *length += 11; *offset = CASE_NAV_PITCH_ALT; } else if (strmatch(buffer, PSTR("throttlete"))) { *length += 10; *offset = CASE_TE_THROTTLE; } else if (strmatch(buffer, PSTR("throttlealt"))) { *length += 11; *offset = CASE_ALT_THROTTLE; } else { return 0; } return 1; } /* print_rlocation prints the relative location of the specified waypoint from the plane in easy-to-read cartesian format */ void GCS_DEBUGTERMINAL::print_rlocation(Location *wp) { //float x, y; //y = (float)(wp->lat - current_loc.lat) * 0.0111194927; //x = (float)(wp->lng - current_loc.lng) * cos(radians(current_loc.lat)) * 0.0111194927; BetterStream *port = _port; int x, y; y = (wp->lat - current_loc.lat) * 0.0111194927; x = (wp->lng - current_loc.lng) * cos(radians(current_loc.lat)) * 0.0111194927; port->printf_P(PSTR("dP = <%d%c, %d%c, %.1f> meters\n"), abs(y), (y >= 0 ? 'N' : 'S'), abs(x), (x >= 0 ? 'E' : 'W'), (float)(wp->alt - current_loc.alt) / 100); } /* print_error prints an error message if the user sends an invalid command */ void GCS_DEBUGTERMINAL::print_error(const char *msg) { BetterStream *port = _port; if (msg == 0) port->println_P(PSTR("ERROR: Invalid command")); else port->println_P(msg); } void GCS_DEBUGTERMINAL::send_text(uint8_t severity, const char *str) { BetterStream *port = _port; if(severity >= DEBUG_LEVEL){ port->print_P(PSTR("MSG: ")); port->println(str); } } void GCS_DEBUGTERMINAL::send_message(uint8_t id, uint32_t param) { switch(id) { case MSG_MODE_CHANGE: print_control_mode(); break; case MSG_HEARTBEAT: if (report_heartbeat) print_control_mode(); break; case MSG_ATTITUDE: if (report_attitude) print_attitude(); break; case MSG_LOCATION: if (report_location) print_position(); if (first_location == 0) { send_text(0,"First location received"); first_location = 1; } break; case MSG_CPU_LOAD: if (report_cpu_load) { _port->printf_P(PSTR("MSG: load %ld%%\n"), param); } break; case MSG_COMMAND_LIST: struct Location cmd = get_wp_with_index(param); print_command(&cmd, param); break; } } void GCS_DEBUGTERMINAL::print_current_waypoints() { _port->printf_P(PSTR("Current waypoints:" " Prev:\t%ld,\t%ld\t%ld\n" " Cur: \t%ld,\t%ld\t%ld\n" " Next:%d\t%ld,\t%ld\t%ld\n"), prev_WP.lat, prev_WP.lng, prev_WP.alt, current_loc.lat, current_loc.lng, current_loc.alt, (int)get(PARAM_WP_INDEX), next_WP.lat, next_WP.lng, next_WP.alt); } void GCS_DEBUGTERMINAL::print_position(void) { recalc_climb_rate(); _port->printf_P(PSTR("Pos: %ld, %ld, %ldcm, %ldcm/s GS, %d cm/s AS, %d cm above home, %d? climb, %ldm from wp, %d%% throttle, %ld alt err\n"), current_loc.lat, current_loc.lng, current_loc.alt, gps.ground_speed, airspeed, get_altitude_above_home(), climb_rate, wp_distance, get(PARAM_TRIM_THROTTLE), altitude_error); } void GCS_DEBUGTERMINAL::print_attitude(void) { _port->printf_P(PSTR("Att: %u roll_in, %u pitch in, %u throttle_in, " "%ld roll_sensor, %ld pitch_sensor, " "%ld ground_course, %ld target_bearing, " "%ld nav_roll, %d loiter_sum, " "%d roll servo_out, %d pitch_servo_out\n"), radio_in[CH_ROLL], radio_in[CH_PITCH], radio_in[CH_THROTTLE], dcm.roll_sensor, dcm.pitch_sensor, gps.ground_course, target_bearing, nav_roll, loiter_sum, servo_out[CH_ROLL], servo_out[CH_PITCH]); } // required by Groundstation to plot lateral tracking course void GCS_DEBUGTERMINAL::print_new_wp_info() { _port->printf_P(PSTR("New waypt (%d): %ld, %ld, %ldm -> " "%ld, %ld, %ldm; " "%ldm dist, %u roll trim, %u pitch trim\n"), (int)get(PARAM_WP_INDEX), prev_WP.lat, prev_WP.lng, prev_WP.alt, next_WP.lat, next_WP.lng, next_WP.alt, wp_totalDistance, radio_trim(CH_ROLL), radio_trim(CH_PITCH)); } void GCS_DEBUGTERMINAL::print_control_mode(void) { BetterStream *port = _port; switch (control_mode){ case MANUAL: port->println_P(PSTR("##MANUAL")); break; case STABILIZE: port->println_P(PSTR("##STABILIZE")); break; case FLY_BY_WIRE_A: port->println_P(PSTR("##FBW A")); break; case FLY_BY_WIRE_B: port->println_P(PSTR("##FBW B")); break; case AUTO: port->println_P(PSTR("##AUTO")); break; case RTL: port->println_P(PSTR("##RTL")); break; case LOITER: port->println_P(PSTR("##LOITER")); break; case 98: port->println_P(PSTR("##Air Start Complete")); break; case 99: port->println_P(PSTR("##Ground Start Complete")); break; } } void GCS_DEBUGTERMINAL::print_tuning(void) { _port->printf_P(PSTR("TUN:%d, %ld, %ld, %d, %ld, %ld\n"), servo_out[CH_ROLL], nav_roll / 100, dcm.roll_sensor / 100, servo_out[CH_PITCH], nav_pitch / 100, dcm.pitch_sensor / 100); } void GCS_DEBUGTERMINAL::print_command_id(byte id) { BetterStream *port = _port; switch (id) { // Command IDs - Must case CMD_BLANK: port->print_P(PSTR("CMD_BLANK")); break; case CMD_WAYPOINT: port->print_P(PSTR("waypoint")); break; case CMD_LOITER: port->print_P(PSTR("loiter")); break; case CMD_LOITER_N_TURNS: port->print_P(PSTR("loiternturns")); break; case CMD_LOITER_TIME: port->print_P(PSTR("loitertime")); break; case CMD_RTL: port->print_P(PSTR("rtl")); break; case CMD_LAND: port->print_P(PSTR("land")); break; case CMD_TAKEOFF: port->print_P(PSTR("takeoff")); break; // Command IDs - May case CMD_DELAY: port->print_P(PSTR("delay")); break; case CMD_CLIMB: port->print_P(PSTR("climb")); break; case CMD_LAND_OPTIONS: port->print_P(PSTR("landoptions")); break; // Command IDs - Now case CMD_RESET_INDEX: port->print_P(PSTR("resetindex")); break; case CMD_GOTO_INDEX: port->print_P(PSTR("CMD_GOTO_INDEX")); break; case CMD_GETVAR_INDEX: port->print_P(PSTR("CMD_GETVAR_INDEX")); break; case CMD_SENDVAR_INDEX: port->print_P(PSTR("CMD_SENDVAR_INDEX")); break; case CMD_TELEMETRY: port->print_P(PSTR("CMD_TELEMETRY")); break; case CMD_THROTTLE_CRUISE: port->print_P(PSTR("throttlecruise")); break; case CMD_AIRSPEED_CRUISE: port->print_P(PSTR("CMD_AIRSPEED_CRUISE")); break; case CMD_RESET_HOME: port->print_P(PSTR("resethome")); break; case CMD_KP_GAIN: port->print_P(PSTR("CMD_KP_GAIN")); break; case CMD_KI_GAIN: port->print_P(PSTR("CMD_KI_GAIN")); break; case CMD_KD_GAIN: port->print_P(PSTR("CMD_KD_GAIN")); break; case CMD_KI_MAX: port->print_P(PSTR("CMD_KI_MAX")); break; case CMD_KFF_GAIN: port->print_P(PSTR("CMD_KFF_GAIN")); break; case CMD_RADIO_TRIM: port->print_P(PSTR("CMD_RADIO_TRIM")); break; case CMD_RADIO_MAX: port->print_P(PSTR("CMD_RADIO_MAX")); break; case CMD_RADIO_MIN: port->print_P(PSTR("CMD_RADIO_MIN")); break; case CMD_ELEVON_TRIM: port->print_P(PSTR("CMD_ELEVON_TRIM")); break; case CMD_INDEX: port->print_P(PSTR("index")); break; case CMD_REPEAT: port->print_P(PSTR("CMD_REPEAT")); break; case CMD_RELAY: port->print_P(PSTR("relay")); break; case CMD_SERVO: port->print_P(PSTR("servo")); break; default: port->print(id,DEC); } } void GCS_DEBUGTERMINAL::print_command(struct Location *cmd,byte index) { BetterStream *port = _port; port->print_P(PSTR(" command #: ")); port->print(index, DEC); port->print_P(PSTR(" id: ")); print_command_id(cmd->id); port->print_P(PSTR(" p1: ")); port->print(cmd->p1,DEC); port->print_P(PSTR(" p2/alt: ")); port->print(cmd->alt,DEC); port->print_P(PSTR(" p3/lat: ")); port->print(cmd->lat,DEC); port->print_P(PSTR(" p4/lng: ")); port->println(cmd->lng,DEC); } void GCS_DEBUGTERMINAL::print_commands() { print_commands(1, get(PARAM_WP_TOTAL)); } void GCS_DEBUGTERMINAL::print_commands(unsigned char i1, unsigned char i2) { BetterStream *port = _port; port->println_P(PSTR("Commands in memory:")); port->print_P(PSTR(" ")); port->print(get(PARAM_WP_TOTAL), DEC); port->println_P(PSTR(" commands total")); // create a location struct to hold the temp Waypoints for printing //Location tmp; port->println_P(PSTR(" Home: ")); struct Location cmd = get_wp_with_index(0); print_command(&cmd, 0); port->println_P(PSTR(" Commands: ")); for (int i=i1; i<=i2; i++){ cmd = get_wp_with_index(i); print_command(&cmd, i); delay(10); } } void GCS_DEBUGTERMINAL::print_gains() { BetterStream *port = _port; unsigned char i; port->println_P(PSTR("PID gains \tP \tI \tD \tIMax)")); port->print_P(PSTR("Servo roll \t")); print_gain(CASE_SERVO_ROLL); port->print_P(PSTR("Servo pitch \t")); print_gain(CASE_SERVO_PITCH); port->print_P(PSTR("Servo yaw \t")); print_gain(CASE_SERVO_RUDDER); port->print_P(PSTR("Nav roll \t")); print_gain(CASE_NAV_ROLL); port->print_P(PSTR("Nav pitch \t")); if (AIRSPEED_SENSOR) print_gain(CASE_NAV_PITCH_ASP); else print_gain(CASE_NAV_PITCH_ALT); port->print_P(PSTR("Nav throttle\t")); if (AIRSPEED_SENSOR) print_gain(CASE_TE_THROTTLE); else print_gain(CASE_ALT_THROTTLE); port->println_P(PSTR("Feed-forward gains")); port->print_P(PSTR("Pitch compensation\t")); port->println(get(PARAM_KFF_PTCHCOMP),3); port->print_P(PSTR("Rudder mix \t")); port->println(get(PARAM_KFF_RDDRMIX),3); port->print_P(PSTR("Pitch to throttle \t")); port->println(get(PARAM_KFF_PTCH2THR),3); //port->print_P(PSTR("Throttle to pitch \t")); port->println(kff[CASE_T_TO_P],3); } void GCS_DEBUGTERMINAL::print_gain(unsigned char g) { BetterStream *port = _port; port->print(pid_index[g]->kP(),3); port->print_P(PSTR("\t")); port->print(pid_index[g]->kI(),3); port->print_P(PSTR("\t")); port->print(pid_index[g]->kD(),3); port->print_P(PSTR("\t")); port->println(pid_index[g]->imax(),DEC); } void GCS_DEBUGTERMINAL::print_gain_keyword_error() { print_error(ERR("ERROR: Did not recognize keyword; type k -? for more information")); } void GCS_DEBUGTERMINAL::print_PID(long PID_error, long dt, float scaler, float derivative, float integrator, float last_error) { BetterStream *port = _port; port->print_P(PSTR("P = ")); port->print(pid_index[display_PID]->kP() * scaler * (float)PID_error,2); port->print_P(PSTR(",\tI = ")); port->print(integrator,2); port->print_P(PSTR(",\tD = ")); port->print(pid_index[display_PID]->kD() * scaler * derivative,2); port->print_P(PSTR("\terrors = {")); port->print(PID_error,DEC); port->print_P(PSTR(", ")); port->print(last_error,DEC); port->print_P(PSTR("} with dt = ")); port->println(dt,DEC); display_PID = -1; } #endif // GCS_PROTOCOL_DEBUGTERMINAL