Skip to content

Commit 215b996

Browse files
zhiquanyeoZhiquan Yeo
andauthored
Gyro Support (#6)
* Initial IMU work * IMU integration * Set gyro identifier upon init * Handle Gyro initialization * Properly handle Gyro messages --------- Co-authored-by: Zhiquan Yeo <[email protected]>
1 parent 08737c3 commit 215b996

File tree

8 files changed

+291
-5
lines changed

8 files changed

+291
-5
lines changed

include/imu.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#pragma once
2+
3+
#include <Wire.h>
4+
#include <Adafruit_LSM6DSOX.h>
5+
6+
#define IMU_I2C_ADDR 0x6B
7+
#define IMU_UPDATE_RATE_HZ 20
8+
9+
namespace xrp {
10+
11+
bool imuIsReady();
12+
13+
void imuSetEnabled(bool enabled);
14+
bool imuIsEnabled();
15+
16+
void imuInit(uint8_t addr, TwoWire *theWire);
17+
18+
bool imuPeriodic();
19+
20+
float gyroGetAngleX();
21+
float gyroGetRateX();
22+
23+
float gyroGetAngleY();
24+
float gyroGetRateY();
25+
26+
float gyroGetAngleZ();
27+
float gyroGetRateZ();
28+
29+
void gyroReset();
30+
31+
} // namespace xrp

include/robot.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ bool robotInitialized();
5656
uint8_t robotPeriodic();
5757

5858
// Robot control
59-
void setEnabled(bool enabled);
59+
void robotSetEnabled(bool enabled);
6060

6161
// Encoder Related
6262
void configureEncoder(int deviceId, int chA, int chB);

include/wpilibws.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,20 @@
44

55
namespace wpilibws {
66

7+
enum ws_gyro_axis_t {
8+
AXIS_X,
9+
AXIS_Y,
10+
AXIS_Z
11+
};
12+
713
bool dsWatchdogActive();
814

915
void processWSMessage(JsonDocument& jsonMsg);
1016

1117
// Message Encoders
1218
std::string makeEncoderMessage(int deviceId, int count);
1319
std::string makeDIOMessage(int deviceId, bool value);
20+
std::string makeGyroCombinedMessage(float rates[3], float angles[3]);
21+
std::string makeGyroSingleMessage(ws_gyro_axis_t axis, float rate, float angle);
1422

1523
} // namespace wpilibws

platformio.ini

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,7 @@ board = rpipicow
99
lib_deps =
1010
links2004/WebSockets@^2.4.1
1111
bblanchon/ArduinoJson
12+
Wire
13+
adafruit/Adafruit LSM6DS@^4.7.0
14+
adafruit/Adafruit BusIO@^1.14.1
15+
adafruit/Adafruit Unified Sensor@^1.1.9

src/imu.cpp

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
#include "imu.h"
2+
3+
namespace xrp {
4+
5+
unsigned long _imuUpdatePeriod = 1000 / IMU_UPDATE_RATE_HZ;
6+
Adafruit_LSM6DSOX _lsm6;
7+
bool _imuReady = false;
8+
bool _imuEnabled = false;
9+
10+
unsigned long _lastIMUUpdateTime = 0;
11+
bool _imuOnePassComplete = false;
12+
13+
float _gyroOffsetsDegPerSec[3] = {0, 0, 0};
14+
float _gyroRatesDegPerSec[3] = {0, 0, 0};
15+
float _gyroAnglesDeg[3] = {0, 0, 0};
16+
17+
float _radToDeg(float angleRad) {
18+
return angleRad * 180.0 / PI;
19+
}
20+
21+
bool imuIsReady() {
22+
return _imuReady;
23+
}
24+
25+
void imuSetEnabled(bool enabled) {
26+
_imuEnabled = enabled;
27+
Serial.printf("[IMU] %s\n", enabled ? "Enabling" : "Disabling");
28+
}
29+
30+
bool imuIsEnabled() {
31+
return _imuEnabled;
32+
}
33+
34+
void imuInit(uint8_t addr, TwoWire *theWire) {
35+
if (!_lsm6.begin_I2C(addr, theWire, 0)) {
36+
Serial.println("Failed to find LSM6DSOX");
37+
_imuReady = false;
38+
}
39+
else {
40+
_imuReady = true;
41+
Serial.println("--- IMU ---");
42+
Serial.println("LSM6DSOX detected");
43+
Serial.print("Accel Range: ");
44+
switch (_lsm6.getAccelRange()) {
45+
case LSM6DS_ACCEL_RANGE_2_G:
46+
Serial.println("+-2G");
47+
break;
48+
case LSM6DS_ACCEL_RANGE_4_G:
49+
Serial.println("+-4G");
50+
break;
51+
case LSM6DS_ACCEL_RANGE_8_G:
52+
Serial.println("+-8G");
53+
break;
54+
case LSM6DS_ACCEL_RANGE_16_G:
55+
Serial.println("+-16G");
56+
break;
57+
}
58+
59+
Serial.print("Gyro Range: ");
60+
switch(_lsm6.getGyroRange()) {
61+
case LSM6DS_GYRO_RANGE_125_DPS:
62+
Serial.println("125 DPS");
63+
break;
64+
case LSM6DS_GYRO_RANGE_250_DPS:
65+
Serial.println("250 DPS");
66+
break;
67+
case LSM6DS_GYRO_RANGE_500_DPS:
68+
Serial.println("500 DPS");
69+
break;
70+
case LSM6DS_GYRO_RANGE_1000_DPS:
71+
Serial.println("1000 DPS");
72+
break;
73+
case LSM6DS_GYRO_RANGE_2000_DPS:
74+
Serial.println("2000 DPS");
75+
break;
76+
case ISM330DHCX_GYRO_RANGE_4000_DPS:
77+
break;
78+
}
79+
}
80+
}
81+
82+
bool imuPeriodic() {
83+
if (!_imuReady) return false;
84+
if (!_imuEnabled) return false;
85+
86+
unsigned long currTime = millis();
87+
unsigned long dt = currTime - _lastIMUUpdateTime;
88+
89+
// Send the IMU data at the specified IMU_UPDATE_RATE_HZ
90+
if (dt < _imuUpdatePeriod) return false;
91+
92+
// Get IMU data
93+
sensors_event_t accel;
94+
sensors_event_t gyro;
95+
sensors_event_t temp;
96+
97+
_lsm6.getEvent(&accel, &gyro, &temp);
98+
99+
float rateX = _radToDeg(gyro.gyro.x);
100+
float rateY = _radToDeg(gyro.gyro.y);
101+
float rateZ = _radToDeg(gyro.gyro.z);
102+
_gyroRatesDegPerSec[0] = rateX - _gyroOffsetsDegPerSec[0];
103+
_gyroRatesDegPerSec[1] = rateY - _gyroOffsetsDegPerSec[1];
104+
_gyroRatesDegPerSec[2] = rateZ - _gyroOffsetsDegPerSec[2];
105+
106+
// We can't integrate with only a single value, so bail out
107+
if (!_imuOnePassComplete) {
108+
_imuOnePassComplete = true;
109+
_lastIMUUpdateTime = currTime;
110+
return false;
111+
}
112+
113+
float dtInSeconds = dt / 1000.0;
114+
115+
for (int i = 0; i < 3; i++) {
116+
_gyroAnglesDeg[i] = _gyroAnglesDeg[i] + (_gyroRatesDegPerSec[i] * dtInSeconds);
117+
}
118+
119+
_lastIMUUpdateTime = currTime;
120+
return true;
121+
}
122+
123+
float gyroGetAngleX() {
124+
return _gyroAnglesDeg[0];
125+
}
126+
127+
float gyroGetRateX() {
128+
return _gyroRatesDegPerSec[0];
129+
}
130+
131+
float gyroGetAngleY() {
132+
return _gyroAnglesDeg[1];
133+
}
134+
135+
float gyroGetRateY() {
136+
return _gyroRatesDegPerSec[1];
137+
}
138+
139+
float gyroGetAngleZ() {
140+
return _gyroAnglesDeg[2];
141+
}
142+
143+
float gyroGetRateZ() {
144+
return _gyroRatesDegPerSec[2];
145+
}
146+
147+
void gyroReset() {
148+
for (int i = 0; i < 3; i++) {
149+
_gyroRatesDegPerSec[i] = 0;
150+
_gyroAnglesDeg[i] = 0;
151+
}
152+
153+
_imuOnePassComplete = false;
154+
}
155+
156+
} // namespace xrp

src/main.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@
44
#include <WebSockets4WebServer.h>
55
#include <WebSocketsServer.h>
66
#include <WiFi.h>
7+
#include <Wire.h>
8+
79
#include <vector>
810

11+
#include "imu.h"
912
#include "robot.h"
1013
#include "wpilibws.h"
1114

@@ -94,8 +97,19 @@ void setup() {
9497

9598
Serial.begin(115200);
9699

100+
// Set up the I2C pins
101+
Wire1.setSCL(19);
102+
Wire1.setSDA(18);
103+
Wire1.begin();
104+
97105
delay(2000);
98106

107+
// Initialize IMU
108+
Serial.println("[IMU] Initializing IMU");
109+
xrp::imuInit(IMU_I2C_ADDR, &Wire1);
110+
111+
// TODO Calibrate IMU
112+
99113
// Busy-loop if there's no WiFi hardware
100114
if (WiFi.status() == WL_NO_MODULE) {
101115
Serial.println("[NET] No WiFi Module");
@@ -148,7 +162,9 @@ void loop() {
148162
// Disable the robot when we no longer have a connection
149163
int numConnectedClients = wsServer.connectedClients();
150164
if (lastCheckedNumClients > 0 && numConnectedClients == 0) {
151-
xrp::setEnabled(false);
165+
xrp::robotSetEnabled(false);
166+
xrp::imuSetEnabled(false);
167+
outboundMessages.clear();
152168
}
153169
lastCheckedNumClients = numConnectedClients;
154170

@@ -170,6 +186,14 @@ void loop() {
170186
sendMessage(wpilibws::makeDIOMessage(0, xrp::isUserButtonPressed()));
171187
}
172188

189+
// Read Gyro Data
190+
if (xrp::imuPeriodic()) {
191+
float rateZ = xrp::gyroGetRateZ();
192+
float angleZ = xrp::gyroGetAngleZ();
193+
194+
sendMessage(wpilibws::makeGyroSingleMessage(wpilibws::AXIS_Z, rateZ, angleZ));
195+
}
196+
173197
}
174198

175199
updateLoopTime(loopStartTime);

src/robot.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ bool isUserButtonPressed() {
249249
return digitalRead(XRP_BUILTIN_BUTTON) == LOW;
250250
}
251251

252-
void setEnabled(bool enabled) {
252+
void robotSetEnabled(bool enabled) {
253253
// Prevent motors from starting with arbitrary values when enabling
254254
if (!_robotEnabled && enabled) {
255255
_pwmShutoff();

0 commit comments

Comments
 (0)