UPDATED CODE:
I updated my code to allow variable speed control with the Blynk Joystick Widget.
Enjoy.
/*
Differential Motor with Speed Control using Blynk Joystick
Using TB6612FNG Motor Controller (drop-in replacement for L298N, but with greater efficiency)
Gunner 2020
Main variable speed control code from
DroneBot Workshop 2017
http://dronebotworkshop.com
*/
// For Blynk
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#define BLYNK_MSG_LIMIT 0
#define BLYNK_HEARTBEAT 5
// For Servo
#include <Servo.h>
// For OTA:
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
BlynkTimer timer;
Servo myservo;
// Project Auth Token and WiFi settings
char auth[] = "xxxxxxxxxx"; // Set for Local Server
char ssid[] = "xxxxxxxxxx";
char pass[] = "xxxxxxxxxx";
// Motor A
int PWMA = 12; // D6 // L298N = EnA
int AIN1 = 14; // D5 // L298N = IN1
int AIN2 = 15; // D8 // L298N = IN2
// Motor B
int PWMB = 13; // D7 // L298N = EnB
int BIN1 = 5; // D1 // L298N = IN3
int BIN2 = 4; // D2 // L298N = IN4
// LED Headlamp
int HeadLamp = 2; // D4
// Gear Shift Servo
int servoPin = 0; // D3
// Motor Speed Values - Start at zero
int MotorSpeed1 = 0;
int MotorSpeed2 = 0;
// Joystick Values - Start at 512 (middle position)
int joyposVert = 512;
int joyposHorz = 512;
void setup() {
// Set to LOW gear:
myservo.attach(servoPin);
myservo.write(0);
timer.setTimeout(2000L, []() { // Timer to Disengage Servo
myservo.detach();
}); // END Timer Function
// Set all the motor and other control pins to outputs
pinMode(PWMA, OUTPUT);
pinMode(PWMB, OUTPUT);
pinMode(AIN1, OUTPUT);
pinMode(AIN2, OUTPUT);
pinMode(BIN1, OUTPUT);
pinMode(BIN2, OUTPUT);
pinMode(HeadLamp, OUTPUT);
digitalWrite(HeadLamp, LOW); // Turn off headlamp
// Start with motors disabled and direction forward
// Motor A
digitalWrite(PWMA, LOW);
digitalWrite(AIN1, HIGH);
digitalWrite(AIN2, LOW);
// Motor B
digitalWrite(PWMB, LOW);
digitalWrite(BIN1, HIGH);
digitalWrite(BIN2, LOW);
// Log into Blynk Local Server
Blynk.begin(auth, ssid, pass, "xxx.xxx.xxx.xxx", 8080); // Set for Local Server
Blynk.connect();
Blynk.virtualWrite(V0, "Bootup"); // First Battery Message
timer.setInterval(1000L, []() { // Battery Check timer
Blynk.virtualWrite(V0, analogRead(A0) * 0.0145); // ADC range up to 14.8v
}); // END Timer Function
Blynk.virtualWrite(V10, BLYNK_VERSION);
// Setup OTA programming
ArduinoOTA.setHostname("Gunnerator");
ArduinoOTA.begin();
}
BLYNK_CONNECTED() {
Blynk.syncAll();
}
void loop() {
Blynk.run();
timer.run();
ArduinoOTA.handle();
}
// Stop all motors if App disconnects
BLYNK_APP_DISCONNECTED() {
MotorSpeed1 = 0;
MotorSpeed2 = 0;
analogWrite(PWMA, MotorSpeed1);
analogWrite(PWMB, MotorSpeed2);
}
// Main Joystick and Speed Control Function
BLYNK_WRITE(V6) { // Read the Joystick X and Y positions
int joyposHorz = param[0].asInt();
int joyposVert = param[1].asInt();
// Determine if this is a forward or backward motion
// Do this by reading the Vertical Value
// Apply results to MotorSpeed and to Direction
if (joyposVert < 460) { // This is Backward
// Set Motor A backward
digitalWrite(AIN1, LOW);
digitalWrite(AIN2, HIGH);
// Set Motor B backward
digitalWrite(BIN1, LOW);
digitalWrite(BIN2, HIGH);
// Determine Motor Speeds
// As we are going backwards we need to reverse readings
joyposVert = joyposVert - 460; // This produces a negative number
joyposVert = joyposVert * -1; // Make the number positive
MotorSpeed1 = map(joyposVert, 0, 460, 0, 1023);
MotorSpeed2 = map(joyposVert, 0, 460, 0, 1023);
} else if (joyposVert > 564) { // This is Forward
// Set Motor A forward
digitalWrite(AIN1, HIGH);
digitalWrite(AIN2, LOW);
// Set Motor B forward
digitalWrite(BIN1, HIGH);
digitalWrite(BIN2, LOW);
//Determine Motor Speeds
MotorSpeed1 = map(joyposVert, 564, 1023, 0, 1023);
MotorSpeed2 = map(joyposVert, 564, 1023, 0, 1023);
} else { // This is Stopped
MotorSpeed1 = 0;
MotorSpeed2 = 0;
}
// Now do the steering
// The Horizontal position will "weigh" the motor speed
// Values for each motor
if (joyposHorz < 460) { // Move Left
// As we are going left we need to reverse readings
joyposHorz = joyposHorz - 460; // This produces a negative number
joyposHorz = joyposHorz * -1; // Make the number positive
// Map the number to a value of 1023 maximum
joyposHorz = map(joyposHorz, 0, 460, 0, 1023);
MotorSpeed1 = MotorSpeed1 - joyposHorz;
MotorSpeed2 = MotorSpeed2 + joyposHorz;
// Don't exceed range of 0-1023 for motor speeds
if (MotorSpeed1 < 0)MotorSpeed1 = 0;
if (MotorSpeed2 > 1023)MotorSpeed2 = 1023;
} else if (joyposHorz > 564) { // Move Right
// Map the number to a value of 1023 maximum
joyposHorz = map(joyposHorz, 564, 1023, 0, 1023);
MotorSpeed1 = MotorSpeed1 + joyposHorz;
MotorSpeed2 = MotorSpeed2 - joyposHorz;
// Don't exceed range of 0-1023 for motor speeds
if (MotorSpeed1 > 1023)MotorSpeed1 = 1023;
if (MotorSpeed2 < 0)MotorSpeed2 = 0;
}
// Adjust to prevent "buzzing" at very low speed
if (MotorSpeed1 < 8)MotorSpeed1 = 0;
if (MotorSpeed2 < 8)MotorSpeed2 = 0;
// Set the motor speeds
analogWrite(PWMA, MotorSpeed1);
analogWrite(PWMB, MotorSpeed2);
}
// Servo controlled gearing:
BLYNK_WRITE(V8) {
if (param.asInt() == 1) {
digitalWrite(AIN1, LOW);
digitalWrite(AIN2, LOW);
digitalWrite(BIN1, LOW);
digitalWrite(BIN2, LOW);
myservo.attach(servoPin);
myservo.write(175); // High gear
timer.setTimeout(2000L, []() { // Timer to Disengage Servo
myservo.detach();
}); // END Timer Function
} else {
digitalWrite(AIN1, LOW);
digitalWrite(AIN2, LOW);
digitalWrite(BIN1, LOW);
digitalWrite(BIN2, LOW);
myservo.attach(servoPin);
myservo.write(0); // Low gear
timer.setTimeout(2000L, []() { // Timer to Disengage Servo
myservo.detach();
}); // END Timer Function
}
}
// Headlamp Control:
BLYNK_WRITE(V9) {
if (param.asInt() == 1) {
digitalWrite(2, HIGH); // Headlamp ON
} else {
digitalWrite(2, LOW); // Headlamp OFF
}
}