Blynk Joystick Controlled Tracked Rover with Wemos D1 Mini Pro

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
  }
}
2 Likes