After viewing the plans for a 3D-printed Jeep Rancher on the 3DSets.com website I decided it would be a perfect project for my grandson and I (but really for me). The.stl files and instructions supplied by 3DSets.com are near perfect particularly for original Prusa printers and a real value at $30.00.
I don't know a thing about RC (radio controlled) gear. It's a hobby I have never explored. As I investigated the part for RC controlled vehicles I got intimidated by the wide assortment of transmitters, receivers, esc's (electronic speed controllers) and motors involved in RC. I also don't have a group of RC knowledgeable people around that I could rely on for advice.
Rather than investing in a traditional RC hardware I decided to create my own using Blynk on my iPhone as the 'remote control' and a Wemos D1 Mini and Cytron MD13S as the receiver/motor controller onboard the Jeep. I knew from other projects I have made that I could make this work. I just wasn't sure if I could make it small enough to fit in the same area as the 3D Sets Jeep designers had set aside for the RC hardware.
Desired features for the electronics: 3DSets evolved the Jeep's design during my development of the electronics. The original build had only one motor, a 21T, 540 high torque brushed dc motor providing the forward and reverse motion. It requires a high current reversible motor controller. During my design process 3DSets added a winch for the front bumper. It is specified as a 3-5V geared to 150 rpm. It also requires a separate reversible controller. The steering is actuated by a 180 degree servo. The suggested battery for this project is a 2S Shorty Lipo 7.4V 100C 4600 mAh hardcase. To be safe I used BEC's (battery elimination circuits) for the microcontroller and motor controller. I also wanted a circuit to monitor the charge level of the battery to protect it from over-discharge. Since it was possible that I would operate the Jeep in a location where cellular internet service was unavailable I decided to host the communication between the iPhone and Jeep with a Blynk local server on a Raspberry Pi.
The First DesignIn my initial design I used parts I had in the parts bin so I could learn about the requirements for motor controllers. This was also going to be my first time incorporating a servo for steering and I needed to learn about that too. I started with an Arduino Nano to make the footprint as small as possible, an HM-10 bluetooth radio, 5V mini buck, and PCA8695 servo controller. I also had a L298 Dual H-Bridge controller that I though might drive the motor.
I set everything up on the bench with a spare low current motor and a 270 degree servo so that I could start coding and getting the bluetooth, battery monitor and Blynk set up. One of the things I learned right away is that the Arduino Nano and HM-10 bluetooth would not allow me to send battery status data from the hardware to Blynk without crashing. At this point I had everything working as it should but I needed a work-around for the battery status
.When I received the 21T 540 brushed motor I wired it up. The L298 H-bridge would not turn this big motor. I started searching for an alternative and settled on the Cytron MD13S. It is spec'd at 13A continuous and 30A peak and is only ~$13. It turns out this controller works great. It's relatively small, reversible and easy to code. At this point I decided to hardwire everything in a package I could fit into the Jeep. It required me to remove the back seat and use that space for the electronics.
During the development of the electronics the designers at 3D added a front bumper mounted winch to the Jeep. This required an additional motor controller. I decided on an Adafruit DRV8871 motor driver breakout board.
I also learned in the bench test that the HM10 bluetooth and Arduino Nano could not communicate the battery voltage back to the Blynk interface.
With this I decided to redesign the electronics package to include a battery voltage measurement circuit that would readout on a 2 x 16 LCD. The redesign also included the second motor driver for the winch - The Blynk interface is shown in the beginning of the video. It uses a slider switch for the motor speed, a three segment switch for motor direction and a joystick for steering.
While I was able to acheive my design goals with the Arduino Nano and Blynk via bluetooth the electronics module occupied the entire area behind the front seats. In addition the Arduino - HM-10 combination did not have the horsepower to communicate the battery data to the Blynk app. Given the dimensions of a Wemos D1 mini, the Cytron and Adafruit motor controllers it appeared that I could get them to fit under the front seat in the area the designers set aside for the RC- ESC. With the code functional I began exploring the design using the Wemos. the parts are wired as shown in Figure-2.
The Wemos D1 mini uses the ESP8266 chip and has WiFi on board. The Wemos can be programmed via the Arduino IDE. The instructions for setting up the Arduino IDE for the ESP8266 are here. This allows coding and uploading sketches in the same way as an Arduino.
The BLYNK interface is set-up as shown in figures 1-10.
The Wemos sketch and the Blynk interface are very interactive. When the segmented switch STOP buttons are pressed the Wemos sketch turns the STOP segment red and stops the motors. It also resets the slider switch speed to 0 and stops the motor. When the segmented switch FORWARD, REVERSE, UNWIND or REWIND segments are selected the Wemos sketch turns them green. The battery status meters are also color coded. When the battery condition is acceptable the meters are green. As the battery charge declines they turn yellow. When the battery needs recharging they turn red. The sketch does not lock out the drive motor when it drops below a certain voltage but that could be added. I did not add this as the drive motor load will cause the meters to turn red, i.e the battery voltage will drop below 6.7 volts but will quickly recover. Some user judgement is required to decide when to stop and recharge the battery.
Figure 11 shows the settings on the Arduino IDE.
The ESP8266 has an ADC built-in with a 1.0v maximum voltage. The Wemos has a voltage divider with R1=220 and R2=100 on Pin A0. The Wemos ADC has 10 bit resolution for an output range of 0 - 1023. For 3.3 V on A0 the divider yields 1.023V. A fully charged LiPo yields 8.4V. Adding 520K (I used 300K+100K+100K+20K precision resistors in series) to R1 with 8.3V yields 0.99V at A0. (I use 8.3 in my calculation to get better agreement with my voltmeter and batteries) The sketch displays three meters on the Blynk interface. One displays the analog reading variable named BitVoltage, the second is the analog reading (BitVoltage) converted to voltage. The third is percent battery charge remaining. The Blynk interface displays will change color as the voltage drops. When they are RED it's time to recharge.
This project was my first attempt at using a Blynk local server. It took a few false starts to get it going but was worth the effort. The Blynk local server eliminates the cellular wifi latency which was an annoyance in operating the Jeep. I did the development on a Raspberry Pi 4 since it is the fastest of the Pi's and makes the booting, downloading and installation go faster. The Blynk local server will run on a Pi 3 or Pi Zero - W.
The first step is to install the latest version of Raspian OS on your Raspberry Pi. Downloads and installation instructions can be found here - RASPIAN DOWNLOADS. The desktop versions make the installation a little easier but are not necessary. The headless versions will boot faster and will extend battery life but can make life a little easier for the gui fans.
The second step in the set-up is to install the Blynk local server. There is an installation guide here - BLYNK LOCAL SERVER INSTALLATION.
The Blynk local server guide is set up for Java 8. If your version of Raspian comes with Java 11 you may have to adjust the commands in the installation guide:
Start by updating the repository listing:
sudo apt-get update
To check the Java version:
java -version
Java 8 Blynk Local Server install:
wget https://github.com/blynkkk/blynk-server/releases/download/v0.41.11/server-0.41.11-java8.jar
Java 8 Blynk Start Local Server:
java -jar server-0.41.11-java8.jar -dataFolder /home/pi/Blynk
Java 11 Blynk Local Server install:
wget https://github.com/blynkkk/blynk-server/releases/download/v0.41.11/server-0.41.11.jar
Java 11 Blynk Start Local Server:
java -jar server-0.41.11.jar -dataFolder /home/pi/Blynk
You will need to make similar adjustments to the commands for starting the server on boot, etc shown in the quide.
The third step involves configuring the Raspi as an ACCESS POINT. An excellent guide is available here - RASPI ACCESS POINT. This guide also teaches setting up the access point as a bridge. STOP when you get the bridge setup in the procedure. REMINDER - once the access point is set up, you can see it and connect to it on your phone, laptop or other wifi device that is within range. Try it with your phone at this point. You can also ssh into it from your laptop.
On an iPhone go to Settings>WIFI>My Networks and select the access point as configured in step 2.
Now open the Blynk app.
The logon name is: admin@blynk.cc
Password: admin
On the lower part of the screen is rectangular button with three dots in it(see figure 11). Press this button and move the switch to Custom. In the long box below the switch enter the ip address you set in the access point setup and port 9443 in the smaller box. Press ok and the Blynk app will connect to the Blynk server.
With a successful logon use the QR code in figure 12 to load the Jeep Blynk interface. Press the QR Code button in the green bar at the top of the screen. The camera will open and point it at the QR Code. The interface will load. In this process an 'auth code' will be generated for the interface.
The last step is to upload the code to the Wemos. The code is below (the latest code is here - https://github.com/jlmyra/JEEP_Wemos_BLYNK):
// JEEP_Wemos_Blynk_WiFi_Cytron_Motor_Controller_Adafruit_Motor_Controller
//#define BLYNK_DEBUG // Optional, this enables lots of prints
#define BLYNK_PRINT Serial
//****************STEERING SERVO*************************/
//Servo on GPIO 13 = Wemos Pin D7
#include <Servo.h>
Servo steerServo;
int ServoMin = 65;
int ServoMax = 130;
//****************END STEERING SERVO*************************/
//****************Battery Voltage Alarm******************************/
float bitVoltage; //ADC converted voltage on batPin A0
float batteryVoltage; //computed battery voltage
int batRemPercent;
const int batPin = A0; //GPIO - ADC0 variable that holds analog pin 0
unsigned long previousMillis = 0; //for timer reading A0
unsigned long interval = 5000; // millis between read A0
//****************END Battery Voltage Alarm******************************/
//**************** BLYNK - ESP8266 - WiFi-Local Server ******************/
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
// Your WiFi credentials.
// Set password to "" for open networks.
char auth_2[] = "XXXXXXXXXXXXXXXXXXXXX";//Blynk Auth Code
char ssid_2[] = "XXXXXXX"; //Raspi WIFI SSID
char pass_2[] = "XXXXXXXXXXX"; //Raspi WIFI Password
//define colors for Blynk interface
#define BLYNK_GREEN "#23C48E"
#define BLYNK_BLUE "#04C0F8"
#define BLYNK_YELLOW "#ED9D00"
#define BLYNK_RED "#D3435C"
#define BLYNK_DARK_BLUE "#5F7CD8"
//**************** END BLYNK - WiFi *************************/
//********************MOTOR***********************************/
#define DIR 5 //GPIO5 = Wemos D1- Cytron yellow wire
#define PWM 4 //GPIO4 = Wemos D2- Cytron white wire
int motorSpeed = 0; // Variable for motor rotation speed set by Blynk Slider
const int slideState = 0; //Variable for motor rotation speed
uint8_t switchState = 0; //Variable for Blynk segmented switch (V0)
//********************END MOTOR*******************************/
//********************WINCH Adafruit DRV8871 Motor Driver********************/
#define winchDIR1 0 //GPIO 0 = Wemos D3 Winch Motor + (IN1)
#define winchDIR2 2 //GPIO 2 = Wemos D4 Winch Motor - (IN2)
int winchSpeed = 0; // Variable for motor rotation speed set by Blynk Slider
uint8_t winchStop = 0; // Variable for motor speed in stop condition
const int winchSlideState = 0; //for restting the slider to 0 on change
uint8_t winchState = 0; //Variable for Winch Segmented switch position
//********************END WINCH Adafruit DRV8871 Motor Driver****************/
void setup(){
Serial.begin(115200);
Blynk.begin(auth_2, ssid_2 , pass_2, IPAddress(192,168,4,1), 8080); //START BLYNK
pinMode(PWM,OUTPUT); //Set Wemos D2 PIN to OUTPUT (Cytron White Wire)
pinMode(DIR,OUTPUT); //Set Wemos D1 PIN to OUTPUT (Cytron Yellow Wire)
pinMode(winchDIR1,OUTPUT); //Set Wemos D3 PIN to OUTPUT
pinMode(winchDIR2,OUTPUT); //Set Wemos D4 PIN to OUTPUT
pinMode (A0, INPUT); //ADC 0 Set voltage read pin A0 to input
steerServo.attach(13);//Wemos Pin D7 = GPIO 13
//Inialize Blynk Motor Segmented Switch to Stop, Red and Slider to 0
Blynk.setProperty(V0, "color", BLYNK_RED);
Blynk.virtualWrite(V0, 2);
Blynk.syncVirtual(V0);
Blynk.virtualWrite(V1, 0);
Blynk.syncVirtual(V1);
//Inialize Blynk Winch Segmented Switch to Stop, Red and Slider to 0
Blynk.setProperty(V4, "color", BLYNK_RED);
Blynk.virtualWrite(V4, 2);
Blynk.syncVirtual(V4);
Blynk.setProperty(V3, "color", BLYNK_GREEN);
Blynk.virtualWrite(V3, 0);
Blynk.syncVirtual(V3);
}
void loop(){
Blynk.run();
computeBatteryVoltage();
}
//** V2 BLYNK Read JOYSTICK position and adjust steering Servo Position******/
BLYNK_WRITE(V2) {
int joystick_Pos;
int x_position = param[0].asInt(); //uses joystick x position for steering left/right
joystick_Pos = map(x_position, 0, 1023, ServoMin, ServoMax); //map joystick Blynk values to servo values
steerServo.write(joystick_Pos);
Serial.print("x_Position= "); Serial.print(x_position); Serial.print(" joystick_Pos= ");
Serial.println(joystick_Pos);
}
//* END V2 BLYNK Read JOYSTICK position and adjust steering Servo Position***/
//*** V1 Read Blynk SLIDER SWITCH and Convert to MOTOR SPEED Variables****/
BLYNK_WRITE(V1) {
motorSpeed = param.asInt(); // assigning incoming value from pin V1 to a variable for Motor Speed (0-255)
// this value is used in the stateMachine function
Serial.print("V1 Slider value is: "); Serial.println(motorSpeed);
if (switchState == 1){
analogWrite(PWM, motorSpeed); // Send PWM signal to motor
digitalWrite(DIR, HIGH);
}
else if (switchState == 2){
analogWrite(PWM, 0); // Send PWM signal to motor
digitalWrite(DIR, LOW);
}
else if (switchState == 3){
analogWrite(PWM,motorSpeed); // Send PWM signal to motor
digitalWrite(DIR, LOW);
}
}
//*** END V6 Read Blynk SLIDER SWITCH and Convert to MOTOR SPEED Variables***/
//************* V0 BLYNK THREE SEGMENT SWITCH Vehicle Direction *************/
BLYNK_WRITE(V0) {
switchState = (param.asInt()); // Get Switch state value 1 = Forward, 2 = Neutral, 3= Reverse switch (switchState){ //From BLYNK_WRITE(V3) switchState = 1, 2 or 3 on Blynk App
Serial.print ("Switchstate= "); Serial.println (switchState);
Blynk.virtualWrite(V1, 0);
switch (switchState) {
case 1: // FORWARD
analogWrite(PWM, 0);// Send PWM signal to motor
Blynk.setProperty(V0, "color", BLYNK_GREEN);
Blynk.virtualWrite(V1, 0);
break;
case 2: // NEUTRAL
analogWrite(PWM, 0); // Set motor speed to 0
Blynk.setProperty(V0, "color", BLYNK_RED);
Blynk.virtualWrite(V1, 0);
break;
case 3: // REVERSE
analogWrite(PWM, 0); // Send PWM signal to motor
Blynk.setProperty(V0, "color", BLYNK_GREEN);
Blynk.virtualWrite(V1, 0);
break;
}
}
//*************END V7 BLYNK THREE SEGMENT SWITCH Vehicle Direction***********/
//********** V8 Read Blynk WINCH SLIDER SWITCH and Convert to Winch WIND Speed Variables*********/
BLYNK_WRITE(V3) {
winchSpeed = param.asInt(); // assigning incoming value from pin V3 to a variable for Motor Speed (0-1023)
// this value is used in the stateMachine function
if (winchState == 1){
analogWrite(winchDIR1, 0);
analogWrite(winchDIR2, winchSpeed); // Send PWM signal to motor
}
else if (winchState == 2){
analogWrite(winchDIR1, 0);
analogWrite(winchDIR2, 0);
//analogWrite(winchDIR1, winchStop); // Set motor speed to 0
}
else if (winchState == 3){
analogWrite(winchDIR1, winchSpeed);
analogWrite(winchDIR2, 0); // Send PWM signal to motor
}
Serial.print("V3 winch Slider value is: ");
Serial.println(winchSpeed);
}
//********** END V8 Read Blynk WINCH SLIDER SWITCH and Convert to Winch WIND Speed Variables*********
//**************V9 Blynk Read SEGMENTED SWITCH for WINCH*******************
BLYNK_WRITE(V4) {
winchState = (param.asInt()); // Get Switch state value 1 = Forward, 2 = Neutral, 3= Reverse
Serial.print ("Winchstate= "); Serial.println (winchState);
Blynk.virtualWrite(V3, 0);
switch (winchState){ //From BLYNK_WRITE(V5) winchState = 1, 2 or 3 on Blynk App
case 1: // Unwind
Blynk.virtualWrite(V3, 0);
analogWrite(winchDIR1, 0);
analogWrite(winchDIR2, 0); // Send PWM signal to motor
Blynk.setProperty(V4, "color", BLYNK_GREEN);
break;
case 2: // Stop
Blynk.virtualWrite(V3, 0);
analogWrite(winchDIR1, 0);
analogWrite(winchDIR2, 0);
//analogWrite(winchDIR1, winchStop); // Set motor speed to 0
Blynk.setProperty(V4, "color", BLYNK_RED);
break;
case 3: // RE-Wind
Blynk.virtualWrite(V3, 0);
analogWrite(winchDIR2, 0);
analogWrite(winchDIR1, 0); // Send PWM signal to motor
Blynk.setProperty(V4, "color", BLYNK_GREEN);
break;
}
}
//*************Battery Voltage*************
// The max voltage to ESP8266 A0 is 1.0V. The WEMOS has a voltage divider built-in that has
// R1=220 and R2=100. For 3.3 V on A0 the divider yields 1.023V. A fully charged LiPo yields 8.4V.
// Adding a 300K+100K+100K+20K to R1 with 8.3V yields 0.99V at A0. (I use 8.3 in my calculation to get
// better agreement with my voltmeter and batteries) The BLYNK interface displays will change color as
// the voltage drops. When RED it's time to recharge.
//********************Send Battery Voltage to BLYNK interface*********
BLYNK_READ(V5) { //BLYNK Virtual Pin V5 - BitVoltage Meter
if(bitVoltage > 920) {
Blynk.setProperty(V5, "color", BLYNK_GREEN);
Blynk.virtualWrite(V5, bitVoltage);
}
else if(bitVoltage <= 920 && bitVoltage > 820 ) {
Blynk.setProperty(V5, "color", BLYNK_YELLOW);
Blynk.virtualWrite(V5, bitVoltage);
}
else if(bitVoltage < 820 ) {
Blynk.setProperty(V5, "color", BLYNK_RED);
Blynk.virtualWrite(V5, bitVoltage);
}
}
BLYNK_READ(V6) { //BLYNK Virtual Pin V6 - Battery Meter
if(batteryVoltage > 7.5) {
Blynk.setProperty(V6, "color", BLYNK_GREEN);
Blynk.virtualWrite(V6, batteryVoltage);
}
else if(batteryVoltage <= 7.5 && batteryVoltage >= 6.7) {
Blynk.setProperty(V6, "color", BLYNK_YELLOW);
Blynk.virtualWrite(V6, batteryVoltage);
}
else if(batteryVoltage <6.7 ) {
Blynk.setProperty(V6, "color", BLYNK_RED);
Blynk.virtualWrite(V6, batteryVoltage);
}
}
BLYNK_READ(V7) { //BLYNK Virtual Pin V7 - Battery Meter
if(bitVoltage > 920 ) {
Blynk.setProperty(V7, "color", BLYNK_GREEN);
Blynk.virtualWrite(V7, batRemPercent);
}
else if(bitVoltage <= 920 && bitVoltage >= 820) {
Blynk.setProperty(V7, "color", BLYNK_YELLOW);
Blynk.virtualWrite(V7, batRemPercent);
}
else if(bitVoltage < 820) {
Blynk.setProperty(V7, "color", BLYNK_RED);
Blynk.virtualWrite(V7, batRemPercent);
}
}
//*********************END Send Battery Voltage to BLYNK interface*********
//*************************compute Battery Voltage function***********************
void computeBatteryVoltage(){
unsigned long currentMillis = millis(); //set the current time
if (currentMillis - previousMillis > interval) { //check to see if the interval has been met
previousMillis = currentMillis; //reset the time
bitVoltage = analogRead(A0); // read the ADC voltage on Pin A0
batteryVoltage = 8.3 * bitVoltage / 1023; //Convert the ADC voltage to actual voltage
batRemPercent = map(bitVoltage, 820, 1023, 0, 100); //Map ADC voltage to percent
Serial.print ("bitVoltage= "); Serial.print (bitVoltage); Serial.print("\t"); Serial.print("batteryVoltage= ");
Serial.println (batteryVoltage);
}
}
//************************compute Battery Voltage function***********************
/********************* THANKS TO: ***********************
-Steering Servo Tutorial inspiring the servo code -
https://dronebotworkshop.com/servo-motors-with-arduino/
-Cytron MD13S Motor Controller Guide-
https://docs.google.com/document/d/1icu1GVDxZhUn3ADSUc3JknNcmUMdPcsnJ4MhxOPRo-I/view
Battery Voltage Monitor Inspiration-
https://arduinodiy.wordpress.com/2016/12/25/monitoring-lipo-battery-voltage-with-wemos-d1-minibattery-shield-and-thingspeak/
************************BLYNK****************************
Download latest Blynk library here:
https://github.com/blynkkk/blynk-library/releases/latest
Blynk is a platform with iOS and Android apps to control
Arduino, Raspberry Pi and the likes over the Internet.
You can easily build graphic interfaces for all your
projects by simply dragging and dropping widgets.
Downloads, docs, tutorials: http://www.blynk.cc
Sketch generator: http://examples.blynk.cc
Blynk community: http://community.blynk.cc
Follow us: http://www.fb.com/blynkapp
http://twitter.com/blynk_app
Blynk library is licensed under MIT license
This example code is in public domain.
*************************************************************/
With the code loaded the WEMOS will connect to the server as well as enabling control of the Jeep.
The amazing thing about the Blynk server is that it con host multiple Blynk devices. At this time I have connected two vehicles to the server and can control both of them with separate IOS devices.
In closing I want to thank everyone who has shared code, tips and advice on similar projects. Without the virtual help I have received and incorporated in this project I would never have been successful. So, Thank-you. I also invite your feedback. If you have ideas to make this process easier please share them in the comments. If you have questions I will try to answer them.
Good LucK!
Comments