UAVX Multicopter Flight Controller.

Dependencies:   mbed

Revision:
0:62a1c91a859a
Child:
1:1e3318a30ddd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/telemetry.c	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,613 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: you can redistribute it and/or modify it under the terms of the GNU
+//    General Public License as published by the Free Software Foundation, either version 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+#include "UAVXArm.h"
+
+void RxTelemetryPacket(uint8);
+void InitTelemetryPacket(void);
+void BuildTelemetryPacket(uint8);
+
+void SendPacketHeader(void);
+void SendPacketTrailer(void);
+
+void SendTelemetry(void);
+void SendCycle(void);
+void SendControl(void);
+void SendFlightPacket(void);
+void SendNavPacket(void);
+void SendControlPacket(void);
+void SendStatsPacket(void);
+void SendParamPacket(uint8);
+void SendMinPacket(void);
+void SendArduStation(void);
+void SendCustom(void);
+void SensorTrace(void);
+
+uint8 UAVXCurrPacketTag;
+uint8 RxPacketLength, RxPacketByteCount;
+uint8 RxCheckSum;
+uint8 RxPacketTag, ReceivedPacketTag;
+uint8 PacketRxState;
+boolean CheckSumError, TelemetryPacketReceived;
+
+int16 RxLengthErrors, RxTypeErrors, RxCheckSumErrors;
+
+uint8 UAVXPacket[256];
+
+FILE *logfile = NULL;
+boolean EchoToLogFile = false;
+uint32 LogChars;
+boolean LogfileIsOpen = false;
+
+uint8 TxCheckSum;
+
+void InitTelemetryPacket(void) {
+    RxPacketByteCount = 0;
+    RxCheckSum = 0;
+    RxPacketTag = UnknownPacketTag;
+    RxPacketLength = 2; // set as minimum
+    PacketRxState = WaitRxSentinel;
+} // InitTelemetryPacket
+
+void BuildTelemetryPacket(uint8 ch) {
+    static boolean RxPacketError;
+
+    UAVXPacket[RxPacketByteCount++] = ch;
+
+    if (RxPacketByteCount == 1) {
+        RxPacketTag = ch;
+        PacketRxState=WaitRxBody;
+    } else
+        if (RxPacketByteCount == 2) {
+            RxPacketLength = ch; // ignore
+            PacketRxState = WaitRxBody;
+        } else
+            if (RxPacketByteCount >= (RxPacketLength + 3)) {
+                RxPacketError = CheckSumError = RxCheckSum != 0;
+
+                if (CheckSumError)
+                    RxCheckSumErrors++;
+
+                if (!RxPacketError) {
+                    TelemetryPacketReceived = true;
+                    ReceivedPacketTag=RxPacketTag;
+                }
+                PacketRxState = WaitRxSentinel;
+                //   InitPollPacket();
+            } else
+                PacketRxState = WaitRxBody;
+} // BuildTelemetryPacket
+
+void RxTelemetryPacket(uint8 ch) {
+
+    RxCheckSum ^= ch;
+    switch (PacketRxState) {
+        case WaitRxSentinel:
+            if (ch == SOH) {
+                InitTelemetryPacket();
+                CheckSumError = false;
+                PacketRxState = WaitRxBody;
+            }
+            break;
+        case WaitRxBody:
+            if (ch == ESC)
+                PacketRxState = WaitRxESC;
+            else
+                if (ch == SOH) { // unexpected start of packet
+                    RxLengthErrors++;
+
+                    InitTelemetryPacket();
+                    PacketRxState = WaitRxBody;
+                } else
+                    if (ch == EOT) { // unexpected end of packet
+                        RxLengthErrors++;
+                        PacketRxState = WaitRxSentinel;
+                    } else
+                        BuildTelemetryPacket(ch);
+            break;
+        case WaitRxESC:
+            BuildTelemetryPacket(ch);
+            break;
+        default:
+            PacketRxState = WaitRxSentinel;
+            break;
+    }
+} // ParseTelemetryPacket
+
+
+#define NAV_STATS_INTERLEAVE    10
+static int8 StatsNavAlternate = 0;
+
+void CheckTelemetry(void) {
+
+    // check incoming - switch on associated action
+
+    // do routine telemetry Tx
+    if ( mSClock() > mS[TelemetryUpdate] )
+        switch ( P[TelemetryType] ) {
+            case UAVXTelemetry:
+                mS[TelemetryUpdate] = mSClock() + UAVX_TEL_INTERVAL_MS;
+                SendCycle();
+                break;
+            case ArduStationTelemetry:
+                mS[TelemetryUpdate] = mSClock() + UAVX_CONTROL_TEL_INTERVAL_MS;
+                SendArduStation();
+                break;
+            case UAVXControlTelemetry:
+                mS[TelemetryUpdate] = mSClock() + UAVX_CONTROL_TEL_INTERVAL_MS;
+                SendControlPacket();
+                break;
+            case UAVXMinTelemetry:
+                mS[TelemetryUpdate] = mSClock() + UAVX_MIN_TEL_INTERVAL_MS;
+                SendMinPacket();
+                break;
+            case CustomTelemetry:
+                mS[TelemetryUpdate] = mSClock() + CUSTOM_TEL_INTERVAL_MS;
+                SendCustom();
+                break;
+            case GPSTelemetry:
+                break;
+        }
+
+} // CheckTelemetry
+
+void SendPacketHeader(void) {
+    static int8 b;
+
+    EchoToLogFile = true;
+
+#ifdef TELEMETRY_PREAMBLE
+    for (b=10;b;b--)
+        TxChar(0x55);
+#endif // TELEMETRY_PREAMBLE
+
+    TxChar(0xff); // synchronisation to "jolt" USART
+    TxChar(SOH);
+    TxCheckSum = 0;
+} // SendPacketHeader
+
+void SendPacketTrailer(void) {
+    TxESCu8(TxCheckSum);
+    TxChar(EOT);
+
+    TxChar(CR);
+    TxChar(LF);
+
+    EchoToLogFile = false;
+} // SendPacketTrailer
+
+void ShowAttitude(void) {
+    // Stick units
+    TxESCi16(DesiredRoll);
+    TxESCi16(DesiredPitch);
+    TxESCi16(DesiredYaw);
+
+    // mRadian and mG
+    TxESCi16(Gyro[Roll] * 1000.0); // Rate
+    TxESCi16(Gyro[Pitch] * 1000.0);
+    TxESCi16(Gyro[Yaw] * 1000.0);
+
+    TxESCi16(Angle[Roll] * 1000.0);
+    TxESCi16(Angle[Pitch] * 1000.0);
+    TxESCi16(Angle[Yaw] * 1000.0);
+
+    TxESCi16(Acc[LR] * 1000.0);
+    TxESCi16(Acc[BF] * 1000.0);
+    TxESCi16(Acc[UD] * 1000.0);
+} // ShowAttitude
+
+void SendFlightPacket(void) {
+    static int8 b;
+
+    SendPacketHeader();
+
+    TxESCu8(UAVXFlightPacketTag);
+    TxESCu8(48 + TELEMETRY_FLAG_BYTES);
+    for ( b = 0; b < TELEMETRY_FLAG_BYTES; b++ )
+        TxESCu8(F.AllFlags[b]);
+
+    TxESCu8(State);
+
+    // dV, dA, mAH
+    TxESCi16(BatteryVolts * 10.0); // to do scaling
+    TxESCi16(BatteryCurrent * 10.0);
+    TxESCi16(BatteryChargeUsedAH * 1000.0);
+
+    TxESCi16(RCGlitches);
+    TxESCi16(DesiredThrottle);
+
+    ShowAttitude();
+
+    TxESCi8((int8)Comp[LR]);
+    TxESCi8((int8)Comp[BF]);
+    TxESCi8((int8)Comp[UD]);
+    TxESCi8((int8)Comp[Alt]);
+
+    for ( b = 0; b < 4; b++ )
+        TxESCu8((uint8)PWM[b]);
+
+    TxESCu8((uint8)PWM[CamRollC]);
+    TxESCu8((uint8)PWM[CamPitchC]);
+
+    TxESCi24(mSClock() - mS[StartTime]);
+
+    SendPacketTrailer();
+} // SendFlightPacket
+
+void SendControlPacket(void) {
+    static int8 b;
+
+    SendPacketHeader();
+
+    TxESCu8(UAVXControlPacketTag);
+    TxESCu8(35);
+
+    TxESCi16(DesiredThrottle);
+
+    ShowAttitude();
+
+    for ( b = 0; b < 6; b++ ) // motor/servo channels
+        TxESCu8((uint8)PWM[b]);
+
+    TxESCi24( time(NULL) );
+
+    SendPacketTrailer();
+
+} // SendControlPacket
+
+void SendNavPacket(void) {
+    SendPacketHeader();
+
+    TxESCu8(UAVXNavPacketTag);
+    TxESCu8(59);
+
+    TxESCu8(NavState);
+    TxESCu8(FailState);
+    TxESCu8(GPSNoOfSats);
+    TxESCu8(GPSFix);
+
+    TxESCu8(CurrWP);
+
+    TxESCi16(ROC * 10.0 );                         // dm/S
+    TxESCi24(BaroRelAltitude * 10.0);
+
+    TxESCi16(GPSHeading * 1000.0);
+    TxESCi16(RangefinderAltitude * 100.0);          // cm
+
+    TxESCi16(GPSHDilute);
+    TxESCi16(Heading * 1000.0);
+    TxESCi16(WayHeading * 1000.0);
+
+    TxESCi16(GPSVel * 10.0);
+    TxESCi16(0);                                   // was GPSROC;
+
+    TxESCi24(GPSRelAltitude * 10.0);               // dm
+    TxESCi32(GPSLatitude);                         // 5 decimal minute units
+    TxESCi32(GPSLongitude);
+
+    TxESCi24(DesiredAltitude * 10.0 );
+    TxESCi32(DesiredLatitude);
+    TxESCi32(DesiredLongitude);
+
+    TxESCi24(mS[NavStateTimeout] - mSClock());    // mS
+
+    TxESCi16(AmbientTemperature.i16);             // 0.1C
+    TxESCi32( time(NULL) );                       //GPSSeconds);
+
+    TxESCu8(NavSensitivity);
+    TxESCi8(NavCorr[Roll]);
+    TxESCi8(NavCorr[Pitch]);
+    TxESCi8(NavCorr[Yaw]);
+
+    SendPacketTrailer();
+
+} // SendNavPacket
+
+void SendStatsPacket(void) {
+    SendPacketHeader();
+
+    TxESCu8(UAVXStatsPacketTag);
+    TxESCu8(44);
+
+    TxESCi16(Stats[I2CFailS]);
+    TxESCi16(Stats[GPSInvalidS]);
+    TxESCi16(Stats[AccFailS]);
+    TxESCi16(Stats[GyroFailS]);
+    TxESCi16(Stats[CompassFailS]);
+    TxESCi16(Stats[BaroFailS]);
+    TxESCi16(Stats[ESCI2CFailS]);
+
+    TxESCi16(Stats[RCFailsafesS]);
+
+    TxESCi16(Stats[GPSAltitudeS]);
+    TxESCi16(Stats[GPSVelS]);
+    TxESCi16(Stats[GPSMinSatsS]);
+    TxESCi16(Stats[GPSMaxSatsS]);
+    TxESCi16(Stats[MinHDiluteS]);
+    TxESCi16(Stats[MaxHDiluteS]);
+
+    TxESCi16(Stats[BaroRelAltitudeS]);
+    TxESCi16(0);//Stats[MinBaroROCS]);
+    TxESCi16(0);//Stats[MaxBaroROCS]);
+
+    TxESCi16(Stats[MinTempS]);
+    TxESCi16(Stats[MaxTempS]);
+
+    TxESCi16(Stats[BadS]);
+
+    TxESCu8(UAVXAirframe | 0x80);
+    TxESCu8(Orientation);
+    TxESCi16(Stats[BadNumS]);
+
+    SendPacketTrailer();
+
+} // SendStatsPacket
+
+void SendMinPacket(void) {
+    static int8 b;
+
+    SendPacketHeader();
+
+    TxESCu8(UAVXMinPacketTag);
+    TxESCu8(33 + TELEMETRY_FLAG_BYTES);
+    for ( b = 0; b < TELEMETRY_FLAG_BYTES; b++ )
+        TxESCu8(F.AllFlags[b]);
+
+    TxESCu8(State);
+    TxESCu8(NavState);
+    TxESCu8(FailState);
+    
+    TxESCi16(BatteryVolts * 10.0); // to do scaling
+    TxESCi16(BatteryCurrent * 10.0);
+    TxESCi16(BatteryChargeUsedAH * 1000.0);
+
+    TxESCi16(Angle[Roll] * 1000.0);
+    TxESCi16(Angle[Pitch] * 1000.0);
+
+    TxESCi24(BaroRelAltitude * 10.0);
+    TxESCi16(RangefinderAltitude * 100.0);                 // cm
+
+    TxESCi16(Heading * 1000.0);
+
+    TxESCi32(GPSLatitude);                         // 5 decimal minute units
+    TxESCi32(GPSLongitude);
+
+    TxESCu8(UAVXAirframe | 0x80 ); // ARM has top bit set
+    TxESCu8(Orientation);
+
+    TxESCi24(mSClock() - mS[StartTime]);
+
+    SendPacketTrailer();
+
+} // SendMinPacket
+
+void SendParamPacket(uint8 p) {
+
+    static uint8 b;
+
+    SendPacketHeader();
+
+    TxESCu8(UAVXParamsPacketTag);
+    TxESCu8(MAX_PARAMETERS+1);
+    TxESCu8(p);
+    for (b = 0; b < (uint8)MAX_PARAMETERS; b++ )
+        TxESCi8(PX[MAX_PARAMETERS*2 + b]);
+
+    SendPacketTrailer();
+
+} // SendParamPacket
+
+void SendCycle(void) { 
+
+    switch ( UAVXCurrPacketTag ) {
+        case UAVXFlightPacketTag:
+            SendFlightPacket();
+
+            UAVXCurrPacketTag = UAVXNavPacketTag;
+            break;
+
+        case UAVXNavPacketTag:
+            if ( ++StatsNavAlternate < NAV_STATS_INTERLEAVE)
+                SendNavPacket();
+            else {
+                SendStatsPacket();
+                StatsNavAlternate = 0;
+            }
+
+            UAVXCurrPacketTag = UAVXFlightPacketTag;
+            break;
+
+        default:
+            UAVXCurrPacketTag = UAVXFlightPacketTag;
+            break;
+    }
+
+} // SendCycle
+
+void SendArduStation(void) {
+
+    static int8 Count = 0;
+    /*
+    Definitions of the low rate telemetry (1Hz):
+    LAT: Latitude
+    LON: Longitude
+    SPD: Speed over ground from GPS
+    CRT: Climb Rate in M/S
+    ALT: Altitude in meters
+    ALH: The altitude is trying to hold
+    CRS: Course over ground in degrees.
+    BER: Bearing is the heading you want to go
+    WPN: Waypoint number, where WP0 is home.
+    DST: Distance from Waypoint
+    BTV: Battery Voltage.
+    RSP: Roll setpoint used to debug, (not displayed here).
+
+    Definitions of the high rate telemetry (~4Hz):
+    ASP: Airspeed, right now is the raw data.
+    TTH: Throttle in 100% the autopilot is applying.
+    RLL: Roll in degrees + is right - is left
+    PCH: Pitch in degrees
+    SST: Switch Status, used for debugging, but is disabled in the current version.
+    */
+
+    if ( ++Count == 4 ) { 
+        TxString("!!!");
+        TxString("LAT:");
+        TxVal32(GPSLatitude / 6000, 3, 0);
+        TxString(",LON:");
+        TxVal32(GPSLongitude / 6000, 3, 0);
+        TxString(",ALT:");
+        TxVal32(Altitude / 10,0,0);
+        TxString(",ALH:");
+        TxVal32(DesiredAltitude / 10, 0, 0);
+        TxString(",CRT:");
+        TxVal32(ROC / 100, 0, 0);
+        TxString(",CRS:");
+        TxVal32(Heading * RADDEG, 0, 0); // scaling to degrees?
+        TxString(",BER:");
+        TxVal32(WayHeading * RADDEG, 0, 0);
+        TxString(",SPD:");
+        TxVal32(GPSVel, 0, 0);
+        TxString(",WPN:");
+        TxVal32(CurrWP,0,0);
+        TxString(",DST:");
+        TxVal32(0, 0, 0); // distance to WP
+        TxString(",BTV:");
+        TxVal32((BatteryVoltsADC * 61)/205, 1, 0);
+        TxString(",RSP:");
+        TxVal32(DesiredRoll, 0, 0);
+
+        Count = 0;
+    } else {
+        TxString("+++");
+        TxString("ASP:");
+        TxVal32(GPSVel / 100, 0, 0);
+        TxString(",RLL:");
+        TxVal32(Angle[Roll] / 35, 0, 0); // scale to degrees?
+        TxString(",PCH:");
+        TxVal32(Angle[Pitch] / 35, 0, 0);
+        TxString(",THH:");
+        TxVal32( ((int24)DesiredThrottle * 100L) / RC_MAXIMUM, 0, 0);
+    }
+
+    TxString(",***\r\n");
+
+} // SendArduStation
+
+void SendCustom(void)
+{ // user defined telemetry human readable OK for small amounts of data < 1mS
+
+    EchoToLogFile = true;
+
+    // insert values here using TxVal32(n, dp, separator)
+    // dp is the scaling to decimal places, separator
+    // separator may be a single 'char', HT for tab, or 0 (no space)
+    // ->
+
+    TxVal32(mSClock(), 3, HT);
+
+    if ( F.HoldingAlt ) // are we holding
+        TxChar('H');
+    else
+        TxChar('N');
+    TxChar(HT);
+
+    if (F.UsingRangefinderAlt ) // are we using the rangefinder
+        TxChar('R');
+    else
+        TxChar('B');
+    TxChar(HT);
+
+    TxVal32(SRS32(Comp[Alt],1), 1, HT);        // ~% throttle compensation
+
+    TxVal32(GPSRelAltitude, 1, HT);
+    TxVal32(BaroRelAltitude, 1, HT);
+    TxVal32(RangefinderAltitude, 2, HT);
+
+    TxVal32(BaroPressure, 0, HT);            // eff. sensor reading
+    TxVal32(BaroTemperature, 0, HT);         // eff. sensor reading redundant for MPX4115
+    TxVal32(CompBaroPressure, 0, HT);          // moving sum of last 8 readings
+
+    // <-
+
+    TxChar(CR);
+    TxChar(LF);
+
+    EchoToLogFile = false;
+} // SendCustom
+
+void SensorTrace(void) {
+#ifdef TESTING
+
+    if ( DesiredThrottle > 20 ) {
+        EchoToLogFile = false; // direct to USART
+
+        TxValH16(((int24)Heading * 180)/MILLIPI);
+        TxChar(';');
+
+        TxValH16(BaroRelAltitude);
+        TxChar(';');
+        TxValH16(RangefinderAltitude);
+        TxChar(';');
+        TxValH16(0);
+        TxChar(';');
+
+        TxValH16(DesiredThrottle);
+        TxChar(';');
+        TxValH16(DesiredRoll);
+        TxChar(';');
+        TxValH16(DesiredPitch);
+        TxChar(';');
+        TxValH16(DesiredYaw);
+        TxChar(';');
+
+        TxValH16(Rate[Roll]);
+        TxChar(';');
+        TxValH16(Rate[Pitch]);
+        TxChar(';');
+        TxValH16(Rate[Yaw]);
+        TxChar(';');
+
+        TxValH16(Angle[Roll]);
+        TxChar(';');
+        TxValH16(Angle[Pitch]);
+        TxChar(';');
+        TxValH16(Angle[Yaw]);
+        TxChar(';');
+
+        TxValH16(Acc[LR]);
+        TxChar(';');
+        TxValH16(Acc[FB]);
+        TxChar(';');
+        TxValH16(Acc[DU]);
+        TxChar(';');
+
+        TxValH16(Comp[LR]);
+        TxChar(';');
+        TxValH16(Comp[FB]);
+        TxChar(';');
+        TxValH16(Comp[DU]);
+        TxChar(';');
+        TxValH16(Comp[Alt]);
+        TxChar(';');
+        TxNextLine();
+    }
+#endif // TESTING
+} // SensorTrace