I'm trying to make a wifi controlled tank.
I use the nodemcu v3 with a build in esp8266 that I try to control with a Unity app.
When I tried to send commands as fast as possible, I could barely do 20 get commands per second, and those were very inconsistent. How can I program/control the tank with fast response time and good reliability? I know that the mavic mini has good wifi controls, so that makes me think that it is possible. I'm very new to programming Arduino and I couldn't find anything online.
I would be glad with anything you can tell me, to help me understand. Thanks in advance.
ps. this is my first post.
This is my test code on the nodemcu v3:
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
char * ssid_ap = "remoteTank";
char * password_ap = "remoteTank";
IPAddress ip(192,168,4,1);
IPAddress gateway(192,168,4,2);
IPAddress subnet(255,255,255,0);
ESP8266WebServer server;
WiFiClient client;
long timePast;//Time between the two lates client requests
bool allowedToDrive;
unsigned long previousMillis = 0;
long interval = 1000;
bool isConnected;
void setup(){
WiFi.mode(WIFI_AP);
WiFi.softAPConfig(ip,gateway,subnet);
WiFi.softAP(ssid_ap,password_ap);
Serial.begin(115200);
Serial.println();
Serial.print("IP Adress: "); Serial.println(WiFi.localIP());
//server.on("/",handleIndex);
server.on("/connectionCheck", connectionCheck);
server.begin();
}
void loop(){
server.handleClient();
failSafe();
}
/*void handleIndex() {
server.send(200,"text/plain",String(interval));
}*/
void connectionCheck(){
timeChange();
server.send(200,"text/plain","CheckingConnection");
}
//Set timePast to the time between the two latest client requests
void timeChange(){
unsigned long currentMillis = millis();
timePast = currentMillis - previousMillis;
previousMillis = currentMillis;
}
void failSafe(){
if(client.connected() && timePast < interval){
isConnected = true;
}
else{
isConnected = false;
}
}
and here my code in Unity:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
using TMPro;
public class CheckConnection : MonoBehaviour
{
public GameObject colorImage;
private Image image;
public float waitTime;
public bool allowCommandSending;
// Start is called before the first frame update
void Start()
{
image = colorImage.GetComponent<Image>();
StartCoroutine(SendCheckConnection());
}
IEnumerator SendCheckConnection()
{
while (true)
{
UnityWebRequest www = UnityWebRequest.Get("192.168.4.1/connectionCheck");
www.timeout = 1;
yield return www.SendWebRequest();
if (www.isNetworkError || www.isHttpError)
{
image.color = new Color32(150, 24, 45, 255);
Debug.Log("Set color to red");
waitTime = 3f;
}
else
{
image.color = new Color32(47, 97, 150, 255);
Debug.Log("Set color to blue");
waitTime = 0.5f;
}
yield return new WaitForSeconds(waitTime);
}
}
}
The HTTP protocol introduces a lot of overhead which is the probable cause for the delays and inconsistensies. You could try to use datagram sockets (UDP) instead, alternatively you could use TCP in order to maintain a continuous connection between devices.
I doubt very much if it is necessary to send messages more often than 5 per second. Apart from anything else, you need to allow time for the machinery of the tank to respond.
ESP8266 offers the ESP-NOW protocol. Which can transfer up to 250 bytes within a few milliseconds.
I made a test of how fast it can be
a first ESP8266 sends 128 bytes to the a second ESP8266 receiver. The receiver checks a certain byte and switches an IO-pin On/off
You could call this a remotely created PWM-signal. It was around 250 Hz. The downside is ESP-NOW is special to
ESP8266 and ESP32. So your remote-control must be the a second ESP8266 or ESP32
And ESP-NOW can't be used in parallel with a standard WiFi-connection.
If your RC-tankvehicle should drive and react quick there is nothing better than a classical 2,4 GHz RC remote-control. As your tank can't drop out of the sky or crush into a wall at high-speed a really cheap RC-remote-control from Hobbyking will do.
A 9 channel RC- remote-control inclusive a receiver is about $35
200ms is a long time delay for an input. It would feel significantly less direct. 250hz might be overkill but I come here to learn about all the possibilities. I would be satisfied with a constant reliable connection with 20 messages per second. Even with a reaction time test I got under 200ms on my second try.
Robin2:
And if 200ms is a bit unresponsive, what about 150 or 100? There is nothing to be gained by overwhelming the car with new data.
An "update-rate" at 5hz will certanly feel sluggish for small adjustmets and if the mechanism is fast, 5hz will be unacceptable. Try to play a computer-game with an input lag of 200ms - that's gonna get frustrating very fast.
Even if the update-rate is too fast for the mechanism to handle, un-processable messages can be dropped. If the messages contain absolute control positions and not "1 step to the left"-commands, the tank can read all incoming messages and only process the last. That should ensure the best responsiveness possible.
Even if UDP is not the optimal sollution (LoRa, NRF), it will allow the tank to be controlled by most network-enabled devices from (almost) anywhere on the planet.
ESP-NOW-sender send variable IO_state with value "1"
ESP-NOW-receiver receives the data
if (IO_state == 1) {
digitalWrite(Testpin,HIGH);
}
else {
digitalWrite(Testpin,HIGH,LOW); **// corrected **
}
So everytime the variable has value 0 set IOpin low
everytime the variable has value 1 set IOpin HIGH
the ESP-NOW-Sender sends his data all the time every few milliseconds with alternating IO-state.
The ESP-NOW-receiver switches an IO-pin depending on the received value
In this way it is a remote-PWM because the sender sends his data in a regular way every 2 milliseconds
Robin2:
The OP is not trying to play a computer game - he is trying to control a physical machine that has inertia and momentum.
...R
Well, I do aim to get response time like in games(20+hz would do the trick probably). If I rotate the tank to aim at something I Wouldn't like the tank to keep rotating for another 200ms after releasing the rotation input. Lets say I rotate the tank with a speed of 1 full rotation per second then 200ms would equal 72 degrees.
Robin2:
The OP is not trying to play a computer game
True that, but I would still prefer a protocol which delivers "too much" and being able to throttle it programmatically than I would have a protocol which is generally too slow at its fastest.
Danois90:
True that, but I would still prefer a protocol which delivers "too much" and being able to throttle it programmatically than I would have a protocol which is generally too slow at its fastest.
My approach to this would be to start with a 5 Hz update rate and only increase it if it proved necessary. Start simple.
gerwonpro:
If I rotate the tank to aim at something I Wouldn't like the tank to keep rotating for another 200ms after releasing the rotation input.
I doubt if you could tell the difference. And unless you have a camera that rotates with the gun and gives you a real-time view of where the gun is pointing the position at which you release the button will have a large measure of error in any case.
Or just release the button 200ms early
To my mind this is a case of the best being the enemy of the good.