Code for autonomous rover for Sparkfun AVC. DataBus won 3rd in 2012 and the same code was used on Troubled Child, a 1986 Jeep Grand Wagoneer to win 1st in 2014.

Dependencies:   mbed Watchdog SDFileSystem DigoleSerialDisp

Files at this revision

API Documentation at this revision

Comitter:
shimniok
Date:
Thu Jun 06 13:40:23 2013 +0000
Parent:
1:cb84b477886c
Child:
3:42f3821c4e54
Commit message:
Sort-of working version, still some errors with estimation. Added clamp() function.

Changed in this revision

Actuators/Steering/Steering.cpp Show annotated file Show diff for this revision Revisions of this file
Actuators/Steering/Steering.h Show annotated file Show diff for this revision Revisions of this file
Estimation/CartPosition/CartPosition.cpp Show annotated file Show diff for this revision Revisions of this file
Estimation/kalman.cpp Show annotated file Show diff for this revision Revisions of this file
Sensors/GPS/Sirf3.cpp Show annotated file Show diff for this revision Revisions of this file
Sensors/GPS/Sirf3.h Show annotated file Show diff for this revision Revisions of this file
Sensors/GPS/TinyGPS/TinyGPS.h Show annotated file Show diff for this revision Revisions of this file
Sensors/GPS/Venus638flpx.cpp Show annotated file Show diff for this revision Revisions of this file
Sensors/Sensors.cpp Show annotated file Show diff for this revision Revisions of this file
Sensors/Sensors.h Show annotated file Show diff for this revision Revisions of this file
globals.h Show annotated file Show diff for this revision Revisions of this file
logging/b64.cpp Show diff for this revision Revisions of this file
logging/b64.h Show diff for this revision Revisions of this file
logging/logging.cpp Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
updater.cpp Show annotated file Show diff for this revision Revisions of this file
util.cpp Show annotated file Show diff for this revision Revisions of this file
util.h Show annotated file Show diff for this revision Revisions of this file
--- a/Actuators/Steering/Steering.cpp	Tue May 28 13:58:35 2013 +0000
+++ b/Actuators/Steering/Steering.cpp	Thu Jun 06 13:40:23 2013 +0000
@@ -6,10 +6,10 @@
 /** create a new steering calculator for a particular vehicle
  *
  */
-Steering::Steering(float wheelbase, float track)
-    : _wheelbase(wheelbase)
-    , _track(track)
-    , _intercept(2.0)
+Steering::Steering(float wheelbase, float track):
+    _wheelbase(wheelbase),
+    _track(track),
+    _intercept(2.0)
 {
 }
 
@@ -101,6 +101,7 @@
     return 0;
 }
 
+//static int skip=0;
 
 float Steering::pathPursuitSA(float hdg, float Bx, float By, float Ax, float Ay, float Cx, float Cy)
 {
@@ -116,31 +117,37 @@
     // along the path by the lookahead distance
     float legLength = sqrtf(Lx*Lx + Ly*Ly); // ||L||
     float proj = (Lx*Rx + Ly*Ry)/legLength; // R dot L/||L||, projection magnitude, bot vector onto leg vector
-    float LAx = (proj+_intercept)*Lx/legLength + Ax; // find projection point + lookahead, along leg
-    float LAy = (proj+_intercept)*Ly/legLength + Ay;
+    float LAx = (proj + _intercept)*Lx/legLength; // find projection point + lookahead, along leg, relative to Bx
+    float LAy = (proj + _intercept)*Ly/legLength;
     // Compute a circle that is tangential to bot heading and intercepts bot
     // and goal point (LAx,LAy), the intercept circle. Then compute the steering
     // angle to trace that circle. (x,y because 0 deg points up not right)
-    float brg = 180*atan2(LAx-Rx,LAy-Ry)/PI;
+    float brg = angle_degrees(atan2(LAx-Rx,LAy-Ry));
+    if (brg >= 360.0) brg -= 360.0;
+    if (brg < 0) brg += 360.0;
     // would be nice to add in some noise to heading info
-    float relBrg = brg-hdg;
+    float relBrg = brg - hdg;
     if (relBrg < -180.0) relBrg += 360.0;
     if (relBrg >= 180.0) relBrg -= 360.0;
-    // I haven't had time to work out why the equation is asymmetrical, that is, 
-    // negative angle produces slightly less steering angle. So instead, just use
-    // absolute value and restore sign later.
-    float sign = (relBrg < 0) ? -1 : 1;
     // The equation peaks out at 90* so clamp theta artifically to 90, so that
     // if theta is actually > 90, we select max steering
     if (fabs(relBrg) > 90.0) relBrg = 90.0;
     // Compute radius based on intercept distance and specified angle
-    float radius = _intercept/(2*sin(fabs(relBrg)*PI/180));
+    float radius = _intercept/(2*sin(angle_radians(fabs(relBrg))));
     // optionally, limit radius min/max
     // Now compute the steering angle to achieve the circle of 
     // Steering angle is based on wheelbase and track width
-    SA = sign * angle_degrees(asin(_wheelbase / (radius - _track/2)));
-
-    //fprintf(stdout, "R(%.4f,%.4f) A(%.4f,%.4f) C(%.4f,%.4f) L(%.4f,%.4f) b=%.2f rb=%.2f sa=%.2f\n", Bx, By, Ax, Ay, Cx, Cy, Lx, Ly, brg, relBrg, SA);
+    SA = angle_degrees(asin(_wheelbase / (radius - _track/2)));
+    // I haven't had time to work out why the equation is asymmetrical, that is, 
+    // negative angle produces slightly less steering angle.
+    if (relBrg < 0) SA = -SA; 
+    
+    /*
+    if (++skip >= 20) {
+        fprintf(stdout, "R(%.4f,%.4f) A(%.4f,%.4f) C(%.4f,%.4f) LA(%.4f,%.4f) h=%.2f b=%.2f rb=%.2f sa=%.2f\n", Bx, By, Ax, Ay, Cx, Cy, LAx, LAy, hdg, brg, relBrg, SA);
+        skip = 0;
+    }
+    */
         
     return SA;
 }
