A public repository for BMS algorithms for a NUCLEO BOARD.
Hi Everyone!
Welcome to this repository from Howey's Research Group at the University of Oxford.
The code published here incorporates BMS algorithms for diagnosis functions such as SOC, SOH and Power estimation on a Kokam 53Ah Li-ion battery. This code was designed to work with a NUCLEO F401-RE board and to be tested with a dSPACE HIL Simulator. A short guide on how the set up works is available at https://bitbucket.org/ff95/bms .
The code is made up of three key parts. "Headers" and "Source" folders and the "main.cpp" file. As the code was generated by converting a Simulink model ( available on the BitBucket page), the headers and source code files generated by the conversion are in the corresponding "Headers" and "Source" folders. The "main.cpp" file sets up the ADC, the USB data transmission and starts the estimation (once a character "y" has been received by the computer it is connected to). It also transmits the data from the estimation via USB. Explanation on how to set up the communication with the board is available at BitBucket webpage, from where a MATLAB file can be downloaded which allows real time communication.
For any questions you can contact the author at federicomariaferrari@gmail.com .
The Simulink and Matlab files, together with a short guide, are all available at: https://bitbucket.org/ff95/bms.
Thanks for trying this out!
Federico
main.cpp@23:447ef1071e49, 2017-07-13 (annotated)
- Committer:
- fmferrari
- Date:
- Thu Jul 13 10:50:13 2017 +0000
- Revision:
- 23:447ef1071e49
- Parent:
- 22:caf41c9bb9d0
A working version of the code needed to run an mbed micro controller.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
fmferrari | 14:4b5df635f248 | 1 | |
fmferrari | 0:1e567a5a99c3 | 2 | |
fmferrari | 0:1e567a5a99c3 | 3 | #include "mbed.h" |
fmferrari | 6:cb71171a7108 | 4 | #include "EKF.h" |
fmferrari | 15:b39f568faa27 | 5 | #include <vector> |
fmferrari | 0:1e567a5a99c3 | 6 | |
fmferrari | 12:bf3e3b87224e | 7 | |
fmferrari | 0:1e567a5a99c3 | 8 | |
fmferrari | 13:831eab218c33 | 9 | Timer OutputTimer; |
fmferrari | 13:831eab218c33 | 10 | Timer MacroTime; |
fmferrari | 14:4b5df635f248 | 11 | Ticker TimerforIteration; |
fmferrari | 15:b39f568faa27 | 12 | Ticker TimerforSampling; |
fmferrari | 14:4b5df635f248 | 13 | |
fmferrari | 12:bf3e3b87224e | 14 | Serial TRANSMIT(SERIAL_TX, SERIAL_RX); |
fmferrari | 13:831eab218c33 | 15 | |
fmferrari | 12:bf3e3b87224e | 16 | AnalogIn VoltageSensor(PA_0); |
fmferrari | 12:bf3e3b87224e | 17 | AnalogIn CurrentSensor(PA_1); |
fmferrari | 14:4b5df635f248 | 18 | AnalogIn TemperatureSensor(PA_4); |
fmferrari | 12:bf3e3b87224e | 19 | DigitalOut DATATRANSMISSION(LED1); |
fmferrari | 14:4b5df635f248 | 20 | InterruptIn OnOrOff(USER_BUTTON); |
fmferrari | 14:4b5df635f248 | 21 | |
fmferrari | 12:bf3e3b87224e | 22 | float VoltageMeas = 0; |
fmferrari | 12:bf3e3b87224e | 23 | float CurrentMeas = 0; |
fmferrari | 14:4b5df635f248 | 24 | float TemperatureMeas=0; |
fmferrari | 14:4b5df635f248 | 25 | |
fmferrari | 12:bf3e3b87224e | 26 | float Result_V = 0; |
fmferrari | 12:bf3e3b87224e | 27 | float Result_I = 0; |
fmferrari | 14:4b5df635f248 | 28 | float Result_T = 0; |
fmferrari | 14:4b5df635f248 | 29 | |
fmferrari | 12:bf3e3b87224e | 30 | float MinStepRes = 0; |
fmferrari | 12:bf3e3b87224e | 31 | float SocOutput = 0.0f; |
fmferrari | 12:bf3e3b87224e | 32 | float R0Output=0.0f; |
fmferrari | 13:831eab218c33 | 33 | float Q0Output=0.0f; |
fmferrari | 14:4b5df635f248 | 34 | float mVoltRange = 3300; // This is the supplay voltage of ADC (or MCU) |
fmferrari | 14:4b5df635f248 | 35 | float ADCres = 65536; // This is the ADC resolution oxFFFF |
fmferrari | 14:4b5df635f248 | 36 | int Count=0; |
fmferrari | 14:4b5df635f248 | 37 | |
fmferrari | 21:534cd02b6bc4 | 38 | float MaxCurrentAmp=250; |
fmferrari | 14:4b5df635f248 | 39 | float MaxTemperature=80; |
fmferrari | 14:4b5df635f248 | 40 | float MaxdSpaceOut=6; |
fmferrari | 15:b39f568faa27 | 41 | float CircuitGain=0.545; |
fmferrari | 14:4b5df635f248 | 42 | |
fmferrari | 14:4b5df635f248 | 43 | bool ButtonPressed=0.0f; |
fmferrari | 14:4b5df635f248 | 44 | bool StateEKF=1.0f; |
fmferrari | 17:9b1f3bf6da0f | 45 | char RunMed=0; |
fmferrari | 20:efb192150248 | 46 | const int nIterations=200; |
fmferrari | 15:b39f568faa27 | 47 | |
fmferrari | 15:b39f568faa27 | 48 | float StoreVoltage[nIterations]; |
fmferrari | 15:b39f568faa27 | 49 | float StoreCurrent[nIterations]; |
fmferrari | 15:b39f568faa27 | 50 | float StoreTemperature[nIterations]; |
fmferrari | 15:b39f568faa27 | 51 | |
fmferrari | 15:b39f568faa27 | 52 | float MeanVoltage; |
fmferrari | 15:b39f568faa27 | 53 | float MeanCurrent; |
fmferrari | 15:b39f568faa27 | 54 | float MeanTemperature; |
fmferrari | 15:b39f568faa27 | 55 | |
fmferrari | 21:534cd02b6bc4 | 56 | double StoreTime=0; |
fmferrari | 21:534cd02b6bc4 | 57 | double StorePrevTime=0; |
fmferrari | 21:534cd02b6bc4 | 58 | float TimerLimit=600; |
fmferrari | 21:534cd02b6bc4 | 59 | double TimerTimeStep=0; |
fmferrari | 21:534cd02b6bc4 | 60 | double MacroPrevTime=0; |
fmferrari | 15:b39f568faa27 | 61 | |
fmferrari | 21:534cd02b6bc4 | 62 | //Get Mean Function |
fmferrari | 21:534cd02b6bc4 | 63 | float GetMean(float Array[]) |
fmferrari | 21:534cd02b6bc4 | 64 | { |
fmferrari | 21:534cd02b6bc4 | 65 | float Sum=0; |
fmferrari | 21:534cd02b6bc4 | 66 | float mean=0; |
fmferrari | 21:534cd02b6bc4 | 67 | |
fmferrari | 21:534cd02b6bc4 | 68 | for ( int iter=0; iter<nIterations; iter++ ) { |
fmferrari | 21:534cd02b6bc4 | 69 | Sum=Sum+Array[iter]; |
fmferrari | 21:534cd02b6bc4 | 70 | } |
fmferrari | 21:534cd02b6bc4 | 71 | |
fmferrari | 21:534cd02b6bc4 | 72 | mean=Sum/nIterations; |
fmferrari | 21:534cd02b6bc4 | 73 | |
fmferrari | 21:534cd02b6bc4 | 74 | return mean; |
fmferrari | 21:534cd02b6bc4 | 75 | } |
fmferrari | 15:b39f568faa27 | 76 | |
fmferrari | 15:b39f568faa27 | 77 | |
fmferrari | 17:9b1f3bf6da0f | 78 | |
fmferrari | 21:534cd02b6bc4 | 79 | //SAMPLING function |
fmferrari | 15:b39f568faa27 | 80 | void SAMPLE() |
fmferrari | 15:b39f568faa27 | 81 | { |
fmferrari | 15:b39f568faa27 | 82 | for ( int iter=0; iter<nIterations; iter++ ) { |
fmferrari | 15:b39f568faa27 | 83 | |
fmferrari | 15:b39f568faa27 | 84 | // SAMPLE THE ADCs |
fmferrari | 15:b39f568faa27 | 85 | VoltageMeas = VoltageSensor.read_u16(); |
fmferrari | 15:b39f568faa27 | 86 | CurrentMeas = CurrentSensor.read_u16(); |
fmferrari | 15:b39f568faa27 | 87 | TemperatureMeas=TemperatureSensor.read_u16(); |
fmferrari | 15:b39f568faa27 | 88 | |
fmferrari | 15:b39f568faa27 | 89 | //CALCULATE THE RESOLUTION OF EACH BIT |
fmferrari | 15:b39f568faa27 | 90 | MinStepRes = (mVoltRange / ADCres); |
fmferrari | 15:b39f568faa27 | 91 | |
fmferrari | 15:b39f568faa27 | 92 | // CONVERT MEASURED VALUES TO ACTUAL SCALED VALUES |
fmferrari | 15:b39f568faa27 | 93 | Result_V = ((MinStepRes * VoltageMeas))/1000; |
fmferrari | 15:b39f568faa27 | 94 | Result_I = ((MinStepRes * CurrentMeas))/1000; |
fmferrari | 15:b39f568faa27 | 95 | Result_T = ((MinStepRes * TemperatureMeas))/1000; |
fmferrari | 15:b39f568faa27 | 96 | |
fmferrari | 15:b39f568faa27 | 97 | |
fmferrari | 15:b39f568faa27 | 98 | // INPUT THE DATA TO THE EKF_STEP |
fmferrari | 15:b39f568faa27 | 99 | |
fmferrari | 23:447ef1071e49 | 100 | |
fmferrari | 22:caf41c9bb9d0 | 101 | StoreVoltage[iter]=Result_V*1.8272; |
fmferrari | 22:caf41c9bb9d0 | 102 | StoreCurrent[iter]=(Result_I*1.8225-MaxdSpaceOut/2)*(2*MaxCurrentAmp/MaxdSpaceOut); |
fmferrari | 22:caf41c9bb9d0 | 103 | StoreTemperature[iter]=Result_T*1.8245*(MaxTemperature/MaxdSpaceOut); |
fmferrari | 15:b39f568faa27 | 104 | } |
fmferrari | 21:534cd02b6bc4 | 105 | |
fmferrari | 23:447ef1071e49 | 106 | |
fmferrari | 22:caf41c9bb9d0 | 107 | |
fmferrari | 22:caf41c9bb9d0 | 108 | MeanVoltage=GetMean(StoreVoltage)/1.0005; |
fmferrari | 22:caf41c9bb9d0 | 109 | MeanCurrent=GetMean(StoreCurrent)/1.003; |
fmferrari | 22:caf41c9bb9d0 | 110 | MeanTemperature=GetMean(StoreTemperature)/1.0008; |
fmferrari | 22:caf41c9bb9d0 | 111 | |
fmferrari | 15:b39f568faa27 | 112 | } |
fmferrari | 15:b39f568faa27 | 113 | |
fmferrari | 15:b39f568faa27 | 114 | |
fmferrari | 15:b39f568faa27 | 115 | |
fmferrari | 12:bf3e3b87224e | 116 | |
fmferrari | 14:4b5df635f248 | 117 | //USE THE FUNCTION WITH A TIMER TO STEP AT KNOWN TIME LENGTHS |
fmferrari | 14:4b5df635f248 | 118 | void ITERATE() |
fmferrari | 14:4b5df635f248 | 119 | { |
fmferrari | 21:534cd02b6bc4 | 120 | |
fmferrari | 21:534cd02b6bc4 | 121 | |
fmferrari | 21:534cd02b6bc4 | 122 | if (MacroTime.read()>TimerLimit) { |
fmferrari | 21:534cd02b6bc4 | 123 | MacroTime.reset(); |
fmferrari | 21:534cd02b6bc4 | 124 | TimerTimeStep=EKF_U.TimeStep; |
fmferrari | 21:534cd02b6bc4 | 125 | MacroPrevTime=0; |
fmferrari | 21:534cd02b6bc4 | 126 | } else { |
fmferrari | 21:534cd02b6bc4 | 127 | |
fmferrari | 21:534cd02b6bc4 | 128 | TimerTimeStep=MacroTime.read()-MacroPrevTime; |
fmferrari | 21:534cd02b6bc4 | 129 | MacroPrevTime=MacroTime.read(); |
fmferrari | 21:534cd02b6bc4 | 130 | } |
fmferrari | 21:534cd02b6bc4 | 131 | |
fmferrari | 21:534cd02b6bc4 | 132 | //THIS IS THE OVERALL CLOCK |
fmferrari | 21:534cd02b6bc4 | 133 | StoreTime=StoreTime+TimerTimeStep; |
fmferrari | 21:534cd02b6bc4 | 134 | |
fmferrari | 21:534cd02b6bc4 | 135 | |
fmferrari | 15:b39f568faa27 | 136 | //TimerforSampling.attach(&SAMPLE, 0.001); |
fmferrari | 15:b39f568faa27 | 137 | SAMPLE(); |
fmferrari | 15:b39f568faa27 | 138 | EKF_U.Voltage=MeanVoltage; |
fmferrari | 15:b39f568faa27 | 139 | EKF_U.Current=MeanCurrent; |
fmferrari | 15:b39f568faa27 | 140 | EKF_U.TemperatureIn=MeanTemperature; |
fmferrari | 14:4b5df635f248 | 141 | |
fmferrari | 21:534cd02b6bc4 | 142 | EKF_U.TimeStep=StoreTime-EKF_U.MacroTime; |
fmferrari | 21:534cd02b6bc4 | 143 | EKF_U.MacroTime=StoreTime; |
fmferrari | 14:4b5df635f248 | 144 | |
fmferrari | 14:4b5df635f248 | 145 | // STEP THE EKF MODEL |
fmferrari | 14:4b5df635f248 | 146 | EKF_step(); |
fmferrari | 14:4b5df635f248 | 147 | |
fmferrari | 14:4b5df635f248 | 148 | //FLASH THE LIGHT |
fmferrari | 14:4b5df635f248 | 149 | DATATRANSMISSION=1; |
fmferrari | 14:4b5df635f248 | 150 | |
fmferrari | 14:4b5df635f248 | 151 | //TRANSMIT DATA |
fmferrari | 14:4b5df635f248 | 152 | TRANSMIT.printf("%f \n", EKF_Y.SOC); |
fmferrari | 14:4b5df635f248 | 153 | TRANSMIT.printf("%f \n", EKF_Y.Q0); |
fmferrari | 21:534cd02b6bc4 | 154 | TRANSMIT.printf("%f \n", EKF_Y.R0); |
fmferrari | 21:534cd02b6bc4 | 155 | |
fmferrari | 18:4a769322eb39 | 156 | TRANSMIT.printf("%f \n", EKF_Y.PowerDisch); |
fmferrari | 18:4a769322eb39 | 157 | TRANSMIT.printf("%f \n", EKF_Y.PowerCh); |
fmferrari | 21:534cd02b6bc4 | 158 | |
fmferrari | 14:4b5df635f248 | 159 | TRANSMIT.printf(" %f \n",EKF_U.Voltage); |
fmferrari | 14:4b5df635f248 | 160 | TRANSMIT.printf("%f \n", EKF_U.Current); |
fmferrari | 14:4b5df635f248 | 161 | TRANSMIT.printf("%f \n", EKF_U.TemperatureIn); |
fmferrari | 14:4b5df635f248 | 162 | |
fmferrari | 21:534cd02b6bc4 | 163 | TRANSMIT.printf(" %f \n", EKF_U.MacroTime); |
fmferrari | 21:534cd02b6bc4 | 164 | TRANSMIT.printf(" %f \n", EKF_U.TimeStep); |
fmferrari | 21:534cd02b6bc4 | 165 | |
fmferrari | 21:534cd02b6bc4 | 166 | TRANSMIT.printf("%f \n", EKF_Y.DegradationIndex); |
fmferrari | 14:4b5df635f248 | 167 | } |
fmferrari | 12:bf3e3b87224e | 168 | |
fmferrari | 12:bf3e3b87224e | 169 | |
fmferrari | 17:9b1f3bf6da0f | 170 | //MAIN SCRIPT |
fmferrari | 13:831eab218c33 | 171 | int main() |
fmferrari | 13:831eab218c33 | 172 | { |
fmferrari | 0:1e567a5a99c3 | 173 | while(1) { |
fmferrari | 15:b39f568faa27 | 174 | |
fmferrari | 13:831eab218c33 | 175 | |
fmferrari | 21:534cd02b6bc4 | 176 | char RunMBED=TRANSMIT.getc(); |
fmferrari | 18:4a769322eb39 | 177 | |
fmferrari | 21:534cd02b6bc4 | 178 | EKF_initialize(); |
fmferrari | 21:534cd02b6bc4 | 179 | OutputTimer.reset(); |
fmferrari | 21:534cd02b6bc4 | 180 | MacroTime.reset(); |
fmferrari | 21:534cd02b6bc4 | 181 | |
fmferrari | 21:534cd02b6bc4 | 182 | while (RunMBED=='y') { |
fmferrari | 21:534cd02b6bc4 | 183 | |
fmferrari | 18:4a769322eb39 | 184 | TimerforIteration.attach(&ITERATE,0.2); |
fmferrari | 14:4b5df635f248 | 185 | //START TIMER AND LED |
fmferrari | 14:4b5df635f248 | 186 | MacroTime.start(); |
fmferrari | 14:4b5df635f248 | 187 | OutputTimer.start(); |
fmferrari | 14:4b5df635f248 | 188 | DATATRANSMISSION=0; |
fmferrari | 17:9b1f3bf6da0f | 189 | RunMBED=TRANSMIT.getc(); |
fmferrari | 21:534cd02b6bc4 | 190 | |
fmferrari | 13:831eab218c33 | 191 | } |
fmferrari | 10:c4f0c3a5223f | 192 | } |
fmferrari | 10:c4f0c3a5223f | 193 | |
fmferrari | 13:831eab218c33 | 194 | } |