/ Ada_BLE_RC / Ada_BLE_RC.ino
Ada_BLE_RC.ino
1 // SPDX-FileCopyrightText: 2016 James DeVito for Adafruit Industries 2 // 3 // SPDX-License-Identifier: MIT 4 // 5 /********************************************************************* 6 This is an example for our nRF51822 based Bluefruit LE modules 7 8 Modified to drive a 3-wheeled BLE Robot Rover! by http://james.devi.to 9 10 Pick one up today in the Adafruit shop! 11 12 Adafruit invests time and resources providing this open source code, 13 please support Adafruit and open-source hardware by purchasing 14 products from Adafruit! 15 16 MIT license, check LICENSE for more information 17 All text above, and the splash screen below must be included in 18 any redistribution 19 *********************************************************************/ 20 21 #include <string.h> 22 #include <Arduino.h> 23 #include <SPI.h> 24 #if not defined (_VARIANT_ARDUINO_DUE_X_) 25 #include <SoftwareSerial.h> 26 #endif 27 28 #include "Adafruit_BLE.h" 29 #include "Adafruit_BluefruitLE_SPI.h" 30 #include "Adafruit_BluefruitLE_UART.h" 31 32 #include "BluefruitConfig.h" 33 34 #include <Wire.h> 35 #include <Adafruit_MotorShield.h> 36 // #include "utility/Adafruit_PWMServoDriver.h" 37 // #include <Servo.h> 38 39 // Create the motor shield object with the default I2C address 40 Adafruit_MotorShield AFMS = Adafruit_MotorShield(); 41 42 // And connect 2 DC motors to port M3 & M4 ! 43 Adafruit_DCMotor *L_MOTOR = AFMS.getMotor(4); 44 Adafruit_DCMotor *R_MOTOR = AFMS.getMotor(3); 45 46 //not used, testing acceleration 47 // int accelTime = 200; 48 49 //Name your RC here 50 String BROADCAST_NAME = "adafruit red robot rover"; 51 52 String BROADCAST_CMD = String("AT+GAPDEVNAME=" + BROADCAST_NAME); 53 54 Adafruit_BluefruitLE_SPI ble(BLUEFRUIT_SPI_CS, BLUEFRUIT_SPI_IRQ, BLUEFRUIT_SPI_RST); 55 56 57 // A small helper 58 void error(const __FlashStringHelper*err) { 59 Serial.println(err); 60 while (1); 61 } 62 63 // function prototypes over in packetparser.cpp 64 uint8_t readPacket(Adafruit_BLE *ble, uint16_t timeout); 65 float parsefloat(uint8_t *buffer); 66 void printHex(const uint8_t * data, const uint32_t numBytes); 67 68 // the packet buffer 69 extern uint8_t packetbuffer[]; 70 71 char buf[60]; 72 73 /**************************************************************************/ 74 /*! 75 @brief Sets up the HW an the BLE module (this function is called 76 automatically on startup) 77 */ 78 /**************************************************************************/ 79 void setup(void) 80 { 81 Serial.begin(9600); 82 83 AFMS.begin(); // create with the default frequency 1.6KHz 84 85 // turn on motors 86 L_MOTOR->setSpeed(0); 87 L_MOTOR->run(RELEASE); 88 89 R_MOTOR->setSpeed(0); 90 R_MOTOR->run(RELEASE); 91 92 Serial.begin(115200); 93 Serial.println(F("Adafruit Bluefruit Robot Controller Example")); 94 Serial.println(F("-----------------------------------------")); 95 96 /* Initialize the module */ 97 BLEsetup(); 98 99 100 } 101 102 int velocity = 0; 103 104 float x, y; 105 106 int L_restrict = 0; 107 int R_restrict = 0; 108 109 unsigned long lastAccelPacket = 0; 110 111 bool modeToggle = false; 112 113 void loop(void) 114 { 115 // read new packet data 116 uint8_t len = readPacket(&ble, BLE_READPACKET_TIMEOUT); 117 // if (len == 0) return; 118 119 // Read from Accelerometer input 120 if( accelMode() ) { 121 lastAccelPacket = millis(); 122 modeToggle = true; 123 return; 124 } 125 126 // Stop motors if accelerometer data is turned off (100ms timeout) 127 if( millis() - lastAccelPacket > 100 & modeToggle) { 128 L_MOTOR->run(RELEASE); 129 R_MOTOR->run(RELEASE); 130 modeToggle = false; 131 return; 132 } 133 134 //if no accelerometer, use control pad 135 if( !modeToggle ) buttonMode(); 136 137 } 138 139 140 bool accelMode(){ 141 if (packetbuffer[1] == 'A') { 142 x = parsefloat( packetbuffer + 2 ); 143 y = parsefloat( packetbuffer + 6 ); 144 145 if( x <= -0.55 ){ 146 x += 0.55; 147 x *= -100.0; 148 L_MOTOR->run( BACKWARD ); 149 R_MOTOR->run( BACKWARD ); 150 if( x >= 45 ) x = 45; 151 if( x <= 0 ) x = 0; 152 velocity = map( x, 0, 45, 0 ,255 ); 153 } 154 else if( x >= -0.25 ){ 155 x+= 0.25; 156 x *= 100; 157 L_MOTOR->run( FORWARD ); 158 R_MOTOR->run( FORWARD ); 159 if( x>= 45 ) x = 45; 160 if( x<= 0 ) x = 0; 161 velocity = map( x, 0, 45, 0, 255 ); 162 } 163 else{ 164 L_MOTOR->run( RELEASE ); 165 R_MOTOR->run( RELEASE ); 166 velocity = 0; 167 } 168 169 //account for L / R accel 170 171 if( y >= 0.1 ){ 172 y -= 0.1; 173 y *= 100; 174 if( y >= 50 ) y = 50; 175 if( y <= 0 ) y = 0; 176 177 L_restrict = fscale( y, 0.0, 50.0, 0.0, 100.0, -4.0 ); 178 } 179 else if( y <= -0.1 ){ 180 y += 0.1; 181 y *= -100; 182 if( y>= 50 ) y = 50; 183 if( y<= 0 ) y = 0; 184 185 R_restrict = fscale( y, 0.0, 50.0, 0.0, 100.0, -4.0 ); 186 } 187 else{ 188 L_restrict = 0; 189 R_restrict = 0; 190 } 191 192 float Lpercent = ( 100.0 - L_restrict ) / 100.00 ; 193 float Rpercent = ( 100.0 - R_restrict ) / 100.00 ; 194 195 // Serial.print( x ); 196 // Serial.print( "\t" ); 197 // Serial.print( Lpercent ); 198 // Serial.print( "\t" ); 199 // Serial.print( velocity ); 200 // Serial.print( "\t" ); 201 // Serial.println( Rpercent ); 202 203 L_MOTOR->setSpeed( velocity * Lpercent ); 204 R_MOTOR->setSpeed( velocity * Rpercent ); 205 206 return true; 207 } 208 return false; 209 } 210 211 bool isMoving = false; 212 213 bool buttonMode(){ 214 215 static unsigned long lastPress = 0; 216 217 218 // Buttons 219 if (packetbuffer[1] == 'B') { 220 221 uint8_t buttnum = packetbuffer[2] - '0'; 222 boolean pressed = packetbuffer[3] - '0'; 223 224 // Serial.println(buttnum); 225 226 Serial.println(isMoving); 227 if (pressed) { 228 isMoving = true; 229 if(buttnum == 5){ 230 L_MOTOR->run(FORWARD); 231 R_MOTOR->run(FORWARD); 232 } 233 if(buttnum == 6){ 234 L_MOTOR->run(BACKWARD); 235 R_MOTOR->run(BACKWARD); 236 } 237 if(buttnum == 7){ 238 L_MOTOR->run(RELEASE); 239 R_MOTOR->run(FORWARD); 240 } 241 if(buttnum == 8){ 242 L_MOTOR->run(FORWARD); 243 R_MOTOR->run(RELEASE); 244 } 245 246 lastPress = millis(); 247 248 L_MOTOR->setSpeed(255); 249 R_MOTOR->setSpeed(255); 250 } 251 252 else { 253 isMoving = false; 254 L_MOTOR->run(RELEASE); 255 R_MOTOR->run(RELEASE); 256 } 257 return true; 258 } 259 // if(isMoving){ 260 261 // unsigned long timeSincePress = millis() - lastPress; 262 263 // if(timeSincePress <= accelTime){ 264 265 // Serial.println( timeSincePress ) ; 266 267 // int motorSpeed = map( timeSincePress, 0, accelTime, 0, 255 ); 268 269 // L_MOTOR->setSpeed(motorSpeed); 270 // R_MOTOR->setSpeed(motorSpeed); 271 // } 272 273 // else{ 274 // // full speed ahead! 275 // L_MOTOR->setSpeed(255); 276 // R_MOTOR->setSpeed(255); 277 // } 278 // } 279 280 return false; 281 282 } 283 284 void BLEsetup(){ 285 Serial.print(F("Initialising the Bluefruit LE module: ")); 286 287 if ( !ble.begin(VERBOSE_MODE) ) 288 { 289 error(F("Couldn't find Bluefruit, make sure it's in CoMmanD mode & check wiring?")); 290 } 291 Serial.println( F("OK!") ); 292 293 /* Perform a factory reset to make sure everything is in a known state */ 294 Serial.println(F("Performing a factory reset: ")); 295 if (! ble.factoryReset() ){ 296 error(F("Couldn't factory reset")); 297 } 298 299 //Convert the name change command to a char array 300 BROADCAST_CMD.toCharArray(buf, 60); 301 302 //Change the broadcast device name here! 303 if(ble.sendCommandCheckOK(buf)){ 304 Serial.println("name changed"); 305 } 306 delay(250); 307 308 //reset to take effect 309 if(ble.sendCommandCheckOK("ATZ")){ 310 Serial.println("resetting"); 311 } 312 delay(250); 313 314 //Confirm name change 315 ble.sendCommandCheckOK("AT+GAPDEVNAME"); 316 317 /* Disable command echo from Bluefruit */ 318 ble.echo(false); 319 320 Serial.println("Requesting Bluefruit info:"); 321 /* Print Bluefruit information */ 322 ble.info(); 323 324 Serial.println(F("Please use Adafruit Bluefruit LE app to connect in Controller mode")); 325 Serial.println(F("Then activate/use the sensors, color picker, game controller, etc!")); 326 Serial.println(); 327 328 ble.verbose(false); // debug info is a little annoying after this point! 329 330 /* Wait for connection */ 331 while (! ble.isConnected()) { 332 delay(500); 333 } 334 335 Serial.println(F("*****************")); 336 337 // Set Bluefruit to DATA mode 338 Serial.println( F("Switching to DATA mode!") ); 339 ble.setMode(BLUEFRUIT_MODE_DATA); 340 341 Serial.println(F("*****************")); 342 } 343 344 //Logarithmic mapping function from http://playground.arduino.cc/Main/Fscale 345 float fscale( float inputValue, float originalMin, float originalMax, float newBegin, float newEnd, float curve){ 346 347 float OriginalRange = 0; 348 float NewRange = 0; 349 float zeroRefCurVal = 0; 350 float normalizedCurVal = 0; 351 float rangedValue = 0; 352 boolean invFlag = 0; 353 354 355 // condition curve parameter 356 // limit range 357 358 if (curve > 10) curve = 10; 359 if (curve < -10) curve = -10; 360 361 curve = (curve * -.1) ; // - invert and scale - this seems more intuitive - postive numbers give more weight to high end on output 362 curve = pow(10, curve); // convert linear scale into lograthimic exponent for other pow function 363 364 /* 365 Serial.println(curve * 100, DEC); // multply by 100 to preserve resolution 366 Serial.println(); 367 */ 368 369 // Check for out of range inputValues 370 if (inputValue < originalMin) { 371 inputValue = originalMin; 372 } 373 if (inputValue > originalMax) { 374 inputValue = originalMax; 375 } 376 377 // Zero Refference the values 378 OriginalRange = originalMax - originalMin; 379 380 if (newEnd > newBegin){ 381 NewRange = newEnd - newBegin; 382 } 383 else 384 { 385 NewRange = newBegin - newEnd; 386 invFlag = 1; 387 } 388 389 zeroRefCurVal = inputValue - originalMin; 390 normalizedCurVal = zeroRefCurVal / OriginalRange; // normalize to 0 - 1 float 391 392 /* 393 Serial.print(OriginalRange, DEC); 394 Serial.print(" "); 395 Serial.print(NewRange, DEC); 396 Serial.print(" "); 397 Serial.println(zeroRefCurVal, DEC); 398 Serial.println(); 399 */ 400 401 // Check for originalMin > originalMax - the math for all other cases i.e. negative numbers seems to work out fine 402 if (originalMin > originalMax ) { 403 return 0; 404 } 405 406 if (invFlag == 0){ 407 rangedValue = (pow(normalizedCurVal, curve) * NewRange) + newBegin; 408 409 } 410 else // invert the ranges 411 { 412 rangedValue = newBegin - (pow(normalizedCurVal, curve) * NewRange); 413 } 414 415 return rangedValue; 416 } 417