--- a/Actuators/Steering/Steering.h	Tue May 28 13:58:35 2013 +0000
+++ b/Actuators/Steering/Steering.h	Thu Jun 06 13:40:23 2013 +0000
@@ -1,5 +1,7 @@
+#ifndef __STEERING_H
+#define __STEERING_H
 
-#define PI 3.141592653589
+#include "globals.h"
 
 /** A class for managing steering angle calculations based on current and desired heading
  *  and specified intercept distance along the new path.  
@@ -67,4 +69,6 @@
     float _wheelbase;
     float _track;
     float _intercept;
-};
\ No newline at end of file
+};
+
+#endif
\ No newline at end of file
--- a/Estimation/CartPosition/CartPosition.cpp	Tue May 28 13:58:35 2013 +0000
+++ b/Estimation/CartPosition/CartPosition.cpp	Thu Jun 06 13:40:23 2013 +0000
@@ -1,7 +1,7 @@
 #include "mbed.h" // debug
 #include "CartPosition.h"
 
-#define PI 3.1415926535897932
+#include "globals.h"
 
 CartPosition::CartPosition(void)
 {
--- a/Estimation/kalman.cpp	Tue May 28 13:58:35 2013 +0000
+++ b/Estimation/kalman.cpp	Thu Jun 06 13:40:23 2013 +0000
@@ -14,8 +14,8 @@
 static float H[4]={ 1, 0, 0, 1 };           // Observer matrix maps measurements to state transition
 float K[4]={ 0, 0, 0, 0 };                  // Kalman gain
 static float P[4]={ 1000, 0, 0, 1000 };     // Covariance matrix
-static float R[4]={ 3, 0, 0, 0.03 };        // Measurement noise, hdg, hdg rate
-static float Q[4]={ 0.01, 0, 0, 0.01 };     // Process noise matrix
+static float R[4]={ 100, 0, 0, 0.03 };        // Measurement noise, hdg, hdg rate
+static float Q[4]={ 100, 0, 0, 0.01 };        // Process noise matrix
 static float I[4]={ 1, 0, 0, 1 };           // Identity matrix
 
 float kfGetX(int i)
--- a/Sensors/GPS/Sirf3.cpp	Tue May 28 13:58:35 2013 +0000
+++ b/Sensors/GPS/Sirf3.cpp	Thu Jun 06 13:40:23 2013 +0000
@@ -6,7 +6,6 @@
 Sirf3::Sirf3(PinName tx, PinName rx):
     serial(tx, rx)
 {
-    setBaud(4800);
     enable();
 }
 
@@ -28,11 +27,13 @@
 void Sirf3::enable(void)
 {
     reset_available();
+    setBaud(4800);
     serial.attach(this, &Sirf3::recv_handler, Serial::RxIrq);
 }
 
 void Sirf3::disable(void)
 {
+    setBaud(4800);
     serial.attach(NULL, Serial::RxIrq);
 }
 
@@ -41,8 +42,13 @@
  */
 void Sirf3::enableVerbose(void)
 {
+    setBaud(4800);
     gsaMessage(true);
+    ggaMessage(true);
+    gllMessage(false);
     gsvMessage(true);
+    rmcMessage(true);
+    vtgMessage(false);
 }
 
 /**
@@ -50,8 +56,27 @@
  */
 void Sirf3::disableVerbose(void)
 {
-    gsaMessage(false);
+    setBaud(4800);
+    gsaMessage(true);
+    ggaMessage(true);
+    gllMessage(false);
     gsvMessage(false);
+    rmcMessage(true);
+    vtgMessage(false);
+}
+
+void Sirf3::setUpdateRate(int rate)
+{
+    // We're stuck at 1Hz
+    return;
+}
+
+int Sirf3::getAvailable(void)
+{
+    int answer = 0x00;
+    if (nmea.gga_ready()) answer |= 0x01;
+    if (nmea.rmc_ready()) answer |= 0x02;
+    return answer;
 }
 
 double Sirf3::latitude(void)
