2017-03-23 update
I still don't know why it works so well on Yún. Maybe it has a better antenna? Anyway, I've returned Uno WiFi and got a SparkFun ESP32 Thing. Unfortunately, it has the same problem as Uno WiFi. To fix it I've switched from TCP to UDP. It made a world of difference: servos are very responsive now. UDP is OK for my use case: I can send the state of the whole system in each message and lost messages or messages arriving out of order are not a big problem.
Original question
I want to control servos over WiFi with high precision and low latency. I managed to achieve this using TCP socket communication with Arduino Yún. I want to repeat this with Arduino Uno WiFi, but I can't find example code for socket communication. I connected to the board using telnet but servo output is jerky — as if there was a delay after each servo.write call.
How can I run a TCP socket server on Arduino Uno WiFi in a way that allows for fast low latency communication?
Longer description
I experimented with controlling servos over WiFi using an Arduino Yún board that I borrowed from a friend. I connected a MG92B servo to pin 9, 5V, and GND. I start a TCP socket server on the Arduino and send angle values from a Python script dozens of times per second. It works smoothly.
Encouraged by this experiment I bought my own Arduino. I chose Arduino Uno WiFi (developer edition) because, unlike Yún, it's compatible with shields. Unfortunately I can't find example code for socket communication. I found an example that uses telnet, so I adapted it and used it with my Python script. Sadly, the servo movement is jerky — as if there was a delay after each servo.write call.
Below is a video showing both boards running two sketches: "no network movement" and "network movement".
Video
Code
I attach all code I used.
Arduino oscillation test with no remote control
I use this code to test that the servo is working correctly. It works on both Arduino Yún and Arduino Uno WiFi.
#include <Servo.h>
const int servoPin = 9;
Servo servo;
void setup() {
servo.attach(servoPin);
}
void loop() {
// configure movement
int angleMin = 15;
int angleMax = 165;
int interval = 30;
// oscillate between `angle_min` and `angle_max`
int angle = angleMin;
for (int i = 0; i < 2; i = (i + 1) % 2) {
int sign = pow(-1, i);
for (int j = 0; j < angleMax - angleMin; j += 1) {
angle += sign;
servo.write(angle);
delay(interval);
}
}
}
Arduino Uno WiFi reading from telnet
This is jerky.
#include <Servo.h>
#include <UnoWiFiDevEd.h>
const int servoPin = 9;
Servo servo;
void setup() {
Wifi.begin();
servo.attach(servoPin);
}
void loop() {
while (Wifi.available()) {
servo.write(Wifi.read());
}
}
Arduino Yún reading from socket
This is smooth.
#include <Bridge.h>
#include <Servo.h>
#include <YunClient.h>
#include <YunServer.h>
// configure
const int port = 5555;
const int servoPin = 9;
// listen on given port
Servo servo;
YunServer server(port);
void setup() {
// set up servo
servo.attach(servoPin);
// start server
Bridge.begin();
server.noListenOnLocalhost();
server.begin();
}
void loop() {
YunClient client = server.accept();
byte angle;
if (client) {
while (client.connected()) {
angle = client.read();
if (angle != 255) {
servo.write(angle);
}
}
client.stop();
}
Serial.println("waiting for client");
delay(1000);
}
Python writing to socket
This is the network equivalent of the Arduino oscillation test. Works both with Yún (port 5555) and Uno (port 23).
import socket
from time import sleep
# connect
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('192.168.240.1', 5555)) # use 5555 for Yun and 23 for Uno
# configure movement
angle_min = 15
angle_max = 165
interval = 30 / 1e3
# oscillate between `angle_min` and `angle_max`
while True:
angle = angle_min
for sign in [1, -1]:
for _ in range(angle_max - angle_min):
angle += sign
client.send(bytearray([angle]))
sleep(interval)
