1 (edited by Gunner 2021-11-17 23:50:07)

Topic: My GUNNERATOR Tracked Rover

Many years ago, I had build this tracked rover out of the base of an old RC toy from the 80's, and it has gone through many hardware revisions and control software since. 

But I have found RemoteXY the best to date for simplicity and ease of use, and have a dedicated controller (old Nexus 6) on hand for quick power up and control... no middleman server, no manual switching of SSID, no hassles.  From shelf to road in seconds.

Images:
https://www.dropbox.com/s/k7mzwwxsrq92ppu/RemoteXY%20-%20Gunnerator%20Screenshot.png?dl=1
https://www.dropbox.com/s/sl9otvzc2jl4iii/Gunnerator%202.jpg?dl=1
https://www.dropbox.com/s/adlv1xxrttcl4me/Gunnerator%204.jpg?dl=1

- Wemos D1 Mini Pro with external antenna
- Powered by a 13v LiFePO4 battery that I pulled from an old car booster.
- Original 6v motors (and gearing) are overdriven by the 13v - This has provided lots of power with no degradation over the years.
- DC Power Shield for the Wemos
- TB6612FNG Dual Motor Driver Module - Compatible with but much more efficient than L298N.  This thing now track turns in high gear on carpeting or thick grass without problems.
- 12v LED Lamp switched from GPIO via MJE803 NPN transistor
- Servo Motor switching former manually controlled High/Low gearing knob

To date it has the smoothest variable speed, differential drive, code I have used.  I wish I could say I coded it all, but it was mostly copied from RemoteXY's example wink and modded for my rovers features.

https://remotexy.com/en/examples/car/

I am looking into ways to add in an ESP32Cam (possibly to replace the ESP8266, but limited GPIO might be an issue).  And I would love to see that display streaming in a "new" Web Element in RemoteXY - Hint smile

My full code:

/*
   -- Gunnerator --

   This source code of graphical user interface
   has been generated automatically by RemoteXY editor.
   To compile this code using RemoteXY library 2.4.3 or later version
   download by link http://remotexy.com/en/library/
   To connect using RemoteXY mobile app by link http://remotexy.com/en/download/
     - for ANDROID 4.7.12 or later version;
     - for iOS 1.4.7 or later version;

   This source code is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.
*/

//////////////////////////////////////////////
//        RemoteXY include library          //
//////////////////////////////////////////////

// RemoteXY select connection mode and include library
#define REMOTEXY_MODE__ESP8266WIFI_LIB_POINT
#include <ESP8266WiFi.h>

#include <RemoteXY.h>

// RemoteXY connection settings
#define REMOTEXY_WIFI_SSID "Gunnerator"
#define REMOTEXY_WIFI_PASSWORD "12345678"
#define REMOTEXY_SERVER_PORT 6377


// RemoteXY configurate
#pragma pack(push, 1)
uint8_t RemoteXY_CONF[] =
  { 255,4,0,0,0,82,0,11,24,1,
  5,47,9,39,52,52,93,26,2,2,
  0,35,15,22,11,30,3,2,2,79,
  78,0,79,70,70,0,129,0,6,42,
  18,6,24,72,0,3,130,7,15,22,
  8,6,3,129,0,40,8,12,6,3,
  76,69,68,0,129,0,9,8,18,6,
  3,71,69,65,82,0,129,0,10,18,
  17,7,2,72,32,32,32,76,0 };

// this structure defines all the variables and events of your control interface
struct {

  // input variables
  int8_t joystick_1_x; // =-100..100 x-coordinate joystick position
  int8_t joystick_1_y; // =-100..100 y-coordinate joystick position
  uint8_t switch_1; // =1 if switch ON and =0 if OFF
  uint8_t select_1; // =0 if select position A, =1 if position B, =2 if position C, ...

  // other variable
  uint8_t connect_flag;  // =1 if wire connected, else =0
  uint8_t RemoteXY_isConnected;

} RemoteXY;
#pragma pack(pop)

/////////////////////////////////////////////
//           END RemoteXY include          //
/////////////////////////////////////////////

#include <Servo.h>
#include <SimpleTimer.h>