@@ -107,6 +132,28 @@
     }
 }
 
+void Sirf3::ggaMessage(bool enable)
+{
+    if (enable) {
+        serial.printf("$PSRF103,00,00,01,01*25\r\n");     // Enable GGA
+    } else {
+        serial.printf("$PSRF103,00,00,00,01*24\r\n");     // Disable GGA
+    }
+
+    return;
+}
+
+void Sirf3::gllMessage(bool enable)
+{
+    if (enable) {
+        serial.printf("$PSRF103,01,00,01,01*24\r\n");     // Enable GLL
+    } else {
+        serial.printf("$PSRF103,01,00,00,01*25\r\n");     // Disable GLL
+    }
+
+    return;
+}
+
 void Sirf3::gsaMessage(bool enable)
 {
     if (enable) {
@@ -129,3 +176,24 @@
     return;
 }
 
+void Sirf3::rmcMessage(bool enable)
+{
+    if (enable) {
+        serial.printf("$PSRF103,04,00,01,01*21\r\n");     // Enable RMC
+    } else {
+        serial.printf("$PSRF103,04,00,00,01*20\r\n");     // Disable RMC
+    }
+
+    return;
+}
+
+void Sirf3::vtgMessage(bool enable)
+{
+    if (enable) {
+        serial.printf("$PSRF103,05,00,01,01*20\r\n");     // Enable VTG
+    } else {
+        serial.printf("$PSRF103,05,00,00,01*21\r\n");     // Disable VTG
+    }
+
+    return;
+}
--- a/Sensors/GPS/Sirf3.h	Tue May 28 13:58:35 2013 +0000
+++ b/Sensors/GPS/Sirf3.h	Thu Jun 06 13:40:23 2013 +0000
@@ -48,6 +48,17 @@
     virtual void disableVerbose(void);
 
     /**
+     * stub function for compatibility
+     */
+    int getAvailable(void);
+
+    /**
+     * stub function for compatibility
+     * Configure GPS update rate (doesn't do anything on Sirf3)
+     */
+    void setUpdateRate(int rate);
+
+    /**
      * get latitude
      */
     virtual double latitude(void);
@@ -90,8 +101,12 @@
 
 private:
     void recv_handler(void);
+    void ggaMessage(bool enable);
     void gsaMessage(bool enable);
     void gsvMessage(bool enable);
+    void gllMessage(bool enable);
+    void rmcMessage(bool enable);
+    void vtgMessage(bool enable);
     Serial serial;
     TinyGPS nmea;
 };
--- a/Sensors/GPS/TinyGPS/TinyGPS.h	Tue May 28 13:58:35 2013 +0000
+++ b/Sensors/GPS/TinyGPS/TinyGPS.h	Thu Jun 06 13:40:23 2013 +0000
@@ -197,7 +197,11 @@
     /** determine if GSV sentence parsed since last reset_ready()
      */
     inline bool gsv_ready() { return _gsv_ready; }
+
+    inline bool gga_ready() { return _gga_ready; }
     
+    inline bool rmc_ready() { return _rmc_ready; }
+   
     /** Reset the ready flags for all the parsed sentences
      */
     inline void reset_ready() { _gsv_ready = _rmc_ready = _gga_ready = false; }
--- a/Sensors/GPS/Venus638flpx.cpp	Tue May 28 13:58:35 2013 +0000
+++ b/Sensors/GPS/Venus638flpx.cpp	Thu Jun 06 13:40:23 2013 +0000
@@ -167,6 +167,7 @@
 
 int Venus638flpx::getAvailable(void)
 {
+    // TODO 2 not sure what to do here
     return 0xff;
 }
 
--- a/Sensors/Sensors.cpp	Tue May 28 13:58:35 2013 +0000
+++ b/Sensors/Sensors.cpp	Thu Jun 06 13:40:23 2013 +0000
@@ -39,8 +39,7 @@
 ///////////////////// MAGNETOMETER CALIBRATION
 
 Sensors::Sensors():
-    //gps(p9, p10),              // Ublox6 GPS
-    gps(p26, p25),               // Venus GPS
+    gps(p26, p25),
     _voltage(p19),               // Voltage from sensor board
     _current(p20),               // Current from sensor board
     _left(p30),                  // left wheel encoder
@@ -111,7 +110,7 @@
     // TODO: get rid of state variable
     lrEncDistance  = (WHEEL_CIRC / WHEEL_STRIPES) * (double) leftCount;
     rrEncDistance = (WHEEL_CIRC / WHEEL_STRIPES) * (double) rightCount;
-    encDistance = (lrEncDistance + rrEncDistance) / 2.0;
+    //encDistance = (lrEncDistance + rrEncDistance) / 2.0;
     // compute speed from time between ticks
     int leftTime = _left.readTime();
     int rightTime = _right.readTime();
