Skip to content

Instantly share code, notes, and snippets.

@reefwing
Last active March 20, 2024 21:17
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save reefwing/b6b51197ffe1b238fdbfc558a0c26e56 to your computer and use it in GitHub Desktop.
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).
/*
* 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();
}
}
@butcha1
Copy link

butcha1 commented Aug 25, 2023

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...

@reefwing
Copy link
Author

@butcha1 - glad you found it useful!

8-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment