Skip to content

Commit 4da00c1

Browse files
authored
Merge pull request #52 from gotvinne/got/flight-controller/add-state-machine
Flight-controller: Add state machine
2 parents 5717261 + d71eda1 commit 4da00c1

12 files changed

Lines changed: 121 additions & 59 deletions

File tree

img/state-machine.png

369 KB
Loading

src/flight-controller/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Flight controller
22
Reimplement the javascript logic found [here](https://github.com/gomakekit/Airbit_V2/blob/master/custom.ts).
33

4+
![State machine](../../img/state-machine.png)
5+
46
### Ultrasonic sensor (external hardware HC-SR04)
57

68
The microbit PCB is equiped with a barometer which can be used to calculate the altitude of the quadcopter. However, due to the properllers impacting the sounding pressure, this measurement is not reliable. To circumvent this problem, and retieving a reliable measurement, an external ultrasonic sensor can be connected to the microbit.

src/flight-controller/WonderKit/I2C.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ MicroBitPin SCL = uBit.io.P1;
77
void InitI2C() {
88
// Redirect I2C to use P1 and P2.
99
if (uBit.i2c.redirect(uBit.io.P2, uBit.io.P1)) {
10-
SetState(State::PANIC);
10+
SetState(State::ERROR);
1111
uBit.display.print("I2C");
1212
}
1313
}

src/flight-controller/WonderKit/servoController.cpp

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,20 @@ const uint8_t SERVO_CONTROLLER_MODE2_VALUE = 5;
1717
const uint8_t SERVO_CONTROLLER_MODE3_VALUE = 170;
1818

1919
// Servo Motors
20-
const int NUM_MOTORS = 4;
2120
const uint8_t MOTOR_CW1_REG = 4;
2221
const uint8_t MOTOR_CCW1_REG = 2;
2322
const uint8_t MOTOR_CW2_REG = 3;
2423
const uint8_t MOTOR_CCW2_REG = 5;
24+
const uint8_t motorRegs[] = {MOTOR_CW1_REG, MOTOR_CW2_REG, MOTOR_CCW1_REG,
25+
MOTOR_CCW2_REG};
26+
2527
const int MAX_ACTUATION = 255;
2628
const int MIN_ACTUATION = 0;
2729

30+
static uint8_t lastPropellerActuation[NUM_MOTORS] = {0, 0, 0, 0};
31+
2832
static void failSafe() {
29-
SetState(State::PANIC);
33+
SetState(State::ERROR);
3034
uBit.display.print("NM"); // No Motor detected
3135
}
3236

@@ -36,7 +40,7 @@ static void WriteToServoController(uint8_t reg, uint8_t value) {
3640
}
3741
}
3842

