forked from LuSeKa/HoverBot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
HoverBot.ino
116 lines (98 loc) · 3.42 KB
/
HoverBot.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include "config.h"
#include <Wire.h>
#include <Metro.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BNO055.h>
#include <utility/imumaths.h>
#include <ODriveArduino.h>
int motorsActive = 0; // motor state
bool tilt_limit_exceeded = false; // motor desired state
Adafruit_BNO055 bno = Adafruit_BNO055(); // instantiate IMU
ODriveArduino odrive(Serial2); // instantiate ODrive
Metro ledMetro = Metro(BLINK_INTERVAL);
Metro controllerMetro = Metro(CONTROLLER_INTERVAL);
Metro activationMetro = Metro(ACTIVATION_INTERVAL);
// PWM decoder variables
int pwmDutyCycle_throttle = 0;
int pwmDutyCycle_steering = 0;
int pwmDutyCycle_mode = 0;
void setup() {
pinMode(LEDPIN, OUTPUT);
Serial2.begin(BAUDRATE_ODRIVE); // ODrive uses 115200 baud
Serial.begin(BAUDRATE_PC); // Serial to PC
// IMU
if (!bno.begin())
{
Serial.print("Ooops, no BNO055 detected ... Check your wiring or I2C ADDR!");
while (1); // halt for safety
}
delay(1000);
bno.setExtCrystalUse(true);
// pwm decoder interrupts
attachInterrupt(digitalPinToInterrupt(PWM_CHANNEL_1), decodePwm_1, CHANGE);
attachInterrupt(digitalPinToInterrupt(PWM_CHANNEL_2), decodePwm_2, CHANGE);
attachInterrupt(digitalPinToInterrupt(PWM_CHANNEL_3), decodePwm_3, CHANGE);
}
void loop() {
controlTask();
activationTask();
blinkTask();
}
void controlTask() {
if (controllerMetro.check()) {
motionController();
}
}
void activationTask() {
if (activationMetro.check()) {
modeSwitch(pwmDutyCycle_mode > ENGAGE_THRESHOLD && !tilt_limit_exceeded);
}
}
void blinkTask() {
if (ledMetro.check()) {
digitalWrite(LEDPIN, !digitalRead(LEDPIN));
}
}
void motionController() {
// IMU sampling
imu::Vector<3> euler = bno.getVector(Adafruit_BNO055::VECTOR_EULER);
imu::Vector<3> gyro = bno.getVector(Adafruit_BNO055::VECTOR_GYROSCOPE);
if (abs(euler.z()) > TILT_LIMIT){
tilt_limit_exceeded = true;
}
else{
tilt_limit_exceeded = false;
}
// balance controller
float balanceControllerOutput = euler.z() * KP_BALANCE + gyro.x() * KD_BALANCE;
// planar controllera (lateral position and steering angle)
float positionControllerOutput = KP_POSITION * (pwmDutyCycle_throttle - PWM_CENTER);
float steeringControllerOutput = KP_STEERING * (pwmDutyCycle_steering - PWM_CENTER) + gyro.z() * KD_ORIENTATION;
float controllerOutput_right = balanceControllerOutput + positionControllerOutput + steeringControllerOutput;
float controllerOutput_left = balanceControllerOutput + positionControllerOutput - steeringControllerOutput;
odrive.SetCurrent(0, MOTORDIR_0 * controllerOutput_right);
odrive.SetCurrent(1, MOTORDIR_1 * controllerOutput_left);
}
void modeSwitch(int mode_desired) {
if (mode_desired == motorsActive) {
}
else {
if (mode_desired == 1) {
int requested_state = ODriveArduino::AXIS_STATE_CLOSED_LOOP_CONTROL;
Serial.println("Engaging motors");
odrive.run_state(0, requested_state, false);
odrive.run_state(1, requested_state, false);
}
else if (mode_desired == 0) {
int requested_state = ODriveArduino::AXIS_STATE_IDLE;
Serial.println("Disengaging motors");
odrive.run_state(0, requested_state, false);
odrive.run_state(1, requested_state, false);
}
else {
Serial.println("Invalid mode selection");
}
motorsActive = mode_desired;
}
return;
}