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:
- 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 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
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
}
}
}