
Лет десять назад я сконструировал и изготовил пару анемометр и флюгер, которые описал тогда вот в этой статье. Сейчас устройства, конечно, износились: если флюгер еще в общем работает, то анемометр практически дохлый. Сказывается еще то, что на зиму их приходится убирать: под снегом они отказали бы гораздо быстрее, а периодический монтаж-демонтаж сказывается на их состоянии не лучшим образом. Поэтому вплотную встал вопрос замены на более долговечную конструкцию.
Об ультразвуковом принципе работы измерителей различных потоков (морских и речных течений, ветра, жидкостей и газов в трубопроводах) я осведомлен издавна, так как в 80-90-е годы вплотную занимался измерителями морских течений. Ультразвуковой датчик ветра хорош тем, что объединяет функции анемометра (измерителя скорости) и флюгера (измерителя направления) в одном приборе. При этом датчик не имеет никаких движущихся частей, максимально изолирован от непогоды, следовательно, гораздо долговечнее, чем любая механическая конструкция. Измерение скорости производится на основе эффекта Допплера в двух взаимно перпендикулярных направлениях, так что значение направления получается автоматически из двух измеренных векторов. В некоторых конструкциях используется также принцип измерения составляющих вектора в трех направлениях по периметру треугольника.
Попытки десять лет назад найти что-то из этой области по части ветра натолкнулись на ценовой порог: в продаже имелись лишь ультразвуковые измерители профессионального класса, как импортные, так и отечественные (или, правильней сказать, под отечественным лейблом), с соответствующей ценой с тремя нулями в долларах. Но в прошлом году решил проверить новинки по этой теме, и с изумлением обнаружил большое количество моделей бытового уровня ценой от единиц до десятков тысяч обычных рублей.
Отобрал из всего многообразия похожие друг на друга изделия, вероятно, имеющие отношение к одному и тому же производителю — китайской фирме Renke, имеющей, кстати, многоязычный сайт. Датчик, на котором я остановился, доступен на Ali Express по этой ссылке и по цене находится где-то на средней позиции: около 8 тыс. рублей.

У данного продавца он называется ZQW-600, хотя в Сети его проще встретить под названием RS-CFSFX-*-2H-EX или SN-*-CFSFX-N01. Первые буквы — от названия производителя, звездочка кодирует исполнение (в нашем случае должно быть 3003), N01 означает интерфейс RS-485. Для варианта с интерфейсом RS-485 удалось даже разыскать английский перевод описания; потом нашлась и русскоязычная статья на эту тему с описанием подключения к Arduino. Для других вариантов интерфейса описаний не нашлось даже по-китайски, зато оказалось, что продавец по вышеуказанной ссылке вкладывает в коробку с прибором распечатанное руководство на английском. Сравнение руководств и сведений из русскоязычной статьи показало, что речь идет об одной и той же конструкции, различающейся производителями и, возможно, заявленными погрешностями измерения.
Почему-то ультразвуковой датчик ветра на различных ресурсах принято называть анемометром, что неправильно: как вы догадались, анемометр — только часть этого прибора, относящаяся к измерению скорости. Устоявшихся названий ждать не приходится, поэтому если хотите поискать на Ali другие варианты (имеются предложения и дешевле, а также аналогичные датчики других исполнений), набирайте название полностью: «Ultrasonic Wind Speed and Direction Sensor», или по-русски «Ультразвуковой датчик скорости и направления ветра».
Подключение к контроллеру
Для подключения мы будем использовать Arduino, как самый простой, отработанный и всем хорошо знакомый вариант. В случае интегрирования в какую-нибудь из систем типа «Умный дом» сложностей с переносом кода возникнуть не должно. Так как мы рассматриваем датчик с интерфейсом RS-485, то понадобится преобразователь для подключения к последовательному порту контроллера. Интерфейс этот очень удобен для таких целей: не требуется размещать контроллер, обрабатывающий данные, в непосредственной близости от датчика. Датчик ветра необходимо размещать достаточно высоко — по нормативам для метеостанций на высоте 10 метров, причем в отсутствие поблизости высоких строений и деревьев. На 10 метров (высота трехэтажного дома) мы, скорее всего, не дотянемся, но вынести датчик метра на полтора-два поверх конька крыши деревенского дома крайне желательно. То есть общая длина соединительного кабеля между датчиком и контроллером может составить десяток-другой метров. Для RS-485, это, к счастью, не проблема.
Приобретаем стандартный ардуиновский конвертор RS-485/UART (он называется HW-97). Еще нам понадобится адаптер питания с напряжением 12 вольт. Чтобы меньше паять, в качестве контроллера используем Arduino Nano, уже имеющий встроенные стабилизаторы питания 5,0 и 3,3 вольта (предназначение последнего мы увидим далее). Кстати, кое-где задержавшаяся информация о том, что вывод 3,3 V у Arduino Nano работает только при подключении к USB, не соответствует действительности ни для итальянского оригинала, ни для клонов, что легко проверить на практике (вероятно, это относилось к старым версиям платы).
К сожалению, к штатному UART микроконтроллера ATmega328P в Nano уже подключен преобразователь RS-232/UART, служащий для загрузки скетчей, поэтому для подключения конвертора RS-485/UART придется организовывать отдельный программный последовательный порт. Интерфейс датчика работает со скоростью 4800 бит/с, соответственно настраивается скорость программного порта. Заметим еще, что нормативное время отклика датчика (согласно документации) составляет 1 секунду, потому увеличить скорость чтения показаний сверх величины 1 раз в секунду не получится.
Схема простого проверочного подключения приведена на рисунке ниже. Выводы интерфейса датчика помечены цветами проводов: в данной модификации питание 12 В — коричневый (что удобно — красным на схемах обычно обозначены контроллерные 5 В), общий провод GND — как и положено, черный, вывод A — синий, вывод B — желтый (или зеленый, как свидетельствуют некоторые фото). Для тестового подключения удлинять кабель не требуется. В сравнении со схемой, приведенной в русскоязычной статье по ссылке выше, здесь исправлены ошибки в подключении питания 5 В: отдельный стабилизатор здесь не требуется, встроенного в Nano LM1117 (его ставят и в оригинал и в большинство приличных клонов) хватит с запасом, и в любом случае бессмысленно замыкать выход «5V» Arduino Nano с выходом внешнего стабилизатора.

