71
71
#include " hw.h"
72
72
#include " motor.h"
73
73
#include " pid.h"
74
+ #include " shell.h"
75
+
76
+ /* BNO055 Imu */
77
+ #include < Wire.h>
78
+ #include < Adafruit_Sensor.h>
79
+ #include < Adafruit_BNO055.h>
80
+ #include < utility/imumaths.h>
74
81
75
82
// TODO(jballoffet): Move this variables to a different module.
76
83
@@ -79,22 +86,12 @@ unsigned long nextPID = andino::Constants::kPidPeriod;
79
86
80
87
long lastMotorCommand = andino::Constants::kAutoStopWindow ;
81
88
82
- // A pair of varibles to help parse serial commands
83
- int arg = 0 ;
84
- int index = 0 ;
85
-
86
- // Variable to hold an input character
87
- char chr;
88
-
89
- // Variable to hold the current single-character command
90
- char cmd;
91
-
92
- // Character arrays to hold the first and second arguments
93
- char argv1[16 ];
94
- char argv2[16 ];
89
+ bool HAS_IMU = true ;
95
90
96
91
namespace andino {
97
92
93
+ Shell App::shell_;
94
+
98
95
Motor App::left_motor_ (Hw::kLeftMotorEnableGpioPin , Hw::kLeftMotorForwardGpioPin ,
99
96
Hw::kLeftMotorBackwardGpioPin );
100
97
Motor App::right_motor_ (Hw::kRightMotorEnableGpioPin , Hw::kRightMotorForwardGpioPin ,
@@ -108,6 +105,8 @@ PID App::left_pid_controller_(Constants::kPidKp, Constants::kPidKd, Constants::k
108
105
PID App::right_pid_controller_ (Constants::kPidKp , Constants::kPidKd , Constants::kPidKi ,
109
106
Constants::kPidKo , -Constants::kPwmMax , Constants::kPwmMax );
110
107
108
+ Adafruit_BNO055 App::bno_{55 , BNO055_ADDRESS_A, &Wire};
109
+
111
110
void App::setup () {
112
111
// Required by Arduino libraries to work.
113
112
init ();
@@ -123,47 +122,32 @@ void App::setup() {
123
122
124
123
left_pid_controller_.reset (left_encoder_.read ());
125
124
right_pid_controller_.reset (right_encoder_.read ());
125
+
126
+ // Initialize command shell.
127
+ shell_.init (Serial);
128
+ shell_.set_default_callback (cmd_unknown_cb);
129
+ shell_.register_command (Commands::kReadAnalogGpio , cmd_read_analog_gpio_cb);
130
+ shell_.register_command (Commands::kReadDigitalGpio , cmd_read_digital_gpio_cb);
131
+ shell_.register_command (Commands::kReadEncoders , cmd_read_encoders_cb);
132
+ shell_.register_command (Commands::kReadHasImu , cmd_read_has_imu_cb);
133
+ shell_.register_command (Commands::kReadEncodersAndImu , cmd_read_encoders_and_imu_cb);
134
+ shell_.register_command (Commands::kResetEncoders , cmd_reset_encoders_cb);
135
+ shell_.register_command (Commands::kSetMotorsSpeed , cmd_set_motors_speed_cb);
136
+ shell_.register_command (Commands::kSetMotorsPwm , cmd_set_motors_pwm_cb);
137
+ shell_.register_command (Commands::kSetPidsTuningGains , cmd_set_pid_tuning_gains_cb);
138
+ /* Initialise the IMU sensor */
139
+ if (!bno_.begin ())
140
+ {
141
+ /* There was a problem detecting the BNO055 ... check your connections */
142
+ Serial.print (" Ooops, no BNO055 detected ... Check your wiring or I2C ADDR!" );
143
+ HAS_IMU = false ;
144
+ }
145
+ bno_.setExtCrystalUse (true );
126
146
}
127
147
128
148
void App::loop () {
129
- while (Serial.available () > 0 ) {
130
- // Read the next character
131
- chr = Serial.read ();
132
-
133
- // Terminate a command with a CR
134
- if (chr == 13 ) {
135
- if (arg == 1 )
136
- argv1[index ] = 0 ;
137
- else if (arg == 2 )
138
- argv2[index ] = 0 ;
139
- run_command ();
140
- reset_command ();
141
- }
142
- // Use spaces to delimit parts of the command
143
- else if (chr == ' ' ) {
144
- // Step through the arguments
145
- if (arg == 0 )
146
- arg = 1 ;
147
- else if (arg == 1 ) {
148
- argv1[index ] = 0 ;
149
- arg = 2 ;
150
- index = 0 ;
151
- }
152
- continue ;
153
- } else {
154
- if (arg == 0 ) {
155
- // The first arg is the single-letter command
156
- cmd = chr;
157
- } else if (arg == 1 ) {
158
- // Subsequent arguments can be more than one character
159
- argv1[index ] = chr;
160
- index ++;
161
- } else if (arg == 2 ) {
162
- argv2[index ] = chr;
163
- index ++;
164
- }
165
- }
166
- }
149
+ // Process command prompt input.
150
+ shell_.process_input ();
167
151
168
152
// Run a PID calculation at the appropriate intervals
169
153
if (millis () > nextPID) {
@@ -191,72 +175,89 @@ void App::loop() {
191
175
}
192
176
}
193
177
194
- void App::reset_command () {
195
- cmd = 0 ;
196
- memset (argv1, 0 , sizeof (argv1));
197
- memset (argv2, 0 , sizeof (argv2));
198
- arg = 0 ;
199
- index = 0 ;
200
- }
178
+ void App::cmd_unknown_cb (int , char **) { Serial.println (" Unknown command." ); }
201
179
202
- void App::run_command () {
203
- switch (cmd) {
204
- case Commands::kReadAnalogGpio :
205
- cmd_read_analog_gpio (argv1, argv2);
206
- break ;
207
- case Commands::kReadDigitalGpio :
208
- cmd_read_digital_gpio (argv1, argv2);
209
- break ;
210
- case Commands::kReadEncoders :
211
- cmd_read_encoders (argv1, argv2);
212
- break ;
213
- case Commands::kResetEncoders :
214
- cmd_reset_encoders (argv1, argv2);
215
- break ;
216
- case Commands::kSetMotorsSpeed :
217
- cmd_set_motors_speed (argv1, argv2);
218
- break ;
219
- case Commands::kSetMotorsPwm :
220
- cmd_set_motors_pwm (argv1, argv2);
221
- break ;
222
- case Commands::kSetPidsTuningGains :
223
- cmd_set_pid_tuning_gains (argv1, argv2);
224
- break ;
225
- default :
226
- cmd_unknown (argv1, argv2);
227
- break ;
180
+ void App::cmd_read_analog_gpio_cb (int argc, char ** argv) {
181
+ if (argc < 2 ) {
182
+ return ;
228
183
}
229
- }
230
-
231
- void App::cmd_unknown (const char *, const char *) { Serial.println (" Unknown command." ); }
232
184
233
- void App::cmd_read_analog_gpio (const char * arg1, const char *) {
234
- const int pin = atoi (arg1);
185
+ const int pin = atoi (argv[1 ]);
235
186
Serial.println (analogRead (pin));
236
187
}
237
188
238
- void App::cmd_read_digital_gpio (const char * arg1, const char *) {
239
- const int pin = atoi (arg1);
189
+ void App::cmd_read_digital_gpio_cb (int argc, char ** argv) {
190
+ if (argc < 2 ) {
191
+ return ;
192
+ }
193
+
194
+ const int pin = atoi (argv[1 ]);
240
195
Serial.println (digitalRead (pin));
241
196
}
242
197
243
- void App::cmd_read_encoders ( const char *, const char *) {
198
+ void App::cmd_read_encoders_cb ( int , char * *) {
244
199
Serial.print (left_encoder_.read ());
245
200
Serial.print (" " );
246
201
Serial.println (right_encoder_.read ());
247
202
}
248
203
249
- void App::cmd_reset_encoders (const char *, const char *) {
204
+ void App::cmd_read_has_imu_cb (int argc, char ** argv) {
205
+ Serial.println (HAS_IMU);
206
+ }
207
+
208
+ void App::cmd_read_encoders_and_imu_cb (int argc, char ** argv) {
209
+ Serial.print (left_encoder_.read ());
210
+ Serial.print (" " );
211
+ Serial.print (right_encoder_.read ());
212
+ Serial.print (" " );
213
+
214
+ // Quaternion data
215
+ imu::Quaternion quat = bno_.getQuat ();
216
+ Serial.print (quat.x (), 4 );
217
+ Serial.print (" " );
218
+ Serial.print (quat.y (), 4 );
219
+ Serial.print (" " );
220
+ Serial.print (quat.z (), 4 );
221
+ Serial.print (" " );
222
+ Serial.print (quat.w (), 4 );
223
+ Serial.print (" " );
224
+
225
+ /* Display the floating point data */
226
+ imu::Vector<3 > euler_angvel = bno_.getVector (Adafruit_BNO055::VECTOR_GYROSCOPE);
227
+ Serial.print (euler_angvel.x ());
228
+ Serial.print (" " );
229
+ Serial.print (euler_angvel.y ());
230
+ Serial.print (" " );
231
+ Serial.print (euler_angvel.z ());
232
+ Serial.print (" " );
233
+
234
+ /* Display the floating point data */
235
+ imu::Vector<3 > euler_linearaccel = bno_.getVector (Adafruit_BNO055::VECTOR_LINEARACCEL);
236
+ Serial.print (euler_linearaccel.x ());
237
+ Serial.print (" " );
238
+ Serial.print (euler_linearaccel.y ());
239
+ Serial.print (" " );
240
+ Serial.print (euler_linearaccel.z ());
241
+ Serial.print (" \t\t " );
242
+
243
+ Serial.println (" OK" );
244
+ }
245
+
246
+ void App::cmd_reset_encoders_cb (int , char **) {
250
247
left_encoder_.reset ();
251
248
right_encoder_.reset ();
252
249
left_pid_controller_.reset (left_encoder_.read ());
253
250
right_pid_controller_.reset (right_encoder_.read ());
254
251
Serial.println (" OK" );
255
252
}
256
253
257
- void App::cmd_set_motors_speed (const char * arg1, const char * arg2) {
258
- const int left_motor_speed = atoi (arg1);
259
- const int right_motor_speed = atoi (arg2);
254
+ void App::cmd_set_motors_speed_cb (int argc, char ** argv) {
255
+ if (argc < 3 ) {
256
+ return ;
257
+ }
258
+
259
+ const int left_motor_speed = atoi (argv[1 ]);
260
+ const int right_motor_speed = atoi (argv[2 ]);
260
261
261
262
// Reset the auto stop timer.
262
263
lastMotorCommand = millis ();
@@ -279,9 +280,13 @@ void App::cmd_set_motors_speed(const char* arg1, const char* arg2) {
279
280
Serial.println (" OK" );
280
281
}
281
282
282
- void App::cmd_set_motors_pwm (const char * arg1, const char * arg2) {
283
- const int left_motor_pwm = atoi (arg1);
284
- const int right_motor_pwm = atoi (arg2);
283
+ void App::cmd_set_motors_pwm_cb (int argc, char ** argv) {
284
+ if (argc < 3 ) {
285
+ return ;
286
+ }
287
+
288
+ const int left_motor_pwm = atoi (argv[1 ]);
289
+ const int right_motor_pwm = atoi (argv[2 ]);
285
290
286
291
// Reset the auto stop timer.
287
292
lastMotorCommand = millis ();
@@ -295,15 +300,20 @@ void App::cmd_set_motors_pwm(const char* arg1, const char* arg2) {
295
300
Serial.println (" OK" );
296
301
}
297
302
298
- void App::cmd_set_pid_tuning_gains (const char * arg1, const char *) {
303
+ void App::cmd_set_pid_tuning_gains_cb (int argc, char ** argv) {
304
+ // TODO(jballoffet): Refactor to expect command multiple arguments.
305
+ if (argc < 2 ) {
306
+ return ;
307
+ }
308
+
299
309
static constexpr int kSizePidArgs {4 };
300
310
int i = 0 ;
301
311
char arg[20 ];
302
312
char * str;
303
313
int pid_args[kSizePidArgs ]{0 , 0 , 0 , 0 };
304
314
305
315
// Example: "u 30:20:10:50".
306
- strcpy (arg, arg1 );
316
+ strcpy (arg, argv[ 1 ] );
307
317
char * p = arg;
308
318
while ((str = strtok_r (p, " :" , &p)) != NULL && i < kSizePidArgs ) {
309
319
pid_args[i] = atoi (str);
0 commit comments