Подключить Arduino Uno к веб-серверу видеокамеры через Ethernet (не работает)

Я работаю с камерами в кино- и телеиндустрии. Недавно я начал работать над проектом, связанным с созданием устройства на базе Arduino Uno, которое будет автоматически собирать метаданные (настройки и т.д.) через встроенный веб-сервер камеры (по крайней мере, сейчас через Ethernet). Речь идёт о камере Arri Alexa.

Как я уже говорил, эта камера уже имеет веб-сервер и встроенную функцию, позволяющую напрямую подключить компьютер к камере с помощью кабеля Ethernet (на самом деле используется разъём RJ45 — фирменная кабельная система Lemo для поддержки некоторых аксессуаров, потребляющих больше энергии, чем RJ45). Затем, когда вы вводите IP-адрес камеры в веб-браузере, открывается веб-страница со всеми настройками камеры и другими данными.

Я обнаружил, что мой тестовый компьютер идеально подключился к камере без каких-либо изменений в сетевых настройках, как, похоже, указано в документации производителя. Вот основные сетевые настройки моего компьютера при прямом подключении к камере через Ethernet (Arduino пока не было):

Настройки IPConfig

Обратите внимание на IP-адрес и маску подсети: 169.254.106.46 и 255.255.0.0 соответственно.

Просто отмечу, что это рекомендуемые производителем настройки, которые я нашел в некоторой литературе:

Поскольку всё работало, я протестировал Arduino с теми же настройками. Я использую Arduino Uno в сочетании с Seeed Ethernet Shield (v2.0), который использует процессор Wiznet 5200 (а не 5100, как обычно). Поэтому вместо стандартной библиотеки Ethernet необходимо использовать библиотеку Ethernetv2_0, предоставляемую Seeed.

Вот мой код, по сути, адаптированная версия примера WebClientRepeating. Он заработал, когда я просто подключался, скажем, к arduino.cc, и соединение проходило через концентратор моего маршрутизатора (IP-адрес был назначен автоматически). Однако, когда я пытаюсь подключиться к камере с помощью Arduino без концентратора/коммутатора, с назначенным вручную IP-адресом, маской подсети и всем прочим, я не могу заставить клиент (объект) подключиться. По сути, этот код выводит сообщение «connection failed» на последовательный монитор, указывая, что соединение так и не было установлено.

#include <SPI.h>
#include <EthernetV2_0.h>

// назначить MAC-адрес для контроллера Ethernet.
// введите свой адрес здесь:
byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};

// введите здесь доступный IP-адрес в вашей сети,
// для ручной настройки:
//IPAddress ip(169, 254, 106, 46); //Адрес, который работал на моем компьютере
IPAddress ip(169, 254, 1, 2); //Рекомендуемый производителем адрес

// введите здесь адрес вашего сервера доменных имен:
IPAddress myDns(1, 1, 1, 1); //Случайно, не уверен, нужно ли мне здесь что-то конкретное делать

// маска подсети, рекомендованная производителем и та, которая сработала на моем компьютере
IPAddress subnet(255, 255, 0, 0);

// инициализируем экземпляр библиотеки:
EthernetClient client;

//IP-адрес сервера(64,131,82,241); //arduino.cc IP-адрес
IPAddress server(169, 254, 184, 143); //Arri Alexa (камера) IPAddress

unsigned long lastConnectionTime = 0; // время последнего подключения к серверу в миллисекундах
const unsigned long postingInterval = 10L * 1000L; // задержка между обновлениями в миллисекундах
// «L» необходимо для использования длинных чисел

#define W5200_CS  10
#define SDCARD_CS 4

void setup() {
  // запуск последовательного порта:
  Serial.begin(9600);
  while (!Serial) {
    ; // дождитесь подключения последовательного порта. Требуется только для собственного USB-порта.
  }
  pinMode(SDCARD_CS,OUTPUT);
  digitalWrite(SDCARD_CS,HIGH);//Отменить выбор SD-карты
  // даем модулю Ethernet время на загрузку:
  delay(1000);
  // запускаем Ethernet-соединение, используя фиксированный IP-адрес и DNS-сервер:
  Ethernet.begin(mac, ip, myDns, subnet);
  // распечатать IP-адрес платы/щита Ethernet:
  Serial.print("My IP address: ");
  Serial.println(Ethernet.localIP());
}

void loop() {
  // если есть входящие данные из сетевого соединения.
  // отправьте его через последовательный порт. Это для отладки.
  // только для целей:
  if (client.available()) {
    char c = client.read();
    Serial.write(c);
  }
  // если с момента последнего подключения прошло десять секунд ,
  // затем снова подключитесь и отправьте данные:
  if (millis() - lastConnectionTime > postingInterval) {
    httpRequest();
  }
}

