SOFT261_CW
Dependencies: X_NUCLEO_IKS01A1 mbed
main.cpp
- Committer:
- jbindin
- Date:
- 2018-08-15
- Revision:
- 0:d9a14a63c3ed
File content as of revision 0:d9a14a63c3ed:
/* This programme reads an accelerometer every 1/10 of a second. The data is then stored in a ring buffer, for each sample the previous sample is subtraced away from the current sample and a moving average of the past 10 samples are taken. this moving average is then passed to a struct which is then passed to a message queue. thread1 passes a signal to thread2 so it can process the values from the struct. thread2 works out the mean of the past 10 values and outputs it serially to a console. This works out as one output per second (althouch not exact). the project was made with MBEDs online compiler */ // imports #include "mbed.h" #include "rtos.h" #include "x_nucleo_iks01a1.h" //to pass signal from threads (easier to read) #define READ 1 //to show maximum ammount of samples stored #define COUNTMAX 10 //declarations Serial pc(USBTX, USBRX); Thread* thread1; Thread* thread2; //struct to store x, y and z values from the accelerometer. typedef struct { float xVal; float yVal; float zVal; } accMessage_t; //declarations of additional functions used. float movingAverage(float newSample, float previousSample, float rBuffer[]); float average(float values[10]); //used to collect samples from the expantion boards sensors static X_NUCLEO_IKS01A1 *expBoard = X_NUCLEO_IKS01A1::Instance(D14, D15); static MotionSensor *accelerometer = expBoard->GetAccelerometer(); //array to store x,y,z values in thread1 int accVals[3]; //used to store samples float valuesX[COUNTMAX]; float valuesY[COUNTMAX]; float valuesZ[COUNTMAX]; //flag to discard the first output. the array is not populated yet so this output //is not as accurate bool arrayPopulated = false; //queue and memory pool to create structs and pass messages efficiently Queue<accMessage_t, 20> que; MemoryPool<accMessage_t, 20> memPool; /*this function is used by thread1, it samples values, passes them to the movingAverage function, uses the memory pool to store them as structs the structs are passed to a queue and sets a message to thread2 to allow it to be active*/ void producer() { //collects data as previous values to make average more accurate accelerometer->get_x_axes(accVals); float previousX = accVals[0]; float previousY = accVals[1]; float previousZ = accVals[2]; //thread loop involves a 10ms delay while(1) { Thread::wait(100); //sample data from accelerometer accelerometer->get_x_axes(accVals); float newAverageX = movingAverage((float)accVals[0], (float)previousX, valuesX); float newAverageY = movingAverage((float)accVals[1], (float)previousY, valuesY); float newAverageZ = movingAverage((float)accVals[2], (float)previousZ, valuesZ); previousX = accVals[0]; previousY = accVals[1]; previousZ = accVals[2]; //adds values to struct accMessage_t *message = memPool.alloc(); message->xVal = newAverageX; message->yVal = newAverageY; message->zVal = newAverageZ; //passes structs to queue and sets thread2s signal que.put(message); thread2->signal_set(READ); } } /* function is used by thread2. it gets structs to the queue. Every 10 stucts recieved calls the average function which returns the mean of the past 10 values. this is done for the x,y and z axes. the average is outputted although the first output is discarded to ensure the first set of data is populated. */ void consumer() { int count = 0; //stores structs data in arrays so the values can be averaged later float valuesReadX[10]; float valuesReadY[10]; float valuesReadZ[10]; while(1) { //waits for thread1 Thread::signal_wait(READ); osEvent evt = que.get(); if(evt.status == osEventMessage) { accMessage_t *message = (accMessage_t*)evt.value.p; valuesReadX[count] = message->xVal; valuesReadY[count] = message->yVal; valuesReadZ[count] = message->zVal; memPool.free(message); if(count >= 9) { if(arrayPopulated == true){ //output averages seperated by commas to ensure data can be //easily read and processed pc.printf("%.2f,\t %.2f,\t %.2f\n\r", average(valuesReadX), average(valuesReadY), average(valuesReadZ)); } count = 0; arrayPopulated = true; } } count++; } } //main function main() { //attaching thereads to their functions thread1 = new Thread(&producer); thread2 = new Thread(&consumer); while(1) { wait(50000); } } /* calculats the moving average for the past 10 values. it also is responsible for keeping the array ring buffered and subtracting the previous sample from the current. */ float movingAverage(float newSample, float previousSample, float rBuffer[]) { float ave = 0.0; // to calculate the change in acceleration newSample = newSample - previousSample; //move up every value in the array for(int i = (COUNTMAX-1); i > 0; i--) { rBuffer[i] = rBuffer[i-1]; } //add new value rBuffer[0] = newSample; //summing every value in the array for(int i = 0; i < COUNTMAX; i++) { ave = ave + rBuffer[i]; } //divide the sum by 10 to work out the mean ave = ave / (float)COUNTMAX; //return the mean value return ave; } /* used to work out the final average that is to be ouputted every second */ float average(float values[10]) { float sum = 0; float result = 0; for(int i = 0; i < 10; i++) { sum = values[i] + sum; } result = sum / 10; //returns the final mean value return result; } // please note an attempt to use a Ticker as an interupt was used to make the // samples more accurate however the command "accelerometer->get_x_axes(accVals);" // only returned 0 so two threads were used insted.