The program presented below makes the assumption that the Bluetooth can not be used while the joystick is not in the centre position. The joystick will override the Bluetooth.
loop() consists of three functional blocks. I have used some static variables in loop() to remember what is happening.
I have used an enum that has two values to indicate if the program is in Bluetooth mode or in joystick mode.
enum MODE
{
BLUETOOTH,
JOYSTICK
};
void loop()
{
// we start in joystic mode
static MODE mode = JOYSTICK;
...
...
}
To be able to detect changes in the joystick we keep track of the old values for speed and turn.
{
// we start in joystick mode
static MODE mode = JOYSTICK;
// we keep track of the old speed and turn value
static int oldSpeed;
static int oldTurn;
...
...
}
The first functional block reads the joystick and maps them.
// Jika tidak ada data dari Bluetooth, kontrol motor berdasarkan joystick
xVal = analogRead(joyXpin);
yVal = analogRead(joyYpin);
// Normalisasi nilai joystick
int speed = map(yVal, 0, 1023, -255, 255); // Peta nilai Y untuk kecepatan
int turn = map(xVal, 0, 1023, -255, 255); // Peta nilai X untuk belok
if (abs(speed) < zeroVal)
{
speed = 0;
}
if (abs(turn) < zeroVal)
{
turn = 0;
}
The two if statements are needed because it is difficult to get exactly zero with the potentiometers that I have. zeroVal has the value 50 and any speed value or turn value between -50 and 50 will become 0. Next we can check if the joystick changed and if so, set the mode accordingly.
// if the joystick changed
if (abs(speed - oldSpeed) > deltaVal || (abs(turn - oldTurn) > deltaVal))
{
Serial.print(F("speed = "));
Serial.print(speed);
Serial.print(F(", oldSpeed = "));
Serial.println(oldSpeed);
Serial.print(F("turn = "));
Serial.print(turn);
Serial.print(F(", oldTurn = "));
Serial.println(oldTurn);
// switch to joystick mode
Serial.println(F("Switching to joystick"));
mode = JOYSTICK;
oldSpeed = speed;
oldTurn = turn;
}
That completes the first block
The second functional block handles the reading of the Bluetooth.
if (Serial.available() > 0)
{
data = Serial.read(); // Read received data
Serial.println(data); // Debugging: Print received data
// debug
Serial.print(F("speed = "));
Serial.println(speed);
Serial.print(F("turn = "));
Serial.println(turn);
// if the joystick is in the centre
if (speed == 0 && turn == 0)
{
// switch to bluetooth mode
Serial.println(F("Switching to bluetooth"));
mode = BLUETOOTH;
}
}
The code always reads available data (as in my earlier reply); it will only switch to Bluetooth mode if the joystick is in the centre position.
And the last functional block handles the "selected" mode.
if (mode == BLUETOOTH)
{
handleBluetooth(data);
}
else
{
handleJoystick(speed, turn);
}
This calls one of two functions depending on the mode.
The complete code
char data; // Variable to store received data
int joyXpin = A0;
int joyYpin = A1;
int xVal;
int yVal;
// potentiometers are 0 between -50 and 50
const int zeroVal = 50;
// only react on changes of 50 or more
const int deltaVal = 50;
void setup()
{
Serial.begin(9600); // Start serial communication at 9600 baud rate
// Set motor control pins as output
pinMode(7, OUTPUT);
pinMode(6, OUTPUT);
pinMode(5, OUTPUT);
pinMode(4, OUTPUT);
pinMode(joyXpin, INPUT);
pinMode(joyYpin, INPUT);
}
enum MODE
{
BLUETOOTH,
JOYSTICK
};
void loop()
{
// we start in joystick mode
static MODE mode = JOYSTICK;
// we keep track of the old speed and tunr value
static int oldSpeed;
static int oldTurn;
// Jika tidak ada data dari Bluetooth, kontrol motor berdasarkan joystick
xVal = analogRead(joyXpin);
yVal = analogRead(joyYpin);
// Normalisasi nilai joystick
int speed = map(yVal, 0, 1023, -255, 255); // Peta nilai Y untuk kecepatan
int turn = map(xVal, 0, 1023, -255, 255); // Peta nilai X untuk belok
if (abs(speed) < zeroVal)
{
speed = 0;
}
if (abs(turn) < zeroVal)
{
turn = 0;
}
// only one potentiometer
//turn = 0;
// if the joystick changed
if (abs(speed - oldSpeed) > deltaVal || (abs(turn - oldTurn) > deltaVal))
{
Serial.print(F("speed = "));
Serial.print(speed);
Serial.print(F(", oldSpeed = "));
Serial.println(oldSpeed);
Serial.print(F("turn = "));
Serial.print(turn);
Serial.print(F(", oldTurn = "));
Serial.println(oldTurn);
// switch to joystick mode
Serial.println(F("Switching to joystick"));
mode = JOYSTICK;
oldSpeed = speed;
oldTurn = turn;
}
if (Serial.available() > 0)
{
data = Serial.read(); // Read received data
Serial.println(data); // Debugging: Print received data
// debug
Serial.print(F("speed = "));
Serial.println(speed);
Serial.print(F("turn = "));
Serial.println(turn);
// if the joystick is in the centre
if (speed == 0 && turn == 0)
{
// switch to bluetooth mode
Serial.println(F("Switching to bluetooth"));
mode = BLUETOOTH;
}
}
if (mode == BLUETOOTH)
{
handleBluetooth(data);
}
else
{
handleJoystick(speed, turn);
}
}
/*
Handle Bluetooth commands
In:
received character
*/
void handleBluetooth(char ch)
{
// Kontrol motor berdasarkan perintah dari Bluetooth
switch (ch)
{
case 'F': // Move Forward
Serial.println(F("Forward"));
digitalWrite(7, HIGH);
digitalWrite(6, LOW);
digitalWrite(5, HIGH);
digitalWrite(4, LOW);
return; // Keluar dari loop
case 'B': // Move Backward
Serial.println(F("Backward"));
digitalWrite(7, LOW);
digitalWrite(6, HIGH);
digitalWrite(5, LOW);
digitalWrite(4, HIGH);
return; // Keluar dari loop
case 'R': // Turn Left
Serial.println(F("Left"));
digitalWrite(7, LOW);
digitalWrite(6, HIGH);
digitalWrite(5, HIGH);
digitalWrite(4, LOW);
return; // Keluar dari loop
case 'L': // Turn Right
Serial.println(F("Right"));
digitalWrite(7, HIGH);
digitalWrite(6, LOW);
digitalWrite(5, LOW);
digitalWrite(4, HIGH);
return; // Keluar dari loop
case 'S': // Stop
Serial.println(F("Stop"));
digitalWrite(7, LOW);
digitalWrite(6, LOW);
digitalWrite(5, LOW);
digitalWrite(4, LOW);
return; // Keluar dari loop
}
}
/*
Handle joystick values
In:
speed
turn
*/
void handleJoystick(int speed, int turn)
{
// Batas untuk mengabaikan gerakan kecil
int threshold = 100;
// Kontrol motor berdasarkan joystick
if (abs(speed) > threshold)
{
if (speed > 0)
{ // Maju
digitalWrite(5, LOW); // Motor B maju
digitalWrite(4, HIGH);
digitalWrite(7, HIGH); // Motor A maju
digitalWrite(6, LOW);
}
else
{ // Mundur
digitalWrite(5, HIGH); // Motor B mundur
digitalWrite(4, LOW);
digitalWrite(7, HIGH); // Motor A maju
digitalWrite(6, LOW);
}
}
else
{ // Stop jika tidak ada gerakan
digitalWrite(7, LOW);
digitalWrite(6, LOW);
digitalWrite(5, LOW);
digitalWrite(4, LOW);
}
if (abs(turn) > threshold)
{
if (turn > 0)
{ // Belok kiri
digitalWrite(5, HIGH); // Motor B maju
digitalWrite(4, LOW);
digitalWrite(7, LOW); // Motor A mundur
digitalWrite(6, HIGH);
}
else
{ // Belok kanan
digitalWrite(5, LOW); // Motor B mundur
digitalWrite(4, HIGH);
digitalWrite(7, HIGH); // Motor A maju
digitalWrite(6, LOW);
}
}
}
This was tested relying on the the serial outputs with only one potentiometer (I don't have a joystick).