--- a/Sensors/Sensors.h	Tue May 28 13:58:35 2013 +0000
+++ b/Sensors/Sensors.h	Thu Jun 06 13:40:23 2013 +0000
@@ -32,6 +32,7 @@
 
 /** Sensor interface library abstracts sensor drivers, next step to a pluggable architecture */
 
+#include "Sirf3.h"
 #include "Ublox6.h"
 #include "Venus638flpx.h"
 #include "L3G4200D.h"
@@ -117,8 +118,9 @@
     float encDistance;                      // encoder distance since last check
     float encSpeed;                         // encoder calculated speed
 
-    Venus638flpx gps;                       // Venus GPS
-    //Ublox6 gps;                             // Ublox6 GPS
+    //Sirf3 gps;                              // Pharos SiRF III GPS
+    //Venus638flpx gps;                       // Venus GPS
+    Ublox6 gps;                             // Ublox6 GPS
     AnalogIn _voltage;                      // Voltage from sensor board
     AnalogIn _current;                      // Current from sensor board
     IncrementalEncoder _left;               // Left wheel encoder
--- a/globals.h	Tue May 28 13:58:35 2013 +0000
+++ b/globals.h	Thu Jun 06 13:40:23 2013 +0000
@@ -3,6 +3,8 @@
 
 /** Global parameters */
 
+#define PI 3.1415926535897932
+
 // Waypoint queue parameters
 #define MAXWPT    10
 #define ENDWPT    9999.0
