Last active
March 20, 2024 21:17
-
-
Save reefwing/b6b51197ffe1b238fdbfc558a0c26e56 to your computer and use it in GitHub Desktop.
Control a DFRobot Devastator tank via a Romeo BLE (Uno equivalent) using Bluetooth (BLE).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* BluetoothControl: Control a DFRobot Devastator tank via a Romeo BLE | |
* (Uno equivalent) using Bluetooth (BLE). | |
* | |
* Compatible with iPhone app AVA BLE - https://itunes.apple.com/au/app/ava-ble-remote/id1073023233?mt=8 | |
* | |
* Version 0.3, August, 2018 | |
* Copyright 2018 David Such | |
* | |
*/ | |
#define NO_DATA -1 | |
#define MAX_DUTY_CYCLE 255 | |
const byte M2_DIRECTION = 4; // M1 Direction Control | |
const byte M2_SPEED = 5; // M1 Speed Control | |
const byte M1_SPEED = 6; // M2 Speed Control | |
const byte M1_DIRECTION = 7; // M2 Direction Control | |
const char VERSION[] = "BLE Remote v0.2"; | |
// Task Definitions | |
enum task_t { statusReport, remoteControl, patrol, followIR, avoidIR, findIR, noTask }; | |
task_t task; | |
String taskDescription; | |
bool commsDetected, remoteControlled, speedData; | |
int speed; | |
// Motor Control | |
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
// Functions | |
int dutyCycleFromSpeed() | |
{ | |
float speedPercentage = (float)speed / 100; | |
int dutyCycle = MAX_DUTY_CYCLE * speedPercentage; | |
return constrain(dutyCycle, 0, 255); | |
} | |
void stop() | |
{ | |
digitalWrite(M1_SPEED, LOW); | |
digitalWrite(M1_DIRECTION, LOW); | |
digitalWrite(M2_SPEED, LOW); | |
digitalWrite(M2_DIRECTION, LOW); | |
} | |
void forward() | |
{ | |
int dutyCycle = dutyCycleFromSpeed(); | |
analogWrite (M1_SPEED, dutyCycle); | |
digitalWrite(M1_DIRECTION, HIGH); | |
analogWrite (M2_SPEED, dutyCycle); | |
digitalWrite(M2_DIRECTION, HIGH); | |
} | |
void back() | |
{ | |
int dutyCycle = dutyCycleFromSpeed(); | |
analogWrite (M1_SPEED, dutyCycle); | |
digitalWrite(M1_DIRECTION, LOW); | |
analogWrite (M2_SPEED, dutyCycle); | |
digitalWrite(M2_DIRECTION, LOW); | |
} | |
void left() | |
{ | |
int dutyCycle = dutyCycleFromSpeed(); | |
analogWrite (M1_SPEED, dutyCycle); | |
digitalWrite(M1_DIRECTION, LOW); | |
analogWrite (M2_SPEED, dutyCycle); | |
digitalWrite(M2_DIRECTION, HIGH); | |
} | |
void right() | |
{ | |
int dutyCycle = dutyCycleFromSpeed(); | |
analogWrite (M1_SPEED, dutyCycle); | |
digitalWrite(M1_DIRECTION, HIGH); | |
analogWrite (M2_SPEED, dutyCycle); | |
digitalWrite(M2_DIRECTION, LOW); | |
} | |
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
void setup() | |
{ | |
// Serial Monitor | |
Serial.begin(115200); | |
Serial.println(VERSION); | |
Serial.println("Romeo BLE Device"); | |
Serial.println("Initializing..."); | |
Serial.println("Serial connected - awaiting command (f, b, l, r, s, t): "); | |
// PIN Definitions | |
pinMode(M1_DIRECTION, OUTPUT); | |
pinMode(M1_SPEED, OUTPUT); | |
pinMode(M2_DIRECTION, OUTPUT); | |
pinMode(M2_SPEED, OUTPUT); | |
// Initial State - stopped with no set task, awaiting command with speed = 100%. | |
task = remoteControl; | |
speed = 100; | |
speedData = false; | |
digitalWrite(M1_SPEED, LOW); | |
digitalWrite(M2_SPEED, LOW); | |
} | |
void loop() { | |
if (Serial.available()) { | |
// Get the number of bytes (characters) available for reading from the serial port. | |
// This is data that's already arrived and stored in the serial receive buffer (which holds 64 bytes). | |
char incomingByte = Serial.read(); | |
int oldSpeed = speed; | |
if (speedData) { | |
int newSpeed = incomingByte; | |
speed = constrain(newSpeed, 0 , 100); | |
Serial.print("Set Speed: "); | |
Serial.println(speed); | |
speedData = false; | |
} | |
else if (incomingByte != NO_DATA) | |
{ | |
switch (incomingByte) | |
{ | |
case 'f': | |
Serial.print("Forward "); | |
Serial.print(speed); | |
Serial.println("%"); | |
forward(); | |
break; | |
case 'b': | |
Serial.print("Backward "); | |
Serial.print(speed); | |
Serial.println("%"); | |
back(); | |
break; | |
case 'l': | |
Serial.println("Turning Left"); | |
speed = 40; | |
left(); | |
speed = oldSpeed; | |
break; | |
case 'r': | |
Serial.println("Turning Right"); | |
speed = 40; | |
right(); | |
speed = oldSpeed; | |
break; | |
case 't': | |
Serial.println("Hello"); | |
break; | |
case 's': | |
Serial.println("Stopped"); | |
stop(); | |
break; | |
case 'w': | |
Serial.println("Set speed 25%"); | |
speed = 25; | |
break; | |
case 'x': | |
Serial.println("Set speed 50%"); | |
speed = 50; | |
break; | |
case 'y': | |
Serial.println("Set speed 75%"); | |
speed = 75; | |
break; | |
case 'z': | |
Serial.println("Set speed 100%"); | |
speed = 100; | |
break; | |
case '0': | |
task = statusReport; | |
taskDescription = "T0: Status"; | |
Serial.println(taskDescription); | |
remoteControlled = false; | |
break; | |
case '1': | |
task = remoteControl; | |
taskDescription = "T1: Remote"; | |
Serial.println(taskDescription); | |
remoteControlled = true; | |
break; | |
case '2': | |
task = patrol; | |
taskDescription = "T2: Patrol"; | |
Serial.print(taskDescription); | |
remoteControlled = false; | |
break; | |
case '3': | |
task = followIR; | |
taskDescription = "T3: Follow IR"; | |
Serial.print(taskDescription); | |
remoteControlled = false; | |
break; | |
case '4': | |
task = avoidIR; | |
taskDescription = "T4: Avoid IR"; | |
Serial.print(taskDescription); | |
remoteControlled = false; | |
break; | |
case '5': | |
task = findIR; | |
taskDescription = "T5: Find IR"; | |
Serial.print(taskDescription); | |
remoteControlled = false; | |
break; | |
case '!': // Start byte indicating encoded speed is the next byte | |
speedData = true; | |
break; | |
default: | |
Serial.println("Unknown Command..."); | |
// Serial.println("Valid Commands are: f = forward, l = left, b = back, r = right, t = test message, s = stop."); | |
break; | |
} | |
} | |
else stop(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Excellent work. I uploaded this and it worked first time. I couldn't find the GoBLE App that is supposed to work with it on the UK iTunes store. Thought I'd take a look on GitHub and here it is...