Servo myservo;
SimpleTimer timer;

int select_prev = 0;

/* defined the right motor control pins */
#define PIN_MOTOR_RIGHT_UP 14
#define PIN_MOTOR_RIGHT_DN 15
#define PIN_MOTOR_RIGHT_SPEED 12

/* defined the left motor control pins */
#define PIN_MOTOR_LEFT_UP 5
#define PIN_MOTOR_LEFT_DN 4
#define PIN_MOTOR_LEFT_SPEED 13

/* defined the LED pin */
#define PIN_LED 2

/* defined the Servo pin */
#define servoPin 0

/* defined two arrays with a list of pins for each motor */
unsigned char RightMotor[3] =
{PIN_MOTOR_RIGHT_UP, PIN_MOTOR_RIGHT_DN, PIN_MOTOR_RIGHT_SPEED};
unsigned char LeftMotor[3] =
{PIN_MOTOR_LEFT_UP, PIN_MOTOR_LEFT_DN, PIN_MOTOR_LEFT_SPEED};

/*
   speed control of the motor
   motor - pointer to an array of pins
   v - motor speed can be set from -100 to 100
*/
void Wheel (unsigned char * motor, int v)
{
  if (v > 100) v = 100;
  if (v < -100) v = -100;
  if (v > 0) {
    digitalWrite(motor[0], HIGH);
    digitalWrite(motor[1], LOW);
    analogWrite(motor[2], v * 2.55);
  }
  else if (v < 0) {
    digitalWrite(motor[0], LOW);
    digitalWrite(motor[1], HIGH);
    analogWrite(motor[2], (-v) * 2.55);
  }
  else {
    digitalWrite(motor[0], LOW);
    digitalWrite(motor[1], LOW);
    analogWrite(motor[2], 0);
  }
}

void setup()
{
  Serial.begin(9600);

  /* initialization pins */
  pinMode (PIN_MOTOR_RIGHT_UP, OUTPUT);
  pinMode (PIN_MOTOR_RIGHT_DN, OUTPUT);
  pinMode (PIN_MOTOR_LEFT_UP, OUTPUT);
  pinMode (PIN_MOTOR_LEFT_DN, OUTPUT);
  pinMode (PIN_LED, OUTPUT);

  myservo.attach(servoPin);

  /* initialization module RemoteXY */
  RemoteXY_Init ();
  RemoteXY.select_1 = 1;

}

void loop()
{
  timer.run();

  /* event handler module RemoteXY */
  RemoteXY_Handler ();

  // Connection Failsafe
  if (RemoteXY_isConnected() == 0) {
    RemoteXY.joystick_1_x = 0; // Set for dead stop
    RemoteXY.joystick_1_y = 0; // Set for dead stop
    // Flash headlamp LED when App not connected.
    digitalWrite(PIN_LED, !digitalRead(PIN_LED));
    delay(500);
  }

  /* manage LED pin */
  digitalWrite(PIN_LED, (RemoteXY.switch_1 == 0) ? LOW : HIGH);

  /* manage the right motor */
  Wheel (RightMotor, RemoteXY.joystick_1_y - RemoteXY.joystick_1_x);
  /* manage the left motor */
  Wheel (LeftMotor, RemoteXY.joystick_1_y + RemoteXY.joystick_1_x);

  /* Manage High/Low gear shifting with timed servo disable to avoid unnecessary current draw and servo chatter */
  if (RemoteXY.select_1 != select_prev) {
    if (RemoteXY.select_1 == 0) {
      myservo.attach(servoPin);
      myservo.write(175); // High gear
      select_prev = RemoteXY.select_1;
      timer.setTimeout(2000L, []() {  // Timer to disengage Servo
        myservo.detach();
      });  // END Timer Function
    } else if (RemoteXY.select_1 == 1) {
      myservo.attach(servoPin);
      myservo.write(0);  // Low gear
      select_prev = RemoteXY.select_1;
      timer.setTimeout(2000L, []() {  // Timer to disengage Servo
        myservo.detach();
      });  // END Timer Function
    }
  }

}
"And voila, which is French for.......'and then I found out.'" - Ready Player One