--- a/logging/b64.cpp	Tue May 28 13:58:35 2013 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,140 +0,0 @@
-/*********************************************************************
-
-MODULE NAME:    b64.c
-
-AUTHOR:         Bob Trower 08/04/01, Michael Shimniok 04/04/13
-
-COPYRIGHT:      Copyright (c) Trantor Standard Systems Inc., 2001
-
-NOTES:          This source code may be used as you wish, subject to
-                the MIT license.  See the LICENCE section below.
-
-                Canonical source should be at:
-                    http://base64.sourceforge.net
-
-DESCRIPTION:    Implements Base64 Content-Transfer-Encoding standard
-                described in RFC1113 (http://www.faqs.org/rfcs/rfc1113.html).
-
-                Groups of 3 binary bytes from a binary stream are coded as
-                groups of 4 printable bytes in a text stream.
-*********************************************************************/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "b64.h"
-
-/**
- * Translation Table as described in RFC1113
- */
-static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-/**
- * Translation Table to decode (created by author)
- */
-//static const char cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
-
-/**
- * returnable errors
- *
- * Error codes returned to the operating system.
- *
- */
-#define B64_SYNTAX_ERROR        1
-#define B64_FILE_ERROR          2
-#define B64_FILE_IO_ERROR       3
-#define B64_ERROR_OUT_CLOSE     4
-#define B64_LINE_SIZE_TO_MIN    5
-#define B64_SYNTAX_TOOMANYARGS  6
-
-/**
- * encodeblock
- *
- * encode 3 8-bit binary bytes as 4 '6-bit' characters
- */
-void encodeblock( const unsigned char *in, unsigned char *out, const int len )
-{
-    out[0] = (unsigned char) cb64[ (int)(in[0] >> 2) ];
-    out[1] = (unsigned char) cb64[ (int)(((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4)) ];
-    out[2] = (unsigned char) (len > 1 ? cb64[ (int)(((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6)) ] : '=');
-    out[3] = (unsigned char) (len > 2 ? cb64[ (int)(in[2] & 0x3f) ] : '=');
-}
-
-/**
- * encodeblock
- *
- * encode a buffer of binary data into lines of '6-bit' characters
- */
-int encode( const unsigned char *sin, const int length, unsigned char *sout, const int linesize )
-{
-    unsigned char in[3];
-    int i;
-    int j; // j is the sin position index
-    int len, blocksout = 0;
-    int retcode = 0;
-
-    in[0] = 0;
-    j = 0;
-    while( j < length ) {
-        // Get a block of three bytes to encode
-        // If there's < 3 bytes left in the string,
-        // pad with '\0'
-        len = 0;
-        for (i=0; i < 3; i++, j++) {
-            if (j < length) {
-                len++;
-                in[i] = sin[j];
-            } else {
-                in[i] = '\0';
-            }
-        }
-        //printf("2. in=%02x %02x %02x j=%u length=%u\n", in[0], in[1], in[2], j, length);
-        encodeblock( in, sout, len );
-        //printf("4. sout=%c%c%c%c\n", sout[0], sout[1], sout[2], sout[3]);
-        sout += 4;
-        blocksout++;
-        if( linesize && blocksout >= (linesize/4) ) {
-            *sout++ = '\n';
-            blocksout = 0;
-        }
-    }
-    *sout = '\0';
-    return( retcode );
-}
-
-/******************************************************************************
-LICENCE:        Copyright (c) 2001 Bob Trower, Trantor Standard Systems Inc.
-
-                Permission is hereby granted, free of charge, to any person
-                obtaining a copy of this software and associated
-                documentation files (the "Software"), to deal in the
-                Software without restriction, including without limitation
-                the rights to use, copy, modify, merge, publish, distribute,
-                sublicense, and/or sell copies of the Software, and to
-                permit persons to whom the Software is furnished to do so,
-                subject to the following conditions:
-
-                The above copyright notice and this permission notice shall
-                be included in all copies or substantial portions of the
-                Software.
-
-                THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-                KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-                WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-                PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
-                OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-                OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-                OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-                SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-VERSION HISTORY:
-                Bob Trower 08/04/01 -- Create Version 0.00.00B
-                Bob Trower 08/17/01 -- Correct documentation, messages.
-                                    -- Correct help for linesize syntax.
-                                    -- Force error on too many arguments.
-                Bob Trower 08/19/01 -- Add sourceforge.net reference to
-                                       help screen prior to release.
-                Bob Trower 10/22/04 -- Cosmetics for package/release.
-                Bob Trower 02/28/08 -- More Cosmetics for package/release.
-                Bob Trower 02/14/11 -- Cast altered to fix warning in VS6.
-
-*****************************************************************************/
--- a/logging/b64.h	Tue May 28 13:58:35 2013 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-/*********************************************************************
-
-MODULE NAME:    b64.c
-
-AUTHOR:         Bob Trower 08/04/01, Michael Shimniok 04/04/13
-
-COPYRIGHT:      Copyright (c) Trantor Standard Systems Inc., 2001
-
-NOTES:          This source code may be used as you wish, subject to
-                the MIT license.  See the LICENCE section below.
-
-                Canonical source should be at:
-                    http://base64.sourceforge.net
-
-DESCRIPTION:    Implements Base64 Content-Transfer-Encoding standard
-                described in RFC1113 (http://www.faqs.org/rfcs/rfc1113.html).
-
-                Groups of 3 binary bytes from a binary stream are coded as
-                groups of 4 printable bytes in a text stream.
-*********************************************************************/
-
-#ifndef __B64_H
-#define __B64_H
-
-/**
- * encodeblock
- *
- * encode 3 8-bit binary bytes as 4 '6-bit' characters
- */
-void encodeblock( const unsigned char *in, unsigned char *out, const int len );
-
-/**
- * encode
- *
- * encode a buffer of binary data into lines of '6-bit' characters
- */
-int encode( const unsigned char *sin, const int length, unsigned char *sout, const int linesize );
-
-#endif
-
-/******************************************************************************
-LICENCE:        Copyright (c) 2001 Bob Trower, Trantor Standard Systems Inc.
-
-                Permission is hereby granted, free of charge, to any person
-                obtaining a copy of this software and associated
-                documentation files (the "Software"), to deal in the
-                Software without restriction, including without limitation
-                the rights to use, copy, modify, merge, publish, distribute,
-                sublicense, and/or sell copies of the Software, and to
-                permit persons to whom the Software is furnished to do so,
-                subject to the following conditions:
-
-                The above copyright notice and this permission notice shall
-                be included in all copies or substantial portions of the
-                Software.
-
-                THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-                KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-                WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-                PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
-                OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-                OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-                OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-                SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-VERSION HISTORY:
-                Bob Trower 08/04/01 -- Create Version 0.00.00B
-                Bob Trower 08/17/01 -- Correct documentation, messages.
-                                    -- Correct help for linesize syntax.
-                                    -- Force error on too many arguments.
-                Bob Trower 08/19/01 -- Add sourceforge.net reference to
-                                       help screen prior to release.
-                Bob Trower 10/22/04 -- Cosmetics for package/release.
-                Bob Trower 02/28/08 -- More Cosmetics for package/release.
-                Bob Trower 02/14/11 -- Cast altered to fix warning in VS6.
-
-*****************************************************************************/
--- a/logging/logging.cpp	Tue May 28 13:58:35 2013 +0000
+++ b/logging/logging.cpp	Thu Jun 06 13:40:23 2013 +0000
@@ -1,7 +1,6 @@
 #include "logging.h"
 #include "SDHCFileSystem.h"
 #include "SerialGraphicLCD.h"
-#include "b64.h"
 
 extern Serial pc;
 extern SerialGraphicLCD lcd;
@@ -212,7 +211,7 @@
     fputc('\n',logp);
 
     t2 = logtimer.read_us();
-    fprintf(stdout, "%d\n", t2-t1);
+    //fprintf(stdout, "%d\n", t2-t1);
 
     return;
 }
--- a/main.cpp	Tue May 28 13:58:35 2013 +0000
+++ b/main.cpp	Thu Jun 06 13:40:23 2013 +0000
@@ -55,6 +55,7 @@
 #define GYRO_CHAN        5
 
 // Chassis specific parameters
+// TODO 1 put WHEEL_CIRC, WHEELBASE, and TRACK in config.txt
 #define WHEEL_CIRC 0.321537             // m; calibrated with 4 12.236m runs. Measured 13.125" or 0.333375m circumference
 #define WHEELBASE  0.290
 #define TRACK      0.280
@@ -169,23 +170,31 @@
 {
     // Let's try setting priorities...
     NVIC_SetPriority(TIMER3_IRQn, 0);   // updater running off Ticker
-    NVIC_SetPriority(DMA_IRQn, 1);
-    NVIC_SetPriority(EINT0_IRQn, 5);    // wheel encoders
-    NVIC_SetPriority(EINT1_IRQn, 5);    // wheel encoders
-    NVIC_SetPriority(EINT2_IRQn, 5);    // wheel encoders
-    NVIC_SetPriority(EINT3_IRQn, 5);    // wheel encoders
-    NVIC_SetPriority(UART1_IRQn, 10);   // GPS p25,p26
-    NVIC_SetPriority(I2C0_IRQn, 20);    // sensors?
-    NVIC_SetPriority(I2C1_IRQn, 20);    // sensors?
-    NVIC_SetPriority(I2C2_IRQn, 20);    // sensors?
-    NVIC_SetPriority(UART3_IRQn, 30);   // LCD p17,p18
-    NVIC_SetPriority(UART0_IRQn, 30);   // USB
-    NVIC_SetPriority(ADC_IRQn, 40);     // Voltage/current
-    NVIC_SetPriority(TIMER0_IRQn, 255); // unused(?)
-    NVIC_SetPriority(TIMER1_IRQn, 255); // unused(?)
-    NVIC_SetPriority(TIMER2_IRQn, 255); // unused(?)
-    NVIC_SetPriority(SPI_IRQn, 255);    // uSD card, logging
+    NVIC_SetPriority(DMA_IRQn, 0);
+    NVIC_SetPriority(EINT0_IRQn, 0);    // wheel encoders
+    NVIC_SetPriority(EINT1_IRQn, 0);    // wheel encoders
+    NVIC_SetPriority(EINT2_IRQn, 0);    // wheel encoders
+    NVIC_SetPriority(EINT3_IRQn, 0);    // wheel encoders
+    NVIC_SetPriority(UART0_IRQn, 5);   // USB
+    NVIC_SetPriority(UART1_IRQn, 10);
+    NVIC_SetPriority(UART2_IRQn, 10);
+    NVIC_SetPriority(UART3_IRQn, 10);
+    NVIC_SetPriority(I2C0_IRQn, 10);    // sensors?
+    NVIC_SetPriority(I2C1_IRQn, 10);    // sensors?
+    NVIC_SetPriority(I2C2_IRQn, 10);    // sensors?
+    NVIC_SetPriority(ADC_IRQn, 10);     // Voltage/current
+    NVIC_SetPriority(TIMER0_IRQn, 10); // unused(?)
+    NVIC_SetPriority(TIMER1_IRQn, 10); // unused(?)
+    NVIC_SetPriority(TIMER2_IRQn, 10); // unused(?)
+    NVIC_SetPriority(SPI_IRQn, 10);    // uSD card, logging
 
+    // Something here is jacking up the I2C stuff
+    // Also when initializing with ESC powered, it causes motor to run which
+    // totally jacks up everything (noise?)
+    initSteering();
+    initThrottle();
+    // initFlasher();                                   // Initialize autonomous mode flasher
+    
     // Send data back to the PC
     pc.baud(115200);
     fprintf(stdout, "Data Bus 2013\n");
@@ -211,13 +220,6 @@
     if (config.load())                          // Load various configurable parameters, e.g., waypoints, declination, etc.
         confStatus = 1;
 
-    // Something here is jacking up the I2C stuff
-    // Also when initializing with ESC powered, it causes motor to run which
-    // totally jacks up everything (noise?)
-    initSteering();
-    initThrottle();
-    // initFlasher();                                   // Initialize autonomous mode flasher
-        
     sensors.Compass_Calibrate(config.magOffset, config.magScale);
     //pc.printf("Declination: %.1f\n", config.declination);
     pc.printf("Speed: escZero=%d escMax=%d top=%.1f turn=%.1f Kp=%.4f Ki=%.4f Kd=%.4f\n", 
@@ -313,7 +315,7 @@
             display.update(s);
             nextUpdate = thisUpdate + 2000;
             // TODO move this statistic into display class
-            fprintf(stdout, "update time: %d\n", getUpdateTime());
+            //fprintf(stdout, "update time: %d\n", getUpdateTime());
         }
         
         if (keypad.pressed) {
@@ -359,10 +361,9 @@
             fprintf(stdout, "%d) Display AHRS\n", i++);
             fprintf(stdout, "%d) Mavlink mode\n", i++);
             fprintf(stdout, "%d) Shell\n", i++);
-            fprintf(stdout, "%d) Bridge serial to 2nd GPS\n", i++);
             fprintf(stdout, "R) Reset\n");
             fprintf(stdout, "\nSelect from the above: ");
-            fflush(stdout);
+            //fflush(stdout);
             printMenu = false;
         }
 
@@ -840,7 +841,8 @@
     sensors.gps.enableVerbose();
     wait(2.0);
     //dev = &gps;
-    serial.attach(NULL, Serial::RxIrq);
+    sensors.gps.disable();
+    serial.baud(4800);
     while (!done) {
         if (pc.readable()) {
             x = pc.getc();
@@ -935,6 +937,8 @@
                     sensors.gps.latitude(), sensors.gps.longitude(), sensors.gps.heading_deg(), 
                     sensors.gps.speed_mps(), sensors.gps.hdop(), sensors.gps.sat_count(),
                     (unsigned char) sensors.gps.getAvailable() );
+                fprintf(stdout, "brg=%6.2f d=%8.4f sa=%6.2f\n", 
+                    state[inState].bearing, state[inState].distance, state[inState].steerAngle);
                 /*
                 fprintf(stdout, "gps2=(%.6f, %.6f, %.1f, %.1f, %.1f, %d) %02x\n", 
                     gps2.latitude(), gps2.longitude(), gps2.heading_deg(), gps2.speed_mps(), gps2.hdop(), gps2.sat_count(),
--- a/updater.cpp	Tue May 28 13:58:35 2013 +0000
+++ b/updater.cpp	Thu Jun 06 13:40:23 2013 +0000
@@ -1,4 +1,6 @@
 #include "mbed.h"
+#include "util.h"
+#include "globals.h"
 #include "updater.h"
 #include "Config.h"
 #include "Actuators.h"
@@ -25,6 +27,7 @@
 //#define LOG_SKIP 1  // 50ms, 20hz, log entry entered into fifo
 
 // The following is for main loop at 10ms = 100hz
+#define HDG_LAG 100
 #define CTRL_SKIP 5 // 50ms (20hz), control update
 #define MAG_SKIP 2  // 20ms (50hz), magnetometer update
 #define LOG_SKIP 2  // 20ms (50hz), log entry entered into fifo
@@ -98,10 +101,10 @@
     float dt;       // delta time
 } history[MAXHIST]; // fifo for sensor data, position, heading, dt
 
-int hCount;         // history counter; one > 100, we can go back in time to reference gyro history
+int hCount;         // history counter; one > HDG_LAG, we can go back in time to reference gyro history
 int now = 0;        // fifo input index, latest entry
 int prev = 0;       // previous fifo iput index, next to latest entry
-int lag = 0;        // fifo output index, entry from 1 second ago (100 entries prior)
+int lag = 0;        // fifo output index, entry from 1 second ago (HDG_LAG entries prior)
 int lagPrev = 0;    // previous fifo output index, 101 entries prior
 
 /** attach update to Ticker */
@@ -122,7 +125,7 @@
     return;
 }
 
-/** instruct the controller to arm, begin estimation */
+/** instruct the controller to start running */
 void beginRun()
 {
     go = true;
@@ -298,15 +301,16 @@
     history[now].dist = (sensors.lrEncDistance + sensors.rrEncDistance) / 2.0; // current distance traveled
     history[now].gyro = sensors.gyro[_z_];  // current raw gyro data
     history[now].dt = dt; // current dt, to address jitter
-    history[now].hdg = history[prev].hdg + dt*history[now].gyro; // compute current heading from current gyro
-    if (history[now].hdg >= 360.0) history[now].hdg -= 360.0;
-    if (history[now].hdg < 0)      history[now].hdg += 360.0;
+    history[now].hdg = history[prev].hdg + dt*(history[now].gyro - gyroBias); // compute current heading from current gyro
+    clamp(history[now].hdg, 0, 360.0);
+    //if (history[now].hdg >= 360.0) history[now].hdg -= 360.0;
+    //if (history[now].hdg < 0)      history[now].hdg += 360.0;
     float r = PI/180 * history[now].hdg;
     history[now].x = history[prev].x + history[now].dist * sin(r);    // update current position
     history[now].y = history[prev].y + history[now].dist * cos(r);
 
     // We can't do anything until the history buffer is full
-    if (hCount < 100) {
+    if (hCount < HDG_LAG) {
         estLagHeading = history[now].hdg;
         // Until the fifo is full, only keep track of current gyro heading
         hCount++; // after n iterations the fifo will be full
@@ -354,25 +358,33 @@
         // Heading is easy. Original heading - estimated heading gives a tiny error. Add this to all the historical
         // heading data up to present.
         //
-        // For position re-calculation, we iterate 100 times up to present record. Haversine is way, way too slow,
+        // For position re-calculation, we iterate HDG_LAG times up to present record. Haversine is way, way too slow,
         // trig calcs is marginal. Update rate is 10ms and we can't hog more than maybe 2-3ms as the outer
         // loop has logging work to do. Rotating each point is faster; pre-calculate sin/cos, etc. for rotation
         // matrix.
-        //
-        // initialize these once
-        errAngle = (estLagHeading - history[lag].hdg);
-        if (errAngle <= -180.0) errAngle += 360.0;
-        if (errAngle > 180) errAngle -= 360.0;
+
+        // Low pass filter the error correction.  Multiplying by 0.01, it takes HDG_LAG updates to correct a 
+        // consistent error; that's 0.10s/0.01 = 1 sec.  0.005 is 2 sec, 0.0025 is 4 sec, etc.
+        errAngle = (estLagHeading - history[lag].hdg); 
+        // low pass filter error angle:
+        clamp(errAngle, -180.0, 180.0);
+        //if (errAngle > 180.0) errAngle -= 360.0;
+        //if (errAngle <= -180.0) errAngle += 360.0;
+        errAngle *= 0.01; // multiply only after clamping to -180:180 range.
 
         //fprintf(stdout, "%d %.2f, %.2f, %.4f %.4f\n", lag, estLagHeading, history[lag].hdg, estLagHeading - history[lag].hdg, errAngle);
         float cosA = cos(errAngle * PI / 180.0);
         float sinA = sin(errAngle * PI / 180.0);
         // Update position & heading from history[lag] through history[now]
         int i = lag;
-        for (int j=0; j < 100; j++) {
+        // TODO 2 parameterize heading lag -- for uBlox it seems to be ~ 600ms, for Venus, about 1000ms
+        for (int j=0; j < HDG_LAG; j++) {
             //fprintf(stdout, "i=%d n=%d l=%d\n", i, now, lag);
             // Correct gyro-calculated headings from past to present including history[lag].hdg
             history[i].hdg += errAngle;
+            clamp(history[i].hdg, 0, 360.0);
+            //if (history[i].hdg >= 360.0) history[i].hdg -= 360.0;
+            //if (history[i].hdg < 0) history[i].hdg += 360.0;
             // Rotate x, y by errAngle around pivot point; no need to rotate pivot point (j=0)
             if (j > 0) {
                 float dx = history[i].x-history[lag].x;
@@ -399,9 +411,9 @@
     float prevDistance = cartHere.distanceTo(config.cwpt[lastWaypoint]);
     double relativeBrg = bearing - history[now].hdg;
     // if correction angle is < -180, express as negative degree
-    // TODO 3 turn this into a function
-    if (relativeBrg < -180.0) relativeBrg += 360.0;
-    if (relativeBrg > 180.0)  relativeBrg -= 360.0;
+    clamp(relativeBrg, -180.0, 180.0);
+    //if (relativeBrg < -180.0) relativeBrg += 360.0;
+    //if (relativeBrg > 180.0)  relativeBrg -= 360.0;
 
     // if within config.waypointDist distance threshold move to next waypoint
     // TODO 3 figure out how to output feedback on wpt arrival external to this function
@@ -410,10 +422,10 @@
         // if we're within brakeDist of next or previous waypoint, run @ turn speed
         // This would normally mean we run at turn speed until we're brakeDist away
         // from waypoint 0, but we trick the algorithm by initializing prevWaypoint to waypoint 1
-        if (distance < config.brakeDist || prevDistance < config.brakeDist) {
+        if ( (thisTime - timeZero) < 3000 ) {
+            setSpeed( config.startSpeed );
+        } else if (distance < config.brakeDist || prevDistance < config.brakeDist) {
             setSpeed( config.turnSpeed );
-        } else if ( (thisTime - timeZero) < 1000 ) {
-            setSpeed( config.startSpeed );
         } else {
             setSpeed( config.topSpeed );
         }
@@ -568,7 +580,7 @@
     state[inState].bearing = bearing;
     state[inState].distance = distance;
     state[inState].nextWaypoint = nextWaypoint;
-    //state[inState].gbias = gyroBias;
+    state[inState].gbias = gyroBias;
     state[inState].errAngle = biasErrAngle;
     //state[inState].leftRanger = sensors.leftRanger;
     //state[inState].rightRanger = sensors.rightRanger;
--- a/util.cpp	Tue May 28 13:58:35 2013 +0000
+++ b/util.cpp	Thu Jun 06 13:40:23 2013 +0000
@@ -1,3 +1,14 @@
+/** 
+ * Clamp a value (angle) between min (non-inclusive) and max (inclusive)
+ * e.g. clamp(v, 0, 360) or clamp(v, -180, 180)
+ */
+float clamp(float v, float min, float max) 
+{
+    float mod = (max - min);
+    if (v >= max) float -= mod;
+    if (v < min) float += mod;
+}
+
 // convert character to an int
 //
 int ctoi(char c)
--- a/util.h	Tue May 28 13:58:35 2013 +0000
+++ b/util.h	Thu Jun 06 13:40:23 2013 +0000
@@ -12,10 +12,15 @@
 #define M_PI 3.14159265358979323846
 #endif
 
+/** Clamp value between min (non-inclusive) and max (inclusive) */
+float clamp(float v, float min, float max);
+
 /** Convert char to integer */
 int ctoi(char c);
+
 /** Convert string to floating point */
 double cvstof(char *s);
+
 /** Tokenize a string 
  * @param s is the string to tokenize
  * @param max is the maximum number of characters