Code for autonomous ground vehicle, Data Bus, 3rd place winner in 2012 Sparkfun AVC.
Dependencies: Watchdog mbed Schedule SimpleFilter LSM303DLM PinDetect DebounceIn Servo
updater.c@0:826c6171fc1b, 2012-06-20 (annotated)
- Committer:
- shimniok
- Date:
- Wed Jun 20 14:57:48 2012 +0000
- Revision:
- 0:826c6171fc1b
Updated documentation
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
shimniok | 0:826c6171fc1b | 1 | #include "Config.h" |
shimniok | 0:826c6171fc1b | 2 | #include "Actuators.h" |
shimniok | 0:826c6171fc1b | 3 | #include "Sensors.h" |
shimniok | 0:826c6171fc1b | 4 | #include "SystemState.h" |
shimniok | 0:826c6171fc1b | 5 | #include "GPS.h" |
shimniok | 0:826c6171fc1b | 6 | #include "Steering.h" |
shimniok | 0:826c6171fc1b | 7 | #include "Servo.h" |
shimniok | 0:826c6171fc1b | 8 | #include "Mapping.h" |
shimniok | 0:826c6171fc1b | 9 | #include "CartPosition.h" |
shimniok | 0:826c6171fc1b | 10 | #include "GeoPosition.h" |
shimniok | 0:826c6171fc1b | 11 | #include "kalman.h" |
shimniok | 0:826c6171fc1b | 12 | |
shimniok | 0:826c6171fc1b | 13 | #define _x_ 0 |
shimniok | 0:826c6171fc1b | 14 | #define _y_ 1 |
shimniok | 0:826c6171fc1b | 15 | #define _z_ 2 |
shimniok | 0:826c6171fc1b | 16 | |
shimniok | 0:826c6171fc1b | 17 | // Every ... |
shimniok | 0:826c6171fc1b | 18 | // 10ms (100Hz) -- update gyro, encoders; update AHRS; update navigation; set log data |
shimniok | 0:826c6171fc1b | 19 | // 10ms (100Hz) -- camera (actually runs 30fps |
shimniok | 0:826c6171fc1b | 20 | // 20ms (50Hz) -- update compass sensor |
shimniok | 0:826c6171fc1b | 21 | // 50ms (20Hz) -- create new log entry in log FIFO |
shimniok | 0:826c6171fc1b | 22 | // 100ms (10Hz) -- GPS update |
shimniok | 0:826c6171fc1b | 23 | // 100ms (10Hz) -- control update |
shimniok | 0:826c6171fc1b | 24 | |
shimniok | 0:826c6171fc1b | 25 | #define CTRL_SKIP 5 |
shimniok | 0:826c6171fc1b | 26 | #define MAG_SKIP 2 |
shimniok | 0:826c6171fc1b | 27 | #define LOG_SKIP 5 |
shimniok | 0:826c6171fc1b | 28 | |
shimniok | 0:826c6171fc1b | 29 | int control_count=CTRL_SKIP; |
shimniok | 0:826c6171fc1b | 30 | int update_count=MAG_SKIP; // call Update_mag() every update_count calls to schedHandler() |
shimniok | 0:826c6171fc1b | 31 | int log_count=LOG_SKIP; // buffer a new status entry for logging every log_count calls to schedHandler |
shimniok | 0:826c6171fc1b | 32 | int tReal; // calculate real elapsed time |
shimniok | 0:826c6171fc1b | 33 | |
shimniok | 0:826c6171fc1b | 34 | // TODO: 3 better encapsulation, please |
shimniok | 0:826c6171fc1b | 35 | extern Sensors sensors; |
shimniok | 0:826c6171fc1b | 36 | extern SystemState state[SSBUF]; |
shimniok | 0:826c6171fc1b | 37 | extern unsigned char inState; |
shimniok | 0:826c6171fc1b | 38 | extern unsigned char outState; |
shimniok | 0:826c6171fc1b | 39 | extern bool ssBufOverrun; |
shimniok | 0:826c6171fc1b | 40 | extern GPS gps; |
shimniok | 0:826c6171fc1b | 41 | extern Mapping mapper; |
shimniok | 0:826c6171fc1b | 42 | extern Steering steerCalc; // steering calculator |
shimniok | 0:826c6171fc1b | 43 | extern Timer timer; |
shimniok | 0:826c6171fc1b | 44 | extern DigitalOut ahrsStatus; // AHRS status LED |
shimniok | 0:826c6171fc1b | 45 | |
shimniok | 0:826c6171fc1b | 46 | // Navigation |
shimniok | 0:826c6171fc1b | 47 | extern Config config; |
shimniok | 0:826c6171fc1b | 48 | int nextWaypoint = 0; // next waypoint destination |
shimniok | 0:826c6171fc1b | 49 | int lastWaypoint = 1; |
shimniok | 0:826c6171fc1b | 50 | double bearing; // bearing to next waypoint |
shimniok | 0:826c6171fc1b | 51 | double distance; // distance to next waypoint |
shimniok | 0:826c6171fc1b | 52 | float steerAngle; // steering angle |
shimniok | 0:826c6171fc1b | 53 | float cte; // Cross Track error |
shimniok | 0:826c6171fc1b | 54 | float cteI; // Integral of Cross Track Error |
shimniok | 0:826c6171fc1b | 55 | |
shimniok | 0:826c6171fc1b | 56 | // Throttle PID |
shimniok | 0:826c6171fc1b | 57 | float speedDt=0; // dt for the speed PID |
shimniok | 0:826c6171fc1b | 58 | float integral=0; // error integral for speed PID |
shimniok | 0:826c6171fc1b | 59 | float lastError=0; // previous error, used for calculating derivative |
shimniok | 0:826c6171fc1b | 60 | bool go=false; // initiate throttle (or not) |
shimniok | 0:826c6171fc1b | 61 | float desiredSpeed; // speed set point |
shimniok | 0:826c6171fc1b | 62 | float nowSpeed; |
shimniok | 0:826c6171fc1b | 63 | |
shimniok | 0:826c6171fc1b | 64 | |
shimniok | 0:826c6171fc1b | 65 | // Pose Estimation |
shimniok | 0:826c6171fc1b | 66 | bool initNav = true; |
shimniok | 0:826c6171fc1b | 67 | float initHdg = true; // indiciates that heading needs to be initialized by gps |
shimniok | 0:826c6171fc1b | 68 | float initialHeading=-999; // initial heading |
shimniok | 0:826c6171fc1b | 69 | float myHeading=0; // heading sent to KF |
shimniok | 0:826c6171fc1b | 70 | CartPosition cartHere; // position estimate, cartesian |
shimniok | 0:826c6171fc1b | 71 | GeoPosition here; // position estimate, lat/lon |
shimniok | 0:826c6171fc1b | 72 | extern GeoPosition gps_here; |
shimniok | 0:826c6171fc1b | 73 | int timeZero=0; |
shimniok | 0:826c6171fc1b | 74 | int lastTime=-1; // used to calculate dt for KF |
shimniok | 0:826c6171fc1b | 75 | int thisTime; // used to calculate dt for KF |
shimniok | 0:826c6171fc1b | 76 | float dt; // dt for the KF |
shimniok | 0:826c6171fc1b | 77 | float lagHeading = 0; // lagged heading estimate |
shimniok | 0:826c6171fc1b | 78 | //GeoPosition lagHere; // lagged position estimate; use here as the current position estimate |
shimniok | 0:826c6171fc1b | 79 | float errAngle; // error between gyro hdg estimate and gps hdg estimate |
shimniok | 0:826c6171fc1b | 80 | float gyroBias=0; // exponentially weighted moving average of gyro error |
shimniok | 0:826c6171fc1b | 81 | float Ag = (2.0/(1000.0+1.0)); // Gyro bias filter alpha, gyro; # of 10ms steps |
shimniok | 0:826c6171fc1b | 82 | float Kbias = 0.995; |
shimniok | 0:826c6171fc1b | 83 | float filtErrRate = 0; |
shimniok | 0:826c6171fc1b | 84 | float biasErrAngle = 0; |
shimniok | 0:826c6171fc1b | 85 | |
shimniok | 0:826c6171fc1b | 86 | #define MAXHIST 128 // must be multiple of 0x08 |
shimniok | 0:826c6171fc1b | 87 | #define inc(x) (x) = ((x)+1)&(MAXHIST-1) |
shimniok | 0:826c6171fc1b | 88 | struct { |
shimniok | 0:826c6171fc1b | 89 | float x; // x coordinate |
shimniok | 0:826c6171fc1b | 90 | float y; // y coordinate |
shimniok | 0:826c6171fc1b | 91 | float hdg; // heading |
shimniok | 0:826c6171fc1b | 92 | float dist; // distance |
shimniok | 0:826c6171fc1b | 93 | float gyro; // heading rate |
shimniok | 0:826c6171fc1b | 94 | float ghdg; // uncorrected gyro heading |
shimniok | 0:826c6171fc1b | 95 | float dt; // delta time |
shimniok | 0:826c6171fc1b | 96 | } history[MAXHIST]; // fifo for sensor data, position, heading, dt |
shimniok | 0:826c6171fc1b | 97 | |
shimniok | 0:826c6171fc1b | 98 | int hCount=0; // history counter; one > 100, we can go back in time to reference gyro history |
shimniok | 0:826c6171fc1b | 99 | int now = 0; // fifo input index |
shimniok | 0:826c6171fc1b | 100 | int prev = 0; // previous fifo iput index |
shimniok | 0:826c6171fc1b | 101 | int lag = 0; // fifo output index |
shimniok | 0:826c6171fc1b | 102 | int lagPrev = 0; // previous fifo output index |
shimniok | 0:826c6171fc1b | 103 | |
shimniok | 0:826c6171fc1b | 104 | |
shimniok | 0:826c6171fc1b | 105 | /** set flag to initialize navigation at next schedHandler() call |
shimniok | 0:826c6171fc1b | 106 | */ |
shimniok | 0:826c6171fc1b | 107 | void restartNav() |
shimniok | 0:826c6171fc1b | 108 | { |
shimniok | 0:826c6171fc1b | 109 | initNav = true; |
shimniok | 0:826c6171fc1b | 110 | initHdg = true; |
shimniok | 0:826c6171fc1b | 111 | return; |
shimniok | 0:826c6171fc1b | 112 | } |
shimniok | 0:826c6171fc1b | 113 | |
shimniok | 0:826c6171fc1b | 114 | /** instruct the controller to throttle up |
shimniok | 0:826c6171fc1b | 115 | */ |
shimniok | 0:826c6171fc1b | 116 | void beginRun() |
shimniok | 0:826c6171fc1b | 117 | { |
shimniok | 0:826c6171fc1b | 118 | go = true; |
shimniok | 0:826c6171fc1b | 119 | timeZero = thisTime; // initialize |
shimniok | 0:826c6171fc1b | 120 | return; |
shimniok | 0:826c6171fc1b | 121 | } |
shimniok | 0:826c6171fc1b | 122 | |
shimniok | 0:826c6171fc1b | 123 | void endRun() |
shimniok | 0:826c6171fc1b | 124 | { |
shimniok | 0:826c6171fc1b | 125 | go = false; |
shimniok | 0:826c6171fc1b | 126 | initNav = true; |
shimniok | 0:826c6171fc1b | 127 | return; |
shimniok | 0:826c6171fc1b | 128 | } |
shimniok | 0:826c6171fc1b | 129 | |
shimniok | 0:826c6171fc1b | 130 | /** get elasped time in update loop |
shimniok | 0:826c6171fc1b | 131 | */ |
shimniok | 0:826c6171fc1b | 132 | int getUpdateTime() |
shimniok | 0:826c6171fc1b | 133 | { |
shimniok | 0:826c6171fc1b | 134 | return tReal; |
shimniok | 0:826c6171fc1b | 135 | } |
shimniok | 0:826c6171fc1b | 136 | |
shimniok | 0:826c6171fc1b | 137 | void setSpeed(float speed) |
shimniok | 0:826c6171fc1b | 138 | { |
shimniok | 0:826c6171fc1b | 139 | if (desiredSpeed != speed) { |
shimniok | 0:826c6171fc1b | 140 | desiredSpeed = speed; |
shimniok | 0:826c6171fc1b | 141 | integral = 0; |
shimniok | 0:826c6171fc1b | 142 | } |
shimniok | 0:826c6171fc1b | 143 | return; |
shimniok | 0:826c6171fc1b | 144 | } |
shimniok | 0:826c6171fc1b | 145 | |
shimniok | 0:826c6171fc1b | 146 | /** schedHandler fires off the various routines at appropriate schedules |
shimniok | 0:826c6171fc1b | 147 | * |
shimniok | 0:826c6171fc1b | 148 | */ |
shimniok | 0:826c6171fc1b | 149 | void update() |
shimniok | 0:826c6171fc1b | 150 | { |
shimniok | 0:826c6171fc1b | 151 | tReal = timer.read_us(); |
shimniok | 0:826c6171fc1b | 152 | |
shimniok | 0:826c6171fc1b | 153 | ahrsStatus = 0; |
shimniok | 0:826c6171fc1b | 154 | thisTime = timer.read_ms(); |
shimniok | 0:826c6171fc1b | 155 | dt = (lastTime < 0) ? 0 : ((float) thisTime - (float) lastTime) / 1000.0; // first pass let dt=0 |
shimniok | 0:826c6171fc1b | 156 | lastTime = thisTime; |
shimniok | 0:826c6171fc1b | 157 | |
shimniok | 0:826c6171fc1b | 158 | // Add up dt to speedDt |
shimniok | 0:826c6171fc1b | 159 | speedDt += dt; |
shimniok | 0:826c6171fc1b | 160 | |
shimniok | 0:826c6171fc1b | 161 | // Log Data Timestamp |
shimniok | 0:826c6171fc1b | 162 | int timestamp = timer.read_ms(); |
shimniok | 0:826c6171fc1b | 163 | |
shimniok | 0:826c6171fc1b | 164 | ////////////////////////////////////////////////////////////////////////////// |
shimniok | 0:826c6171fc1b | 165 | // NAVIGATION INIT |
shimniok | 0:826c6171fc1b | 166 | ////////////////////////////////////////////////////////////////////////////// |
shimniok | 0:826c6171fc1b | 167 | // initNav is set with call to restartNav() when the "go" button is pressed. Up |
shimniok | 0:826c6171fc1b | 168 | // to 10ms later this function is called and the code below will initialize the |
shimniok | 0:826c6171fc1b | 169 | // dead reckoning position and estimated position variables |
shimniok | 0:826c6171fc1b | 170 | // |
shimniok | 0:826c6171fc1b | 171 | if (initNav == true) { |
shimniok | 0:826c6171fc1b | 172 | initNav = false; |
shimniok | 0:826c6171fc1b | 173 | here.set(config.wpt[0]); |
shimniok | 0:826c6171fc1b | 174 | nextWaypoint = 1; // Point to the next waypoint; 0th wpt is the starting point |
shimniok | 0:826c6171fc1b | 175 | lastWaypoint = 1; // Init to waypoint 1, we we don't start from wpt 0 at the turning speed |
shimniok | 0:826c6171fc1b | 176 | // Initialize lag estimates |
shimniok | 0:826c6171fc1b | 177 | //lagHere.set( here ); |
shimniok | 0:826c6171fc1b | 178 | // Initialize fifo |
shimniok | 0:826c6171fc1b | 179 | hCount = 0; |
shimniok | 0:826c6171fc1b | 180 | now = 0; |
shimniok | 0:826c6171fc1b | 181 | // initialize what will become lag data in 1 second from now |
shimniok | 0:826c6171fc1b | 182 | history[now].dt = 0; |
shimniok | 0:826c6171fc1b | 183 | // initial position is waypoint 0 |
shimniok | 0:826c6171fc1b | 184 | history[now].x = config.cwpt[0]._x; |
shimniok | 0:826c6171fc1b | 185 | history[now].y = config.cwpt[0]._y; |
shimniok | 0:826c6171fc1b | 186 | cartHere.set(history[now].x, history[now].y); |
shimniok | 0:826c6171fc1b | 187 | // initialize heading to bearing between waypoint 0 and 1 |
shimniok | 0:826c6171fc1b | 188 | //history[now].hdg = here.bearingTo(config.wpt[nextWaypoint]); |
shimniok | 0:826c6171fc1b | 189 | history[now].hdg = cartHere.bearingTo(config.cwpt[nextWaypoint]); |
shimniok | 0:826c6171fc1b | 190 | history[now].ghdg = history[now].hdg; |
shimniok | 0:826c6171fc1b | 191 | initialHeading = history[now].hdg; |
shimniok | 0:826c6171fc1b | 192 | // Initialize Kalman Filter |
shimniok | 0:826c6171fc1b | 193 | headingKalmanInit(history[now].hdg); |
shimniok | 0:826c6171fc1b | 194 | // initialize cross track error |
shimniok | 0:826c6171fc1b | 195 | cte = 0; |
shimniok | 0:826c6171fc1b | 196 | cteI = 0; |
shimniok | 0:826c6171fc1b | 197 | // point next fifo input to slot 1, slot 0 occupied/initialized, now |
shimniok | 0:826c6171fc1b | 198 | lag = 0; |
shimniok | 0:826c6171fc1b | 199 | lagPrev = 0; |
shimniok | 0:826c6171fc1b | 200 | prev = now; // point to the most recently entered data |
shimniok | 0:826c6171fc1b | 201 | now = 1; // new input slot |
shimniok | 0:826c6171fc1b | 202 | } |
shimniok | 0:826c6171fc1b | 203 | |
shimniok | 0:826c6171fc1b | 204 | |
shimniok | 0:826c6171fc1b | 205 | ////////////////////////////////////////////////////////////////////////////// |
shimniok | 0:826c6171fc1b | 206 | // SENSOR UPDATES |
shimniok | 0:826c6171fc1b | 207 | ////////////////////////////////////////////////////////////////////////////// |
shimniok | 0:826c6171fc1b | 208 | |
shimniok | 0:826c6171fc1b | 209 | // TODO: 3 This really should run infrequently |
shimniok | 0:826c6171fc1b | 210 | sensors.Read_Power(); |
shimniok | 0:826c6171fc1b | 211 | |
shimniok | 0:826c6171fc1b | 212 | sensors.Read_Encoders(); |
shimniok | 0:826c6171fc1b | 213 | nowSpeed = sensors.encSpeed; |
shimniok | 0:826c6171fc1b | 214 | |
shimniok | 0:826c6171fc1b | 215 | sensors.Read_Gyro(); |
shimniok | 0:826c6171fc1b | 216 | |
shimniok | 0:826c6171fc1b | 217 | sensors.Read_Rangers(); |
shimniok | 0:826c6171fc1b | 218 | |
shimniok | 0:826c6171fc1b | 219 | //sensors.Read_Camera(); |
shimniok | 0:826c6171fc1b | 220 | |
shimniok | 0:826c6171fc1b | 221 | ////////////////////////////////////////////////////////////////////////////// |
shimniok | 0:826c6171fc1b | 222 | // Obtain GPS data |
shimniok | 0:826c6171fc1b | 223 | ////////////////////////////////////////////////////////////////////////////// |
shimniok | 0:826c6171fc1b | 224 | |
shimniok | 0:826c6171fc1b | 225 | // synchronize when RMC and GGA sentences received w/ AHRS |
shimniok | 0:826c6171fc1b | 226 | // Do this in schedHandler?? GPS data is coming in not entirely in sync |
shimniok | 0:826c6171fc1b | 227 | // with the logging info |
shimniok | 0:826c6171fc1b | 228 | if (gps.nmea.rmc_ready() && gps.nmea.gga_ready()) { |
shimniok | 0:826c6171fc1b | 229 | char gpsdate[32], gpstime[32]; |
shimniok | 0:826c6171fc1b | 230 | |
shimniok | 0:826c6171fc1b | 231 | gps.process(gps_here, gpsdate, gpstime); |
shimniok | 0:826c6171fc1b | 232 | //gpsStatus = (gps.hdop > 0.0 && gps.hdop < 3.0) ? 1 : 0; |
shimniok | 0:826c6171fc1b | 233 | |
shimniok | 0:826c6171fc1b | 234 | // update system status struct for logging |
shimniok | 0:826c6171fc1b | 235 | state[inState].gpsLatitude = gps_here.latitude(); |
shimniok | 0:826c6171fc1b | 236 | state[inState].gpsLongitude = gps_here.longitude(); |
shimniok | 0:826c6171fc1b | 237 | state[inState].gpsHDOP = gps.hdop; |
shimniok | 0:826c6171fc1b | 238 | state[inState].gpsCourse = gps.nmea.f_course(); |
shimniok | 0:826c6171fc1b | 239 | state[inState].gpsSpeed = gps.nmea.f_speed_mph(); // can we just do kph/1000 ? or mps? |
shimniok | 0:826c6171fc1b | 240 | state[inState].gpsSats = gps.nmea.sat_count(); |
shimniok | 0:826c6171fc1b | 241 | } |
shimniok | 0:826c6171fc1b | 242 | |
shimniok | 0:826c6171fc1b | 243 | ////////////////////////////////////////////////////////////////////////////// |
shimniok | 0:826c6171fc1b | 244 | // HEADING AND POSITION UPDATE |
shimniok | 0:826c6171fc1b | 245 | ////////////////////////////////////////////////////////////////////////////// |
shimniok | 0:826c6171fc1b | 246 | |
shimniok | 0:826c6171fc1b | 247 | // TODO: 2 Position filtering |
shimniok | 0:826c6171fc1b | 248 | // position will be updated based on heading error from heading estimate |
shimniok | 0:826c6171fc1b | 249 | // TODO: 2 Distance/speed filtering |
shimniok | 0:826c6171fc1b | 250 | // this might be useful, but not sure it's worth the effort |
shimniok | 0:826c6171fc1b | 251 | |
shimniok | 0:826c6171fc1b | 252 | // So the big pain in the ass is that the GPS data coming in represents the |
shimniok | 0:826c6171fc1b | 253 | // state of the system ~1s ago. Yes, a full second of lag despite running |
shimniok | 0:826c6171fc1b | 254 | // at 10hz (or whatever). So if we try and fuse a lagged gps heading with a |
shimniok | 0:826c6171fc1b | 255 | // relatively current gyro heading rate, the gyro is ignored and the heading |
shimniok | 0:826c6171fc1b | 256 | // estimate lags reality |
shimniok | 0:826c6171fc1b | 257 | // |
shimniok | 0:826c6171fc1b | 258 | // In real life testing, the robot steering control was highly unstable with |
shimniok | 0:826c6171fc1b | 259 | // too much gain (typical of any negative feedback system with a very high |
shimniok | 0:826c6171fc1b | 260 | // phase shift and too much feedback). It'd drive around in circles trying to |
shimniok | 0:826c6171fc1b | 261 | // hunt for the next waypoint. Dropping the gain restored stability but the |
shimniok | 0:826c6171fc1b | 262 | // steering overshot significantly, because of the lag. It sort of worked but |
shimniok | 0:826c6171fc1b | 263 | // it was ugly. So here's my lame attempt to fix all this. |
shimniok | 0:826c6171fc1b | 264 | // |
shimniok | 0:826c6171fc1b | 265 | // We'll find out how much error there is between gps heading and the integrated |
shimniok | 0:826c6171fc1b | 266 | // gyro heading from a second ago. |
shimniok | 0:826c6171fc1b | 267 | |
shimniok | 0:826c6171fc1b | 268 | // stick precalculated gyro data, with bias correction, into fifo |
shimniok | 0:826c6171fc1b | 269 | //history[now].gyro = sensors.gyro[_z_] - gyroBias; |
shimniok | 0:826c6171fc1b | 270 | history[now].gyro = sensors.gyro[_z_]; |
shimniok | 0:826c6171fc1b | 271 | |
shimniok | 0:826c6171fc1b | 272 | // Have to store dt history too (feh) |
shimniok | 0:826c6171fc1b | 273 | history[now].dt = dt; |
shimniok | 0:826c6171fc1b | 274 | |
shimniok | 0:826c6171fc1b | 275 | // Store distance travelled in a fifo for later use |
shimniok | 0:826c6171fc1b | 276 | history[now].dist = (sensors.lrEncDistance + sensors.rrEncDistance) / 2.0; |
shimniok | 0:826c6171fc1b | 277 | |
shimniok | 0:826c6171fc1b | 278 | |
shimniok | 0:826c6171fc1b | 279 | // Calc and store heading |
shimniok | 0:826c6171fc1b | 280 | history[now].ghdg = history[prev].ghdg + dt*history[now].gyro; // raw gyro calculated heading |
shimniok | 0:826c6171fc1b | 281 | //history[now].hdg = history[prev].ghdg - dt*gyroBias; // bias-corrected gyro heading |
shimniok | 0:826c6171fc1b | 282 | history[now].hdg = history[prev].hdg + dt*history[now].gyro; |
shimniok | 0:826c6171fc1b | 283 | if (history[now].hdg >= 360.0) history[now].hdg -= 360.0; |
shimniok | 0:826c6171fc1b | 284 | if (history[now].hdg < 0) history[now].hdg += 360.0; |
shimniok | 0:826c6171fc1b | 285 | |
shimniok | 0:826c6171fc1b | 286 | //fprintf(stdout, "%d %d %.4f %.4f\n", now, prev, history[now].hdg, history[prev].hdg); |
shimniok | 0:826c6171fc1b | 287 | |
shimniok | 0:826c6171fc1b | 288 | // We can't do anything until the history buffer is full |
shimniok | 0:826c6171fc1b | 289 | if (hCount < 100) { |
shimniok | 0:826c6171fc1b | 290 | // Until the fifo is full, only keep track of current gyro heading |
shimniok | 0:826c6171fc1b | 291 | hCount++; // after n iterations the fifo will be full |
shimniok | 0:826c6171fc1b | 292 | } else { |
shimniok | 0:826c6171fc1b | 293 | // Now that the buffer is full, we'll maintain a Kalman Filtered estimate that is |
shimniok | 0:826c6171fc1b | 294 | // time-shifted to the past because the GPS output represents the system state from |
shimniok | 0:826c6171fc1b | 295 | // the past. We'll also take our history of gyro readings from the most recent |
shimniok | 0:826c6171fc1b | 296 | // filter update to the present time and update our current heading and position |
shimniok | 0:826c6171fc1b | 297 | |
shimniok | 0:826c6171fc1b | 298 | //////////////////////////////////////////////////////////////////////////////// |
shimniok | 0:826c6171fc1b | 299 | // UPDATE LAGGED ESTIMATE |
shimniok | 0:826c6171fc1b | 300 | |
shimniok | 0:826c6171fc1b | 301 | // Recover data from 1 second ago which will be used to generate |
shimniok | 0:826c6171fc1b | 302 | // updated lag estimates |
shimniok | 0:826c6171fc1b | 303 | |
shimniok | 0:826c6171fc1b | 304 | // GPS heading is unavailable from this particular GPS at speeds < 0.5 mph |
shimniok | 0:826c6171fc1b | 305 | bool useGps = (state[inState].gpsLatitude != 0 && |
shimniok | 0:826c6171fc1b | 306 | state[inState].lrEncSpeed > 1.0 && |
shimniok | 0:826c6171fc1b | 307 | state[inState].rrEncSpeed > 1.0 && |
shimniok | 0:826c6171fc1b | 308 | (thisTime-timeZero) > 3000); // gps hdg converges by 3-5 sec. |
shimniok | 0:826c6171fc1b | 309 | |
shimniok | 0:826c6171fc1b | 310 | // This represents the best estimate for heading... for one second ago |
shimniok | 0:826c6171fc1b | 311 | // If we do nothing else, the robot will think it is located at a position 1 second behind |
shimniok | 0:826c6171fc1b | 312 | // where it actually is. That means that any control feedback needs to have a longer time |
shimniok | 0:826c6171fc1b | 313 | // constant than 1 sec or the robot will have unstable heading correctoin. |
shimniok | 0:826c6171fc1b | 314 | // Use gps data when available, always use gyro data |
shimniok | 0:826c6171fc1b | 315 | |
shimniok | 0:826c6171fc1b | 316 | // Clamp heading to initial heading when we're not moving; hopefully this will |
shimniok | 0:826c6171fc1b | 317 | // give the KF a head start figuring out how to deal with the gyro |
shimniok | 0:826c6171fc1b | 318 | if (go) { |
shimniok | 0:826c6171fc1b | 319 | lagHeading = headingKalman(history[lag].dt, state[inState].gpsCourse, useGps, history[lag].gyro, true); |
shimniok | 0:826c6171fc1b | 320 | } else { |
shimniok | 0:826c6171fc1b | 321 | lagHeading = headingKalman(history[lag].dt, initialHeading, true, history[lag].gyro, true); |
shimniok | 0:826c6171fc1b | 322 | } |
shimniok | 0:826c6171fc1b | 323 | |
shimniok | 0:826c6171fc1b | 324 | // TODO 1: need to figure out exactly how to update t-1 position correctly |
shimniok | 0:826c6171fc1b | 325 | // Update the lagged position estimate |
shimniok | 0:826c6171fc1b | 326 | //lagHere.move(lagHeading, history[lag].dist); |
shimniok | 0:826c6171fc1b | 327 | history[lag].x = history[lagPrev].x + history[lag].dist * sin(lagHeading); |
shimniok | 0:826c6171fc1b | 328 | history[lag].y = history[lagPrev].y + history[lag].dist * cos(lagHeading); |
shimniok | 0:826c6171fc1b | 329 | |
shimniok | 0:826c6171fc1b | 330 | //////////////////////////////////////////////////////////////////////////////// |
shimniok | 0:826c6171fc1b | 331 | // UPDATE CURRENT ESTIMATE |
shimniok | 0:826c6171fc1b | 332 | |
shimniok | 0:826c6171fc1b | 333 | // Now we need to re-calculate the current heading and position, starting with the most recent |
shimniok | 0:826c6171fc1b | 334 | // heading estimate representing the heading 1 second ago. |
shimniok | 0:826c6171fc1b | 335 | // |
shimniok | 0:826c6171fc1b | 336 | // Nuance: lag and now have already been incremented so that works out beautifully for this loop |
shimniok | 0:826c6171fc1b | 337 | // |
shimniok | 0:826c6171fc1b | 338 | // Heading is easy. Original heading - estimated heading gives a tiny error. Add this to all the historical |
shimniok | 0:826c6171fc1b | 339 | // heading data up to present. |
shimniok | 0:826c6171fc1b | 340 | // |
shimniok | 0:826c6171fc1b | 341 | // For position re-calculation, we iterate 100 times up to present record. Haversine is way, way too slow, |
shimniok | 0:826c6171fc1b | 342 | // so is trig calcs is marginal. Update rate is 10ms and we can't hog more than maybe 2-3ms as the outer |
shimniok | 0:826c6171fc1b | 343 | // loop has logging work to do. Rotating each point is faster; pre-calculate sin/cos, etc. |
shimniok | 0:826c6171fc1b | 344 | // |
shimniok | 0:826c6171fc1b | 345 | // initialize these once |
shimniok | 0:826c6171fc1b | 346 | errAngle = (lagHeading - history[lag].hdg); |
shimniok | 0:826c6171fc1b | 347 | if (errAngle <= -180.0) errAngle += 360.0; |
shimniok | 0:826c6171fc1b | 348 | if (errAngle > 180) errAngle -= 360.0; |
shimniok | 0:826c6171fc1b | 349 | |
shimniok | 0:826c6171fc1b | 350 | //fprintf(stdout, "%d %.2f, %.2f, %.4f %.4f\n", lag, lagHeading, history[lag].hdg, lagHeading - history[lag].hdg, errAngle); |
shimniok | 0:826c6171fc1b | 351 | float cosA = cos(errAngle * PI / 180); |
shimniok | 0:826c6171fc1b | 352 | float sinA = sin(errAngle * PI / 180); |
shimniok | 0:826c6171fc1b | 353 | // Start at the out side of the fifo which is from 1 second ago |
shimniok | 0:826c6171fc1b | 354 | int i = lag; |
shimniok | 0:826c6171fc1b | 355 | for (int j=0; j < 100; j++) { |
shimniok | 0:826c6171fc1b | 356 | history[i].hdg += errAngle; |
shimniok | 0:826c6171fc1b | 357 | // Rotate x, y by errAngle around pivot point; no need to rotate pivot point (j=0) |
shimniok | 0:826c6171fc1b | 358 | if (j > 0) { |
shimniok | 0:826c6171fc1b | 359 | float dx = history[i].x-history[lag].x; |
shimniok | 0:826c6171fc1b | 360 | float dy = history[i].y-history[lag].y; |
shimniok | 0:826c6171fc1b | 361 | history[i].x = history[lag].x + dx*cosA - dy*sinA; |
shimniok | 0:826c6171fc1b | 362 | history[i].y = history[lag].y + dx*sinA + dy*cosA; |
shimniok | 0:826c6171fc1b | 363 | } |
shimniok | 0:826c6171fc1b | 364 | inc(i); |
shimniok | 0:826c6171fc1b | 365 | } |
shimniok | 0:826c6171fc1b | 366 | |
shimniok | 0:826c6171fc1b | 367 | // gyro bias, correct only with shallow steering angles |
shimniok | 0:826c6171fc1b | 368 | // if we're not going, assume heading rate is 0 and correct accordingly |
shimniok | 0:826c6171fc1b | 369 | // If we are going, compare gyro-generated heading estimate with kalman |
shimniok | 0:826c6171fc1b | 370 | // heading estimate and correct bias accordingly using PI controller with |
shimniok | 0:826c6171fc1b | 371 | // fairly long time constant |
shimniok | 0:826c6171fc1b | 372 | // TODO: 3 Add something in here to stop updating if the gps is unreliable; need to find out what indicates poor gps heading |
shimniok | 0:826c6171fc1b | 373 | if (history[lag].dt > 0 && fabs(steerAngle) < 5.0 && useGps) { |
shimniok | 0:826c6171fc1b | 374 | biasErrAngle = Kbias*biasErrAngle + (1-Kbias)*(history[lag].ghdg - state[inState].gpsCourse); // can use this to compute gyro bias |
shimniok | 0:826c6171fc1b | 375 | if (biasErrAngle <= -180.0) biasErrAngle += 360.0; |
shimniok | 0:826c6171fc1b | 376 | if (biasErrAngle > 180) biasErrAngle -= 360.0; |
shimniok | 0:826c6171fc1b | 377 | |
shimniok | 0:826c6171fc1b | 378 | float errRate = biasErrAngle / history[lag].dt; |
shimniok | 0:826c6171fc1b | 379 | |
shimniok | 0:826c6171fc1b | 380 | //if (!go) errRate = history[lag].gyro; |
shimniok | 0:826c6171fc1b | 381 | |
shimniok | 0:826c6171fc1b | 382 | // Filter bias based on errRate which is based on filtered biasErrAngle |
shimniok | 0:826c6171fc1b | 383 | gyroBias = Kbias*gyroBias + (1-Kbias)*errRate; |
shimniok | 0:826c6171fc1b | 384 | //fprintf(stdout, "%d %.2f, %.2f, %.4f %.4f %.4f\n", lag, lagHeading, history[lag].hdg, errAngle, errRate, gyroBias); |
shimniok | 0:826c6171fc1b | 385 | } |
shimniok | 0:826c6171fc1b | 386 | |
shimniok | 0:826c6171fc1b | 387 | // make sure we update the lag heading with the new estimate |
shimniok | 0:826c6171fc1b | 388 | history[lag].hdg = lagHeading; |
shimniok | 0:826c6171fc1b | 389 | |
shimniok | 0:826c6171fc1b | 390 | // increment lag pointer and wrap |
shimniok | 0:826c6171fc1b | 391 | lagPrev = lag; |
shimniok | 0:826c6171fc1b | 392 | inc(lag); |
shimniok | 0:826c6171fc1b | 393 | |
shimniok | 0:826c6171fc1b | 394 | } |
shimniok | 0:826c6171fc1b | 395 | state[inState].estHeading = history[lag].hdg; |
shimniok | 0:826c6171fc1b | 396 | // the variable "here" is the current position |
shimniok | 0:826c6171fc1b | 397 | //here.move(history[now].hdg, history[now].dist); |
shimniok | 0:826c6171fc1b | 398 | float r = PI/180 * history[now].hdg; |
shimniok | 0:826c6171fc1b | 399 | // update current position |
shimniok | 0:826c6171fc1b | 400 | history[now].x = history[prev].x + history[now].dist * sin(r); |
shimniok | 0:826c6171fc1b | 401 | history[now].y = history[prev].y + history[now].dist * cos(r); |
shimniok | 0:826c6171fc1b | 402 | cartHere.set(history[now].x, history[now].y); |
shimniok | 0:826c6171fc1b | 403 | mapper.cartToGeo(cartHere, &here); |
shimniok | 0:826c6171fc1b | 404 | |
shimniok | 0:826c6171fc1b | 405 | // TODO: don't update gyro heading if speed ~0 -- or use this time to re-calc bias? |
shimniok | 0:826c6171fc1b | 406 | // (sensors.lrEncSpeed == 0 && sensors.rrEncSpeed == 0) |
shimniok | 0:826c6171fc1b | 407 | |
shimniok | 0:826c6171fc1b | 408 | ////////////////////////////////////////////////////////////////////////////// |
shimniok | 0:826c6171fc1b | 409 | // NAVIGATION UPDATE |
shimniok | 0:826c6171fc1b | 410 | ////////////////////////////////////////////////////////////////////////////// |
shimniok | 0:826c6171fc1b | 411 | |
shimniok | 0:826c6171fc1b | 412 | //bearing = here.bearingTo(config.wpt[nextWaypoint]); |
shimniok | 0:826c6171fc1b | 413 | bearing = cartHere.bearingTo(config.cwpt[nextWaypoint]); |
shimniok | 0:826c6171fc1b | 414 | //distance = here.distanceTo(config.wpt[nextWaypoint]); |
shimniok | 0:826c6171fc1b | 415 | distance = cartHere.distanceTo(config.cwpt[nextWaypoint]); |
shimniok | 0:826c6171fc1b | 416 | //float prevDistance = here.distanceTo(config.wpt[lastWaypoint]); |
shimniok | 0:826c6171fc1b | 417 | float prevDistance = cartHere.distanceTo(config.cwpt[lastWaypoint]); |
shimniok | 0:826c6171fc1b | 418 | double relativeBrg = bearing - history[now].hdg; |
shimniok | 0:826c6171fc1b | 419 | |
shimniok | 0:826c6171fc1b | 420 | // if correction angle is < -180, express as negative degree |
shimniok | 0:826c6171fc1b | 421 | // TODO: 3 turn this into a function |
shimniok | 0:826c6171fc1b | 422 | if (relativeBrg < -180.0) relativeBrg += 360.0; |
shimniok | 0:826c6171fc1b | 423 | if (relativeBrg > 180.0) relativeBrg -= 360.0; |
shimniok | 0:826c6171fc1b | 424 | |
shimniok | 0:826c6171fc1b | 425 | // if within config.waypointDist distance threshold move to next waypoint |
shimniok | 0:826c6171fc1b | 426 | // TODO: 3 figure out how to output feedback on wpt arrival external to this function |
shimniok | 0:826c6171fc1b | 427 | if (go) { |
shimniok | 0:826c6171fc1b | 428 | |
shimniok | 0:826c6171fc1b | 429 | // if we're within brakeDist of next or previous waypoint, run @ turn speed |
shimniok | 0:826c6171fc1b | 430 | // This would normally mean we run at turn speed until we're brakeDist away |
shimniok | 0:826c6171fc1b | 431 | // from waypoint 0, but we trick the algorithm by initializing prevWaypoint to waypoint 1 |
shimniok | 0:826c6171fc1b | 432 | if (distance < config.brakeDist || prevDistance < config.brakeDist) { |
shimniok | 0:826c6171fc1b | 433 | setSpeed( config.turnSpeed ); |
shimniok | 0:826c6171fc1b | 434 | } else if ( (thisTime - timeZero) < 1000 ) { |
shimniok | 0:826c6171fc1b | 435 | setSpeed( config.startSpeed ); |
shimniok | 0:826c6171fc1b | 436 | } else { |
shimniok | 0:826c6171fc1b | 437 | setSpeed( config.topSpeed ); |
shimniok | 0:826c6171fc1b | 438 | } |
shimniok | 0:826c6171fc1b | 439 | |
shimniok | 0:826c6171fc1b | 440 | if (distance < config.waypointDist) { |
shimniok | 0:826c6171fc1b | 441 | //fprintf(stdout, "Arrived at wpt %d\n", nextWaypoint); |
shimniok | 0:826c6171fc1b | 442 | //speaker.beep(3000.0, 0.5); // non-blocking |
shimniok | 0:826c6171fc1b | 443 | lastWaypoint = nextWaypoint; |
shimniok | 0:826c6171fc1b | 444 | nextWaypoint++; |
shimniok | 0:826c6171fc1b | 445 | cteI = 0; |
shimniok | 0:826c6171fc1b | 446 | } |
shimniok | 0:826c6171fc1b | 447 | |
shimniok | 0:826c6171fc1b | 448 | } else { |
shimniok | 0:826c6171fc1b | 449 | setSpeed( 0.0 ); |
shimniok | 0:826c6171fc1b | 450 | } |
shimniok | 0:826c6171fc1b | 451 | // Are we at the last waypoint? |
shimniok | 0:826c6171fc1b | 452 | // currently handled external to this routine |
shimniok | 0:826c6171fc1b | 453 | |
shimniok | 0:826c6171fc1b | 454 | ////////////////////////////////////////////////////////////////////////////// |
shimniok | 0:826c6171fc1b | 455 | // OBSTACLE DETECTION & AVOIDANCE |
shimniok | 0:826c6171fc1b | 456 | ////////////////////////////////////////////////////////////////////////////// |
shimniok | 0:826c6171fc1b | 457 | // TODO: 1 limit steering angle based on object detection ? |
shimniok | 0:826c6171fc1b | 458 | // or limit relative brg perhaps? |
shimniok | 0:826c6171fc1b | 459 | // TODO: 1 add vision obstacle detection and filtering |
shimniok | 0:826c6171fc1b | 460 | // TODO: 1 add ranger obstacle detection and filtering/fusion with vision |
shimniok | 0:826c6171fc1b | 461 | |
shimniok | 0:826c6171fc1b | 462 | |
shimniok | 0:826c6171fc1b | 463 | ////////////////////////////////////////////////////////////////////////////// |
shimniok | 0:826c6171fc1b | 464 | // CONTROL UPDATE |
shimniok | 0:826c6171fc1b | 465 | ////////////////////////////////////////////////////////////////////////////// |
shimniok | 0:826c6171fc1b | 466 | |
shimniok | 0:826c6171fc1b | 467 | if (--control_count == 0) { |
shimniok | 0:826c6171fc1b | 468 | |
shimniok | 0:826c6171fc1b | 469 | // Compute cross track error |
shimniok | 0:826c6171fc1b | 470 | cte = steerCalc.crossTrack(history[now].x, history[now].y, |
shimniok | 0:826c6171fc1b | 471 | config.cwpt[lastWaypoint]._x, config.cwpt[lastWaypoint]._y, |
shimniok | 0:826c6171fc1b | 472 | config.cwpt[nextWaypoint]._x, config.cwpt[nextWaypoint]._y); |
shimniok | 0:826c6171fc1b | 473 | cteI += cte; |
shimniok | 0:826c6171fc1b | 474 | |
shimniok | 0:826c6171fc1b | 475 | // Use either pure pursuit algorithm or original algorithm |
shimniok | 0:826c6171fc1b | 476 | if (config.usePP) { |
shimniok | 0:826c6171fc1b | 477 | steerAngle = steerCalc.purePursuitSA(state[inState].estHeading, |
shimniok | 0:826c6171fc1b | 478 | history[now].x, history[now].y, |
shimniok | 0:826c6171fc1b | 479 | config.cwpt[lastWaypoint]._x, config.cwpt[lastWaypoint]._y, |
shimniok | 0:826c6171fc1b | 480 | config.cwpt[nextWaypoint]._x, config.cwpt[nextWaypoint]._y); |
shimniok | 0:826c6171fc1b | 481 | } else { |
shimniok | 0:826c6171fc1b | 482 | steerAngle = steerCalc.calcSA(relativeBrg, config.minRadius); // use the configured minimum turn radius |
shimniok | 0:826c6171fc1b | 483 | } |
shimniok | 0:826c6171fc1b | 484 | |
shimniok | 0:826c6171fc1b | 485 | // Apply gain factor for near straight line |
shimniok | 0:826c6171fc1b | 486 | if (fabs(steerAngle) < config.steerGainAngle) steerAngle *= config.steerGain; |
shimniok | 0:826c6171fc1b | 487 | |
shimniok | 0:826c6171fc1b | 488 | // Curb avoidance |
shimniok | 0:826c6171fc1b | 489 | if (sensors.rightRanger < config.curbThreshold) { |
shimniok | 0:826c6171fc1b | 490 | steerAngle -= config.curbGain * (config.curbThreshold - sensors.rightRanger); |
shimniok | 0:826c6171fc1b | 491 | } |
shimniok | 0:826c6171fc1b | 492 | |
shimniok | 0:826c6171fc1b | 493 | setSteering( steerAngle ); |
shimniok | 0:826c6171fc1b | 494 | |
shimniok | 0:826c6171fc1b | 495 | // void throttleUpdate( float speed, float dt ) |
shimniok | 0:826c6171fc1b | 496 | |
shimniok | 0:826c6171fc1b | 497 | // PID control for throttle |
shimniok | 0:826c6171fc1b | 498 | // TODO: 3 move all this PID crap into Actuators.cpp |
shimniok | 0:826c6171fc1b | 499 | // TODO: 3 probably should do KF or something for speed/dist; need to address GPS lag, too |
shimniok | 0:826c6171fc1b | 500 | // if nothing else, at least average the encoder speed over mult. samples |
shimniok | 0:826c6171fc1b | 501 | if (desiredSpeed <= 0.1) { |
shimniok | 0:826c6171fc1b | 502 | setThrottle( config.escZero ); |
shimniok | 0:826c6171fc1b | 503 | } else { |
shimniok | 0:826c6171fc1b | 504 | // PID loop for throttle control |
shimniok | 0:826c6171fc1b | 505 | // http://www.codeproject.com/Articles/36459/PID-process-control-a-Cruise-Control-example |
shimniok | 0:826c6171fc1b | 506 | float error = desiredSpeed - nowSpeed; |
shimniok | 0:826c6171fc1b | 507 | // track error over time, scaled to the timer interval |
shimniok | 0:826c6171fc1b | 508 | integral += (error * speedDt); |
shimniok | 0:826c6171fc1b | 509 | // determine the amount of change from the last time checked |
shimniok | 0:826c6171fc1b | 510 | float derivative = (error - lastError) / speedDt; |
shimniok | 0:826c6171fc1b | 511 | // calculate how much to drive the output in order to get to the |
shimniok | 0:826c6171fc1b | 512 | // desired setpoint. |
shimniok | 0:826c6171fc1b | 513 | int output = config.escZero + (config.speedKp * error) + (config.speedKi * integral) + (config.speedKd * derivative); |
shimniok | 0:826c6171fc1b | 514 | if (output > config.escMax) output = config.escMax; |
shimniok | 0:826c6171fc1b | 515 | if (output < config.escMin) output = config.escMin; |
shimniok | 0:826c6171fc1b | 516 | //fprintf(stdout, "s=%.1f d=%.1f o=%d\n", nowSpeed, desiredSpeed, output); |
shimniok | 0:826c6171fc1b | 517 | setThrottle( output ); |
shimniok | 0:826c6171fc1b | 518 | // remember the error for the next time around. |
shimniok | 0:826c6171fc1b | 519 | lastError = error; |
shimniok | 0:826c6171fc1b | 520 | } |
shimniok | 0:826c6171fc1b | 521 | |
shimniok | 0:826c6171fc1b | 522 | speedDt = 0; // reset dt to begin counting for next time |
shimniok | 0:826c6171fc1b | 523 | control_count = CTRL_SKIP; |
shimniok | 0:826c6171fc1b | 524 | } |
shimniok | 0:826c6171fc1b | 525 | |
shimniok | 0:826c6171fc1b | 526 | ////////////////////////////////////////////////////////////////////////////// |
shimniok | 0:826c6171fc1b | 527 | // DATA FOR LOGGING |
shimniok | 0:826c6171fc1b | 528 | ////////////////////////////////////////////////////////////////////////////// |
shimniok | 0:826c6171fc1b | 529 | |
shimniok | 0:826c6171fc1b | 530 | // Periodically, we enter a new SystemState into the FIFO buffer |
shimniok | 0:826c6171fc1b | 531 | // The main loop handles logging and will catch up to us provided |
shimniok | 0:826c6171fc1b | 532 | // we feed in new log entries slowly enough. |
shimniok | 0:826c6171fc1b | 533 | if (--log_count == 0) { |
shimniok | 0:826c6171fc1b | 534 | // Copy data into system state for logging |
shimniok | 0:826c6171fc1b | 535 | inState++; // Get next state struct in the buffer |
shimniok | 0:826c6171fc1b | 536 | inState &= SSBUF; // Wrap around |
shimniok | 0:826c6171fc1b | 537 | ssBufOverrun = (inState == outState); |
shimniok | 0:826c6171fc1b | 538 | // |
shimniok | 0:826c6171fc1b | 539 | // Need to clear out encoder distance counters; these are incremented |
shimniok | 0:826c6171fc1b | 540 | // each time this routine is called. |
shimniok | 0:826c6171fc1b | 541 | state[inState].lrEncDistance = 0; |
shimniok | 0:826c6171fc1b | 542 | state[inState].rrEncDistance = 0; |
shimniok | 0:826c6171fc1b | 543 | // |
shimniok | 0:826c6171fc1b | 544 | // need to initialize gps data to be safe |
shimniok | 0:826c6171fc1b | 545 | // |
shimniok | 0:826c6171fc1b | 546 | state[inState].gpsLatitude = 0; |
shimniok | 0:826c6171fc1b | 547 | state[inState].gpsLongitude = 0; |
shimniok | 0:826c6171fc1b | 548 | state[inState].gpsHDOP = 0; |
shimniok | 0:826c6171fc1b | 549 | state[inState].gpsCourse = 0; |
shimniok | 0:826c6171fc1b | 550 | state[inState].gpsSpeed = 0; |
shimniok | 0:826c6171fc1b | 551 | state[inState].gpsSats = 0; |
shimniok | 0:826c6171fc1b | 552 | log_count = LOG_SKIP; // reset counter |
shimniok | 0:826c6171fc1b | 553 | } |
shimniok | 0:826c6171fc1b | 554 | |
shimniok | 0:826c6171fc1b | 555 | // Log Data Timestamp |
shimniok | 0:826c6171fc1b | 556 | state[inState].millis = timestamp; |
shimniok | 0:826c6171fc1b | 557 | |
shimniok | 0:826c6171fc1b | 558 | // TODO: 3 recursive filtering on each of the state values |
shimniok | 0:826c6171fc1b | 559 | state[inState].voltage = sensors.voltage; |
shimniok | 0:826c6171fc1b | 560 | state[inState].current = sensors.current; |
shimniok | 0:826c6171fc1b | 561 | for (int i=0; i < 3; i++) { |
shimniok | 0:826c6171fc1b | 562 | state[inState].m[i] = sensors.m[i]; |
shimniok | 0:826c6171fc1b | 563 | state[inState].g[i] = sensors.g[i]; |
shimniok | 0:826c6171fc1b | 564 | state[inState].a[i] = sensors.a[i]; |
shimniok | 0:826c6171fc1b | 565 | } |
shimniok | 0:826c6171fc1b | 566 | state[inState].gTemp = sensors.gTemp; |
shimniok | 0:826c6171fc1b | 567 | state[inState].gHeading = history[now].hdg; |
shimniok | 0:826c6171fc1b | 568 | state[inState].lrEncSpeed = sensors.lrEncSpeed; |
shimniok | 0:826c6171fc1b | 569 | state[inState].rrEncSpeed = sensors.rrEncSpeed; |
shimniok | 0:826c6171fc1b | 570 | state[inState].lrEncDistance += sensors.lrEncDistance; |
shimniok | 0:826c6171fc1b | 571 | state[inState].rrEncDistance += sensors.rrEncDistance; |
shimniok | 0:826c6171fc1b | 572 | //state[inState].encHeading += (state[inState].lrEncDistance - state[inState].rrEncDistance) / TRACK; |
shimniok | 0:826c6171fc1b | 573 | state[inState].estLatitude = here.latitude(); |
shimniok | 0:826c6171fc1b | 574 | state[inState].estLongitude = here.longitude(); |
shimniok | 0:826c6171fc1b | 575 | state[inState].estX = history[now].x; |
shimniok | 0:826c6171fc1b | 576 | state[inState].estY = history[now].y; |
shimniok | 0:826c6171fc1b | 577 | state[inState].bearing = bearing; |
shimniok | 0:826c6171fc1b | 578 | state[inState].distance = distance; |
shimniok | 0:826c6171fc1b | 579 | state[inState].nextWaypoint = nextWaypoint; |
shimniok | 0:826c6171fc1b | 580 | state[inState].gbias = gyroBias; |
shimniok | 0:826c6171fc1b | 581 | state[inState].errAngle = biasErrAngle; |
shimniok | 0:826c6171fc1b | 582 | state[inState].leftRanger = sensors.leftRanger; |
shimniok | 0:826c6171fc1b | 583 | state[inState].rightRanger = sensors.rightRanger; |
shimniok | 0:826c6171fc1b | 584 | state[inState].centerRanger = sensors.centerRanger; |
shimniok | 0:826c6171fc1b | 585 | state[inState].crossTrackErr = cte; |
shimniok | 0:826c6171fc1b | 586 | // Copy AHRS data into logging data |
shimniok | 0:826c6171fc1b | 587 | //state[inState].roll = ToDeg(ahrs.roll); |
shimniok | 0:826c6171fc1b | 588 | //state[inState].pitch = ToDeg(ahrs.pitch); |
shimniok | 0:826c6171fc1b | 589 | //state[inState].yaw = ToDeg(ahrs.yaw); |
shimniok | 0:826c6171fc1b | 590 | |
shimniok | 0:826c6171fc1b | 591 | // increment fifo pointers with wrap-around |
shimniok | 0:826c6171fc1b | 592 | prev = now; |
shimniok | 0:826c6171fc1b | 593 | inc(now); |
shimniok | 0:826c6171fc1b | 594 | |
shimniok | 0:826c6171fc1b | 595 | // timing |
shimniok | 0:826c6171fc1b | 596 | tReal = timer.read_us() - tReal; |
shimniok | 0:826c6171fc1b | 597 | |
shimniok | 0:826c6171fc1b | 598 | ahrsStatus = 1; |
shimniok | 0:826c6171fc1b | 599 | } |