// этот метод устанавливает HTTP-соединение с сервером:
void httpRequest() {
  // закрыть все соединения перед отправкой нового запроса.
  // Это освободит гнездо на WiFi-плате
  client.stop();
  // если соединение успешно установлено:
  if (client.connect(server, 80)) {
    Serial.println("connecting...");
    // отправьте HTTP-запрос GET:
    client.println("GET /webremote/index.html HTTP/1.1");
    client.println("Host: 169.254.184.143");
    client.println("User-Agent: arduino-ethernet");
    client.println("Connection: close");
    client.println();
    // отметьте время установления соединения:
    lastConnectionTime = millis();
  } else {
    // если не удалось установить соединение:
    Serial.println("connection failed");
  }
}

Вопрос такой: если я использую те же самые сетевые настройки, что и на компьютере, подключенном к камере, почему они не работают на Arduino? Понимаю, что ситуация несколько неясная, но буду благодарен за любые идеи. Спасибо!

, 👍3

Обсуждение

На мой взгляд, код выглядит разумно — никаких явных косяков я не заметил. Если вы затрудняетесь, советую вынуть SD-карту и отключить ридер, на всякий случай, если он мешает, а также протестировать на ПК, а не на камере — например, можно будет проверить, есть ли вообще соединение. Если вы используете Linux или, возможно, Mac, то nc или netcat — действительно полезный инструмент для отладки подобных вещей., @Mark Smith

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

На всякий случай я проверил [техническое описание](http://wiki.seeedstudio.com/images/e/e7/W5200_Datasheet.pdf) и убедился, что чип поддерживает [Auto MDI-X](https://en.wikipedia.org/wiki/Medium-dependent_interface#Auto_MDI-X), так что вам не нужен кроссоверный кабель. Однако я бы всё равно рекомендовал попробовать подключение через коммутатор: по крайней мере, у вас будут индикаторы, которые покажут, не создаёт ли один из концов соединение уровня Ethernet., @cjs


2 ответа


1

Согласен с Марком, что весь ваш код выглядит разумно, за исключением строки, определяющей myDNS. У меня нет опыта работы с используемой вами платой/библиотекой, но недавно я видел похожую проблему на промышленной плате. Оказалось, что она пыталась преобразовать IP-адрес в имя с помощью обратного DNS, и из-за неправильной настройки DNS-сервера подключение не удалось. Возможно, если указать в строке myDNS адрес корректного DNS-сервера (того, который использует ваш тестовый компьютер?), проблема исчезнет.

Если это не работает, то можете ли вы прочитать руководство и посмотреть, можно ли убедить объект Client выдать вам код ошибки или сообщение, которые дадут вам подсказку о том, почему он не работает?

Я понимаю, что 169.254.1.2 — это рекомендуемый производителем адрес, но почему вы использовали 169.254.106.49 для тестового ПК? Вряд ли это что-то конкретное, но...

Кроме того (я уверен, что это была ваша первая проверка), является ли соединение между Arduino и камерой прямым, нет ли на пути брандмауэров, маршрутизаторов, коммутаторов или мостов, выполняющих NAT или PAT или блокирующих определенные соединения и т. д.?

(DNS = Служба доменных имен, преобразует имена типа google.com в осмысленные адреса типа 1.2.3.4)

,

1

В духе «Используй исходный код, Люк» я взглянул на код на GitHub, который, надеюсь, совпадает с используемым тобой или очень похож на него.

В четырёхпараметрической версии Ethernet.begin() в качестве четвёртого параметра используется шлюз, а не маска подсети. Маска подсети, переданная явно, является пятым параметром пятипараметрической версии.

На самом деле это не должно иметь никакого значения, поскольку шлюз не должен использоваться ни для чего в той же подсети, а подсеть по умолчанию для адресов класса B (от 128.0.0.0 до 191.255.255.255), в диапазон которой попадает ваш адрес, составляет 16 бит, 255.255.0.0.

Проблема в том, что приведённый ниже код содержит то, что я бы счёл ошибкой:

void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server, IPAddress gateway)
{
  IPAddress subnet(255, 255, 255, 0);
  begin(mac_address, local_ip, dns_server, gateway, subnet);
}

В этом вызове, который вы используете, маска подсети всегда установлена на 24 бита (255.255.255.0).

169.254.1.2 и 16.254.184.143 не имеют одинакового 24-битного префикса, поэтому программное обеспечение (предполагаю, я не до конца разобрался) попытается связаться со шлюзом, который вы случайно указали и который даже не находится в той же сети (не говоря уже о том, что он не существует), и потерпит неудачу.

Попробуйте вызвать Ethernet.begin() с 5 аргументами (передача 0.0.0.0 для шлюза должна быть нормальной) и посмотрите, решит ли это проблему.

Я проверил пример WebClientRepeating в этом репозитории, и там используется версия с тремя параметрами. Возможно, вы перешли на версию с четырьмя параметрами или взяли пример из другой библиотеки. (Этот пример не менялся с момента запуска репозитория в апреле 2014 года.)

,