succes

Dependencies:   microbit

Files at this revision

API Documentation at this revision

Comitter:
mk1
Date:
Sat Feb 11 15:55:34 2017 +0000
Commit message:
succes

Changed in this revision

BNO055.cpp Show annotated file Show diff for this revision Revisions of this file
BNO055.h Show annotated file Show diff for this revision Revisions of this file
PID.cpp Show annotated file Show diff for this revision Revisions of this file
PID.h Show annotated file Show diff for this revision Revisions of this file
kalman.cpp Show annotated file Show diff for this revision Revisions of this file
kalman.h 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
microbit.lib Show annotated file Show diff for this revision Revisions of this file
motor.cpp Show annotated file Show diff for this revision Revisions of this file
motor.h Show annotated file Show diff for this revision Revisions of this file
sample.cpp Show annotated file Show diff for this revision Revisions of this file
sample.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r c15430f1895f BNO055.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BNO055.cpp	Sat Feb 11 15:55:34 2017 +0000
@@ -0,0 +1,134 @@
+#include "BNO055.h"
+#include <vector>
+
+namespace BNO055
+{
+/*
+*  Sensor constructor. This will take care of all necessary initialization and sensor calibration
+*/    
+Sensor::Sensor(MicroBit & bit) : 
+    _bit(bit),
+    _I2CAddress(0x52),  // 0x28 : 0x29
+    _currentPage(0xFF)       
+ {
+    LogDeviceId();
+    Init();
+ }
+ 
+ /*
+ *  This is just a sanity check. Verfies chip/accelerometer/magnetometer and gyro id.
+ */
+void Sensor::LogDeviceId()
+{
+      SelectPage(0); 
+ 
+    char error[200];
+    char cmd[7] = {CHIP_ID_REGISTER, 0, 0, 0, 0, 0, 0};
+    _bit.i2c.write(_I2CAddress, cmd, 1, true);
+    _bit.i2c.read(_I2CAddress, cmd, 7, false);
+    
+    if (cmd[0] == BNO055_CHIP_ID) {
+        _bit.serial.send("BNO055 CHIP ID - OK\n");
+    } else {
+        sprintf(error, "BNO055 CHIP ID - ERROR. Got: %d\n", cmd[0]);
+        _bit.serial.send(error);
+    }
+    if (cmd[1] == BNO055_ACC_ID) {
+        _bit.serial.send("BNO055 ACCELEROMETER ID - OK\n");
+    } else {
+        sprintf(error, "BNO055 ACCELEROMETER ID - ERROR. Got: %d\n", cmd[1]);
+        _bit.serial.send(error);
+    }
+    if (cmd[2] == BNO055_MAG_ID) {
+        _bit.serial.send("BNO055 MAGNETOMETER ID - OK\n");
+    } else {
+        sprintf(error, "BNO055 ACCELERMAGNETOMETEROMETER ID - ERROR. Got: %d\n", cmd[2]);
+        _bit.serial.send(error);
+    }
+    if (cmd[3] == BNO055_GYRO_ID) {
+      _bit.serial.send("BNO055 GYRO ID - OK\n");
+    } else {
+        sprintf(error, "BNO055 GYRO ID - ERROR. Got: %d\n", cmd[3]);
+        _bit.serial.send(error);
+    }
+}
+
+uint8_t Sensor::CalibrationStatus(void)
+{
+    SelectPage(0);
+    char cmd[1] = {CALIBRATION_STATUS};
+    _bit.i2c.write(_I2CAddress, cmd, 1, true);
+    _bit.i2c.read(_I2CAddress, cmd, 1, false);
+    return cmd[0];
+}
+
+void Sensor::Calibrate()
+{
+    _bit.display.scroll("CALIBRATE");
+    while  (true) {
+        uint8_t status = (CalibrationStatus() & 0b11000000) >> 6;
+        _bit.display.scroll(status);
+        if (3 == status)
+            break;
+        wait(0.1);
+    }
+    
+    _bit.display.scroll("OK");
+    
+    for (int i=5; i>= 0; i--) {
+        _bit.display.printChar(i+48);
+        wait(0.5);
+    }
+  
+    
+}
+
+
+void Sensor::SelectNDOFFusion()
+{
+   SelectPage(0); 
+    char cmd[2] = { OPR_MODE_REGISTER, NDOF_FUSION_MODE };
+    _bit.i2c.write(_I2CAddress, cmd, 2); 
+}
+   
+void Sensor::SelectUnits()
+{
+     SelectPage(0);
+     char cmd[2] = {UNIT_SELECTION_REGISTER, UNIT_ORI_WIN + UNIT_ACC_MSS + UNIT_GYR_DPS + UNIT_EULER_DEG + UNIT_TEMP_C};
+    _bit.i2c.write(_I2CAddress, cmd, 2, false);
+}
+
+void Sensor::Init()
+{
+    SelectUnits();
+    SelectNDOFFusion();
+}
+
+void Sensor::SelectPage(uint8_t page)
+{
+    if (page != _currentPage)
+    {
+        char cmd[2] = {PAGE_ID_REGISTER, page};
+        _bit.i2c.write(_I2CAddress, cmd, 2, false);
+        _currentPage = page; // Happy path ;)
+    }
+}
+
+void Sensor::ReadEulerAngles(double & heading, double & roll, double & pitch)
+{
+    char cmd[6] = {EULER_H_REGISTER_LSB, 0, 0, 0, 0, 0};
+    int16_t _heading;
+    int16_t _roll;
+    int16_t _pitch;
+    SelectPage(0);
+    _bit.i2c.write(_I2CAddress, cmd, 1, true);
+    _bit.i2c.read(_I2CAddress, cmd, 6, false);
+    _heading = cmd[1] << 8 | cmd[0];
+    _pitch = cmd[3] << 8 | cmd[2];
+    _roll = cmd[5] << 8 | cmd[4];
+    heading = (double)_heading / 16;
+    roll = (double)_roll / 16;
+    pitch = (double)_pitch / 16;
+}
+
+}
diff -r 000000000000 -r c15430f1895f BNO055.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BNO055.h	Sat Feb 11 15:55:34 2017 +0000
@@ -0,0 +1,64 @@
+#ifndef _BNO055_h_
+#define _BNO055_h_
+
+#include "MicroBit.h"
+
+// Registers
+#define CHIP_ID_REGISTER          0x00
+#define PAGE_ID_REGISTER          0x07
+#define OPR_MODE_REGISTER         0x3d
+#define UNIT_SELECTION_REGISTER   0x3b
+#define EULER_H_REGISTER_LSB      0x1a
+#define EULER_H_REGISTER_MSB      0x1b
+#define CALIBRATION_STATUS        0x35
+
+
+// IDs
+#define BNO055_CHIP_ID        0xa0    
+#define BNO055_ACC_ID         0xfb    
+#define BNO055_MAG_ID         0x32    
+#define BNO055_GYRO_ID         0x0f    
+
+// Units
+#define UNIT_ACC_MSS            0x00 
+#define UNIT_GYR_DPS            0x00 
+#define UNIT_EULER_DEG          0x00 
+#define UNIT_TEMP_C             0x00 
+#define UNIT_ORI_WIN            0x00 
+
+
+#define NDOF_FUSION_MODE 0x0C
+#define IMU_FUSION_MODE 0x08
+
+
+namespace BNO055
+{
+
+
+class Sensor
+{
+    public:
+        Sensor(MicroBit & bit);
+        void Calibrate();
+
+        void ReadEulerAngles(double & heading, double & roll, double & pitch);
+ 
+    private:
+        MicroBit & _bit;
+        char _buffer[12];
+        uint8_t _I2CAddress;
+        
+        void LogDeviceId();
+        void SelectPage(uint8_t page);
+        void SelectNDOFFusion();
+        void SelectUnits();
+        void Init();
+        void CheckID();
+        uint8_t CalibrationStatus(void);
+        
+        uint8_t _currentPage;
+};
+
+}
+    
+#endif
\ No newline at end of file
diff -r 000000000000 -r c15430f1895f PID.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PID.cpp	Sat Feb 11 15:55:34 2017 +0000
@@ -0,0 +1,38 @@
+// Nicked this code from https://nicisdigital.wordpress.com/2011/06/27/proportional-integral-derivative-pid-controller/
+
+#include "PID.h"
+
+void pid_zeroize(PID* pid) {
+    // set prev and integrated error to zero
+    pid->prev_error = 0;
+    pid->int_error = 0;
+}
+ 
+void pid_update(PID* pid, double curr_error, double dt) 
+{
+    double diff;
+    double p_term;
+    double i_term;
+    double d_term;
+ 
+    // integration with windup guarding
+    pid->int_error += (curr_error * dt);
+    if (pid->int_error < -(pid->windup_guard))
+        pid->int_error = -(pid->windup_guard);
+    else if (pid->int_error > pid->windup_guard)
+        pid->int_error = pid->windup_guard;
+ 
+    // differentiation
+    diff = ((curr_error - pid->prev_error) / dt);
+ 
+    // scaling
+    p_term = (pid->proportional_gain * curr_error);
+    i_term = (pid->integral_gain     * pid->int_error);
+    d_term = (pid->derivative_gain   * diff);
+ 
+    // summation of terms
+    pid->control = p_term + i_term + d_term;
+ 
+    // save current error as previous error for next iteration
+    pid->prev_error = curr_error;
+}
\ No newline at end of file
diff -r 000000000000 -r c15430f1895f PID.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PID.h	Sat Feb 11 15:55:34 2017 +0000
@@ -0,0 +1,19 @@
+#ifndef _PID_H
+#define _PID_H
+
+// Shamelessly ripped from the interwebs
+
+typedef struct {
+    double windup_guard;
+    double proportional_gain;
+    double integral_gain;
+    double derivative_gain;
+    double prev_error;
+    double int_error;
+    double control;
+} PID;
+ 
+void pid_zeroize(PID* pid);
+void pid_update(PID* pid, double curr_error, double dt);
+    
+#endif
\ No newline at end of file
diff -r 000000000000 -r c15430f1895f kalman.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kalman.cpp	Sat Feb 11 15:55:34 2017 +0000
@@ -0,0 +1,39 @@
+#include "kalman.h"
+
+// Kalman filter module
+ // Shamelessly ripped from http://forum.arduino.cc/index.php/topic,8652.0.html
+
+ float Q_angle  =  0.001;
+ float Q_gyro   =  0.003;
+ float R_angle  =  0.03; 
+
+ float x_angle = 0;
+ float x_bias = 0;
+ float P_00 = 0, P_01 = 0, P_10 = 0, P_11 = 0;      
+ float y, S;
+ float K_0, K_1;
+
+
+ float kalmanCalculate(float newAngle, float newRate, float  dt) 
+ {
+  // dt = float(looptime)/1000;                                  
+   x_angle += dt * (newRate - x_bias);
+   P_00 +=  - dt * (P_10 + P_01) + Q_angle * dt;
+   P_01 +=  - dt * P_11;
+   P_10 +=  - dt * P_11;
+   P_11 +=  + Q_gyro * dt;
+   
+   y = newAngle - x_angle;
+   S = P_00 + R_angle;
+   K_0 = P_00 / S;
+   K_1 = P_10 / S;
+   
+   x_angle +=  K_0 * y;
+   x_bias  +=  K_1 * y;
+   P_00 -= K_0 * P_00;
+   P_01 -= K_0 * P_01;
+   P_10 -= K_1 * P_00;
+   P_11 -= K_1 * P_01;
+   
+   return x_angle;
+ }
diff -r 000000000000 -r c15430f1895f kalman.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kalman.h	Sat Feb 11 15:55:34 2017 +0000
@@ -0,0 +1,6 @@
+#ifndef _KALMAN_H_
+#define _KALMAN_H_
+
+float kalmanCalculate(float newAngle, float newRate, float  dt);
+ 
+#endif
\ No newline at end of file
diff -r 000000000000 -r c15430f1895f main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Sat Feb 11 15:55:34 2017 +0000
@@ -0,0 +1,72 @@
+#include "MicroBit.h"
+#include "sample.h"
+#include "motor.h"
+#include "PID.h"
+#include "kalman.h"
+#include "mbed.h"
+#include "BNO055.h"
+
+MicroBit uBit;
+
+Ticker stepInterrupt;
+
+int main()
+{
+    
+    BNO055::Sensor sensor(uBit);
+    
+    sensor.Calibrate();
+ 
+   // Initialize PID controller
+    PID pid;
+    pid_zeroize(&pid);
+    pid.windup_guard = 0; 
+    pid.proportional_gain = 95;
+    pid.integral_gain = 0.75;
+    pid.derivative_gain = 0.5;
+  
+   // Initialize motor and set up step interrupt
+    Motor motor(uBit);
+    stepInterrupt.attach(&motor, &Motor::Step, STEP_PERIOD);  
+
+    char logMessage[200];
+    float error = 0;
+    float dt;
+    float loopTime = 0.003; 
+    double heading = 0;
+    double roll = 0;
+    double pitch = 0;
+    while(true)
+    {
+       Timer t;
+        t.start();
+      
+        sensor.ReadEulerAngles(heading, roll, pitch);
+        
+        error = 89-roll;
+        
+        pid_update(&pid, error, dt); 
+  
+        if (error < 0)
+            motor.SetDirection(FORWARD);
+        else
+            motor.SetDirection(REVERSE);
+     
+  
+        motor.SetSpeed(pid.control);      
+       
+        t.stop();
+        dt = t.read();
+        if (dt < loopTime)
+            wait(loopTime-dt);
+   
+        //sprintf(logMessage, "h: %f, r: %f, p: %f\n", heading, roll, pitch);
+        //uBit.serial.send(logMessage);
+ 
+    }
+        
+    release_fiber();
+}
+
+
+
diff -r 000000000000 -r c15430f1895f microbit.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/microbit.lib	Sat Feb 11 15:55:34 2017 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/teams/Lancaster-University/code/microbit/#4b89e7e3494f
diff -r 000000000000 -r c15430f1895f motor.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/motor.cpp	Sat Feb 11 15:55:34 2017 +0000
@@ -0,0 +1,56 @@
+#include "mbed.h"
+#include "motor.h"
+
+
+Motor::Motor(MicroBit & bit)
+    : _bit(bit),
+      _speed(0),
+      _targetSpeed(0)
+{
+    // 50% duty cycle will make a nice step pulse
+    SetPWMDutyCycle(900);
+}
+
+void Motor::SetSpeed(float targetSpeed)
+{
+    _targetSpeed = targetSpeed;
+}
+
+float Motor::Speed()
+{
+    return _speed;
+}
+
+void Motor::Step()
+{
+    if ((_speed - _targetSpeed) > ACCELERATION)
+        _speed -= ACCELERATION;
+    else if ((_speed - _targetSpeed) < -ACCELERATION)
+        _speed += ACCELERATION;
+    else
+        _speed = _targetSpeed;
+ 
+    if ((_speed < 0.00005) && (_speed > -0.00005))
+        _speed = 0.00005; // Prevent int overflow in SetPWMPeriod. 
+        
+    SetPWMPeriod(abs(100000/_speed));
+}
+
+void Motor::SetPWMDutyCycle(int value) const
+{
+    _bit.io.P3.setAnalogValue(value);
+    _bit.io.P4.setAnalogValue(value);
+}
+ 
+void Motor::SetPWMPeriod(int usValue) const
+{
+    _bit.io.P3.setAnalogPeriodUs(usValue); 
+    _bit.io.P4.setAnalogPeriodUs(usValue);
+}
+
+void Motor::SetDirection(STEP_DIRECTION direction) const
+{
+    _bit.io.P8.setDigitalValue(direction);
+    _bit.io.P16.setDigitalValue(direction);
+}
+  
diff -r 000000000000 -r c15430f1895f motor.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/motor.h	Sat Feb 11 15:55:34 2017 +0000
@@ -0,0 +1,37 @@
+#ifndef _MOTOR_H_
+#define _MOTOR_H_
+
+#include "MicroBit.h"
+
+// If you change step frequency, you will implicitly also change acceleration
+// If you change acceleration, you will - wait for it - change acceleration
+const float STEP_FREQUENCY = 4000; // kHz
+const float STEP_PERIOD = 1.0/STEP_FREQUENCY; 
+const float ACCELERATION = 8;
+
+typedef enum 
+{
+    FORWARD = 1,
+    REVERSE = 0
+} STEP_DIRECTION;
+
+class Motor
+{
+public:
+    Motor(MicroBit & bit);
+    void Step();
+    void SetSpeed(float targetSpeed);
+    float Speed();
+    void SetDirection(STEP_DIRECTION direction) const;
+ 
+private:
+    MicroBit & _bit;
+    void SetPWMDutyCycle(int value) const;
+    void SetPWMPeriod(int usValue) const;
+    
+    float _speed;
+    float _targetSpeed;
+};
+
+
+#endif
\ No newline at end of file
diff -r 000000000000 -r c15430f1895f sample.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sample.cpp	Sat Feb 11 15:55:34 2017 +0000
@@ -0,0 +1,18 @@
+#include "sample.h"
+#include "MicroBit.h"
+
+Sample::Sample(float gx, float ay, float az) 
+            : _gx(gx)
+            , _ay(ay)
+            , _az(az) 
+            {}
+   
+double Sample::GyroRate()
+{
+    return -_gx;
+}
+double Sample::AccelerometerAngle()
+{
+    return (atan2(_ay, _az)+pi)*360/pi; // Noise-O-rama
+}
+
diff -r 000000000000 -r c15430f1895f sample.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sample.h	Sat Feb 11 15:55:34 2017 +0000
@@ -0,0 +1,18 @@
+#ifndef _SAMPLE_H
+#define _SAMPLE_H
+
+const float pi = 3.1415926;
+
+struct Sample
+{
+    public:
+        Sample(float gx = 0, float ay = 0, float az = 0);
+        double GyroRate();
+        double AccelerometerAngle();
+        
+    float _gx;
+    float _ay;
+    float _az;
+};
+
+#endif
\ No newline at end of file