Code for autonomous ground vehicle, Data Bus, 3rd place winner in 2012 Sparkfun AVC.

Dependencies:   Watchdog mbed Schedule SimpleFilter LSM303DLM PinDetect DebounceIn Servo

Committer:
shimniok
Date:
Wed Jun 20 14:57:48 2012 +0000
Revision:
0:826c6171fc1b
Updated documentation

Who changed what in which revision?

UserRevisionLine numberNew contents of line
shimniok 0:826c6171fc1b 1 /** Code for "Data Bus" UGV entry for Sparkfun AVC 2012
shimniok 0:826c6171fc1b 2 * http://www.bot-thoughts.com/
shimniok 0:826c6171fc1b 3 */
shimniok 0:826c6171fc1b 4
shimniok 0:826c6171fc1b 5 ///////////////////////////////////////////////////////////////////////////////////////////////////////
shimniok 0:826c6171fc1b 6 // INCLUDES
shimniok 0:826c6171fc1b 7 ///////////////////////////////////////////////////////////////////////////////////////////////////////
shimniok 0:826c6171fc1b 8
shimniok 0:826c6171fc1b 9 #include <stdio.h>
shimniok 0:826c6171fc1b 10 #include <math.h>
shimniok 0:826c6171fc1b 11 #include "mbed.h"
shimniok 0:826c6171fc1b 12 #include "globals.h"
shimniok 0:826c6171fc1b 13 #include "Config.h"
shimniok 0:826c6171fc1b 14 #include "Buttons.h"
shimniok 0:826c6171fc1b 15 #include "Menu.h"
shimniok 0:826c6171fc1b 16 //#include "lcd.h"
shimniok 0:826c6171fc1b 17 #include "SerialGraphicLCD.h"
shimniok 0:826c6171fc1b 18 #include "Bargraph.h"
shimniok 0:826c6171fc1b 19 #include "GPSStatus.h"
shimniok 0:826c6171fc1b 20 #include "logging.h"
shimniok 0:826c6171fc1b 21 #include "shell.h"
shimniok 0:826c6171fc1b 22 #include "Sensors.h"
shimniok 0:826c6171fc1b 23 //#include "DCM.h"
shimniok 0:826c6171fc1b 24 //#include "dcm_matrix.h"
shimniok 0:826c6171fc1b 25 #include "kalman.h"
shimniok 0:826c6171fc1b 26 #include "GPS.h"
shimniok 0:826c6171fc1b 27 #include "Camera.h"
shimniok 0:826c6171fc1b 28 #include "PinDetect.h"
shimniok 0:826c6171fc1b 29 #include "Actuators.h"
shimniok 0:826c6171fc1b 30 #include "IncrementalEncoder.h"
shimniok 0:826c6171fc1b 31 #include "Steering.h"
shimniok 0:826c6171fc1b 32 #include "Schedule.h"
shimniok 0:826c6171fc1b 33 #include "GeoPosition.h"
shimniok 0:826c6171fc1b 34 #include "Mapping.h"
shimniok 0:826c6171fc1b 35 #include "SimpleFilter.h"
shimniok 0:826c6171fc1b 36 #include "Beep.h"
shimniok 0:826c6171fc1b 37 #include "util.h"
shimniok 0:826c6171fc1b 38 #include "MAVlink/include/mavlink_bridge.h"
shimniok 0:826c6171fc1b 39 #include "updater.h"
shimniok 0:826c6171fc1b 40
shimniok 0:826c6171fc1b 41 #define LCD_FMT "%-20s" // used to fill a single line on the LCD screen
shimniok 0:826c6171fc1b 42
shimniok 0:826c6171fc1b 43 ///////////////////////////////////////////////////////////////////////////////////////////////////////
shimniok 0:826c6171fc1b 44 // DEFINES
shimniok 0:826c6171fc1b 45 ///////////////////////////////////////////////////////////////////////////////////////////////////////
shimniok 0:826c6171fc1b 46
shimniok 0:826c6171fc1b 47 #define absf(x) (x *= (x < 0.0) ? -1 : 1)
shimniok 0:826c6171fc1b 48
shimniok 0:826c6171fc1b 49 #define GPS_MIN_SPEED 2.0 // speed below which we won't trust GPS course
shimniok 0:826c6171fc1b 50 #define GPS_MAX_HDOP 2.0 // HDOP above which we won't trust GPS course/position
shimniok 0:826c6171fc1b 51
shimniok 0:826c6171fc1b 52 #define UPDATE_PERIOD 0.010 // update period in s
shimniok 0:826c6171fc1b 53 #define UPDATE_PERIOD_MS 10 // update period in ms
shimniok 0:826c6171fc1b 54
shimniok 0:826c6171fc1b 55 // Driver configuration parameters
shimniok 0:826c6171fc1b 56 #define SONARLEFT_CHAN 0
shimniok 0:826c6171fc1b 57 #define SONARRIGHT_CHAN 1
shimniok 0:826c6171fc1b 58 #define IRLEFT_CHAN 2
shimniok 0:826c6171fc1b 59 #define IRRIGHT_CHAN 3
shimniok 0:826c6171fc1b 60 #define TEMP_CHAN 4
shimniok 0:826c6171fc1b 61 #define GYRO_CHAN 5
shimniok 0:826c6171fc1b 62
shimniok 0:826c6171fc1b 63 // Chassis specific parameters
shimniok 0:826c6171fc1b 64 #define WHEEL_CIRC 0.321537 // m; calibrated with 4 12.236m runs. Measured 13.125" or 0.333375m circumference
shimniok 0:826c6171fc1b 65 #define WHEELBASE 0.290
shimniok 0:826c6171fc1b 66 #define TRACK 0.280
shimniok 0:826c6171fc1b 67
shimniok 0:826c6171fc1b 68 #define INSTRUMENT_CHECK 0
shimniok 0:826c6171fc1b 69 #define AHRS_VISUALIZATION 1
shimniok 0:826c6171fc1b 70 #define DISPLAY_PANEL 2
shimniok 0:826c6171fc1b 71
shimniok 0:826c6171fc1b 72 ///////////////////////////////////////////////////////////////////////////////////////////////////////
shimniok 0:826c6171fc1b 73 // GLOBAL VARIABLES
shimniok 0:826c6171fc1b 74 ///////////////////////////////////////////////////////////////////////////////////////////////////////
shimniok 0:826c6171fc1b 75
shimniok 0:826c6171fc1b 76 // OUTPUT
shimniok 0:826c6171fc1b 77 DigitalOut confStatus(LED1); // Config file status LED
shimniok 0:826c6171fc1b 78 DigitalOut logStatus(LED2); // Log file status LED
shimniok 0:826c6171fc1b 79 DigitalOut gpsStatus(LED3); // GPS fix status LED
shimniok 0:826c6171fc1b 80 DigitalOut ahrsStatus(LED4); // AHRS status LED
shimniok 0:826c6171fc1b 81 //DigitalOut sonarStart(p18); // Sends signal to start sonar array pings
shimniok 0:826c6171fc1b 82 Beep speaker(p24); // Piezo speaker
shimniok 0:826c6171fc1b 83
shimniok 0:826c6171fc1b 84 // INPUT
shimniok 0:826c6171fc1b 85 Menu menu;
shimniok 0:826c6171fc1b 86 Buttons keypad;
shimniok 0:826c6171fc1b 87
shimniok 0:826c6171fc1b 88 // VEHICLE
shimniok 0:826c6171fc1b 89 Steering steerCalc(TRACK, WHEELBASE); // steering calculator
shimniok 0:826c6171fc1b 90
shimniok 0:826c6171fc1b 91 // COMM
shimniok 0:826c6171fc1b 92 Serial pc(USBTX, USBRX); // PC usb communications
shimniok 0:826c6171fc1b 93 SerialGraphicLCD lcd(p17, p18, SD_FW); // Graphic LCD with summoningdark firmware
shimniok 0:826c6171fc1b 94 //Serial *debug = &pc;
shimniok 0:826c6171fc1b 95
shimniok 0:826c6171fc1b 96 // SENSORS
shimniok 0:826c6171fc1b 97 Sensors sensors; // Abstraction of sensor drivers
shimniok 0:826c6171fc1b 98 //DCM ahrs; // ArduPilot/MatrixPilot AHRS
shimniok 0:826c6171fc1b 99 Serial *dev; // For use with bridge
shimniok 0:826c6171fc1b 100 GPS gps(p26, p25, VENUS); // gps
shimniok 0:826c6171fc1b 101
shimniok 0:826c6171fc1b 102 FILE *camlog; // Camera log
shimniok 0:826c6171fc1b 103
shimniok 0:826c6171fc1b 104 // Configuration
shimniok 0:826c6171fc1b 105 Config config; // Persistent configuration
shimniok 0:826c6171fc1b 106 // Course Waypoints
shimniok 0:826c6171fc1b 107 // Sensor Calibration
shimniok 0:826c6171fc1b 108 // etc.
shimniok 0:826c6171fc1b 109
shimniok 0:826c6171fc1b 110 // Timing
shimniok 0:826c6171fc1b 111 Timer timer; // For main loop scheduling
shimniok 0:826c6171fc1b 112 Ticker sched; // scheduler for interrupt driven routines
shimniok 0:826c6171fc1b 113
shimniok 0:826c6171fc1b 114 // Overall system state (used for logging but also convenient for general use
shimniok 0:826c6171fc1b 115 SystemState state[SSBUF]; // system state for logging, FIFO buffer
shimniok 0:826c6171fc1b 116 unsigned char inState; // FIFO items enter in here
shimniok 0:826c6171fc1b 117 unsigned char outState; // FIFO items leave out here
shimniok 0:826c6171fc1b 118 bool ssBufOverrun = false;
shimniok 0:826c6171fc1b 119
shimniok 0:826c6171fc1b 120 // GPS Variables
shimniok 0:826c6171fc1b 121 unsigned long age = 0; // gps fix age
shimniok 0:826c6171fc1b 122
shimniok 0:826c6171fc1b 123 // schedule for LED warning flasher
shimniok 0:826c6171fc1b 124 Schedule blink;
shimniok 0:826c6171fc1b 125
shimniok 0:826c6171fc1b 126 // Estimation & Navigation Variables
shimniok 0:826c6171fc1b 127 GeoPosition dr_here; // Estimated position based on estimated heading
shimniok 0:826c6171fc1b 128 GeoPosition gps_here; // current gps position
shimniok 0:826c6171fc1b 129 Mapping mapper;
shimniok 0:826c6171fc1b 130
shimniok 0:826c6171fc1b 131 ///////////////////////////////////////////////////////////////////////////////////////////////////////
shimniok 0:826c6171fc1b 132 // FUNCTION DEFINITIONS
shimniok 0:826c6171fc1b 133 ///////////////////////////////////////////////////////////////////////////////////////////////////////
shimniok 0:826c6171fc1b 134
shimniok 0:826c6171fc1b 135 void initFlasher(void);
shimniok 0:826c6171fc1b 136 void initDR(void);
shimniok 0:826c6171fc1b 137 int autonomousMode(void);
shimniok 0:826c6171fc1b 138 void mavlinkMode(void);
shimniok 0:826c6171fc1b 139 void servoCalibrate(void);
shimniok 0:826c6171fc1b 140 void serialBridge(Serial &gps);
shimniok 0:826c6171fc1b 141 int instrumentCheck(void);
shimniok 0:826c6171fc1b 142 void displayData(int mode);
shimniok 0:826c6171fc1b 143 int compassCalibrate(void);
shimniok 0:826c6171fc1b 144 int compassSwing(void);
shimniok 0:826c6171fc1b 145 int gyroSwing(void);
shimniok 0:826c6171fc1b 146 int setBacklight(void);
shimniok 0:826c6171fc1b 147 int reverseScreen(void);
shimniok 0:826c6171fc1b 148 float gyroRate(unsigned int adc);
shimniok 0:826c6171fc1b 149 float sonarDistance(unsigned int adc);
shimniok 0:826c6171fc1b 150 float irDistance(unsigned int adc);
shimniok 0:826c6171fc1b 151 float getVoltage(void);
shimniok 0:826c6171fc1b 152 extern "C" void mbed_reset();
shimniok 0:826c6171fc1b 153
shimniok 0:826c6171fc1b 154 extern unsigned int matrix_error;
shimniok 0:826c6171fc1b 155
shimniok 0:826c6171fc1b 156 // If we don't close the log file, when we restart, all the written data
shimniok 0:826c6171fc1b 157 // will be lost. So we have to use a button to force mbed to close the
shimniok 0:826c6171fc1b 158 // file and preserve the data.
shimniok 0:826c6171fc1b 159 //
shimniok 0:826c6171fc1b 160
shimniok 0:826c6171fc1b 161 int dummy(void)
shimniok 0:826c6171fc1b 162 {
shimniok 0:826c6171fc1b 163 return 0;
shimniok 0:826c6171fc1b 164 }
shimniok 0:826c6171fc1b 165
shimniok 0:826c6171fc1b 166
shimniok 0:826c6171fc1b 167 // TODO: 3 move to GPS module
shimniok 0:826c6171fc1b 168 /* GPS serial interrupt handler
shimniok 0:826c6171fc1b 169 */
shimniok 0:826c6171fc1b 170 void gpsRecv() {
shimniok 0:826c6171fc1b 171 while (gps.serial.readable()) {
shimniok 0:826c6171fc1b 172 gpsStatus = !gpsStatus;
shimniok 0:826c6171fc1b 173 gps.nmea.encode(gps.serial.getc());
shimniok 0:826c6171fc1b 174 gpsStatus = !gpsStatus;
shimniok 0:826c6171fc1b 175 }
shimniok 0:826c6171fc1b 176 }
shimniok 0:826c6171fc1b 177
shimniok 0:826c6171fc1b 178
shimniok 0:826c6171fc1b 179 int resetMe()
shimniok 0:826c6171fc1b 180 {
shimniok 0:826c6171fc1b 181 mbed_reset();
shimniok 0:826c6171fc1b 182
shimniok 0:826c6171fc1b 183 return 0;
shimniok 0:826c6171fc1b 184 }
shimniok 0:826c6171fc1b 185
shimniok 0:826c6171fc1b 186
shimniok 0:826c6171fc1b 187 #define DISPLAY_CLEAR 0x01
shimniok 0:826c6171fc1b 188 #define DISPLAY_SET_POS 0x08
shimniok 0:826c6171fc1b 189
shimniok 0:826c6171fc1b 190
shimniok 0:826c6171fc1b 191 int main()
shimniok 0:826c6171fc1b 192 {
shimniok 0:826c6171fc1b 193 // Send data back to the PC
shimniok 0:826c6171fc1b 194 pc.baud(115200);
shimniok 0:826c6171fc1b 195 lcd.baud(115200);
shimniok 0:826c6171fc1b 196 lcd.printf("test\n"); // hopefully force 115200 on powerup
shimniok 0:826c6171fc1b 197 lcd.clear();
shimniok 0:826c6171fc1b 198 wait(0.3);
shimniok 0:826c6171fc1b 199 lcd.printf("Data Bus mAGV V2");
shimniok 0:826c6171fc1b 200
shimniok 0:826c6171fc1b 201 fprintf(stdout, "Data Bus mAGV Control System\n");
shimniok 0:826c6171fc1b 202
shimniok 0:826c6171fc1b 203 fprintf(stdout, "Initialization...\n");
shimniok 0:826c6171fc1b 204 lcd.pos(0,1);
shimniok 0:826c6171fc1b 205 lcd.printf(LCD_FMT, "Initializing");
shimniok 0:826c6171fc1b 206 wait(0.5);
shimniok 0:826c6171fc1b 207
shimniok 0:826c6171fc1b 208 gps.setUpdateRate(10);
shimniok 0:826c6171fc1b 209
shimniok 0:826c6171fc1b 210 // Initialize status LEDs
shimniok 0:826c6171fc1b 211 ahrsStatus = 0;
shimniok 0:826c6171fc1b 212 gpsStatus = 0;
shimniok 0:826c6171fc1b 213 logStatus = 0;
shimniok 0:826c6171fc1b 214 confStatus = 0;
shimniok 0:826c6171fc1b 215
shimniok 0:826c6171fc1b 216 //ahrs.G_Dt = UPDATE_PERIOD;
shimniok 0:826c6171fc1b 217
shimniok 0:826c6171fc1b 218 fprintf(stdout, "Loading configuration...\n");
shimniok 0:826c6171fc1b 219 lcd.pos(0,1);
shimniok 0:826c6171fc1b 220 lcd.printf(LCD_FMT, "Load config");
shimniok 0:826c6171fc1b 221 wait(0.5);
shimniok 0:826c6171fc1b 222 if (config.load()) // Load various configurable parameters, e.g., waypoints, declination, etc.
shimniok 0:826c6171fc1b 223 confStatus = 1;
shimniok 0:826c6171fc1b 224
shimniok 0:826c6171fc1b 225 // Something here is jacking up the I2C stuff
shimniok 0:826c6171fc1b 226 initSteering();
shimniok 0:826c6171fc1b 227 initThrottle();
shimniok 0:826c6171fc1b 228 // initFlasher(); // Initialize autonomous mode flasher
shimniok 0:826c6171fc1b 229
shimniok 0:826c6171fc1b 230 sensors.Compass_Calibrate(config.magOffset, config.magScale);
shimniok 0:826c6171fc1b 231 pc.printf("Declination: %.1f\n", config.declination);
shimniok 0:826c6171fc1b 232 pc.printf("Speed: escZero=%d escMax=%d top=%.1f turn=%.1f Kp=%.4f Ki=%.4f Kd=%.4f\n",
shimniok 0:826c6171fc1b 233 config.escZero, config.escMax, config.topSpeed, config.turnSpeed,
shimniok 0:826c6171fc1b 234 config.speedKp, config.speedKi, config.speedKd);
shimniok 0:826c6171fc1b 235 pc.printf("Steering: steerZero=%0.2f steerGain=%.1f gainAngle=%.1f\n", config.steerZero, config.steerGain, config.steerGainAngle);
shimniok 0:826c6171fc1b 236
shimniok 0:826c6171fc1b 237 // Convert lat/lon waypoints to cartesian
shimniok 0:826c6171fc1b 238 mapper.init(config.wptCount, config.wpt);
shimniok 0:826c6171fc1b 239 for (int w = 0; w < MAXWPT && w < config.wptCount; w++) {
shimniok 0:826c6171fc1b 240 mapper.geoToCart(config.wpt[w], &(config.cwpt[w]));
shimniok 0:826c6171fc1b 241 pc.printf("Waypoint #%d (%.4f, %.4f) lat: %.6f lon: %.6f\n",
shimniok 0:826c6171fc1b 242 w, config.cwpt[w]._x, config.cwpt[w]._y, config.wpt[w].latitude(), config.wpt[w].longitude());
shimniok 0:826c6171fc1b 243 }
shimniok 0:826c6171fc1b 244
shimniok 0:826c6171fc1b 245 // TODO: 3 print mag and gyro calibrations
shimniok 0:826c6171fc1b 246
shimniok 0:826c6171fc1b 247 lcd.pos(0,1);
shimniok 0:826c6171fc1b 248 lcd.printf(LCD_FMT, "GPS configuration ");
shimniok 0:826c6171fc1b 249 gps.setType(config.gpsType);
shimniok 0:826c6171fc1b 250 gps.setBaud(config.gpsBaud);
shimniok 0:826c6171fc1b 251 fprintf(stdout, "GPS config: type=%d baud=%d\n", config.gpsType, config.gpsBaud);
shimniok 0:826c6171fc1b 252
shimniok 0:826c6171fc1b 253 lcd.pos(0,1);
shimniok 0:826c6171fc1b 254 lcd.printf(LCD_FMT, "Nav configuration ");
shimniok 0:826c6171fc1b 255 steerCalc.setIntercept(config.interceptDist); // Setup steering calculator based on intercept distance
shimniok 0:826c6171fc1b 256 pc.printf("Intercept distance: %.1f\n", config.interceptDist);
shimniok 0:826c6171fc1b 257 pc.printf("Waypoint distance: %.1f\n", config.waypointDist);
shimniok 0:826c6171fc1b 258 pc.printf("Brake distance: %.1f\n", config.brakeDist);
shimniok 0:826c6171fc1b 259 pc.printf("Min turn radius: %.3f\n", config.minRadius);
shimniok 0:826c6171fc1b 260
shimniok 0:826c6171fc1b 261 fprintf(stdout, "Calculating offsets...\n");
shimniok 0:826c6171fc1b 262 lcd.pos(0,1);
shimniok 0:826c6171fc1b 263 lcd.printf(LCD_FMT, "Offset calculation ");
shimniok 0:826c6171fc1b 264 wait(0.5);
shimniok 0:826c6171fc1b 265 // TODO: 3 Really need to give the gyro more time to settle
shimniok 0:826c6171fc1b 266 sensors.Calculate_Offsets();
shimniok 0:826c6171fc1b 267
shimniok 0:826c6171fc1b 268 fprintf(stdout, "Starting GPS...\n");
shimniok 0:826c6171fc1b 269 lcd.pos(0,1);
shimniok 0:826c6171fc1b 270 lcd.printf(LCD_FMT, "Start GPS ");
shimniok 0:826c6171fc1b 271 wait(0.5);
shimniok 0:826c6171fc1b 272 // TODO: 3 move this to GPS module
shimniok 0:826c6171fc1b 273 gps.serial.attach(gpsRecv, Serial::RxIrq);
shimniok 0:826c6171fc1b 274 // TODO: 3 enable and process GSV as bar graph
shimniok 0:826c6171fc1b 275 //gps.gsvMessage(false);
shimniok 0:826c6171fc1b 276 //gps.gsaMessage(true);
shimniok 0:826c6171fc1b 277
shimniok 0:826c6171fc1b 278 fprintf(stdout, "Starting Scheduler...\n");
shimniok 0:826c6171fc1b 279 lcd.pos(0,1);
shimniok 0:826c6171fc1b 280 lcd.printf(LCD_FMT, "Start scheduler ");
shimniok 0:826c6171fc1b 281 wait(0.5);
shimniok 0:826c6171fc1b 282 // Startup sensor/AHRS ticker; update every 10ms = 100hz
shimniok 0:826c6171fc1b 283 restartNav();
shimniok 0:826c6171fc1b 284 sched.attach(&update, UPDATE_PERIOD);
shimniok 0:826c6171fc1b 285
shimniok 0:826c6171fc1b 286 /*
shimniok 0:826c6171fc1b 287 fprintf(stdout, "Starting Camera...\n");
shimniok 0:826c6171fc1b 288 lcd.pos(0,1);
shimniok 0:826c6171fc1b 289 lcd.printf(LCD_FMT, "Start Camera ");
shimniok 0:826c6171fc1b 290 wait(0.5);
shimniok 0:826c6171fc1b 291 cam.start();
shimniok 0:826c6171fc1b 292 */
shimniok 0:826c6171fc1b 293
shimniok 0:826c6171fc1b 294 // Let's try setting serial IRQs lower and see if that alleviates issues with I2C reads and AHRS reads
shimniok 0:826c6171fc1b 295 //NVIC_SetPriority(UART0_IRQn, 1); // USB
shimniok 0:826c6171fc1b 296 //NVIC_SetPriority(UART1_IRQn, 2); // GPS p25,p26
shimniok 0:826c6171fc1b 297 //NVIC_SetPriority(UART3_IRQn, 3); // LCD p17,p18
shimniok 0:826c6171fc1b 298
shimniok 0:826c6171fc1b 299 // Insert menu system here w/ timeout
shimniok 0:826c6171fc1b 300 //bool autoBoot=false;
shimniok 0:826c6171fc1b 301
shimniok 0:826c6171fc1b 302 //speaker.beep(3000.0, 0.2); // non-blocking
shimniok 0:826c6171fc1b 303
shimniok 0:826c6171fc1b 304 keypad.init();
shimniok 0:826c6171fc1b 305
shimniok 0:826c6171fc1b 306 // Initialize LCD graphics
shimniok 0:826c6171fc1b 307 Bargraph::lcd = &lcd;
shimniok 0:826c6171fc1b 308 Bargraph v(1, 40, 15, 'V');
shimniok 0:826c6171fc1b 309 v.calibrate(6.3, 8.4);
shimniok 0:826c6171fc1b 310 Bargraph a(11, 40, 15, 'A');
shimniok 0:826c6171fc1b 311 a.calibrate(0, 15.0);
shimniok 0:826c6171fc1b 312 Bargraph g1(21, 40, 15, 'G');
shimniok 0:826c6171fc1b 313 g1.calibrate(0, 10);
shimniok 0:826c6171fc1b 314 Bargraph g2(31, 40, 15, 'H');
shimniok 0:826c6171fc1b 315 g2.calibrate(4.0, 0.8);
shimniok 0:826c6171fc1b 316 //GPSStatus g2(21, 12);
shimniok 0:826c6171fc1b 317 //GPSStatus::lcd = &lcd;
shimniok 0:826c6171fc1b 318
shimniok 0:826c6171fc1b 319 // Setup LCD Input Menu
shimniok 0:826c6171fc1b 320 menu.add("Auto mode", &autonomousMode);
shimniok 0:826c6171fc1b 321 menu.add("Instruments", &instrumentCheck);
shimniok 0:826c6171fc1b 322 menu.add("Calibrate", &compassCalibrate);
shimniok 0:826c6171fc1b 323 menu.add("Compass Swing", &compassSwing);
shimniok 0:826c6171fc1b 324 menu.add("Gyro Calib", &gyroSwing);
shimniok 0:826c6171fc1b 325 //menu.sdd("Reload Config", &loadConfig);
shimniok 0:826c6171fc1b 326 menu.add("Backlight", &setBacklight);
shimniok 0:826c6171fc1b 327 menu.add("Reverse", &reverseScreen);
shimniok 0:826c6171fc1b 328 menu.add("Reset", &resetMe);
shimniok 0:826c6171fc1b 329
shimniok 0:826c6171fc1b 330 char cmd;
shimniok 0:826c6171fc1b 331 bool printMenu = true;
shimniok 0:826c6171fc1b 332 bool printLCDMenu = true;
shimniok 0:826c6171fc1b 333
shimniok 0:826c6171fc1b 334 timer.start();
shimniok 0:826c6171fc1b 335 timer.reset();
shimniok 0:826c6171fc1b 336
shimniok 0:826c6171fc1b 337 int thisUpdate = timer.read_ms();
shimniok 0:826c6171fc1b 338 int nextUpdate = thisUpdate;
shimniok 0:826c6171fc1b 339 //int hdgUpdate = nextUpdate;
shimniok 0:826c6171fc1b 340
shimniok 0:826c6171fc1b 341 while (1) {
shimniok 0:826c6171fc1b 342
shimniok 0:826c6171fc1b 343 /*
shimniok 0:826c6171fc1b 344 if (timer.read_ms() > hdgUpdate) {
shimniok 0:826c6171fc1b 345 fprintf(stdout, "He=%.3f %.5f\n", kfGetX(0), kfGetX(1));
shimniok 0:826c6171fc1b 346 hdgUpdate = timer.read_ms() + 100;
shimniok 0:826c6171fc1b 347 }*/
shimniok 0:826c6171fc1b 348
shimniok 0:826c6171fc1b 349 if ((thisUpdate = timer.read_ms()) > nextUpdate) {
shimniok 0:826c6171fc1b 350 //fprintf(stdout, "Updating...\n");
shimniok 0:826c6171fc1b 351 v.update(sensors.voltage);
shimniok 0:826c6171fc1b 352 a.update(sensors.current);
shimniok 0:826c6171fc1b 353 g1.update((float) gps.nmea.sat_count());
shimniok 0:826c6171fc1b 354 g2.update(gps.hdop);
shimniok 0:826c6171fc1b 355 lcd.posXY(60, 22);
shimniok 0:826c6171fc1b 356 lcd.printf("%.2f", state[inState].rightRanger);
shimniok 0:826c6171fc1b 357 lcd.posXY(60, 32);
shimniok 0:826c6171fc1b 358 lcd.printf("%.2f", state[inState].leftRanger);
shimniok 0:826c6171fc1b 359 lcd.posXY(60, 42);
shimniok 0:826c6171fc1b 360 lcd.printf("%5.1f", state[inState].estHeading);
shimniok 0:826c6171fc1b 361 lcd.posXY(60, 52);
shimniok 0:826c6171fc1b 362 lcd.printf("%.3f", state[inState].gpsCourse);
shimniok 0:826c6171fc1b 363 nextUpdate = thisUpdate + 2000;
shimniok 0:826c6171fc1b 364 // TODO: 3 address integer overflow
shimniok 0:826c6171fc1b 365 // TODO: 3 display scheduler() timing
shimniok 0:826c6171fc1b 366 }
shimniok 0:826c6171fc1b 367
shimniok 0:826c6171fc1b 368 if (keypad.pressed) {
shimniok 0:826c6171fc1b 369 keypad.pressed = false;
shimniok 0:826c6171fc1b 370 printLCDMenu = true;
shimniok 0:826c6171fc1b 371 //causes issue with servo library
shimniok 0:826c6171fc1b 372 //speaker.beep(3000.0, 0.1); // non-blocking
shimniok 0:826c6171fc1b 373 switch (keypad.which) {
shimniok 0:826c6171fc1b 374 case NEXT_BUTTON:
shimniok 0:826c6171fc1b 375 menu.next();
shimniok 0:826c6171fc1b 376 break;
shimniok 0:826c6171fc1b 377 case PREV_BUTTON:
shimniok 0:826c6171fc1b 378 menu.prev();
shimniok 0:826c6171fc1b 379 break;
shimniok 0:826c6171fc1b 380 case SELECT_BUTTON:
shimniok 0:826c6171fc1b 381 lcd.pos(0,0);
shimniok 0:826c6171fc1b 382 lcd.printf(">>%-14s", menu.getItemName());
shimniok 0:826c6171fc1b 383 menu.select();
shimniok 0:826c6171fc1b 384 printMenu = true;
shimniok 0:826c6171fc1b 385 break;
shimniok 0:826c6171fc1b 386 default:
shimniok 0:826c6171fc1b 387 printLCDMenu = false;
shimniok 0:826c6171fc1b 388 break;
shimniok 0:826c6171fc1b 389 }//switch
shimniok 0:826c6171fc1b 390 keypad.pressed = false;
shimniok 0:826c6171fc1b 391 }// if (keypad.pressed)
shimniok 0:826c6171fc1b 392
shimniok 0:826c6171fc1b 393
shimniok 0:826c6171fc1b 394 if (printLCDMenu) {
shimniok 0:826c6171fc1b 395 lcd.pos(0,0);
shimniok 0:826c6171fc1b 396 lcd.printf("< %-14s >", menu.getItemName());
shimniok 0:826c6171fc1b 397 lcd.pos(0,1);
shimniok 0:826c6171fc1b 398 lcd.printf(LCD_FMT, "Ready.");
shimniok 0:826c6171fc1b 399 lcd.posXY(50, 22);
shimniok 0:826c6171fc1b 400 lcd.printf("R");
shimniok 0:826c6171fc1b 401 lcd.rect(58, 20, 98, 30, true);
shimniok 0:826c6171fc1b 402 wait(0.01);
shimniok 0:826c6171fc1b 403 lcd.posXY(50, 32);
shimniok 0:826c6171fc1b 404 lcd.printf("L");
shimniok 0:826c6171fc1b 405 lcd.rect(58, 30, 98, 40, true);
shimniok 0:826c6171fc1b 406 wait(0.01);
shimniok 0:826c6171fc1b 407 lcd.posXY(50, 42);
shimniok 0:826c6171fc1b 408 lcd.printf("H");
shimniok 0:826c6171fc1b 409 lcd.rect(58, 40, 98, 50, true);
shimniok 0:826c6171fc1b 410 wait(0.01);
shimniok 0:826c6171fc1b 411 lcd.posXY(44,52);
shimniok 0:826c6171fc1b 412 lcd.printf("GH");
shimniok 0:826c6171fc1b 413 lcd.rect(58, 50, 98, 60, true);
shimniok 0:826c6171fc1b 414 v.init();
shimniok 0:826c6171fc1b 415 a.init();
shimniok 0:826c6171fc1b 416 g1.init();
shimniok 0:826c6171fc1b 417 g2.init();
shimniok 0:826c6171fc1b 418 printLCDMenu = false;
shimniok 0:826c6171fc1b 419 }
shimniok 0:826c6171fc1b 420
shimniok 0:826c6171fc1b 421 /* if (autoBoot) {
shimniok 0:826c6171fc1b 422 autoBoot = false;
shimniok 0:826c6171fc1b 423 cmd = 'a';
shimniok 0:826c6171fc1b 424 } else {*/
shimniok 0:826c6171fc1b 425
shimniok 0:826c6171fc1b 426 if (printMenu) {
shimniok 0:826c6171fc1b 427 int i=0;
shimniok 0:826c6171fc1b 428 fprintf(stdout, "\n==============\nData Bus Menu\n==============\n");
shimniok 0:826c6171fc1b 429 fprintf(stdout, "%d) Autonomous mode\n", i++);
shimniok 0:826c6171fc1b 430 fprintf(stdout, "%d) Bridge serial to GPS\n", i++);
shimniok 0:826c6171fc1b 431 fprintf(stdout, "%d) Calibrate compass\n", i++);
shimniok 0:826c6171fc1b 432 fprintf(stdout, "%d) Swing compass\n", i++);
shimniok 0:826c6171fc1b 433 fprintf(stdout, "%d) Gyro calibrate\n", i++);
shimniok 0:826c6171fc1b 434 fprintf(stdout, "%d) Instrument check\n", i++);
shimniok 0:826c6171fc1b 435 fprintf(stdout, "%d) Display AHRS\n", i++);
shimniok 0:826c6171fc1b 436 fprintf(stdout, "%d) Mavlink mode\n", i++);
shimniok 0:826c6171fc1b 437 fprintf(stdout, "%d) Shell\n", i++);
shimniok 0:826c6171fc1b 438 fprintf(stdout, "R) Reset\n");
shimniok 0:826c6171fc1b 439 fprintf(stdout, "\nSelect from the above: ");
shimniok 0:826c6171fc1b 440 fflush(stdout);
shimniok 0:826c6171fc1b 441 printMenu = false;
shimniok 0:826c6171fc1b 442 }
shimniok 0:826c6171fc1b 443
shimniok 0:826c6171fc1b 444
shimniok 0:826c6171fc1b 445 // Basic functional architecture
shimniok 0:826c6171fc1b 446 // SENSORS -> FILTERS -> AHRS -> POSITION -> NAVIGATION -> CONTROL | INPUT/OUTPUT | LOGGING
shimniok 0:826c6171fc1b 447 // SENSORS (for now) are polled out of AHRS via interrupt every 10ms
shimniok 0:826c6171fc1b 448 //
shimniok 0:826c6171fc1b 449 // no FILTERing in place right now
shimniok 0:826c6171fc1b 450 // if we filter too heavily we get lag. At 30mph = 14m/s a sensor lag
shimniok 0:826c6171fc1b 451 // of only 10ms means the estimate is 140cm behind the robot
shimniok 0:826c6171fc1b 452 //
shimniok 0:826c6171fc1b 453 // POSITION and NAVIGATION should probably always be running
shimniok 0:826c6171fc1b 454 // log file can have different entry type per module, to be demultiplexed on the PC
shimniok 0:826c6171fc1b 455 //
shimniok 0:826c6171fc1b 456 // Autonomous mode engages CONTROL outputs
shimniok 0:826c6171fc1b 457 //
shimniok 0:826c6171fc1b 458 // I/O mode could be one of: MAVlink, serial bridge (gps), sensor check, shell, log to serial
shimniok 0:826c6171fc1b 459 // Or maybe shell should be the main control for different output modes
shimniok 0:826c6171fc1b 460 //
shimniok 0:826c6171fc1b 461 // LOGGING can be turned on or off, probably best to start with it engaged
shimniok 0:826c6171fc1b 462 // and then disable from user panel or when navigation is ended
shimniok 0:826c6171fc1b 463
shimniok 0:826c6171fc1b 464 if (pc.readable()) {
shimniok 0:826c6171fc1b 465 cmd = pc.getc();
shimniok 0:826c6171fc1b 466 fprintf(stdout, "%c\n", cmd);
shimniok 0:826c6171fc1b 467 printMenu = true;
shimniok 0:826c6171fc1b 468 printLCDMenu = true;
shimniok 0:826c6171fc1b 469
shimniok 0:826c6171fc1b 470 switch (cmd) {
shimniok 0:826c6171fc1b 471 case 'R' :
shimniok 0:826c6171fc1b 472 resetMe();
shimniok 0:826c6171fc1b 473 break;
shimniok 0:826c6171fc1b 474 case '0' :
shimniok 0:826c6171fc1b 475 lcd.pos(0,0);
shimniok 0:826c6171fc1b 476 lcd.printf(">>%-14s", menu.getItemName(0));
shimniok 0:826c6171fc1b 477 autonomousMode();
shimniok 0:826c6171fc1b 478 break;
shimniok 0:826c6171fc1b 479 case '1' :
shimniok 0:826c6171fc1b 480 lcd.pos(0,0);
shimniok 0:826c6171fc1b 481 lcd.printf(">>%-14s", "Serial bridge");
shimniok 0:826c6171fc1b 482 lcd.pos(0,1);
shimniok 0:826c6171fc1b 483 lcd.printf(LCD_FMT, "Standby.");
shimniok 0:826c6171fc1b 484 gps.gsvMessage(true);
shimniok 0:826c6171fc1b 485 gps.gsaMessage(true);
shimniok 0:826c6171fc1b 486 serialBridge(gps.serial);
shimniok 0:826c6171fc1b 487 gps.gsvMessage(false);
shimniok 0:826c6171fc1b 488 gps.gsaMessage(false);
shimniok 0:826c6171fc1b 489 break;
shimniok 0:826c6171fc1b 490 case '2' :
shimniok 0:826c6171fc1b 491 lcd.pos(0,0);
shimniok 0:826c6171fc1b 492 lcd.printf(">>%-14s", menu.getItemName(1));
shimniok 0:826c6171fc1b 493 compassCalibrate();
shimniok 0:826c6171fc1b 494 break;
shimniok 0:826c6171fc1b 495 case '3' :
shimniok 0:826c6171fc1b 496 lcd.pos(0,0);
shimniok 0:826c6171fc1b 497 lcd.printf(">>%-14s", menu.getItemName(2));
shimniok 0:826c6171fc1b 498 compassSwing();
shimniok 0:826c6171fc1b 499 break;
shimniok 0:826c6171fc1b 500 case '4' :
shimniok 0:826c6171fc1b 501 lcd.pos(0,0);
shimniok 0:826c6171fc1b 502 lcd.printf(">>%-14s", menu.getItemName(2));
shimniok 0:826c6171fc1b 503 gyroSwing();
shimniok 0:826c6171fc1b 504 break;
shimniok 0:826c6171fc1b 505 case '5' :
shimniok 0:826c6171fc1b 506 lcd.pos(0,0);
shimniok 0:826c6171fc1b 507 lcd.printf(">>%-14s", "Instruments");
shimniok 0:826c6171fc1b 508 lcd.pos(0,1);
shimniok 0:826c6171fc1b 509 lcd.printf(LCD_FMT, "Standby.");
shimniok 0:826c6171fc1b 510 displayData(INSTRUMENT_CHECK);
shimniok 0:826c6171fc1b 511 break;
shimniok 0:826c6171fc1b 512 case '6' :
shimniok 0:826c6171fc1b 513 lcd.pos(0,0);
shimniok 0:826c6171fc1b 514 lcd.printf(">>%-14s", "AHRS Visual'n");
shimniok 0:826c6171fc1b 515 lcd.pos(0,1);
shimniok 0:826c6171fc1b 516 lcd.printf(LCD_FMT, "Standby.");
shimniok 0:826c6171fc1b 517 displayData(AHRS_VISUALIZATION);
shimniok 0:826c6171fc1b 518 break;
shimniok 0:826c6171fc1b 519 case '7' :
shimniok 0:826c6171fc1b 520 lcd.pos(0,0);
shimniok 0:826c6171fc1b 521 lcd.printf(">>%-14s", "Mavlink mode");
shimniok 0:826c6171fc1b 522 lcd.pos(0,1);
shimniok 0:826c6171fc1b 523 lcd.printf(LCD_FMT, "Standby.");
shimniok 0:826c6171fc1b 524 mavlinkMode();
shimniok 0:826c6171fc1b 525 break;
shimniok 0:826c6171fc1b 526 case '8' :
shimniok 0:826c6171fc1b 527 lcd.pos(0,0);
shimniok 0:826c6171fc1b 528 lcd.printf(">>%-14s", "Shell");
shimniok 0:826c6171fc1b 529 lcd.pos(0,1);
shimniok 0:826c6171fc1b 530 lcd.printf(LCD_FMT, "Standby.");
shimniok 0:826c6171fc1b 531 shell();
shimniok 0:826c6171fc1b 532 break;
shimniok 0:826c6171fc1b 533 default :
shimniok 0:826c6171fc1b 534 break;
shimniok 0:826c6171fc1b 535 } // switch
shimniok 0:826c6171fc1b 536
shimniok 0:826c6171fc1b 537 } // if (pc.readable())
shimniok 0:826c6171fc1b 538
shimniok 0:826c6171fc1b 539 } // while
shimniok 0:826c6171fc1b 540
shimniok 0:826c6171fc1b 541 }
shimniok 0:826c6171fc1b 542
shimniok 0:826c6171fc1b 543
shimniok 0:826c6171fc1b 544
shimniok 0:826c6171fc1b 545 ///////////////////////////////////////////////////////////////////////////////////////////////////////
shimniok 0:826c6171fc1b 546 // INITIALIZATION ROUTINES
shimniok 0:826c6171fc1b 547 ///////////////////////////////////////////////////////////////////////////////////////////////////////
shimniok 0:826c6171fc1b 548
shimniok 0:826c6171fc1b 549
shimniok 0:826c6171fc1b 550 void initFlasher()
shimniok 0:826c6171fc1b 551 {
shimniok 0:826c6171fc1b 552 // Set up flasher schedule; 3 flashes every 80ms
shimniok 0:826c6171fc1b 553 // for 80ms total, with a 9x80ms period
shimniok 0:826c6171fc1b 554 blink.max(9);
shimniok 0:826c6171fc1b 555 blink.scale(80);
shimniok 0:826c6171fc1b 556 blink.mode(Schedule::repeat);
shimniok 0:826c6171fc1b 557 blink.set(0, 1); blink.set(2, 1); blink.set(4, 1);
shimniok 0:826c6171fc1b 558 }
shimniok 0:826c6171fc1b 559
shimniok 0:826c6171fc1b 560
shimniok 0:826c6171fc1b 561 ///////////////////////////////////////////////////////////////////////////////////////////////////////
shimniok 0:826c6171fc1b 562 // OPERATIONAL MODE FUNCTIONS
shimniok 0:826c6171fc1b 563 ///////////////////////////////////////////////////////////////////////////////////////////////////////
shimniok 0:826c6171fc1b 564
shimniok 0:826c6171fc1b 565 int autonomousMode()
shimniok 0:826c6171fc1b 566 {
shimniok 0:826c6171fc1b 567 bool goGoGo = false; // signal to start moving
shimniok 0:826c6171fc1b 568 bool navDone; // signal that we're done navigating
shimniok 0:826c6171fc1b 569 extern int tSensor, tGPS, tAHRS, tLog;
shimniok 0:826c6171fc1b 570
shimniok 0:826c6171fc1b 571 // TODO: 3 move to main?
shimniok 0:826c6171fc1b 572 // Navigation
shimniok 0:826c6171fc1b 573
shimniok 0:826c6171fc1b 574 goGoGo = false;
shimniok 0:826c6171fc1b 575 navDone = false;
shimniok 0:826c6171fc1b 576 keypad.pressed = false;
shimniok 0:826c6171fc1b 577 //bool started = false; // flag to indicate robot has exceeded min speed.
shimniok 0:826c6171fc1b 578
shimniok 0:826c6171fc1b 579 if (initLogfile()) logStatus = 1; // Open the log file in sprintf format string style; numbers go in %d
shimniok 0:826c6171fc1b 580 wait(0.2);
shimniok 0:826c6171fc1b 581
shimniok 0:826c6171fc1b 582 gps.setNmeaMessages(true, true, false, false, true, false); // enable GGA, GSA, RMC
shimniok 0:826c6171fc1b 583 gps.serial.attach(gpsRecv, Serial::RxIrq);
shimniok 0:826c6171fc1b 584
shimniok 0:826c6171fc1b 585 lcd.pos(0,1);
shimniok 0:826c6171fc1b 586 lcd.printf(LCD_FMT, "Select starts.");
shimniok 0:826c6171fc1b 587 wait(1.0);
shimniok 0:826c6171fc1b 588
shimniok 0:826c6171fc1b 589 timer.reset();
shimniok 0:826c6171fc1b 590 timer.start();
shimniok 0:826c6171fc1b 591 wait(0.1);
shimniok 0:826c6171fc1b 592
shimniok 0:826c6171fc1b 593 // Initialize logging buffer
shimniok 0:826c6171fc1b 594 // Needs to happen after we've reset the millisecond timer and after
shimniok 0:826c6171fc1b 595 // the schedHandler() fires off at least once more with the new time
shimniok 0:826c6171fc1b 596 inState = outState = 0;
shimniok 0:826c6171fc1b 597
shimniok 0:826c6171fc1b 598 // Tell the navigation / position estimation stuff to reset to starting waypoint
shimniok 0:826c6171fc1b 599 restartNav();
shimniok 0:826c6171fc1b 600
shimniok 0:826c6171fc1b 601 // Main loop
shimniok 0:826c6171fc1b 602 //
shimniok 0:826c6171fc1b 603 while(navDone == false) {
shimniok 0:826c6171fc1b 604
shimniok 0:826c6171fc1b 605 //////////////////////////////////////////////////////////////////////////////
shimniok 0:826c6171fc1b 606 // USER INPUT
shimniok 0:826c6171fc1b 607 //////////////////////////////////////////////////////////////////////////////
shimniok 0:826c6171fc1b 608
shimniok 0:826c6171fc1b 609 // Button state machine
shimniok 0:826c6171fc1b 610 // if we've not started going, button starts us
shimniok 0:826c6171fc1b 611 // if we have started going, button stops us
shimniok 0:826c6171fc1b 612 // but only if we've released it first
shimniok 0:826c6171fc1b 613 //
shimniok 0:826c6171fc1b 614 // set throttle only if goGoGo set
shimniok 0:826c6171fc1b 615 if (goGoGo) {
shimniok 0:826c6171fc1b 616 /** acceleration curve */
shimniok 0:826c6171fc1b 617 /*
shimniok 0:826c6171fc1b 618 if (go.ticked(timer.read_ms())) {
shimniok 0:826c6171fc1b 619 throttle = go.get() / 1000.0;
shimniok 0:826c6171fc1b 620 //fprintf(stdout, "throttle: %0.3f\n", throttle.read());
shimniok 0:826c6171fc1b 621 }
shimniok 0:826c6171fc1b 622 */
shimniok 0:826c6171fc1b 623
shimniok 0:826c6171fc1b 624 // TODO: 1 Add additional condition of travel for N meters before
shimniok 0:826c6171fc1b 625 // the HALT button is armed
shimniok 0:826c6171fc1b 626
shimniok 0:826c6171fc1b 627 if (keypad.pressed == true) { // && started
shimniok 0:826c6171fc1b 628 fprintf(stdout, ">>>>>>>>>>>>>>>>>>>>>>> HALT\n");
shimniok 0:826c6171fc1b 629 lcd.pos(0,1);
shimniok 0:826c6171fc1b 630 lcd.printf(LCD_FMT, "HALT.");
shimniok 0:826c6171fc1b 631 navDone = true;
shimniok 0:826c6171fc1b 632 goGoGo = false;
shimniok 0:826c6171fc1b 633 keypad.pressed = false;
shimniok 0:826c6171fc1b 634 endRun();
shimniok 0:826c6171fc1b 635 }
shimniok 0:826c6171fc1b 636 } else {
shimniok 0:826c6171fc1b 637 if (keypad.pressed == true) {
shimniok 0:826c6171fc1b 638 fprintf(stdout, ">>>>>>>>>>>>>>>>>>>>>>> GO GO GO\n");
shimniok 0:826c6171fc1b 639 lcd.pos(0,1);
shimniok 0:826c6171fc1b 640 lcd.printf(LCD_FMT, "GO GO GO!");
shimniok 0:826c6171fc1b 641 goGoGo = true;
shimniok 0:826c6171fc1b 642 keypad.pressed = false;
shimniok 0:826c6171fc1b 643 //restartNav();
shimniok 0:826c6171fc1b 644 beginRun();
shimniok 0:826c6171fc1b 645 // Doing this for collecting step response, hopefully an S curve... we'll see.
shimniok 0:826c6171fc1b 646 //throttle = config.escMax;
shimniok 0:826c6171fc1b 647 // TODO: 2 Improve encapsulation of the scheduler
shimniok 0:826c6171fc1b 648 // TODO: 2 can we do something clever with GPS position estimate since we know where we're starting?
shimniok 0:826c6171fc1b 649 // E.g. if dist to wpt0 < x then initialize to wpt0 else use gps
shimniok 0:826c6171fc1b 650 }
shimniok 0:826c6171fc1b 651 }
shimniok 0:826c6171fc1b 652
shimniok 0:826c6171fc1b 653 // Are we at the last waypoint?
shimniok 0:826c6171fc1b 654 //
shimniok 0:826c6171fc1b 655 if (state[inState].nextWaypoint == config.wptCount) {
shimniok 0:826c6171fc1b 656 fprintf(stdout, "Arrived at final destination. Done.\n");
shimniok 0:826c6171fc1b 657 //causes issue with servo library
shimniok 0:826c6171fc1b 658 //speaker.beep(3000.0, 1.0); // non-blocking
shimniok 0:826c6171fc1b 659 lcd.pos(0,1);
shimniok 0:826c6171fc1b 660 lcd.printf(LCD_FMT, "Arrived. Done.");
shimniok 0:826c6171fc1b 661 navDone = true;
shimniok 0:826c6171fc1b 662 endRun();
shimniok 0:826c6171fc1b 663 }
shimniok 0:826c6171fc1b 664
shimniok 0:826c6171fc1b 665 //////////////////////////////////////////////////////////////////////////////
shimniok 0:826c6171fc1b 666 // LOGGING
shimniok 0:826c6171fc1b 667 //////////////////////////////////////////////////////////////////////////////
shimniok 0:826c6171fc1b 668 // sensor reads are happening in the schedHandler();
shimniok 0:826c6171fc1b 669 // Are there more items to come out of the log buffer?
shimniok 0:826c6171fc1b 670 // Since this could take anywhere from a few hundred usec to
shimniok 0:826c6171fc1b 671 // 150ms, we run it opportunistically and use a buffer. That way
shimniok 0:826c6171fc1b 672 // the sensor updates, calculation, and control can continue to happen
shimniok 0:826c6171fc1b 673 if (outState != inState) {
shimniok 0:826c6171fc1b 674 logStatus = !logStatus; // log indicator LED
shimniok 0:826c6171fc1b 675 //fprintf(stdout, "FIFO: in=%d out=%d\n", inState, outState);
shimniok 0:826c6171fc1b 676 if (ssBufOverrun) {
shimniok 0:826c6171fc1b 677 fprintf(stdout, ">>> SystemState Buffer Overrun Condition\n");
shimniok 0:826c6171fc1b 678 ssBufOverrun = false;
shimniok 0:826c6171fc1b 679 }
shimniok 0:826c6171fc1b 680 // do we need to disable interrupts briefly to prevent a race
shimniok 0:826c6171fc1b 681 // condition with schedHandler() ?
shimniok 0:826c6171fc1b 682 int out=outState; // in case we're interrupted this 'should' be atomic
shimniok 0:826c6171fc1b 683 outState++; // increment
shimniok 0:826c6171fc1b 684 outState &= SSBUF; // wrap
shimniok 0:826c6171fc1b 685 logData( state[out] ); // log state data to file
shimniok 0:826c6171fc1b 686 logStatus = !logStatus; // log indicator LED
shimniok 0:826c6171fc1b 687
shimniok 0:826c6171fc1b 688 //fprintf(stdout, "Time Stats\n----------\nSensors: %d\nGPS: %d\nAHRS: %d\nLog: %d\n----------\nTotal: %d",
shimniok 0:826c6171fc1b 689 // tSensor, tGPS, tAHRS, tLog, tSensor+tGPS+tAHRS+tLog);
shimniok 0:826c6171fc1b 690 }
shimniok 0:826c6171fc1b 691
shimniok 0:826c6171fc1b 692 } // while
shimniok 0:826c6171fc1b 693
shimniok 0:826c6171fc1b 694 closeLogfile();
shimniok 0:826c6171fc1b 695 logStatus = 0;
shimniok 0:826c6171fc1b 696 fprintf(stdout, "Completed, file saved.\n");
shimniok 0:826c6171fc1b 697 wait(2); // wait from last printout
shimniok 0:826c6171fc1b 698 lcd.pos(0,1);
shimniok 0:826c6171fc1b 699 lcd.printf(LCD_FMT, "Done. Saved.");
shimniok 0:826c6171fc1b 700 wait(2);
shimniok 0:826c6171fc1b 701
shimniok 0:826c6171fc1b 702 ahrsStatus = 0;
shimniok 0:826c6171fc1b 703 gpsStatus = 0;
shimniok 0:826c6171fc1b 704 //confStatus = 0;
shimniok 0:826c6171fc1b 705 //flasher = 0;
shimniok 0:826c6171fc1b 706
shimniok 0:826c6171fc1b 707 gps.gsaMessage(false);
shimniok 0:826c6171fc1b 708 gps.gsvMessage(false);
shimniok 0:826c6171fc1b 709
shimniok 0:826c6171fc1b 710 return 0;
shimniok 0:826c6171fc1b 711 } // autonomousMode
shimniok 0:826c6171fc1b 712
shimniok 0:826c6171fc1b 713
shimniok 0:826c6171fc1b 714 ///////////////////////////////////////////////////////////////////////////////////////////////////////
shimniok 0:826c6171fc1b 715 // UTILITY FUNCTIONS
shimniok 0:826c6171fc1b 716 ///////////////////////////////////////////////////////////////////////////////////////////////////////
shimniok 0:826c6171fc1b 717
shimniok 0:826c6171fc1b 718
shimniok 0:826c6171fc1b 719 int compassCalibrate()
shimniok 0:826c6171fc1b 720 {
shimniok 0:826c6171fc1b 721 bool done=false;
shimniok 0:826c6171fc1b 722 int m[3];
shimniok 0:826c6171fc1b 723 FILE *fp;
shimniok 0:826c6171fc1b 724
shimniok 0:826c6171fc1b 725 fprintf(stdout, "Entering compass calibration in 2 seconds.\nLaunch _3DScatter Processing app now... type e to exit\n");
shimniok 0:826c6171fc1b 726 lcd.pos(0,1);
shimniok 0:826c6171fc1b 727
shimniok 0:826c6171fc1b 728 lcd.printf(LCD_FMT, "Starting...");
shimniok 0:826c6171fc1b 729
shimniok 0:826c6171fc1b 730 fp = openlog("cal");
shimniok 0:826c6171fc1b 731
shimniok 0:826c6171fc1b 732 wait(2);
shimniok 0:826c6171fc1b 733 lcd.pos(0,1);
shimniok 0:826c6171fc1b 734 lcd.printf(LCD_FMT, "Select exits");
shimniok 0:826c6171fc1b 735 timer.reset();
shimniok 0:826c6171fc1b 736 timer.start();
shimniok 0:826c6171fc1b 737 while (!done) {
shimniok 0:826c6171fc1b 738
shimniok 0:826c6171fc1b 739 if (keypad.pressed) {
shimniok 0:826c6171fc1b 740 keypad.pressed = false;
shimniok 0:826c6171fc1b 741 done = true;
shimniok 0:826c6171fc1b 742 }
shimniok 0:826c6171fc1b 743
shimniok 0:826c6171fc1b 744 while (pc.readable()) {
shimniok 0:826c6171fc1b 745 if (pc.getc() == 'e') {
shimniok 0:826c6171fc1b 746 done = true;
shimniok 0:826c6171fc1b 747 break;
shimniok 0:826c6171fc1b 748 }
shimniok 0:826c6171fc1b 749 }
shimniok 0:826c6171fc1b 750 int millis = timer.read_ms();
shimniok 0:826c6171fc1b 751 if ((millis % 100) == 0) {
shimniok 0:826c6171fc1b 752 sensors.getRawMag(m);
shimniok 0:826c6171fc1b 753
shimniok 0:826c6171fc1b 754 // Correction
shimniok 0:826c6171fc1b 755 // Let's see how our ellipsoid looks after scaling and offset
shimniok 0:826c6171fc1b 756 /*
shimniok 0:826c6171fc1b 757 float mag[3];
shimniok 0:826c6171fc1b 758 mag[0] = ((float) m[0] - M_OFFSET_X) * 0.5 / M_SCALE_X;
shimniok 0:826c6171fc1b 759 mag[1] = ((float) m[1] - M_OFFSET_Y) * 0.5 / M_SCALE_Y;
shimniok 0:826c6171fc1b 760 mag[2] = ((float) m[2] - M_OFFSET_Z) * 0.5 / M_SCALE_Z;
shimniok 0:826c6171fc1b 761 */
shimniok 0:826c6171fc1b 762
shimniok 0:826c6171fc1b 763 bool skipIt = false;
shimniok 0:826c6171fc1b 764 for (int i=0; i < 3; i++) {
shimniok 0:826c6171fc1b 765 if (abs(m[i]) > 1024) skipIt = true;
shimniok 0:826c6171fc1b 766 }
shimniok 0:826c6171fc1b 767 if (!skipIt) {
shimniok 0:826c6171fc1b 768 fprintf(stdout, "%c%d %d %d \r\n", 0xDE, m[0], m[1], m[2]);
shimniok 0:826c6171fc1b 769 fprintf(fp, "%d, %d, %d\n", m[0], m[1], m[2]);
shimniok 0:826c6171fc1b 770 }
shimniok 0:826c6171fc1b 771 }
shimniok 0:826c6171fc1b 772 }
shimniok 0:826c6171fc1b 773 if (fp) {
shimniok 0:826c6171fc1b 774 fclose(fp);
shimniok 0:826c6171fc1b 775 lcd.pos(0,1);
shimniok 0:826c6171fc1b 776 lcd.printf(LCD_FMT, "Done. Saved.");
shimniok 0:826c6171fc1b 777 wait(2);
shimniok 0:826c6171fc1b 778 }
shimniok 0:826c6171fc1b 779
shimniok 0:826c6171fc1b 780 return 0;
shimniok 0:826c6171fc1b 781 }
shimniok 0:826c6171fc1b 782
shimniok 0:826c6171fc1b 783 // Gather gyro data using turntable equipped with dual channel
shimniok 0:826c6171fc1b 784 // encoder. Use onboard wheel encoder system. Left channel
shimniok 0:826c6171fc1b 785 // is the index (0 degree) mark, while the right channel
shimniok 0:826c6171fc1b 786 // is the incremental encoder. Can then compare gyro integrated
shimniok 0:826c6171fc1b 787 // heading with machine-reported heading
shimniok 0:826c6171fc1b 788 //
shimniok 0:826c6171fc1b 789 // Note: some of this code is identical to the compassSwing() code.
shimniok 0:826c6171fc1b 790 //
shimniok 0:826c6171fc1b 791 int gyroSwing()
shimniok 0:826c6171fc1b 792 {
shimniok 0:826c6171fc1b 793 FILE *fp;
shimniok 0:826c6171fc1b 794
shimniok 0:826c6171fc1b 795 // Timing is pretty critical so just in case, disable serial processing from GPS
shimniok 0:826c6171fc1b 796 gps.serial.attach(NULL, Serial::RxIrq);
shimniok 0:826c6171fc1b 797
shimniok 0:826c6171fc1b 798 fprintf(stdout, "Entering gyro swing...\n");
shimniok 0:826c6171fc1b 799 lcd.pos(0,1);
shimniok 0:826c6171fc1b 800 lcd.printf(LCD_FMT, "Starting...");
shimniok 0:826c6171fc1b 801 wait(2);
shimniok 0:826c6171fc1b 802 fp = openlog("gy");
shimniok 0:826c6171fc1b 803 wait(2);
shimniok 0:826c6171fc1b 804 lcd.pos(0,1);
shimniok 0:826c6171fc1b 805 lcd.printf(LCD_FMT, "Begin. Select exits.");
shimniok 0:826c6171fc1b 806
shimniok 0:826c6171fc1b 807 fprintf(stdout, "Begin clockwise rotation, varying rpm... press select to exit\n");
shimniok 0:826c6171fc1b 808
shimniok 0:826c6171fc1b 809 timer.reset();
shimniok 0:826c6171fc1b 810 timer.start();
shimniok 0:826c6171fc1b 811
shimniok 0:826c6171fc1b 812 sensors.rightTotal = 0; // reset total
shimniok 0:826c6171fc1b 813 sensors._right.read(); // easiest way to reset the heading counter
shimniok 0:826c6171fc1b 814
shimniok 0:826c6171fc1b 815 while (1) {
shimniok 0:826c6171fc1b 816 if (keypad.pressed) {
shimniok 0:826c6171fc1b 817 keypad.pressed = false;
shimniok 0:826c6171fc1b 818 break;
shimniok 0:826c6171fc1b 819 }
shimniok 0:826c6171fc1b 820
shimniok 0:826c6171fc1b 821 // Print out data
shimniok 0:826c6171fc1b 822 // fprintf(stdout, "%d,%d,%d,%d,%d\n", timer.read_ms(), heading, sensors.g[0], sensors.g[1], sensors.g[2]);
shimniok 0:826c6171fc1b 823 // sensors.rightTotal gives us each tick of the machine, multiply by 2 for cumulative heading, which is easiest
shimniok 0:826c6171fc1b 824 // to compare with cumulative integration of gyro (rather than dealing with 0-360 degree range and modulus and whatnot
shimniok 0:826c6171fc1b 825 if (fp) fprintf(fp, "%d,%d,%d,%d,%d,%d\n", timer.read_ms(), 2*sensors.rightTotal, sensors.g[0], sensors.g[1], sensors.g[2], sensors.gTemp);
shimniok 0:826c6171fc1b 826 wait(0.200);
shimniok 0:826c6171fc1b 827 }
shimniok 0:826c6171fc1b 828 if (fp) {
shimniok 0:826c6171fc1b 829 fclose(fp);
shimniok 0:826c6171fc1b 830 lcd.pos(0,1);
shimniok 0:826c6171fc1b 831 lcd.printf(LCD_FMT, "Done. Saved.");
shimniok 0:826c6171fc1b 832 fprintf(stdout, "Data collection complete.\n");
shimniok 0:826c6171fc1b 833 wait(2);
shimniok 0:826c6171fc1b 834 }
shimniok 0:826c6171fc1b 835
shimniok 0:826c6171fc1b 836 keypad.pressed = false;
shimniok 0:826c6171fc1b 837
shimniok 0:826c6171fc1b 838 return 0;
shimniok 0:826c6171fc1b 839 }
shimniok 0:826c6171fc1b 840
shimniok 0:826c6171fc1b 841
shimniok 0:826c6171fc1b 842 // Swing compass using turntable equipped with dual channel
shimniok 0:826c6171fc1b 843 // encoder. Use onboard wheel encoder system. Left channel
shimniok 0:826c6171fc1b 844 // is the index (0 degree) mark, while the right channel
shimniok 0:826c6171fc1b 845 // is the incremental encoder.
shimniok 0:826c6171fc1b 846 //
shimniok 0:826c6171fc1b 847 // Note: much of this code is identical to the gyroSwing() code.
shimniok 0:826c6171fc1b 848 //
shimniok 0:826c6171fc1b 849 int compassSwing()
shimniok 0:826c6171fc1b 850 {
shimniok 0:826c6171fc1b 851 int revolutions=5;
shimniok 0:826c6171fc1b 852 int heading=0;
shimniok 0:826c6171fc1b 853 int leftCount = 0;
shimniok 0:826c6171fc1b 854 FILE *fp;
shimniok 0:826c6171fc1b 855 // left is index track
shimniok 0:826c6171fc1b 856 // right is encoder track
shimniok 0:826c6171fc1b 857
shimniok 0:826c6171fc1b 858 fprintf(stdout, "Entering compass swing...\n");
shimniok 0:826c6171fc1b 859 lcd.pos(0,1);
shimniok 0:826c6171fc1b 860 lcd.printf(LCD_FMT, "Starting...");
shimniok 0:826c6171fc1b 861 wait(2);
shimniok 0:826c6171fc1b 862 fp = openlog("sw");
shimniok 0:826c6171fc1b 863 wait(2);
shimniok 0:826c6171fc1b 864 lcd.pos(0,1);
shimniok 0:826c6171fc1b 865 lcd.printf(LCD_FMT, "Ok. Begin.");
shimniok 0:826c6171fc1b 866
shimniok 0:826c6171fc1b 867 fprintf(stdout, "Begin clockwise rotation... exit after %d revolutions\n", revolutions);
shimniok 0:826c6171fc1b 868
shimniok 0:826c6171fc1b 869 timer.reset();
shimniok 0:826c6171fc1b 870 timer.start();
shimniok 0:826c6171fc1b 871
shimniok 0:826c6171fc1b 872 // wait for index to change
shimniok 0:826c6171fc1b 873 while ((leftCount += sensors._left.read()) < 2) {
shimniok 0:826c6171fc1b 874 if (keypad.pressed) {
shimniok 0:826c6171fc1b 875 keypad.pressed = false;
shimniok 0:826c6171fc1b 876 break;
shimniok 0:826c6171fc1b 877 }
shimniok 0:826c6171fc1b 878 }
shimniok 0:826c6171fc1b 879 fprintf(stdout, ">>>> Index detected. Starting data collection\n");
shimniok 0:826c6171fc1b 880 leftCount = 0;
shimniok 0:826c6171fc1b 881 lcd.pos(0,1);
shimniok 0:826c6171fc1b 882 lcd.printf("%1d %-14s", revolutions, "revs left");
shimniok 0:826c6171fc1b 883
shimniok 0:826c6171fc1b 884 sensors._right.read(); // easiest way to reset the heading counter
shimniok 0:826c6171fc1b 885
shimniok 0:826c6171fc1b 886 while (revolutions > 0) {
shimniok 0:826c6171fc1b 887 int encoder;
shimniok 0:826c6171fc1b 888
shimniok 0:826c6171fc1b 889 if (keypad.pressed) {
shimniok 0:826c6171fc1b 890 keypad.pressed = false;
shimniok 0:826c6171fc1b 891 break;
shimniok 0:826c6171fc1b 892 }
shimniok 0:826c6171fc1b 893
shimniok 0:826c6171fc1b 894 // wait for state change
shimniok 0:826c6171fc1b 895 while ((encoder = sensors._right.read()) == 0) {
shimniok 0:826c6171fc1b 896 if (keypad.pressed) {
shimniok 0:826c6171fc1b 897 keypad.pressed = false;
shimniok 0:826c6171fc1b 898 break;
shimniok 0:826c6171fc1b 899 }
shimniok 0:826c6171fc1b 900 }
shimniok 0:826c6171fc1b 901 heading += 2*encoder; // encoder has resolution of 2 degrees
shimniok 0:826c6171fc1b 902 if (heading >= 360) heading -= 360;
shimniok 0:826c6171fc1b 903
shimniok 0:826c6171fc1b 904 // when index is 1, reset the heading and decrement revolution counter
shimniok 0:826c6171fc1b 905 // make sure we don't detect the index mark until after the first several
shimniok 0:826c6171fc1b 906 // encoder pulses. Index is active low
shimniok 0:826c6171fc1b 907 if ((leftCount += sensors._left.read()) > 1) {
shimniok 0:826c6171fc1b 908 // check for error in heading?
shimniok 0:826c6171fc1b 909 leftCount = 0;
shimniok 0:826c6171fc1b 910 revolutions--;
shimniok 0:826c6171fc1b 911 fprintf(stdout, ">>>>> %d left\n", revolutions); // we sense the rising and falling of the index so /2
shimniok 0:826c6171fc1b 912 lcd.pos(0,1);
shimniok 0:826c6171fc1b 913 lcd.printf("%1d %-14s", revolutions, "revs left");
shimniok 0:826c6171fc1b 914 }
shimniok 0:826c6171fc1b 915
shimniok 0:826c6171fc1b 916 float heading2d = 180 * atan2((float) sensors.mag[1], (float) sensors.mag[0]) / PI;
shimniok 0:826c6171fc1b 917 // Print out data
shimniok 0:826c6171fc1b 918 //getRawMag(m);
shimniok 0:826c6171fc1b 919 fprintf(stdout, "%d %.4f\n", heading, heading2d);
shimniok 0:826c6171fc1b 920
shimniok 0:826c6171fc1b 921 // int t1=t.read_us();
shimniok 0:826c6171fc1b 922 if (fp) fprintf(fp, "%d, %d, %.2f, %.4f, %.4f, %.4f\n",
shimniok 0:826c6171fc1b 923 timer.read_ms(), heading, heading2d, sensors.mag[0], sensors.mag[1], sensors.mag[2]);
shimniok 0:826c6171fc1b 924 // int t2=t.read_us();
shimniok 0:826c6171fc1b 925 // fprintf(stdout, "dt=%d\n", t2-t1);
shimniok 0:826c6171fc1b 926 }
shimniok 0:826c6171fc1b 927 if (fp) {
shimniok 0:826c6171fc1b 928 fclose(fp);
shimniok 0:826c6171fc1b 929 lcd.pos(0,1);
shimniok 0:826c6171fc1b 930 lcd.printf(LCD_FMT, "Done. Saved.");
shimniok 0:826c6171fc1b 931 fprintf(stdout, "Data collection complete.\n");
shimniok 0:826c6171fc1b 932 wait(2);
shimniok 0:826c6171fc1b 933 }
shimniok 0:826c6171fc1b 934
shimniok 0:826c6171fc1b 935 keypad.pressed = false;
shimniok 0:826c6171fc1b 936
shimniok 0:826c6171fc1b 937 return 0;
shimniok 0:826c6171fc1b 938 }
shimniok 0:826c6171fc1b 939
shimniok 0:826c6171fc1b 940 void servoCalibrate()
shimniok 0:826c6171fc1b 941 {
shimniok 0:826c6171fc1b 942 }
shimniok 0:826c6171fc1b 943
shimniok 0:826c6171fc1b 944 void bridgeRecv()
shimniok 0:826c6171fc1b 945 {
shimniok 0:826c6171fc1b 946 while (dev && dev->readable()) {
shimniok 0:826c6171fc1b 947 pc.putc(dev->getc());
shimniok 0:826c6171fc1b 948 }
shimniok 0:826c6171fc1b 949 }
shimniok 0:826c6171fc1b 950
shimniok 0:826c6171fc1b 951 void serialBridge(Serial &serial)
shimniok 0:826c6171fc1b 952 {
shimniok 0:826c6171fc1b 953 char x;
shimniok 0:826c6171fc1b 954 int count = 0;
shimniok 0:826c6171fc1b 955 bool done=false;
shimniok 0:826c6171fc1b 956
shimniok 0:826c6171fc1b 957 fprintf(stdout, "\nEntering serial bridge in 2 seconds, +++ to escape\n\n");
shimniok 0:826c6171fc1b 958 //gps.setNmeaMessages(true, true, true, false, true, false); // enable GGA, GSA, GSV, RMC
shimniok 0:826c6171fc1b 959 gps.setNmeaMessages(true, false, false, false, true, false); // enable only GGA, RMC
shimniok 0:826c6171fc1b 960 wait(2.0);
shimniok 0:826c6171fc1b 961 //dev = &gps;
shimniok 0:826c6171fc1b 962 serial.attach(NULL, Serial::RxIrq);
shimniok 0:826c6171fc1b 963 while (!done) {
shimniok 0:826c6171fc1b 964 if (pc.readable()) {
shimniok 0:826c6171fc1b 965 x = pc.getc();
shimniok 0:826c6171fc1b 966 // escape sequence
shimniok 0:826c6171fc1b 967 if (x == '+') {
shimniok 0:826c6171fc1b 968 if (++count >= 3) done=true;
shimniok 0:826c6171fc1b 969 } else {
shimniok 0:826c6171fc1b 970 count = 0;
shimniok 0:826c6171fc1b 971 }
shimniok 0:826c6171fc1b 972 serial.putc(x);
shimniok 0:826c6171fc1b 973 }
shimniok 0:826c6171fc1b 974 if (serial.readable()) {
shimniok 0:826c6171fc1b 975 pc.putc(serial.getc());
shimniok 0:826c6171fc1b 976 }
shimniok 0:826c6171fc1b 977 }
shimniok 0:826c6171fc1b 978 }
shimniok 0:826c6171fc1b 979
shimniok 0:826c6171fc1b 980 /* to be called from panel menu
shimniok 0:826c6171fc1b 981 */
shimniok 0:826c6171fc1b 982 int instrumentCheck(void) {
shimniok 0:826c6171fc1b 983 displayData(INSTRUMENT_CHECK);
shimniok 0:826c6171fc1b 984 return 0;
shimniok 0:826c6171fc1b 985 }
shimniok 0:826c6171fc1b 986
shimniok 0:826c6171fc1b 987 /* Display data
shimniok 0:826c6171fc1b 988 * mode determines the type of data and format
shimniok 0:826c6171fc1b 989 * INSTRUMENT_CHECK : display readings of various instruments
shimniok 0:826c6171fc1b 990 * AHRS_VISUALIZATION : display data for use by AHRS python visualization script
shimniok 0:826c6171fc1b 991 */
shimniok 0:826c6171fc1b 992
shimniok 0:826c6171fc1b 993 void displayData(int mode)
shimniok 0:826c6171fc1b 994 {
shimniok 0:826c6171fc1b 995 bool done = false;
shimniok 0:826c6171fc1b 996
shimniok 0:826c6171fc1b 997 lcd.clear();
shimniok 0:826c6171fc1b 998
shimniok 0:826c6171fc1b 999 // Init GPS
shimniok 0:826c6171fc1b 1000 gps.setNmeaMessages(true, false, false, false, true, false); // enable GGA, GSA, RMC
shimniok 0:826c6171fc1b 1001 gps.serial.attach(gpsRecv, Serial::RxIrq);
shimniok 0:826c6171fc1b 1002 gps.nmea.reset_ready();
shimniok 0:826c6171fc1b 1003
shimniok 0:826c6171fc1b 1004 keypad.pressed = false;
shimniok 0:826c6171fc1b 1005
shimniok 0:826c6171fc1b 1006 timer.reset();
shimniok 0:826c6171fc1b 1007 timer.start();
shimniok 0:826c6171fc1b 1008
shimniok 0:826c6171fc1b 1009 fprintf(stdout, "press e to exit\n");
shimniok 0:826c6171fc1b 1010 while (!done) {
shimniok 0:826c6171fc1b 1011 int millis = timer.read_ms();
shimniok 0:826c6171fc1b 1012
shimniok 0:826c6171fc1b 1013 if (keypad.pressed) {
shimniok 0:826c6171fc1b 1014 keypad.pressed = false;
shimniok 0:826c6171fc1b 1015 done=true;
shimniok 0:826c6171fc1b 1016 }
shimniok 0:826c6171fc1b 1017
shimniok 0:826c6171fc1b 1018 while (pc.readable()) {
shimniok 0:826c6171fc1b 1019 if (pc.getc() == 'e') {
shimniok 0:826c6171fc1b 1020 done = true;
shimniok 0:826c6171fc1b 1021 break;
shimniok 0:826c6171fc1b 1022 }
shimniok 0:826c6171fc1b 1023 }
shimniok 0:826c6171fc1b 1024
shimniok 0:826c6171fc1b 1025 /*
shimniok 0:826c6171fc1b 1026 if (mode == AHRS_VISUALIZATION && (millis % 100) == 0) {
shimniok 0:826c6171fc1b 1027
shimniok 0:826c6171fc1b 1028 fprintf(stdout, "!ANG:%.1f,%.1f,%.1f\r\n", ToDeg(ahrs.roll), ToDeg(ahrs.pitch), ToDeg(ahrs.yaw));
shimniok 0:826c6171fc1b 1029
shimniok 0:826c6171fc1b 1030 } else */
shimniok 0:826c6171fc1b 1031
shimniok 0:826c6171fc1b 1032 if (mode == INSTRUMENT_CHECK) {
shimniok 0:826c6171fc1b 1033
shimniok 0:826c6171fc1b 1034 if ((millis % 1000) == 0) {
shimniok 0:826c6171fc1b 1035
shimniok 0:826c6171fc1b 1036 fprintf(stdout, "update() time = %.3f msec\n", getUpdateTime() / 1000.0);
shimniok 0:826c6171fc1b 1037 fprintf(stdout, "Rangers: L=%.2f R=%.2f C=%.2f", sensors.leftRanger, sensors.rightRanger, sensors.centerRanger);
shimniok 0:826c6171fc1b 1038 fprintf(stdout, "\n");
shimniok 0:826c6171fc1b 1039 //fprintf(stdout, "ahrs.MAG_Heading=%4.1f\n", ahrs.MAG_Heading*180/PI);
shimniok 0:826c6171fc1b 1040 fprintf(stdout, "raw m=(%d, %d, %d)\n", sensors.m[0], sensors.m[1], sensors.m[2]);
shimniok 0:826c6171fc1b 1041 fprintf(stdout, "m=(%2.3f, %2.3f, %2.3f) %2.3f\n", sensors.mag[0], sensors.mag[1], sensors.mag[2],
shimniok 0:826c6171fc1b 1042 sqrt(sensors.mag[0]*sensors.mag[0] + sensors.mag[1]*sensors.mag[1] + sensors.mag[2]*sensors.mag[2] ));
shimniok 0:826c6171fc1b 1043 fprintf(stdout, "g=(%4d, %4d, %4d) %d\n", sensors.g[0], sensors.g[1], sensors.g[2], sensors.gTemp);
shimniok 0:826c6171fc1b 1044 fprintf(stdout, "gc=(%.1f, %.1f, %.1f)\n", sensors.gyro[0], sensors.gyro[1], sensors.gyro[2]);
shimniok 0:826c6171fc1b 1045 fprintf(stdout, "a=(%5d, %5d, %5d)\n", sensors.a[0], sensors.a[1], sensors.a[2]);
shimniok 0:826c6171fc1b 1046 fprintf(stdout, "estHdg=%.2f\n", state[inState].estHeading);
shimniok 0:826c6171fc1b 1047 //fprintf(stdout, "roll=%.2f pitch=%.2f yaw=%.2f\n", ToDeg(ahrs.roll), ToDeg(ahrs.pitch), ToDeg(ahrs.yaw));
shimniok 0:826c6171fc1b 1048 fprintf(stdout, "speed: left=%.3f right=%.3f\n", sensors.lrEncSpeed, sensors.rrEncSpeed);
shimniok 0:826c6171fc1b 1049 fprintf(stdout, "gps=(%.6f, %.6f, %.1f, %.1f, %.1f, %d)\n", gps_here.latitude(), gps_here.longitude(),
shimniok 0:826c6171fc1b 1050 gps.nmea.f_course(), gps.nmea.f_speed_mps(), gps.hdop, gps.nmea.sat_count());
shimniok 0:826c6171fc1b 1051 fprintf(stdout, "v=%.2f a=%.3f\n", sensors.voltage, sensors.current);
shimniok 0:826c6171fc1b 1052 fprintf(stdout, "\n");
shimniok 0:826c6171fc1b 1053
shimniok 0:826c6171fc1b 1054 }
shimniok 0:826c6171fc1b 1055
shimniok 0:826c6171fc1b 1056 if ((millis % 3000) == 0) {
shimniok 0:826c6171fc1b 1057
shimniok 0:826c6171fc1b 1058 lcd.pos(0,1);
shimniok 0:826c6171fc1b 1059 //lcd.printf("H=%4.1f ", ahrs.MAG_Heading*180/PI);
shimniok 0:826c6171fc1b 1060 //wait(0.1);
shimniok 0:826c6171fc1b 1061 lcd.pos(0,2);
shimniok 0:826c6171fc1b 1062 lcd.printf("G=%4.1f,%4.1f,%4.1f ", sensors.gyro[0], sensors.gyro[1], sensors.gyro[2]);
shimniok 0:826c6171fc1b 1063 wait(0.1);
shimniok 0:826c6171fc1b 1064 lcd.pos(0,3);
shimniok 0:826c6171fc1b 1065 lcd.printf("La=%11.6f HD=%1.1f ", gps_here.latitude(), gps.hdop);
shimniok 0:826c6171fc1b 1066 wait(0.1);
shimniok 0:826c6171fc1b 1067 lcd.pos(0,4);
shimniok 0:826c6171fc1b 1068 lcd.printf("Lo=%11.6f Sat=%-2d ", gps_here.longitude(), gps.nmea.sat_count());
shimniok 0:826c6171fc1b 1069 wait(0.1);
shimniok 0:826c6171fc1b 1070 lcd.pos(0,5);
shimniok 0:826c6171fc1b 1071 lcd.printf("V=%5.2f A=%5.3f ", sensors.voltage, sensors.current);
shimniok 0:826c6171fc1b 1072
shimniok 0:826c6171fc1b 1073 }
shimniok 0:826c6171fc1b 1074 }
shimniok 0:826c6171fc1b 1075
shimniok 0:826c6171fc1b 1076 } // while !done
shimniok 0:826c6171fc1b 1077 // clear input buffer
shimniok 0:826c6171fc1b 1078 while (pc.readable()) pc.getc();
shimniok 0:826c6171fc1b 1079 lcd.clear();
shimniok 0:826c6171fc1b 1080 ahrsStatus = 0;
shimniok 0:826c6171fc1b 1081 gpsStatus = 0;
shimniok 0:826c6171fc1b 1082 }
shimniok 0:826c6171fc1b 1083
shimniok 0:826c6171fc1b 1084
shimniok 0:826c6171fc1b 1085 // TODO: 3 move Mavlink into main (non-interrupt) loop along with logging
shimniok 0:826c6171fc1b 1086 // possibly also buffered if necessary
shimniok 0:826c6171fc1b 1087
shimniok 0:826c6171fc1b 1088 void mavlinkMode() {
shimniok 0:826c6171fc1b 1089 uint8_t system_type = MAV_FIXED_WING;
shimniok 0:826c6171fc1b 1090 uint8_t autopilot_type = MAV_AUTOPILOT_GENERIC;
shimniok 0:826c6171fc1b 1091 //int count = 0;
shimniok 0:826c6171fc1b 1092 bool done = false;
shimniok 0:826c6171fc1b 1093
shimniok 0:826c6171fc1b 1094 mavlink_system.sysid = 100; // System ID, 1-255
shimniok 0:826c6171fc1b 1095 mavlink_system.compid = 200; // Component/Subsystem ID, 1-255
shimniok 0:826c6171fc1b 1096
shimniok 0:826c6171fc1b 1097 //mavlink_attitude_t mav_attitude;
shimniok 0:826c6171fc1b 1098 //mavlink_sys_status_t mav_stat;
shimniok 0:826c6171fc1b 1099 mavlink_vfr_hud_t mav_hud;
shimniok 0:826c6171fc1b 1100
shimniok 0:826c6171fc1b 1101 //mav_stat.mode = MAV_MODE_MANUAL;
shimniok 0:826c6171fc1b 1102 //mav_stat.status = MAV_STATE_STANDBY;
shimniok 0:826c6171fc1b 1103 //mav_stat.vbat = 8400;
shimniok 0:826c6171fc1b 1104 //mav_stat.battery_remaining = 1000;
shimniok 0:826c6171fc1b 1105
shimniok 0:826c6171fc1b 1106 mav_hud.airspeed = 0.0;
shimniok 0:826c6171fc1b 1107 mav_hud.groundspeed = 0.0;
shimniok 0:826c6171fc1b 1108 mav_hud.throttle = 0;
shimniok 0:826c6171fc1b 1109
shimniok 0:826c6171fc1b 1110 fprintf(stdout, "Entering MAVlink mode; reset the MCU to exit\n\n");
shimniok 0:826c6171fc1b 1111
shimniok 0:826c6171fc1b 1112 gps.gsvMessage(true);
shimniok 0:826c6171fc1b 1113 gps.gsaMessage(true);
shimniok 0:826c6171fc1b 1114 gps.serial.attach(gpsRecv, Serial::RxIrq);
shimniok 0:826c6171fc1b 1115
shimniok 0:826c6171fc1b 1116 while (done == false) {
shimniok 0:826c6171fc1b 1117
shimniok 0:826c6171fc1b 1118 if (keypad.pressed == true) { // && started
shimniok 0:826c6171fc1b 1119 keypad.pressed = false;
shimniok 0:826c6171fc1b 1120 done = true;
shimniok 0:826c6171fc1b 1121 }
shimniok 0:826c6171fc1b 1122
shimniok 0:826c6171fc1b 1123 int millis = timer.read_ms();
shimniok 0:826c6171fc1b 1124
shimniok 0:826c6171fc1b 1125 if ((millis % 1000) == 0) {
shimniok 0:826c6171fc1b 1126
shimniok 0:826c6171fc1b 1127 mav_hud.heading = 0.0; //ahrs.parser.yaw;
shimniok 0:826c6171fc1b 1128
shimniok 0:826c6171fc1b 1129 mavlink_msg_attitude_send(MAVLINK_COMM_0, millis*1000,
shimniok 0:826c6171fc1b 1130 0.0, //ToDeg(ahrs.roll),
shimniok 0:826c6171fc1b 1131 0.0, //ToDeg(ahrs.pitch),
shimniok 0:826c6171fc1b 1132 0.0, //ToDeg(ahrs.yaw), TODO: 3 fix this to use current estimate
shimniok 0:826c6171fc1b 1133 0.0, // rollspeed
shimniok 0:826c6171fc1b 1134 0.0, // pitchspeed
shimniok 0:826c6171fc1b 1135 0.0 // yawspeed
shimniok 0:826c6171fc1b 1136 );
shimniok 0:826c6171fc1b 1137
shimniok 0:826c6171fc1b 1138 mav_hud.groundspeed = sensors.encSpeed;
shimniok 0:826c6171fc1b 1139 mav_hud.groundspeed *= 2.237; // convert to mph
shimniok 0:826c6171fc1b 1140 //mav_hud.heading = compassHeading();
shimniok 0:826c6171fc1b 1141
shimniok 0:826c6171fc1b 1142 mavlink_msg_vfr_hud_send(MAVLINK_COMM_0,
shimniok 0:826c6171fc1b 1143 mav_hud.groundspeed,
shimniok 0:826c6171fc1b 1144 mav_hud.groundspeed,
shimniok 0:826c6171fc1b 1145 mav_hud.heading,
shimniok 0:826c6171fc1b 1146 mav_hud.throttle,
shimniok 0:826c6171fc1b 1147 0.0, // altitude
shimniok 0:826c6171fc1b 1148 0.0 // climb
shimniok 0:826c6171fc1b 1149 );
shimniok 0:826c6171fc1b 1150
shimniok 0:826c6171fc1b 1151 mavlink_msg_heartbeat_send(MAVLINK_COMM_0, system_type, autopilot_type);
shimniok 0:826c6171fc1b 1152 mavlink_msg_sys_status_send(MAVLINK_COMM_0,
shimniok 0:826c6171fc1b 1153 MAV_MODE_MANUAL,
shimniok 0:826c6171fc1b 1154 MAV_NAV_GROUNDED,
shimniok 0:826c6171fc1b 1155 MAV_STATE_STANDBY,
shimniok 0:826c6171fc1b 1156 0.0, // load
shimniok 0:826c6171fc1b 1157 (uint16_t) (sensors.voltage * 1000),
shimniok 0:826c6171fc1b 1158 1000, // TODO: 3 fix batt remaining
shimniok 0:826c6171fc1b 1159 0 // packet drop
shimniok 0:826c6171fc1b 1160 );
shimniok 0:826c6171fc1b 1161
shimniok 0:826c6171fc1b 1162 wait(0.001);
shimniok 0:826c6171fc1b 1163 } // millis % 1000
shimniok 0:826c6171fc1b 1164
shimniok 0:826c6171fc1b 1165 if (gps.nmea.rmc_ready() && gps.nmea.gga_ready()) {
shimniok 0:826c6171fc1b 1166 char gpsdate[32], gpstime[32];
shimniok 0:826c6171fc1b 1167
shimniok 0:826c6171fc1b 1168 gps.process(gps_here, gpsdate, gpstime);
shimniok 0:826c6171fc1b 1169 gpsStatus = (gps.hdop > 0.0 && gps.hdop < 3.0) ? 1 : 0;
shimniok 0:826c6171fc1b 1170
shimniok 0:826c6171fc1b 1171 mavlink_msg_gps_raw_send(MAVLINK_COMM_0, millis*1000, 3,
shimniok 0:826c6171fc1b 1172 gps_here.latitude(),
shimniok 0:826c6171fc1b 1173 gps_here.longitude(),
shimniok 0:826c6171fc1b 1174 0.0, // altitude
shimniok 0:826c6171fc1b 1175 gps.nmea.f_hdop()*100.0,
shimniok 0:826c6171fc1b 1176 0.0, // VDOP
shimniok 0:826c6171fc1b 1177 mav_hud.groundspeed,
shimniok 0:826c6171fc1b 1178 mav_hud.heading
shimniok 0:826c6171fc1b 1179 );
shimniok 0:826c6171fc1b 1180
shimniok 0:826c6171fc1b 1181 mavlink_msg_gps_status_send(MAVLINK_COMM_0, gps.nmea.sat_count(), 0, 0, 0, 0, 0);
shimniok 0:826c6171fc1b 1182
shimniok 0:826c6171fc1b 1183 gps.nmea.reset_ready();
shimniok 0:826c6171fc1b 1184
shimniok 0:826c6171fc1b 1185 } //gps
shimniok 0:826c6171fc1b 1186
shimniok 0:826c6171fc1b 1187 //mavlink_msg_attitude_send(MAVLINK_COMM_0, millis*1000, mav_attitude.roll, mav_attitude.pitch, mav_attitude.yaw, 0.0, 0.0, 0.0);
shimniok 0:826c6171fc1b 1188 //mavlink_msg_sys_status_send(MAVLINK_COMM_0, mav_stat.mode, mav_stat.nav_mode, mav_stat.status, mav_stat.load,
shimniok 0:826c6171fc1b 1189 // mav_stat.vbat, mav_stat.battery_remaining, 0);
shimniok 0:826c6171fc1b 1190 }
shimniok 0:826c6171fc1b 1191
shimniok 0:826c6171fc1b 1192 gps.serial.attach(NULL, Serial::RxIrq);
shimniok 0:826c6171fc1b 1193 gps.gsvMessage(false);
shimniok 0:826c6171fc1b 1194 gps.gsaMessage(false);
shimniok 0:826c6171fc1b 1195 fprintf(stdout, "\n");
shimniok 0:826c6171fc1b 1196
shimniok 0:826c6171fc1b 1197 return;
shimniok 0:826c6171fc1b 1198 }
shimniok 0:826c6171fc1b 1199
shimniok 0:826c6171fc1b 1200
shimniok 0:826c6171fc1b 1201 int setBacklight(void) {
shimniok 0:826c6171fc1b 1202 Menu bmenu;
shimniok 0:826c6171fc1b 1203 bool done = false;
shimniok 0:826c6171fc1b 1204 bool printUpdate = false;
shimniok 0:826c6171fc1b 1205 static int backlight=100;
shimniok 0:826c6171fc1b 1206
shimniok 0:826c6171fc1b 1207 lcd.pos(0,0);
shimniok 0:826c6171fc1b 1208 lcd.printf(LCD_FMT, ">> Backlight");
shimniok 0:826c6171fc1b 1209
shimniok 0:826c6171fc1b 1210 while (!done) {
shimniok 0:826c6171fc1b 1211 if (keypad.pressed) {
shimniok 0:826c6171fc1b 1212 keypad.pressed = false;
shimniok 0:826c6171fc1b 1213 printUpdate = true;
shimniok 0:826c6171fc1b 1214 switch (keypad.which) {
shimniok 0:826c6171fc1b 1215 case NEXT_BUTTON:
shimniok 0:826c6171fc1b 1216 backlight+=5;
shimniok 0:826c6171fc1b 1217 if (backlight > 100) backlight = 100;
shimniok 0:826c6171fc1b 1218 lcd.backlight(backlight);
shimniok 0:826c6171fc1b 1219 break;
shimniok 0:826c6171fc1b 1220 case PREV_BUTTON:
shimniok 0:826c6171fc1b 1221 backlight-=5;
shimniok 0:826c6171fc1b 1222 if (backlight < 0) backlight = 0;
shimniok 0:826c6171fc1b 1223 lcd.backlight(backlight);
shimniok 0:826c6171fc1b 1224 break;
shimniok 0:826c6171fc1b 1225 case SELECT_BUTTON:
shimniok 0:826c6171fc1b 1226 done = true;
shimniok 0:826c6171fc1b 1227 break;
shimniok 0:826c6171fc1b 1228 }
shimniok 0:826c6171fc1b 1229 }
shimniok 0:826c6171fc1b 1230 if (printUpdate) {
shimniok 0:826c6171fc1b 1231 printUpdate = false;
shimniok 0:826c6171fc1b 1232 lcd.pos(0,1);
shimniok 0:826c6171fc1b 1233 lcd.printf("%3d%%%-16s", backlight, "");
shimniok 0:826c6171fc1b 1234 }
shimniok 0:826c6171fc1b 1235 }
shimniok 0:826c6171fc1b 1236
shimniok 0:826c6171fc1b 1237 return 0;
shimniok 0:826c6171fc1b 1238 }
shimniok 0:826c6171fc1b 1239
shimniok 0:826c6171fc1b 1240 int reverseScreen(void) {
shimniok 0:826c6171fc1b 1241 lcd.reverseMode();
shimniok 0:826c6171fc1b 1242
shimniok 0:826c6171fc1b 1243 return 0;
shimniok 0:826c6171fc1b 1244 }
shimniok 0:826c6171fc1b 1245
shimniok 0:826c6171fc1b 1246 ///////////////////////////////////////////////////////////////////////////////////////////////////////
shimniok 0:826c6171fc1b 1247 // ADC CONVERSION FUNCTIONS
shimniok 0:826c6171fc1b 1248 ///////////////////////////////////////////////////////////////////////////////////////////////////////
shimniok 0:826c6171fc1b 1249
shimniok 0:826c6171fc1b 1250 // returns distance in m for Sharp GP2YOA710K0F
shimniok 0:826c6171fc1b 1251 // to get m and b, I wrote down volt vs. dist by eyeballin the
shimniok 0:826c6171fc1b 1252 // datasheet chart plot. Then used Excel to do linear regression
shimniok 0:826c6171fc1b 1253 //
shimniok 0:826c6171fc1b 1254 float irDistance(unsigned int adc)
shimniok 0:826c6171fc1b 1255 {
shimniok 0:826c6171fc1b 1256 float b = 1.0934; // Intercept from Excel
shimniok 0:826c6171fc1b 1257 float m = 1.4088; // Slope from Excel
shimniok 0:826c6171fc1b 1258
shimniok 0:826c6171fc1b 1259 return m / (((float) adc) * 4.95/4096 - b);
shimniok 0:826c6171fc1b 1260 }