39-
static void ReadServoController() {
43+
static void readServoController() {
4044
uint8_t buf[2] = {0, 0};
4145
if (uBit.i2c.read(SERVO_CONTROLLER_ADDR, buf, 2)) {
4246
failSafe();
@@ -46,7 +50,7 @@ static void ReadServoController() {
4650
}
4751
}
4852

49-
static void SetPropellerActuation(uint8_t motor, uint8_t actuation) {
53+
static void WritePropellerActuation(uint8_t motor, uint8_t actuation) {
5054
actuation = Clamp(actuation, MIN_ACTUATION, MAX_ACTUATION);
5155
if (uBit.i2c.writeRegister(SERVO_CONTROLLER_ADDR, motor, actuation)) {
5256
failSafe();
@@ -56,14 +60,15 @@ static void SetPropellerActuation(uint8_t motor, uint8_t actuation) {
5660
uBit.sleep(10);
5761
}
5862

59-
void SetAllPropellerActuation(uint8_t cw1_v, uint8_t cw2_v, uint8_t ccw1_v,
60-
uint8_t ccw2_v) {
61-
const uint8_t motorRegs[] = {MOTOR_CW1_REG, MOTOR_CW2_REG, MOTOR_CCW1_REG,
62-
MOTOR_CCW2_REG};
63-
const uint8_t motorValues[] = {cw1_v, cw2_v, ccw1_v, ccw2_v};
64-
63+
void SetPropellerActuation() {
64+
const uint8_t *motorValues = GetFlightState().propellerActuation;
6565
for (int i = 0; i < NUM_MOTORS; ++i) {
66-
SetPropellerActuation(motorRegs[i], motorValues[i]);
66+
if (motorValues[i] == lastPropellerActuation[i]) {
67+
continue; // Skip writing to the servo controller if the actuation value
68+
// hasn't changed
69+
}
70+
WritePropellerActuation(motorRegs[i], motorValues[i]);
71+
lastPropellerActuation[i] = motorValues[i];
6772
}
6873
}
6974

@@ -75,7 +80,8 @@ void InitServoController() {
7580
SERVO_CONTROLLER_MODE2_VALUE);
7681
WriteToServoController(SERVO_CONTROLLER_MODE3_REG,
7782
SERVO_CONTROLLER_MODE3_VALUE);
78-
SetAllPropellerActuation(0, 0, 0, 0);
83+
SetPropellerActuation(); // Set all motors to 0 actuation due to initial
84+
// state.
7985
// Detect WonderKit powered.
80-
ReadServoController();
86+
readServoController();
8187
}

src/flight-controller/WonderKit/servoController.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,4 @@
33

44
void InitServoController();
55

6-
void SetAllPropellerActuation(uint8_t cw1_v, uint8_t cw2_v, uint8_t ccw1_v,
7-
uint8_t ccw2_v);
6+
void SetPropellerActuation();
Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
#include "flightController.h"
2+
#include "../utilities.h"
23

34
static FlightState flightState{
45
altitude : 0,
56
state : State::CALIBRATING,
6-
motorActuation : {0, 0, 0, 0},
7+
propellerActuation : {0, 0, 0, 0}, // cw1_v, cw2_v, ccw1_v, ccw2_v
78
};
89

910
void InitFlightController() {
10-
SetState(State::CALIBRATING);
1111
InitBatteryInfo();
1212
InitI2C(); // NB! I2C must be initialized before the servo controller, as the
1313
// servo controller relies on I2C communication.
@@ -16,4 +16,34 @@ void InitFlightController() {
1616

1717
const FlightState &GetFlightState() { return flightState; }
1818

19-
void SetState(State state) { flightState.state = state; }
19+
void SetState(State state) { flightState.state = state; }
20+
21+
void UpdatePropellerActuation(MotorIndex motorIndex, uint8_t actuation) {
22+
flightState.propellerActuation[static_cast<uint8_t>(motorIndex)] = actuation;
23+
}
24+
25+
void UpdatePropellerActuationEqual(uint8_t actuation) {
26+
for (int i = 0; i < NUM_MOTORS; ++i) {
27+
UpdatePropellerActuation(static_cast<MotorIndex>(i), actuation);
28+
}
29+
SetPropellerActuation();
30+
}
31+
32+
void CheckFlightState() {
33+
if (GetFlightState().state == State::ARMED) {
34+
SetState(IsDroneArmed() ? State::ARMED : State::IDLE);
35+
return;
36+
}
37+
if (GetBatteryState().isCharging) { // If the battery is charging, set the
38+
// state to CHARGING again
39+
SetState(State::CHARGING);
40+
return;
41+
}
42+
if (GetBatteryState().batteryLevel == BatteryLevel::EMPTY ||
43+
GetBatteryState().batteryLevel == BatteryLevel::LOW) {
44+
SetState(State::LOWBATTERY);
45+
return;
46+
} else {
47+
SetState(IsDroneArmed() ? State::ARMED : State::IDLE);
48+
}
49+
}

src/flight-controller/flightController.h

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "ultrasonicSensor.h"
88
#include "view.h"
99
#include <MicroBit.h>
10+
#include <cstdint>
1011

1112
// FlightController.h is the umbrella header for the flight controller module,
1213
// which includes all the necessary headers for the flight controller
@@ -18,12 +19,28 @@
1819

1920
#define MICROBIT_UBIT_AS_STATIC_OBJECT
2021

21-
enum class State : uint8_t { CALIBRATING, CHARGING, ARMED, DISARMED, PANIC };
22+
const int NUM_MOTORS = 4;
23+
24+
enum class State : uint8_t {
25+
CALIBRATING,
26+
CHARGING,
27+
LOWBATTERY,
28+
ARMED,
29+
IDLE,
30+
ERROR,
31+
};
32+
33+
enum class MotorIndex : uint8_t {
34+
CW1, // Upper left motor
35+
CW2, // Lower right motor
36+
CCW1, // Upper right motor
37+
CCW2 // Lower left motor
38+
};
2239

2340
struct FlightState {
2441
int altitude;
2542
State state;
26-
uint8_t motorActuation[4];
43+
uint8_t propellerActuation[NUM_MOTORS];
2744
};
2845

2946
#ifdef MICROBIT_UBIT_AS_STATIC_OBJECT
@@ -39,4 +56,10 @@ void SetState(State state);
3956

4057
void InitFlightController();
4158

59+
void UpdatePropellerActuation(MotorIndex motorIndex, uint8_t actuation);
60+
61+
void UpdatePropellerActuationEqual(uint8_t actuation);
62+
63+
void CheckFlightState();
64+
4265
#endif

src/flight-controller/pid.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@ const uint8_t ARMED_THROTTLE = 5;
66
void SetThrottle() {
77
uint8_t throttle = GetDroneThrottle() * 2.55;
88
if (throttle == 0) {
9-
SetAllPropellerActuation(ARMED_THROTTLE, ARMED_THROTTLE, ARMED_THROTTLE,
10-
ARMED_THROTTLE);
9+
UpdatePropellerActuationEqual(ARMED_THROTTLE);
1110
} else {
12-
SetAllPropellerActuation(throttle, throttle, throttle, throttle);
11+
UpdatePropellerActuationEqual(throttle);
1312
}
14-
}
13+
}

src/flight-controller/view.cpp

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,47 +8,39 @@
88
// MicroBit display
99
const uint16_t LED_DISPLAY_SIZE = 5;
1010
const int LED_ON = 255;
11+
const int CHARGING_COLUMN = 4;
1112
const Image ICON_BATTERY_NEEDS_CHARGING =
1213
Image("0,255,255,255,0\n255,0,255,0,255\n255,255,255,255,255\n0,255,0,255,"
1314
"0\n0,255,0,255,0\n");
1415
const Image ICON_BATTERY_CHARGING =
1516
Image("0,0,255,0,0\n0,255,255,255,0\n0,255,255,255,0\n0,255,255,255,0\n0,"
1617
"255,255,255,0\n");
1718

18-
static void addChargingColumn(int column, Image &ledDisplay) {
19-
if (column < 0 || column >= LED_DISPLAY_SIZE) {
20-
return;
21-
}
19+
static void addChargingColumn(Image &ledDisplay) {
2220
int y = static_cast<int>(GetBatteryState().batteryLevel);
2321
for (int i = 4; i >= y; i--) {
24-
ledDisplay.setPixelValue(column, i, LED_ON);
25-
}
26-
}
27-
28-
static void viewBatteryLevel(Image &ledDisplay) {
29-
const BatteryState &batteryState = GetBatteryState();
30-
if (batteryState.isCharging) {
31-
ledDisplay = ICON_BATTERY_CHARGING;
32-
return;
22+
ledDisplay.setPixelValue(CHARGING_COLUMN, i, LED_ON);
3323
}
34-
35-
if (batteryState.batteryLevel == BatteryLevel::EMPTY ||
36-
batteryState.batteryLevel == BatteryLevel::LOW) {
37-
ledDisplay = ICON_BATTERY_NEEDS_CHARGING;
38-
return;
39-
}
40-
41-
addChargingColumn(4, ledDisplay);
4224
}
4325

44-
void UpdateView() {
26+
void UpdateViewIdle() {
4527
uBit.display.clear();
4628

4729
Image ledDisplay = Image(LED_DISPLAY_SIZE, LED_DISPLAY_SIZE);
48-
viewBatteryLevel(ledDisplay);
30+
addChargingColumn(ledDisplay);
4931
DisplayArmed(IsDroneArmed(), ledDisplay);
5032
DisplayThrottle(GetDroneThrottle(), ledDisplay);
5133
DisplayPitchRoll(GetDroneRoll(), GetDronePitch(), ledDisplay);
5234
DisplayYaw(GetDroneYaw(), ledDisplay);
5335
uBit.display.print(ledDisplay);
5436
}
37+
38+
void UpdateViewCharging() {
39+
uBit.display.clear();
40+
uBit.display.print(ICON_BATTERY_CHARGING);
41+
}
42+
43+
void UpdateViewBatteryLow() {
44+
uBit.display.clear();
45+
uBit.display.print(ICON_BATTERY_NEEDS_CHARGING);
46+
}

src/flight-controller/view.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
#pragma once
22

3-
void UpdateView();
3+
void UpdateViewIdle();
4+
void UpdateViewCharging();
5+
void UpdateViewBatteryLow();

0 commit comments

Comments
 (0)