Обработка данных для проверки
Из четырех полученных байт данных первые два байта представляют собой значение скорости ветра в см/сек (в порядке старший:младший); еще два — направление в географических градусах. Уточнение «географических» здесь понадобилось потому, что географы (и метеорологи) отсчитывают градусы от направления на север (0° — вертикально вверх) по часовой стрелке. Чтобы каждый раз не вспоминать, как правильно, достаточно посмотреть на изображение картушки компаса. В математической полярной системе координат отсчет идет против часовой стрелки: если отсчитывать одинаково от направления на север, то у математиков 90° — запад, та же величина у географов — восток. Нам, как вы увидите, этим заморачиваться не придется.
Куда будем девать результаты? В простейшем случае проверки датчика можно их направить через штатный Serial в компьютер. В архиве, доступном по ссылке в конце статьи, имеется такой проверочный скетч по названием Proba_anemometr. Программа выполнена на основе приведенной в русскоязычной статье по ссылке выше, с некоторыми исправлениями: во-первых, скорость ветра в км/час измеряют, наверное, только исследователи ураганов; в быту и в сводках МЧС (а также в спецификациях самого датчика) ее принято измерять в метрах в секунду.
Во-вторых, сразу скажем, что главный недостаток датчика — при снижении скорости направление теряется раньше, чем скорость обращается в ноль. При отсутствии ветра (когда скорость равна нулю) датчик выдает все нули, в том числе и в величине направления. Разумеется, у вектора нулевой длины нет никакого направления, однако в нашем случае ноль градусов имеет вполне определенную интерпретацию, как направление на север. Поэтому. если интерпретировать данные в лоб, то при небольших скоростях и при чистом нуле датчик будет давать ложное направление. Чтобы избежать этой неоднозначности, в программе запоминается последнее значение направления при отличном от нуля значении скорости, и выводится до тех пор, пока скорость опять не станет отличной от нуля. Этим приемом мы как бы имитируем реальное поведение флюгера, при отсутствии ветра замирающего в неподвижности.
Конструктивное оформление датчика
В моем случае датчик устанавливался на мачту, вынесенную почти на два метра над коньком крыши летней бани (см. фото ниже). Сам датчик по конструкции приспособлен для круглогодичного пребывания на открытом воздухе: инструкция уверяет, что ABS-пластик корпуса выдерживает длительное УФ-облучение и перепады температур от -40° до +60°. Однако, считывающий контроллер желательно установить под крышей, потому приходится выносить его от датчика на существенное расстояние. Автономное питание здесь делать необязательно, так как к бане подведено электричество, достаточно только нарастить кабель.

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

