forked from EFeru/hoverboard-firmware-hack-FOC
-
Notifications
You must be signed in to change notification settings - Fork 0
/
hoverserial.ino
178 lines (153 loc) · 6.38 KB
/
hoverserial.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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
// *******************************************************************
// Arduino Nano 5V example code
// for https://github.com/EmanuelFeru/hoverboard-firmware-hack-FOC
//
// Copyright (C) 2019-2020 Emanuel FERU <[email protected]>
//
// *******************************************************************
// INFO:
// • This sketch uses the the Serial Software interface to communicate and send commands to the hoverboard
// • The built-in (HW) Serial interface is used for debugging and visualization. In case the debugging is not needed,
// it is recommended to use the built-in Serial interface for full speed perfomace.
// • The data packaging includes a Start Frame, checksum, and re-syncronization capability for reliable communication
//
// The code starts with zero speed and moves towards +
//
// CONFIGURATION on the hoverboard side in config.h:
// • Option 1: Serial on Right Sensor cable (short wired cable) - recommended, since the USART3 pins are 5V tolerant.
// #define CONTROL_SERIAL_USART3
// #define FEEDBACK_SERIAL_USART3
// // #define DEBUG_SERIAL_USART3
// • Option 2: Serial on Left Sensor cable (long wired cable) - use only with 3.3V devices! The USART2 pins are not 5V tolerant!
// #define CONTROL_SERIAL_USART2
// #define FEEDBACK_SERIAL_USART2
// // #define DEBUG_SERIAL_USART2
// *******************************************************************
// ########################## DEFINES ##########################
#define HOVER_SERIAL_BAUD 115200 // [-] Baud rate for HoverSerial (used to communicate with the hoverboard)
#define SERIAL_BAUD 115200 // [-] Baud rate for built-in Serial (used for the Serial Monitor)
#define START_FRAME 0xABCD // [-] Start frme definition for reliable serial communication
#define TIME_SEND 100 // [ms] Sending time interval
#define SPEED_MAX_TEST 300 // [-] Maximum speed for testing
#define SPEED_STEP 20 // [-] Speed step
// #define DEBUG_RX // [-] Debug received data. Prints all bytes to serial (comment-out to disable)
#include <SoftwareSerial.h>
SoftwareSerial HoverSerial(2,3); // RX, TX
// Global variables
uint8_t idx = 0; // Index for new data pointer
uint16_t bufStartFrame; // Buffer Start Frame
byte *p; // Pointer declaration for the new received data
byte incomingByte;
byte incomingBytePrev;
typedef struct{
uint16_t start;
int16_t steer;
int16_t speed;
uint16_t checksum;
} SerialCommand;
SerialCommand Command;
typedef struct{
uint16_t start;
int16_t cmd1;
int16_t cmd2;
int16_t speedR_meas;
int16_t speedL_meas;
int16_t batVoltage;
int16_t boardTemp;
uint16_t cmdLed;
uint16_t checksum;
} SerialFeedback;
SerialFeedback Feedback;
SerialFeedback NewFeedback;
// ########################## SETUP ##########################
void setup()
{
Serial.begin(SERIAL_BAUD);
Serial.println("Hoverboard Serial v1.0");
HoverSerial.begin(HOVER_SERIAL_BAUD);
pinMode(LED_BUILTIN, OUTPUT);
}
// ########################## SEND ##########################
void Send(int16_t uSteer, int16_t uSpeed)
{
// Create command
Command.start = (uint16_t)START_FRAME;
Command.steer = (int16_t)uSteer;
Command.speed = (int16_t)uSpeed;
Command.checksum = (uint16_t)(Command.start ^ Command.steer ^ Command.speed);
// Write to Serial
HoverSerial.write((uint8_t *) &Command, sizeof(Command));
}
// ########################## RECEIVE ##########################
void Receive()
{
// Check for new data availability in the Serial buffer
if (HoverSerial.available()) {
incomingByte = HoverSerial.read(); // Read the incoming byte
bufStartFrame = ((uint16_t)(incomingByte) << 8) | incomingBytePrev; // Construct the start frame
}
else {
return;
}
// If DEBUG_RX is defined print all incoming bytes
#ifdef DEBUG_RX
Serial.print(incomingByte);
return;
#endif
// Copy received data
if (bufStartFrame == START_FRAME) { // Initialize if new data is detected
p = (byte *)&NewFeedback;
*p++ = incomingBytePrev;
*p++ = incomingByte;
idx = 2;
} else if (idx >= 2 && idx < sizeof(SerialFeedback)) { // Save the new received data
*p++ = incomingByte;
idx++;
}
// Check if we reached the end of the package
if (idx == sizeof(SerialFeedback)) {
uint16_t checksum;
checksum = (uint16_t)(NewFeedback.start ^ NewFeedback.cmd1 ^ NewFeedback.cmd2 ^ NewFeedback.speedR_meas ^ NewFeedback.speedL_meas
^ NewFeedback.batVoltage ^ NewFeedback.boardTemp ^ NewFeedback.cmdLed);
// Check validity of the new data
if (NewFeedback.start == START_FRAME && checksum == NewFeedback.checksum) {
// Copy the new data
memcpy(&Feedback, &NewFeedback, sizeof(SerialFeedback));
// Print data to built-in Serial
Serial.print("1: "); Serial.print(Feedback.cmd1);
Serial.print(" 2: "); Serial.print(Feedback.cmd2);
Serial.print(" 3: "); Serial.print(Feedback.speedR_meas);
Serial.print(" 4: "); Serial.print(Feedback.speedL_meas);
Serial.print(" 5: "); Serial.print(Feedback.batVoltage);
Serial.print(" 6: "); Serial.print(Feedback.boardTemp);
Serial.print(" 7: "); Serial.println(Feedback.cmdLed);
} else {
Serial.println("Non-valid data skipped");
}
idx = 0; // Reset the index (it prevents to enter in this if condition in the next cycle)
}
// Update previous states
incomingBytePrev = incomingByte;
}
// ########################## LOOP ##########################
unsigned long iTimeSend = 0;
int iTest = 0;
int iStep = SPEED_STEP;
void loop(void)
{
unsigned long timeNow = millis();
// Check for new received data
Receive();
// Send commands
if (iTimeSend > timeNow) return;
iTimeSend = timeNow + TIME_SEND;
Send(0, iTest);
// Calculate test command signal
iTest += iStep;
// invert step if reaching limit
if (iTest >= SPEED_MAX_TEST || iTest <= -SPEED_MAX_TEST)
iStep = -iStep;
// Blink the LED
digitalWrite(LED_BUILTIN, (timeNow%2000)<1000);
}
// ########################## END ##########################