Отправка минимальных данных между двумя Arduino далеко друг от друга
Проблема: мне нужно отправить небольшие целые числа (достаточно однозначных чисел) между двумя arduino, расположенными примерно в 50-60 метрах друг от друга.
Подключение должно осуществляться с помощью кабелей. Я читал, что указанное расстояние слишком велико для использования последовательной связи. Меня не волнует, если метод не быстрый, задержки до одной или двух секунд для этого вполне допустимы. Если это поможет: устройства (Arduino UNO или аналогичные) будут запускать еще не написанные коды для простой системы сигнализации (без камер / изображений).
Вопрос: Каков хороший способ для этого?
Мои усилия: я придумал пару альтернатив для решения этой проблемы. Оба варианта предполагают использование ШИМ- сигналов , посылаемых с устройства A на другое B.
- Для одного из них требуется некоторый ЦАП в A и считывание аналогового входа в B. Считанные значения затем сопоставляются с небольшими целочисленными списками. Я обнаружил некоторые недостатки такого подхода:
- Увеличение сложности и стоимости оборудования. Хотя я читал, что цифроаналоговое преобразование может быть произведено с помощью дешевых конденсаторов, у меня было бы много проблем с их приобретением из-за карантина в моей стране.
- Вероятно, мне нужно будет провести много тестов, чтобы настроить процедуру отображения из-за падения напряжения.
- Второй - просто считывать цифровой ввод в B много раз в течение фиксированного периода (например, 0,1 или 1 секунда) и усреднять значения, которые были считаны за этот период. Я готов поспорить, что устройства не синхронизированы, и тогда среднее значение (умноженное на 1023) за такие длительные периоды будет близко к значению, отправленному analogWrite (somepin, value). Наконец, принятое значение будет самым близким значением в списке допустимых значений.
Пример: Для передачи одного из чисел 0,1,2 или 3 устройство A выдаст 0, 341, 682 или 1023 соответственно. Например. для передачи "1" A будет выполнять analogWrite(somepinA, 341). B прочитает int lecture = digitalRead(somepinB) и получит среднее время лекции за некоторый период времени. После умножения на 1023 он может вернуть что-то вроде "312". Затем он должен найти значение в [0, 341, 682,1023], ближайшее к 280 (341), и сопоставить его с 1.
- Даже если бы они были каким-то образом синхронизированы, я думаю, что я мог бы отправить 0 или 1, используя случайные числа или digitalWrite (somepinA) (возможно ли это? Преимущества? Недостатки?)
Я новичок в этой области, поэтому не знаю, есть ли что-то неправильное в моем подходе. Я также был бы признателен, если бы была предложена лучшая альтернатива.
Заранее благодарю.
@user1420303, 👍2
Обсуждение2 ответа
Лучший ответ:
Лучше всего подходит RS-485 (вы можете купить некоторые модули для этого у Adafruit, Amazon, eBay и т. Д.), Но вы можете использовать встроенные аппаратные последовательные интерфейсы RS-232 от каждого на выводах 0 и 1, если скорость передачи данных действительно очень низкая. Чем ниже скорость передачи в бодах, тем больше может быть дальность действия, потому что более низкие скорости передачи в бодах лучше подавляют шум (и чем длиннее кабель, тем хуже шум, поскольку чем длиннее кабель, тем больше он действует как антенна, катушка индуктивности и конденсатор). Вот несколько приблизительных оценок того, как далеко вы можете передавать несбалансированные сигналы RS-232 на уровне обычной логики:
Источник:
https://www.tldp.org/HOWTO/Remote-Serial-Console-HOWTO/serial-distance.html
Если эта тенденция сохранится, вы сможете разогнаться до 120 м со скоростью 1200 бит / с (бод), 240 м со скоростью 600 бит / с, 480 м со скоростью 300 бит / с и т. Д. Возможно, Даже до> 1000 м со скоростью 50 бит / с. Я не думаю, что эта тенденция сохранится, и мы используем логические уровни TTL (напряжение сигнала) 5 В вместо RS-232 + /- 12V или около того, поэтому наши логические уровни намного хуже и будут иметь меньший диапазон, поэтому просто используйте 50
бод и попробуйте:
// делать на каждом Arduino
Serial.begin(50); // 50 бод = пропускная способность 10 байт / сек; см. Ниже
Обратите внимание, что для скорости последовательной передачи данных 8-N-1, которая используется по умолчанию в Arduino, по проводу передается 10 бит на байт. Это связано с тем, что на каждый отправленный 8-битный байт приходится "один начальный бит, восемь битов данных и один стоповый бит". Это эффективная пропускная способность передачи данных составляет 80%. Это означает, что скорость передачи данных в бодах 50 бит / с (бит в секунду) может передавать только 50/10 = 5 байт в секунду. Вот именно! Это очень медленно, но если это достаточно быстро для вашего приложения, то достаточно быстро!
Я предполагаю, что связь 5V TTL twisted quad RS-232 между двумя Arduino будет иметь максимальную дальность при 50
бод около 1000 м / (диапазон 24 В для обычного RS-232 / диапазон 5 В для логики 5V TTL RS-232) = 208м. Просто грубая оценка. Пожалуйста, сообщайте о любых результатах, которые вы получите в результате своих экспериментов. Я хотел бы услышать об этом.
Предполагая, что все это действительно работает, было бы также полезно начать увеличивать скорость передачи данных на каждом устройстве до тех пор, пока данные не начнут повреждаться. Немного снизьте скорость передачи данных в бодах, и это будет ваша максимальная скорость передачи данных в бодах. Возьмите эту максимальную скорость передачи данных в бодах и разделите на 2 или 3, и, возможно, это будет ваша максимальная "безопасная" скорость передачи данных в бодах. Если вам нужна как можно более высокая пропускная способность, то это то, что я бы сделал. Пример: возможно, в вашем случае 50
бод работает просто отлично, поэтому вы увеличиваете его. На скорости 1000
бод вы начинаете видеть поврежденные данные, поэтому вы возвращаетесь к 800
. В этот момент вы больше не видите поврежденных данных. Итак, разделите это на 2 или 3, и вы получите максимальную "безопасную" передачу данных в бодах для вашей установки, возможно, от 800/3 = 267
до 800/2 = 400
.
Попробуйте использовать витой четырехъядерный кабель (провода скручены вместе группами по 4), чтобы уменьшить шум и увеличить дальность действия, и установите скорость передачи данных на каждом Arduino равной 50
. Вам понадобятся 3 провода, соединенных между Arduino:
- GND к GND
- Tx-Rx
- Rx в Tx
Запитывайте каждый из них отдельно с помощью незаземленных источников питания.
Связь осуществляется через Serial.write()
и Serial.read()
(при условии, что Serial.available()
показывает, что некоторые данные доступны в буфере чтения).
Подробнее о сбалансированных и несбалансированных линиях и о том, почему я рекомендую "витой четырехъядерный" провод:
Обычно RS-232 считается несбалансированной системой передачи данных по линии. Это означает, что импеданс в проводе передачи не равен импедансу в обратном проводе, который был бы общим заземлением между отправителем и получателем в сочетании (параллельно) с заземлением через проводку здания и / или фактически через Землю ... буквально, грязь, по которой вы ходите вкл. Однако при питании каждого Arduino от незаземленного источника питания, такого как 2-контактный источник питания, что является обычным явлением, к Arduino не подключается заземление. Кроме того, имея только одну линию передачи, активную в любой момент между двумя Arduino, вы просто сбалансировали передачу между ними. Теперь выходной путь - это один сигнал Tx от одного Arduino к другому, а обратный путь имеет соответствующий импеданс, так как это ваш единственный общий GND-провод между двумя Arduino. Теперь у вас есть сбалансированная линейная передача логического уровня RS-232 TTL между двумя Arduino. Сбалансированная линейная передача может иметь улучшенное подавление шума и дальность действия за счет использования витой пары между двумя линиями. В этом случае, однако, есть 3 строки: Tx -> Rx, Rx -> Tx и Gnd -> Gnd. Итак, вы должны использовать скрученный четырехжильный провод, что означает, что 4 провода одновременно скручены вместе. Соедините все 3 линии в один и тот же скрученный четырехъядерный жгут. Опять же, помните, что это предполагает, что только один Arduino передает одновременно по одному проводу в одном направлении одновременно (чтобы не свести на нет ваш обратный ток через линию GND при передаче по двум линиям, по одной в каждом направлении, или удвоить ваш обратный ток через линию GND при передаче на двух линиях, каждая в одном направлении [при условии, что у вас было несколько UART на каждом устройстве]), таким образом, такое использование создает сбалансированную линейную систему, поскольку они также не заземлены через 3-контактный заземленный источник питания. Если эти 2 требования выполнены (1 Arduino передает одновременно, и по крайней мере один из них не заземлен на проводку здания), используйте витой четырехпровод, так как система имеет сбалансированную линейную связь. Если это не так, потому что вы передаете данные с каждого Arduino на другой в одно и то же время или потому, что оба (а не один) Arduino заземлены в здании, тем самым предлагая альтернативный обратный путь через проводку заземления здания, тогда витой четырехъядерный кабель не принесет вам пользы, и вы следует использовать обычную раскрученную проводку.
Сказав все это, экспериментирование - это настоящий босс здесь. Попробуйте это сделать. если бы у меня не было витого четырехпроводного провода, я бы попробовал витую пару, а если бы у меня не было витой пары, я бы попробовал раскрученный провод.
Что касается вашего подхода к использованию ШИМ для создания аналогового выхода, который будет считан принимающей стороной:
Использование ШИМ для получения аналогового напряжения, считываемого приемным концом, является интересным подходом. Я думаю, что без фильтрации вы бы производили огромный шум, однако, буквально производя электромагнитное излучение (например, низкочастотные радио- или телевизионные волны или что-то в этом роде), где этот огромный 60-метровый провод является вашей вещательной антенной. Однако, если вы установите резистор 20 ~ 50 Ком прямо на передающем конце и конденсатор 1 мкФ прямо на приемном конце, однако, чтобы отфильтровать этот ШИМ в аналоговый выход сразу на передающем конце, я думаю, это устранит эффект вашей антенны, когда вы что-то транслируете, и будет много работать лучше, но все равно быть очень восприимчивым к внешнему шуму, влияющему на него. Попробуйте, но я подозреваю, что простой набор цифровых выводов для установки ВЫСОКОГО или НИЗКОГО уровня на разных выводах для соответствия разным состояниям был бы намного намного лучше, чем любой аналоговый сигнал на таких длинах, а последовательный сигнал в 50 бод является следующим лучшим по соотношению сигнал / шум после этого.
Итак, в порядке от наилучшего к наихудшему отношению сигнал/шум (SNR):
- дифференциальная пара (привязанная друг к другу) цифровых ВЫСОКИХ / НИЗКИХ значений для представления состояний, которые вы обновляете очень медленно
- Последовательная передача дифференциальной пары RS-485
- Примечание: для всех следующих сценариев передачи действительно низкоскоростного цифрового сигнала вы также можете попробовать использовать фильтр нижних частот, показанный на схеме ниже, поскольку это может помочь устранить шум.
- несимметричные (привязанные к GND) цифровые ВЫСОКИЕ / НИЗКИЕ значения для представления состояний, которые обновляются очень медленно
- сверхнизкоскоростной SPI (включая бит-бит); т. е.: объявить любой цифровой вывод
CLOCK_PIN
, а любой другой цифровой вывод- DATA_PIN
. Установите НИЗКИЙ вывод часов, ВЫСОКИЙ вывод данных, ВЫСОКИЙ вывод часов. Тактовый переход сообщает получателю (вы должны закодировать это), чтобы он прочитал вывод данных, поэтому вы просто считываете1
бит. Установите НИЗКИЙ пин данных, установите НИЗКИЙ контакт часов. Тактовый переход сообщает приемнику считывать контакт данных, поэтому вы просто считываетебит 0. Оставьте контакт данных низким, снова установите контакт часов ВЫСОКИМ. Вы только что отправили еще
0
бит и т.д. И т.п. Отправляйте такие данные очень медленно. Он будет работать на большой длине - даже лучше, чем асинхронный последовательный, поскольку он синхронный. - асинхронный последовательный (+/- 12V true RS-232) со скоростью 100 бод
- асинхронный последовательный (+/- 12V true RS-232) со скоростью 50 бод
- асинхронный последовательный (5 В TTL RS-232) со скоростью 50 бод
- асинхронный последовательный (3 В TTL RS-232) со скоростью 50 бод
- аналоговое значение фильтруется с помощью резисторного и конденсаторного низкочастотного RC-фильтра; обновление: я бы попробовал эту схему фильтрации для отправки аналоговых значений через ШИМ (см. Схему ниже, но используйте более высокое значение резистора, которое я описываю в своих маркерах под схемой, а не более низкое значение, которое я показываю на схеме); фильтр также может быть полезен для фильтрации шума при низкоскоростной цифровой связи, поэтому попробуйте использовать его и в приведенной выше настройке последовательной передачи данных со скоростью 50 бод:
- Отправка с
помощью analogWrite()
(PWM); прием спомощью analogRead()
. - Доложите и об этом, пожалуйста. Мне очень любопытно, сработает ли это.
- Отправка с
- нефильтрованная ШИМ -антенна прямоугольной формы, передающая неизвестно что, может создать для вас интересную систему вещания. Добавьте транзистор, и вы действительно сможете увеличить мощность и транслировать некоторые интересные сигналы! Получите здесь хорошую высокую мощность (1 Вт ~ 10 Вт +) и, может быть, даже попросите правительство выяснить, кто глушит GPS и сотовую связь? Я не знаю: это могло бы быть интересно!
Схема низкочастотного RC-фильтра для уменьшения шума между двумя Arduino при передаче действительно низкоскоростных цифровых сигналов (лучше) или медленно меняющихся аналоговых сигналов (хуже) между двумя сторонами:
- Для фильтрации цифровых сигналов (например, 5 В TTL псевдо-последовательный RS232 со скоростью от 50 до 100 бод):
- Используйте 470 Ом для каждого резистора, как показано выше.
- Это приводит к частоте среза 847 Гц, поэтому оставайтесь ниже ~ 169 бод (
cutoff_freq / 5 = 847Hz / 5 = 169
или около того) для отправки цифрового сигнала через этот фильтр.
- Для фильтрации аналоговых сигналов, передаваемых через
analogWrite()
:- Поскольку большинство выводов Arduino имеют частоту ШИМ 490 Гц, нам нужна частота среза ~ 490 Гц / 10 = 49 Гц или ниже, чтобы четко отфильтровать частоту ШИМ и получить настоящий аналоговый выход.
- Используя калькулятор, на который приведена ссылка ниже, это означает, что вы должны использовать значения R не менее 10 кб каждое, что приводит к частоте отсечения. 40 Гц. Вы также можете использовать резисторы по 20 Ком для частоты среза. около 20 Гц.
- Чтобы увеличить частоту среза и обеспечить более высокую скорость передачи данных в бодах, уменьшите либо R, либо C, либо и то, и другое.
- Калькулятор частоты среза см. в разделе: https://electronicbase.net/low-pass-filter-calculator/#rc-low-pass-calculator -> "Калькулятор фильтра нижних частот RC" -> введите, например, 940 Ом (470 x 2) в качестве значения сопротивления и 0,2 мкФ (0,1 мкФ x 2) в качестве значения конденсатора, чтобы увидеть, что результирующая частота среза для этого низкочастотногочастота пропускания фильтра составляет 846,57 Гц.
Я не специалист по фильтрам, но это то, что я бы попробовал. Если кто-то видит какие-то явные ошибки в этом фильтре или способы его улучшения, пожалуйста, прокомментируйте под ответом.
Дополнительно:
Вот график Боде для приведенного выше последовательного фильтра, который я показываю, за исключением резистора 1 Ком и конденсатора 0,1 мкФ (100 Нф), за которым следует то же самое снова. Фиолетовая линия - это напряжение, о котором мы заботимся. Источник: годфрей, здесь.
Частота среза здесь составляет 398 Гц, где происходит падение на -3 дБ, что соответствует половинной мощности и точке ослабления напряжения 70,7%. (sqrt(0.50) = 0.707
, так что 0.707 ^ 2 = 0.5
)). Подробнее о частоте среза вы можете прочитать здесь.
Дополнительное чтение:
- https://www.tldp.org/HOWTO/Remote-Serial-Console-HOWTO/serial-distance.html
- Поиск в Google по запросу "сбалансирован ли rs232?"
- https://www.idc-online.com/technical_references/pdfs/data_communications/tutorial_2.pdf
- http://www.iec-usa.com/Browse05/DTBALUN.html
- https://en.wikipedia.org/wiki/Signal-to-noise_ratio
витая пара для TTL?, @Juraj
Ну, нет: я оговорился. Я должен был сказать "витой четырехъядерный" провод. Я обновил свой ответ и предоставил подробное обоснование этой рекомендации., @Gabriel Staples
Просто терминологический момент: “5V TTL” и “RS-232” - несовместимые термины; ссылка может быть любой, но не обе одновременно. Встроенный аппаратный UART имеет 5 В TTL, поэтому не RS-232., @Edgar Bonet
Я пытаюсь передать информацию о том, что он является асинхронным последовательным, следуя точным битовым шаблонам и протоколу, описанным в RS-232, за исключением того, что отличаются только логические уровни. "5V TTL" ничего не говорит о протоколе, это означает только "логические уровни 5V". У вас может быть "5V TTL SPI", "5V TTL I2C", "5V TTL Dalls One-Wire", "3V TTL SPI", "5V или 3V TTL, как вы называете", но "5V TTL RS-232", хотя и технически неточный, как вы заявляете, является наиболее точное и информативное представление настройки, на мой взгляд, потому что оно описывает напряжение, аппаратное обеспечение и протокол в 3 словах., @Gabriel Staples
У меня были проблемы с этими терминами в течение многих лет из-за этих расхождений, поэтому я предпочитаю говорить об этом максимально информативно (и как можно точнее, оставаясь информативным). "5V TTL" переопределяет часть логического уровня спецификации RS-232. По вашему опыту, есть ли лучший способ сказать это, сохраняя при этом точную информацию о протоколе и битах, только на другом логическом уровне?, @Gabriel Staples
Я обычно использую “[асинхронный последовательный] (https://en.wikipedia.org/wiki/Asynchronous_serial_communication )”, или просто “UART”, хотя последнее относится к аппаратному порту. Например: “вы можете использовать встроенный аппаратный UART”, “Я предполагаю, что 5V TTL twisted quad serial communication [...]” (на данный момент уже ясно, что это из UART), “Диапазон 5V для 5V TTL асинхронный последовательный”. Тогда, возможно, некоторые люди не знают, что означают эти термины..., @Edgar Bonet
Асинхронный последовательный
- неплохой способ сказать это, но это все же более двусмысленно, чем то, как я это сказал. Существует множество форм асинхронного последовательного подключения, и протокол RS-232 является лишь одной из них. Любой протокол связи, который выполняется без общих часов или автоматической синхронизации со скоростью передачи данных, является асинхронным. Опять же, в моей формулировке, указание "RS-232" сужает это до одной формы асинхронного последовательного протокола, и я "переопределяю" уровни напряжения по умолчанию для него, явно указывая "5V TTL", где, опять же, просто "TTL" тоже недостаточно. В любом случае, "асинхронный последовательный" тоже хорош, только менее специфичен., @Gabriel Staples
+1 Спасибо за ваше очень поучительное объяснение! Я внимательно прочитал его, а также прочитал содержимое, на которое даны ссылки. Подход, которому я буду следовать, в значительной степени зависит от наличия местных продуктов и цен. Я не смог найти скрученный четырехъядерный провод в своей стране (по крайней мере, на "нашем eBay"). Я думаю, что выберу RS-485, но я также проведу несколько тестов с RS-232, просто чтобы поиграть. Мне интересно ваше мнение о том, может ли предложенный мной метод сработать (даже если это не лучший выбор) или в нем есть какие-то серьезные заблуждения., @user1420303
Я только что обратился к вашему вопросу о ШИМ в нижней части моего ответа. Пожалуйста, сообщите мне, если вы попробуете мой рекомендуемый подход. Сейчас мне это очень любопытно. Просто помните, что отправка прямоугольных волн по длинной линии - это ... антенна беспроводного вещания. Чем ниже частота, тем длиннее должна быть антенна для правильного вещания. Это связано с согласованием частоты и длины волны со скоростью света и длиной антенны или что-то в этом роде, чтобы получить хороший беспроводной сигнал. Таким образом, вам нужно будет отфильтровать его, чтобы попытаться НЕ передавать беспроводные сигналы таким образом., @Gabriel Staples
Я только что расширил свой список отношения сигнал / шум с 3 до 10 пунктов. Этот ответ просто продолжает расти., @Gabriel Staples
@user1420303, UTP-кабель, используемый для сетей, имеет 4 витые пары. Я уверен, что вы можете купить адаптеры RS485 для Arduino. не тратьте время на попытки заставить UART работать на длинном кабеле., @Juraj
По-видимому, проще всего было бы использовать простой приемопередатчик CAN на каждом конце, один из которых настроен на передачу, а другой - на прием. Вы не упомянули двунаправленную связь, хотя оба физических уровня, предложенные ниже, будут поддерживать это довольно легко. Электрические характеристики кабеля шины CAN ограничивают длину кабеля в соответствии с выбранной скоростью передачи данных. Вы можете использовать кабели длиной до 250 метров со скоростью передачи данных 250 кбит/ с. Максимальная длина шины со скоростью передачи 10 кбит/с составляет 1 км, а самая короткая со скоростью 1 Мбит/с - 40 метров. Другим подходом было бы использование RS485. RS485 популярен для недорогих локальных сетей, многоуровневых линий связи и передачи данных на большие расстояния на расстояния до 4000 футов. Использование сбалансированной линии означает, что RS485 обладает превосходным шумоподавлением и идеально подходит для промышленного и коммерческого применения. Примечание. обычно они управляются с помощью асинхронных сигналов от uart или аналогичного устройства. Программный последовательный будет работать отлично и оставит встроенный последовательный порт для отладки. асинхронная связь выполняет синхронизацию автоматически, вам ничего не нужно делать, просто сохраняйте скорость передачи данных на прежнем уровне.
Протокол CAN кажется значительно более сложным, чем обычный UART (асинхронный последовательный) через RS-485, и Arduino не имеет для него аппаратной поддержки. Или вы предлагаете сделать UART поверх физического уровня CAN?, @Edgar Bonet
Здорово, что он у тебя есть. Используйте физический уровень, но то, что вы отправляете на нем, зависит от вас. Я полагаю, что в вашем случае это будет простая передача в одну сторону на ведомое устройство. Скорость передачи данных, которую вы используете, зависит от того, что вам нравится и удобно. Обычно я запускаю последовательное программное обеспечение со скоростью 9600 бод, а мой терминал - со скоростью 115200, таким образом, терминал может получать все, что отправляется, без наводнения. Получайте удовольствие и дайте нам знать, как это работает., @Gil
- Могу ли я с помощью аналогового контакта на Arduino Mega прочитать, есть ли высокое (5 В) напряжение на проводе от цифрового контакта другой платы?
- Как заставить Arduino взаимодействовать с тремя другими Ардуино?
- Какой тип разъема использует система GROVE?
- Основная связь Arduino ModBus RTU с проблемой измерителя мощности
- Последовательная связь между ESP8266 и Arduino Uno
- Отправка значения с одного Arduino на другой
- SIM900 3G? Или SIM900A умеет подключаться к 3G?
- Контакты RX и TX на esp32
RS485 RS485 RS485, @Juraj
вы можете использовать 10 уровней тока, который, в отличие от напряжения, одинаков на обоих концах., @dandavis
@dandavis, я не совсем понимаю, что ты имеешь в виду, извини., @user1420303
посмотрите, например, на показания "4-20 ма". он используется на очень больших расстояниях. в контуре ток везде одинаков, поэтому, если датчик выдает ток вместо напряжения, вы можете считывать этот ток далеко. самое простое - это считывать падение по известному резистору. Даже встроенный АЦП должен быть способен различать 10 стабильных уровней напряжения. Затем вам нужно преобразовать напряжение датчика в ток, используя готовый драйвер или простую схему операционного усилителя., @dandavis
один из ответов на https://diy.stackexchange.com/questions/197992/re-writing-a-router-into-the-main-control-panel натолкнул меня на мысль воспользоваться модемом ... google
модемный модуль arduino fsk
, @jsotolaкроме того, проверьте https://www.pjon.org/SoftwareBitBang.php, @jsotola