Как запустить TCP-сервер сокетов на Arduino Uno WiFi?

Обновление от 23 марта 2017 г.

Я до сих пор не знаю, почему это так хорошо работает на Юне. Может у него антенна получше? В любом случае, я вернул Uno WiFi и получил вещь SparkFun ESP32. К сожалению, у него та же проблема, что и у Uno WiFi. Чтобы это исправить, я переключился с TCP на UDP. Это имело огромное значение: сервоприводы теперь очень отзывчивы. UDP подходит для моего случая использования: я могу отправлять состояние всей системы в каждом сообщении, и потеря сообщений или сообщения, поступающие не по порядку, не являются большой проблемой.

Оригинальный вопрос

Я хочу управлять сервоприводами через Wi-Fi с высокой точностью и низкой задержкой. Мне удалось добиться этого, используя TCP-сокет связи с Arduino Yun. Я хочу повторить это с Arduino Uno WiFi, но не могу найти пример кода для связи через сокет. Я подключился к плате через telnet, но выход сервопривода прерывистый — как будто после каждого вызова servo.write была задержка.

Как запустить TCP-сервер сокетов на Arduino Uno WiFi таким образом, чтобы обеспечивает быструю связь с низкой задержкой?

Подробное описание

Я экспериментировал с управлением сервоприводами через Wi-Fi, используя плату Arduino Yun, которую одолжил у друга. Я подключил сервопривод MG92B к контактам 9, 5 В и GND. Я запускаю TCP-сервер сокетов на Arduino и отправляю значения угла из скрипта Python десятки раз в секунду. Работает плавно.

Воодушевленный этим экспериментом, я купил себе Arduino. Я выбрал Arduino Uno WiFi (версия для разработчиков), потому что, в отличие от Yun, он совместим с шилдами. К сожалению, я не могу найти пример кода для связи через сокеты. Я нашел пример, использующий telnet, поэтому я адаптировал его и использовал со своим скриптом Python. К сожалению, движение сервопривода прерывистое — как если бы после каждого вызова servo.write была задержка.

Ниже приведено видео, на котором на обеих досках показаны два скетча: «нет движения сети» и «движение сети».

Видео

Код

Я прилагаю весь код, который использовал.

Тест колебаний Arduino без пульта дистанционного управления

Я использую этот код, чтобы проверить правильность работы сервопривода. Он работает как на Arduino Yun, так и на Arduino Uno WiFi.

#include <Servo.h>


const int servoPin = 9;
Servo servo;


void setup() {
    servo.attach(servoPin);
}


void loop() {
    // настраиваем движение
    int angleMin = 15;
    int angleMax = 165;
    int interval = 30;

    // колебаться между angular_min и angular_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);
        }
    }
}

Чтение Wi-Fi Arduino Uno через telnet

Это ерунда.

#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 Yun читает из сокета

Это нормально.

#include <Bridge.h>
#include <Servo.h>
#include <YunClient.h>
#include <YunServer.h>


// настройка
const int port = 5555;
const int servoPin = 9;

// слушаем данный порт
Servo servo;
YunServer server(port);


void setup() {
    // настраиваем сервопривод
    servo.attach(servoPin);

    // запускаем сервер
    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 в сокет

Это сетевой эквивалент теста колебаний Arduino. Работает как с Yun (порт 5555), так и с Uno (порт 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)

, 👍3


1 ответ


1

Я подозреваю, что эти задержки вызваны буферизацией TCP.

Чтобы получить некоторую теорию по этому поводу, возможно, прочитайте Алгоритм Нэгла, который охватывает некоторые проблемы с буферизация небольших пакетов. Мне кажется разумным, что платы с меньшим энергопотреблением и/или меньшей скоростью (или даже «просто другие») будут использовать более агрессивную буферизацию.

TCP использует все виды буферизации и проверок, чтобы гарантировать гарантированную доставку данных (или сообщение об ошибке), тогда как UDP этого не делает.

Если у вас работает UDP, возможно, вы захотите включить в протокол связи некоторые собственные функции отслеживания ошибок, если только отсутствие нечетного пакета не является проблемой для вашей системы управления.

,