Juan Salazar / robotic_fish_7

Dependencies:   mbed ESC mbed MODDMA

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers AcousticController.h Source File

AcousticController.h

00001 /*
00002  * AcousticController.h
00003  * Author: Joseph DelPreto
00004  */
00005 
00006 //#define acousticControl
00007 
00008 #ifdef acousticControl
00009 
00010 #ifndef ACOUSTICCONTROL_ACOUSTICCONTROLLER_H_
00011 #define ACOUSTICCONTROL_ACOUSTICCONTROLLER_H_
00012 
00013 #include "ToneDetector.h"
00014 #include "FishController.h"
00015 #include "mbed.h"
00016 
00017 // ===== INPUT/OUTPUT =====
00018 // NOTE: To be silent (to not use usbSerial object at all), undefine printBufferSummary, streamAcousticControlLog, streamData, and streamSignalLevel
00019 //       To stream the log info used in Fiji, just define streamAcousticControlLog - these are not human-readable streams
00020 //       To view the data as it's being received/decoded, define streamData (or streamSignalLevel for signal level) - these are human-readable streams
00021 //       To view a data summary (ex. number of buffers processed, words received, etc.) define printBufferSummary
00022 #define serialDefaultBaudUSB 921600 // IMPORTANT: must be 921600 when using streaAcousticControlLog (to be fast enough to keep up with data stream)
00023 #define printBufferSummary    // print a summary of how many buffers were processed, the last computed tone powers, etc. once the controller is stopped
00024 /* SEE ALSO: streamAcousticControlLog, defined in ToneDetector.h
00025    If defined, will update the following (see end of processTonePowers for how they're packaged):
00026 
00027  acousticControlLogToStream:
00028  [0]: goertzel powers f1
00029  [1]: goerztel powers f2
00030  [2]: signal level
00031  [3]: AGC gain
00032  [4]: fish state/events over Serial
00033         -1: erroneously missed a bit
00034         -2: erroneously added a bit
00035         -3: detected an uncorrectable error in the Hamming decoding
00036         -4: fish timeout (reset to neutral)
00037         >0: the data word that was successfully decoded and processed
00038         -10: no event
00039 
00040 UPDATE:
00041 
00042   acousticControlLogToStream[4] has been deprecated and replaced with streamCurFishStateEventAcoustic and streamCurFishStateAcoustic
00043   streamCurFishStateEventAcoustic can have the following values:
00044       1: erroneously missed a bit
00045       2: erroneously added a bit
00046       3: detected an uncorrectable error in the Hamming decoding
00047       4: fish timeout (reset to neutral)
00048       5: successfully received a word (note streamCurFishState indicates the current fish state)
00049       6: button board yaw left
00050       7: button board yaw right
00051       8: button board faster
00052       9: button board slower
00053       10: button board pitch up
00054       11: button board pitch down
00055       12: button board shutdown pi
00056       13: button board reset mbed
00057       14: button board auto mode
00058       15: button board unknown
00059 */
00060 
00061 //#define artificialPowers // will use tone powers saved in a file rather than actually sampling (expects two tab-separated columns of powers in /local/powers.wp)
00062 //#define singleDataStream // just read a single continuous stream of bits (as opposed to segmenting into words/decoding)
00063 
00064 //#define saveData   // save data such as received words to an array, then save it to a file at the end - faster than printing continuously but worry about overflow
00065 //#define streamData // stream data to the screen as it's received (controlled independently of saveData)
00066 //#define streamSignalLevel // stream current signal level to the screen
00067 
00068 // ===== EXECUTION =====
00069 #define infiniteLoopAcoustic  // if undefined, will stop after loopCount buffers are processed
00070 #define loopCount 20000       // number of buffers to process before terminating the program (if infiniteLoopAcoustic is not defined)
00071 #define fishTimeoutAcoustic   // whether to reset the fish to neutral if an acoustic word hasn't been received in a while.  Not used with singleDataStream.
00072 #define fishTimeoutAcousticWindow 5000000 // time between good words that cause a timeout (in microseconds)
00073 
00074 #define acousticControllerControlFish // whether to start fishController to control the servos and motor
00075 
00076 #define useAGC        // if undefined, will only set agc (adjustable gain control of the acoustic input board) once at startup
00077 //#define AGCLeds     // if defined, will light the mBed LEDs to indicate the chosen agc gain index (whether or not useAGC is on)
00078 #define agcUpdateWindow 10000000 // how often to update the AGC gain (in microseconds)
00079 
00080 #define dataRate 20 // data rate in bps.  Can be 20, 50, 77, or 100.  20 was used in Fiji. Above 50 may be less reliable.
00081 
00082 //#define threshold1 // older algorithm for processing Goertzel buffers (not sure if it still works)
00083 #define threshold2
00084 
00085 // ===== PINS =====
00086 #define agcPin0 p16
00087 #define agcPin1 p17
00088 #define agcPin2 p18
00089 // note lowBatteryVoltagePin is defined in FishController
00090 
00091 // ===== Sampling / Thresholding configuration =====
00092 // 20 bps (5/45 ms tone/silence)
00093 #if dataRate == 20
00094 #define detectWindow 10    // number of buffers to look at when deciding if a tone is present
00095 #define detectThresh 6     // number of 1s that must be present in a detectWindow group of buffer outputs to declare a tone present
00096 #define period 80          // the number of buffers from a rising edge to when we start looking for the next rising edge
00097 #define bitPeriod 100      // only used with saveData: how many buffers it should actually be between rising edges (only used to size the data array)
00098 #define interWordWait 300  // how many buffers of silence to expect between words
00099 #elif dataRate == 50
00100 // 50 bps (5/15 ms tone/silence)
00101 #define detectWindow 10    // number of buffers to look at when deciding if a tone is present
00102 #define detectThresh 6     // number of 1s that must be present in a detectWindow group of buffer outputs to declare a tone present
00103 #define period 20          // the number of buffers from a rising edge to when we start looking for the next rising edge
00104 #define bitPeriod 40       // only used with saveData: how many buffers it should actually be between rising edges (only used to size the data array)
00105 #define interWordWait 300  // how many buffers of silence to expect between words
00106 #elif dataRate == 77
00107 // 77 bps (5/8 ms tone/silence)
00108 #define detectWindow 10    // number of buffers to look at when deciding if a tone is present
00109 #define detectThresh 6     // number of 1s that must be present in a detectWindow group of buffer outputs to declare a tone present
00110 #define period 10          // the number of buffers from a rising edge to when we start looking for the next rising edge
00111 #define bitPeriod 26       // only used with saveData: how many buffers it should actually be between rising edges (only used to size the data array)
00112 #define interWordWait 300  // how many buffers of silence to expect between words
00113 #elif dataRate == 100
00114 // 100 bps (5/5 ms tone/silence)
00115 #define detectWindow 10    // number of buffers to look at when deciding if a tone is present
00116 #define detectThresh 6     // number of 1s that must be present in a detectWindow group of buffer outputs to declare a tone present
00117 #define period 6           // the number of buffers from a rising edge to when we start looking for the next rising edge
00118 #define bitPeriod 20       // only used with saveData: how many buffers it should actually be between rising edges (only used to size the data array)
00119 #define interWordWait 300  // how many buffers of silence to expect between words
00120 #endif
00121 
00122 // ===== Macros for extracting state from data words =====
00123 #define getSelectIndexAcoustic(d)     ((d & (1 << 0)) >> 0)
00124 #define getPitchIndexAcoustic(d)      ((d & (7 << 1)) >> 1)
00125 #define getYawIndexAcoustic(d)        ((d & (7 << 4)) >> 4)
00126 #define getThrustIndexAcoustic(d)     ((d & (3 << 7)) >> 7)
00127 #define getFrequencyIndexAcoustic(d)  ((d & (3 << 9)) >> 9)
00128 
00129 #define getCurStateWordAcoustic (uint16_t)((uint16_t)newSelectButtonIndex + ((uint16_t)newPitchIndex << 1) + ((uint16_t)newYawIndex << 4) + ((uint16_t)newThrustIndex << 7) + ((uint16_t)newFrequencyIndex << 9));
00130 
00131 class AcousticController
00132 {
00133     public:
00134         // Initialization
00135         AcousticController(Serial* usbSerialObject = NULL); // if serial object is null, one will be created
00136         void init(Serial* usbSerialObject = NULL); // if serial object is null, one will be created
00137         // Execution control
00138         void run();
00139         void stop();
00140         // Called by toneDetector when new tone powers are computed
00141         // Only public since we needed a dummy non-member function to call it from the static instance to pass a pointer to tonedetector (see comments on toneDetectorCallback)
00142         void processTonePowers(int32_t* newTonePowers, uint32_t signalLevel);
00143     private:
00144         // Control
00145         volatile uint32_t bufferCount;
00146         Timer programTimer;
00147         Serial* usbSerial;
00148 
00149         #ifndef singleDataStream
00150         void decodeAcousticWord(volatile bool* data);  // Use Hamming code to decode the data word and check for an error
00151         void processAcousticWord(uint16_t word);       // Parse the decoded word into the various fish states
00152         #endif
00153 
00154         // TODO check what actually needs to be volatile
00155 
00156         // Data detection
00157         volatile bool waitingForEnd;     // got data, now waiting until next bit transmission is expected (waiting until "period" buffers have elapsed since edge)
00158         volatile uint16_t periodIndex;   // how many buffers it's been since the last clock edge
00159         volatile uint8_t fskIndex;       // which set of 0/1 frequencies are next expected
00160 
00161         #if defined(threshold2)
00162         #define powerHistoryLength 50       // number of buffer results to consider when deciding if a tone is present.  should be half of a bit-width
00163         #define powerHistoryDetectWindow 20 // portion of powerHistory to consider as the detection zone (where a peak is expected)
00164         volatile int32_t powerHistory[powerHistoryLength][numTones];  // History of Goertzel results for the last powerHistoryLength buffers
00165         volatile int16_t powerHistoryIndex;                   // Index into powerHistory (circular buffer)
00166         volatile int16_t powerHistoryDetectIndex;             // Marks where in powerHistory to start window for detection; will always be detectWindow elements behind powerHistoryIndex in the circular buffer
00167         volatile int32_t powerHistorySumDetect[numTones];     // Sum of powers stored in powerHistory in the detect window (stand-in for mean)
00168         volatile int32_t powerHistorySumNoDetect[numTones];   // Sum of powers stored in powerHistory outside the detect window (stand-in for mean)
00169         volatile int32_t powerHistoryMaxDetect[numTones];     // Max of powers stored in powerHistory in the detect window
00170         volatile int32_t powerHistoryMaxNoDetect[numTones];   // Max of powers stored in powerHistory outside the detect window
00171         volatile bool readyToThreshold;                       // Whether powerHistory has been filled at least once
00172         volatile bool tonesPresent[detectWindow][numTones];   // Circular buffer of whether tones were detected in last detectWindow powers
00173         volatile uint8_t detectSums[numTones];                // Rolling sum over last detectWindow tonesPresent results (when > detectWindow/2, declares data bit)
00174         volatile uint8_t detectWindowIndex;
00175         #elif defined(threshold1)
00176         #define powerHistoryLength 50                       // number of results to consider when deciding if a tone is present.  should be half of a bit-width
00177         volatile uint8_t detectSums[numTones];              // Rolling sum over last detectWindow buffer results (when > detectWindow/2, declares clock/data)
00178         int32_t powerHistory[powerHistoryLength][numTones]; // History of Goertzel results for the last powerHistoryLength buffers
00179         volatile int16_t powerHistoryIndex;                 // Index into powerHistory (circular buffer)
00180         volatile int16_t powerHistoryDetectIndex;           // Marks where in powerHistory to start window for detection; will always be detectWindow elements behind powerHistoryIndex in the circular buffer
00181         int32_t powerHistorySum[numTones];                  // Sum of powers stored in powerHistory (stand-in for mean)
00182         int32_t powerHistoryMax[numTones];                  // Max of powers stored in powerHistory
00183         volatile bool readyToThreshold;                     // Whether powerHistory has been filled at least once
00184         #endif
00185 
00186         // Segmenting of data into bits/words
00187         #if defined(singleDataStream) && defined(saveData)
00188             volatile bool data[loopCount/(bitPeriod) * (numTones-1) + 50]; // Received data (each clock pulse is associated with numTones-1 bits) // TODO update for multi-hop FSK, but this is fine for one FSK group
00189             volatile uint16_t dataIndex;
00190         #else
00191             #define dataWordLength 16          // bits per word.  note that changing this also requires adjusting the decodeAcousticWord algorithm, since it currently assumes Hamming encoding
00192             volatile uint8_t dataBitIndex;     // current bit of that word
00193             volatile bool interWord;           // whether we are currently in between words (waiting out the long inter-word pause)
00194             #ifdef saveData
00195             volatile bool data[loopCount/(bitPeriod*dataWordLength)][dataWordLength]; // Each element is a word as an array of bits
00196             volatile uint16_t dataWordIndex;   // current data word
00197             #else
00198             volatile bool dataWord[dataWordLength]; // an array of bits making up the current word
00199             #endif
00200         #endif
00201         volatile uint16_t lastDataWord; // not used anymore, but still updated
00202 
00203         // Adjustable gain control (AGC)
00204         volatile uint8_t currentGainIndex;        // the current index into agcGains
00205         volatile int32_t signalLevelSum;          // the running sum of signal level readings
00206         volatile uint16_t signalLevelBufferIndex; // index into signal level buffer // note we don't have a buffer anymore, but use this to know when to reset the sum
00207 
00208         DigitalOut* gain0;
00209         DigitalOut* gain1;
00210         DigitalOut* gain2;
00211         DigitalOut* agc[3]; // facilitates loops and whatnot
00212         #ifdef AGCLeds
00213             #undef debugLEDs
00214             DigitalOut* agcLED0;
00215             DigitalOut* agcLED1;
00216             DigitalOut* agcLED2;
00217             DigitalOut* agcLEDs[3];
00218         #endif
00219 
00220         // Fish reset timeout
00221         volatile uint16_t timeSinceGoodWord; // measured in buffers
00222 
00223         // Low battery monitor
00224         DigitalIn* lowBatteryVoltageInput;
00225         void lowBatteryCallback();
00226 
00227         // Testing/debugging
00228         #ifdef saveData
00229         LocalFileSystem local("local");
00230         FILE* foutDataWords;
00231         #endif
00232         #ifdef artificialPowers
00233             #if (!defined recordStreaming || (!defined recordOutput && !defined recordSamples)) && !defined saveData
00234             LocalFileSystem local("local");
00235             #endif
00236             FILE* finPowers;
00237             int32_t nextPowers[numTones];
00238         #endif
00239         volatile uint16_t streamCurFishStateAcoustic; // the current state of the fish
00240         volatile uint16_t streamCurFishStateEventAcoustic; // events such as decoding words, errors, etc.
00241 
00242         // Fish state extracted from acoustic data word (index into lookup tables defined above)
00243         volatile uint8_t newSelectButtonIndex;
00244         volatile uint8_t newPitchIndex;
00245         volatile uint8_t newYawIndex;
00246         volatile uint8_t newThrustIndex;
00247         volatile uint8_t newFrequencyIndex;
00248 };
00249 
00250 
00251 // Create a static instance of AcousticController to be used by anyone doing detection
00252 extern AcousticController acousticController;
00253 
00254 #endif
00255 
00256 #endif // #ifdef acousticControl