Контроллер устанавливался на противоположной, обращенной в сторону дома стенке строения под свесом крыши (см. фото далее). Расстояние от датчика до контроллера составило около 5-6 м. Так как гигабитный Ethernet мы тут не изобретаем, то тянуть витой парой не требуется; достаточно обычного гибкого кабеля в 4 жилы.
Разбирать датчик полностью, чтобы подключить кабель заново, я не стал: просто нарастил имеющийся. Поскольку место сращивания открыто всем ветрам, его следует оформить очень тщательно. Жилы скручиваются, пропаиваются и тщательно изолируются друг от друга термоусадочным кембриком. Черный провод минуса питания можно при этом объединить с экраном кабеля. Поверх всего этого осаживается более толстая трубка, которая должна перекрывать внешнюю изоляцию с обеих сторон. Поверх этой трубки наматывается слой самослипающейся изоляции, который придает сростке дополнительную прочность при растяжении. Однако, самослипающаяся изоляция не обладает стойкостью к ультрафиолету, потому последним слоем сверху наматывается черная тканевая изоляция, которая потом пропитывается водостойким лаком. Такое соединение (часть его видно внизу на фото в начале статьи), хотя и выглядит не слишком эстетично, но, как показал опыт, выдерживает даже многомесячное пребывание на влажном грунте.

Для удобства монтажа и доступа к контроллеру второй конец кабеля оформляется в виде разъема PC-4 см. (см. здесь и здесь (торчит слева на предыдущем фото).
Ниже сростки кабель прикрепляется к мачте хомутом для разгрузки от механических напряжений. Кабель в месте входа на чердак следует оставить немного провисать, как показано на фото ниже — в противном случае он послужит отличным проводником для попадания дождевой воды внутрь строения.
Конструкцию крепления мачты к стенке строения без нарушения герметичности крыши можно рассмотреть на двух фото ниже. Конструкция собрана из брусков 50×90 мм. Бруски (обязательно до сборки, по отдельности!) грунтуются пинотексом/акватексом и покрываются в два слоя яхтным лаком. При использовании качественных лакокрасочных материалов и хорошо просушенных деревяшек такое исполнение может продержаться без деградации лет двадцать.

Схема подключения и программа обработки
Вместо штатного Serial, как мы делали в пробном скетче ранее, здесь данные посылаются через передатчик SYN115 433 МГц (описан в этой статье) с намеренно замедленной скоростью 1200 бит/с для надежности. Схема подключения (см. рис. ниже) отличается от пробной только подключением этого передатчика и наличием сигнального светодиода. Не удивляйтесь номиналу токограничивающего резистора при светодиоде — если выбрать суперяркий тип (вроде такого), то тока в доли миллиампера ему достаточно для нормального свечения. Передатчик SYN115 требует напряжения питания 3,3 В, которые мы берем от встроенного стабилизатора Arduino Nano. Потребление SYN115 на частоте 433 МГц составляет 12,5 мА в момент передачи, потому даже таким, как в Arduino Nano, заковыристым образом организованного источника 3,3 В с предельным током 50 мА должно хватать гарантировано. Так как передача односторонняя (от контроллера к передатчику), то для согласования уровней достаточно простого резистивного делителя 2:3 (в данном случае 6,8 кОм и 3,3 кОм).

Полученные данные здесь подвергаются более серьезной обработке. Во-первых, нет никакого практического смысла в направлении, измеренном с точностью до градусов, тем более, что это не точность, а разрешение — согласно спецификации, погрешность составляет ±3°. На практике вообще-то достаточно деления на восемь направлений («север», «северо-восток», «восток»…), но, раз предлагают, мы поделим на 16, как принято в метеорологии («север», «северо-северо-восток», «северо-восток», «восток-северо-восток», «восток»…). Каждый из 16 таких румбов направления означает сектор круга в 22,5°, т.е. ±11,75° от центрального радиуса для данного направления. Кто не понял, приглашаю взглянуть на страницу Википедии «румб», где приведены центральные углы и названия всех 32 морских румбов, из которых мы выбираем 16 метеорологических. Попросту обозначим 16 румбов цифрами от 0 до 15, где 0 — направление на север, их мы и будем передавать по радиоканалу.
Преобразование значения угла, полученное от датчика, в коды 0-15 в программе End_Datchik_anemometr_Wind_avr_SYN115 (см. архив по адресу в конце статьи) делается отдельной функцией convert_dir_byte(int degr), состоящей из простого набора условий (в комментариях к каждой строке приведены значения центральных углов, а также общепринятые английские и русские сокращенные названия направлений, которые нам потом понадобятся для вывода на дисплей):
byte convert_dir_byte(int degr) //переводим градусы в 16 значений направления { if ((degr>=349)||(degr<=11)) return(0); //"N " 0,360 С if ((degr>=12)&&(degr<=33)) return(1); //"NNE" 22.5 ССВ if ((degr>=34)&&(degr<=56)) return(2); //"NE " 45 СВ if ((degr>=57)&&(degr<=78)) return(3); //"ENE" 67.5 ВСВ if ((degr>=79)&&(degr<=101)) return(4); //"E " 90 В if ((degr>=102)&&(degr<=123)) return(5); //"ESE" 112.5 ВЮВ if ((degr>=124)&&(degr<=146)) return(6); //"SE " 135 ЮВ if ((degr>=147)&&(degr<=168)) return(7); //"SSE" 157.5 ЮЮВ if ((degr>=169)&&(degr<=191)) return(8); //"S " 180 Ю if ((degr>=192)&&(degr<=213)) return(9); //"SSW" 202.5 ЮЮЗ if ((degr>=214)&&(degr<=236)) return(10); //"SW " 225 ЮЗ if ((degr>=237)&&(degr<=258)) return(11); //"WSW" 247.5 ЗЮЗ if ((degr>=259)&&(degr<=281)) return(12); //"W " 270 З if ((degr>=282)&&(degr<=303)) return(13); //"WNW" 292.5 ЗСЗ if ((degr>=304)&&(degr<=326)) return(14); //"NW " 315 СЗ if ((degr>=327)&&(degr<=348)) return(15); //"NNW" 337,5 ССЗ }
Кроме того, скорость ветра, как мы уже говорили, нагляднее всего показывать в метрах в секунду. При этом второй знак после запятой (единицы см/сек) оказывается не только избыточным, но и находится за пределами точности измерений. Погрешность измерения скорости выражается довольно сложной формулой, представляющей комбинацию аддитивной и мультипликативной составляющих (см. спецификации датчика в фирменном описании, в русскоязычной статье указаны иные значения коэффициентов):
±(0,2 м/с ± 0,02*v)
Здесь v — измеренная величина скорости. То есть даже вблизи нуля погрешность не менее 20 см/сек, и показывать в этих условиях сантиметры бессмысленно, это только мешает четко сформулировать условие отсутствия ветра (напомним, что вблизи нуля направление теряется раньше, чем скорость). Т.е. при тихом ветре мы рискуем получать все время направление на север, которое в реальности не имеет места. Для обхода этой ситуации мы делением на 10 преобразуем значение скорости в целое число дм/сек, и при этом намеренно не округляем, а отбрасываем дробную часть.
Усреднение результатов
Естественно, в отличие от механического флюгера, ультразвуковой датчик не имеет никакой инерции, потому показания и скорости и направления «дребезжат». Цифровые наводки на питание тут ни при чем, так как датчик не имеет аналоговых элементов, на которых эти наводки могли бы сказаться: он просто ловит мгновенные значения в момент запроса. Поэтому значения и скорости и направления надо как-то фильтровать.
Строго говоря, тут надо использовать векторное осреднение, о котором подробно рассказывалось в этой статье. У слабеньких AVR-контроллеров такой алгоритм занимает существенное количество ресурсов из-за использования громоздких функций sin(), cos(), atan2(), а также умножения и деления действительных чисел. Такая обработка вместе с отправкой данных по намеренно замедленному радиоинтерфейсу может даже не влезть в отведенную секунду. Кстати, при разложении вектора на синусную и косинусную проекции спотыкаться на факте различия географических и математических отсчетов угла не нужно. В вышеуказанной статье о векторном осреднении отсчеты углов преобразовывались в математическом стиле, что по здравому рассуждению оказалось излишним усложнением: совершенно безразлично, от какой оси и в какую сторону отсчитывать углы, главное, чтобы их интерпретации до и после расчетов совпадали.
Мы немного облегчим задачу следующим образом: усреднение значений скорости будем выполнять обычным скалярным способом нахождения среднего из ряда значений. С направлением так не получится, поэтому здесь применяется векторное осреднение нормированных значений проекций (т.е. просто значений sin() и cos() для градусов направления). При этом мы имеем некоторую ошибку в результирующих значениях модуля скорости, но мы исходим из предположения, что данные за время осреднения «гуляют» не сильно, потому будем считать эту ошибку сравнимой с собственной погрешностью датчика.
В цитированной программе End_Datchik_anemometr_Wind_avr_SYN115 эта задумка выполняется для четырех значений данных, получаемых с промежутком в 1 секунду. Проверка показала, что направление при этом фильтруется приемлемым образом, хорошо имитируя инерцию механического флюгера. А вот усредненное значение скорости демонстрирует явно заниженные показания, как, собственно, и должно быть при применении фильтра низкой частоты к последовательности разновысотных импульсов. Поэтому я сделал второй вариант скетча (End_Datchik_anemometr_Wind_max_SYN115), в котором вместо усреднения из последовательности четырех значений скорости выбирается наибольшее. Сравнение с ручным фирменным анемометром показало бо́льшую адекватность результатов для этого случая.
Можно использовать любой вариант, в зависимости от ваших предпочтений. Тут еще многое зависит от установки датчика: на моем заросшем участке датчик оказался на уровне верхушек деревьев, что, конечно, не избавляет полностью от турбулентных завихрений. Если его установить выше и на открытом пространстве вдали от препятствий, возможно, более адекватным окажется вариант с усреднением значений скорости.
Заметим, что если у вас показания направления все-таки слишком сильно будут «прыгать» от раза к разу, фильтрацию можно улучшить, объединив векторное осреднение с методом скользящего среднего https://habr.com/ru/articles/325590/. Тут следует вспомнить, что нормативное время отклика датчика составляет 1 секунду, поэтому подобные методы фильтрации замедляют отклик больше, чем обычное усреднение. Реализовывать в виде готовой программы эту идею я не стал, в том числе пожалев Arduino, который все-таки не очень приспособлен для таких вычислительных задач, но любители более мощных контроллеров могут попробовать приложить свои силы.
После обработки данные объединяются в байтовый массив, предваряются тремя байтами идентификатора данных «WND» и посылаются через передатчик с помощью стандартной библиотеки VirtualWare. Процедура пересылки данных с помощью пары передатчик-приемник SYN115/SYN480r описана в уже упоминавшейся статье. Обратим только внимание на скорость передачи 1200 бит/с: в принципе можно и быстрее, но здесь нас ничего не лимитирует, а чем медленнее скорость, тем надежнее.
Прием данных и отображение
Приемная часть с дисплеем для отображения данных не требует множества питаний и может быть организована на голом контроллере, что уменьшает габариты и потребление. Схема показана на рисунке ниже, и в ней не очень требуется даже показанный внизу отдельный 5-вольтовый стабилизатор — вполне можно обойтись внешним адаптером на 5 В. В остальном схема состоит из трех компонентов: контроллера ATmega328P с обвязкой, приемника SYN480r 433 МГц (описанного в той же статье), а также дисплея, в качестве которого был выбран минималистичный OLED-дисплей WEH000802 (8 символов × 2 строки). Не забывайте, что для надежного приема антенны передатчика и приемника желательно располагать в пространстве параллельно друг другу.

В программе, доступной в архиве под названием End_Priemnik_0802_SYN480_timer2 дополнительной обработки данных не ведется, за исключением подстановки последнего сохраненного значения направления при нулевой скорости, как в проверочной программе выше, а также преобразования кода направления в стандартные строковые обозначения. Функция преобразования convert_dir() аналогична используемой в передатчике для преобразования градусов направления в код, но устроена проще:
String convert_dir(int degr) //переводим код в строку направления
{
if (degr==0) return("Северн "); //0 0,360 N
if (degr==1) return("С-С-В "); //1 22.5 NNE
if (degr==2) return("С-В "); //2 45 NE
if (degr==3) return("В-С-В "); //3 67.5 ENE
if (degr==4) return("Восточн"); //4 90 E
if (degr==5) return("В-Ю-В "); //5 112.5 ESE
if (degr==6) return("Ю-В "); //6 135 SE
if (degr==7) return("Ю-Ю-В "); //7 157.5 SSE
if (degr==8) return("Южн "); //8 180 S
if (degr==9) return("Ю-Ю-З "); //9 202.5 SSW
if (degr==10) return("Ю-З "); //10 225 SW
if (degr==11) return("З-Ю-З "); //11 247.5 WSW
if (degr==12) return("Западн "); //12 270 W
if (degr==13) return("З-С-З "); //13 292.5 WNW
if (degr==14) return("С-З "); //14 315 NW
if (degr==15) return("С-С-З "); //15 337,5 NNW
}
Отсчет времени в программе производится с помощью Timer2. Если данные не получены приемником в течение 16 секунд, выводятся прочерки. Для вывода на дисплей русских букв использована библиотека LiquidCrystalRus. Пример вывода результатов представлен на фото ниже.

Общая стоимость проекта должна укладываться к 15 тыс. рублей, в зависимости от использованных материалов. Если, конечно, не захотите разориться на оригинальный ArduinoNano, но у меня уже лет десять отлично работают клоны (в основном с адаптером CH340). Архив со схемами и программами можно скачать с моего сайта по следующему адресу: https://revich.lib.ru/AVR/Ultrasound.zip.
