Loading…
Loading…
- Аудиоинформер скорости ветра
- Что это такое?
- Что для этого необходимо?
- Как это собрать?
- Исходный код
- Демонстрация работы устройства
- Что ещё можно сделать?
- Беспроводная метеостанция
- Что это такое?
- Что для этого необходимо?
- Как это собрать?
- Сборка автономной части
- Сборка ретранслятора
- Исходный код
- Код автономной части
- Код платы, работающей в помещении
- Регистрация метеостанции в «Народном мониторинге»
- Демонстрация работы устройства
- Что ещё можно сделать?
- Электронный ветроуказатель
- Первая версия
- Вторая версия
- Конструкция
- Программа расчета скорости ветра
- P.S.
- P.P.S. 2018
Аудиоинформер скорости ветра
Платформы: Arduino Uno
Тэги: метео, метеостанция, ветер, скорость ветра, аудио, mp3, dfplayer, анемометр
Что это такое?
В этой статье мы расскажем о том, как собрать информер скорости ветра. Наше устройство будет сообщать об изменении скорости ветра проигрыванием различных аудиофайлов. Каждой скорости будет соответствовать свой аудиофайл.
Что для этого необходимо?
Для изготовления информера нам понадобятся:
Карта памяти microSD объемом ≤32 ГБ
Динамик или колонка мощностью ≤3 Вт
Как это собрать?
Соберите аппаратную часть по схеме, изображённой на рисунке выше (питание на данном этапе не подключайте).
Запишите на microSD 7 композиций с именами
01.mp3
…07.mp3
.Вставьте microSD в MP3-модуль.
Подключите питание.
Прошейте Arduino Uno скетчем, приведённым ниже (на время прошивки необходимо отсоединить провода «TX» и «RX» от Arduino Uno).
Подуйте на анемометр, убедитесь в работоспособности. При воспроизведении композиций на MP3-модуле будет зажигаться светодиод.
Исходный код
- wind_informer.ino
#include <mp3TF.h> mp3TF mp3tf = mp3TF (); unsigned int speed; unsigned char prev_speed; unsigned int speed_change_counter = 0; boolean speed_changed = false; void setup() { mp3tf.init(&Serial); Serial.begin(9600); } unsigned int measureSpeed() { return analogRead(A0); } void saySpeed() { unsigned char pseudospeed = speed/40; if(pseudospeed == 0) mp3tf.stop(); else if(pseudospeed > 6) mp3tf.play(7); else mp3tf.play(pseudospeed); } void loop() { speed = measureSpeed(); if (abs(speed-prev_speed) > 40 && speed/40 != prev_speed/40) { speed_change_counter = 0; speed_changed = true; prev_speed = speed; } else { if(speed_changed) { if(++speed_change_counter == 10) { speed_changed = false; saySpeed(); } } } delay(100); }
Демонстрация работы устройства
Что ещё можно сделать?
Автономную метеостанцию. Несмотря на потребление в 30 мА, анемометр может быть использован и в автономных устройствах. Для этого надо подавать на него питание через MOSFET-транзистор. Одно измерение будет занимать 1 секунду, а следовательно расходовать всего 8,3 нА·ч. Если снимать показания 1 раз в 1 минуту, то на батарее из двух стандартных АА Li-Ion аккумуляторах устройство сможет проработать более полугода.
Вы используете устаревший браузер. Этот и другие сайты могут отображаться в нём некорректно.
Необходимо обновить браузер или попробовать использовать другой.
Страница 1 из 2
Необходимо контролировать работу вентиляции, есть движение воздуха в канале – все нормально, если нет или даже реверс – то как то сигнализировать.
К сожалению никак не могу найти что использовать в качестве датчика движение воздуха. Была идея подключить вентилятор от БП, но по моему там наведенная эдс ничтожна мала, чтоб замерить. Может я ошибаюсь и есть схема включения?Лопух из резины на шарнире (двух веревочках) и концевик. Или лопух с потенциометром вместо шарнира.
?Например плоский кусок пластика. Размер и тяжесть его надо подбирать в зависимости от диаметра воздуховода и скорости потока. При движении воздуха он будет отклоняться в ту или иную сторону.
Канал горизонтальный или вертикальный?
Понятно. Шибко кустарно. Но все равно спасибо.
Хм. Пытаюсь найти датчик используемый в анемометре, кайтеры например юзают такой приборчик.
Вот нарыл интересный пример, хотя конечно тоже ручной труд http://vladikoms.livejournal.com/18329.htmlПоследнее редактирование: 10 ноя 2015
Он вычислит скорость потока, но не укажет направление. И опять же кустарщина. Такой надо.
Если заменить крыльчаку на лопасти (пропеллер) и установить в центре канала так, что бы лопасти занимали максимально площадь канала в поперечном сечении, то можно будет с определенной точностью измерять с помощью этого “интересного примера” (после небольшой доработки) не только скорость потока, но и направление.
А еще есть такое новое изобретение человечества как флюгер!
Если нет идей, то не надо встревать. Для флуда откройте свою тему.
Бери вентилятор от Б.П. или кулер от процессора.
В качестве сигнала не эдс, а сигналы от датчиков холла.А если просто вентилятор и две оптопары на просвет с небольшим смещением. По времени срабатывания опптопар определяем направление вращения, а по частоте – скорость потока. Возможно что оптопары будут быстро забиваться пылью. Самый простой и надежный способ, по моему, с потенциометром и флажком на нем (как предложил DrProg). Если канал горизонтальный, то флажок просто висит вертикально и отклоняется в зависимости от потока воздуха. Если канал вертикальный, то флажок делается в виде буквы Г и так же отклоняется в зависимости от направления потока.
Последнее редактирование: 11 ноя 2015
Чем, собственно, это флуд? Это идея. Тем более, что он используется в реальных приборах для определения направления ветра (см. картинку выше).
Ну если только како-нибудь совсем компактный образец флюгера, иначе как его в канал вентиляции запихать.
Решил попробовать 3х осевой гироскоп использовать, закрепив его на подвижной пластне.Открытая оптопара в канале вентиляции наврное не очень хорошо.
Я пробовал подключать вывод тахометра кулера к мультиметру, дул на него феном, показания какие то странные, больше похоже на шум.
Вы же не написали какой диаметр воздуховода. В роли самодельного флюгера можно, после доработки, использовать хоть потенциотметр, хоть энкодер. А оптопара в любом реальном воздуховоде зарастет пылью за 2 – 3 месяца.
Когда то довелось разбираться с газовыми счетчиками. В одном из них скорость потока газа измерялась по доплеровскому смещению. Поток сильнее, смещение больше ( против потока звук распространяется хуже). На Ардуино это вряд ли можно сделать, а на голом Си реально. На одном пине висит излучатель звука и генерит звук с известной частотой. Установить на некотором расстоянии микрофон и завести усиленный сигнал с микрофона на счетный вход таймера и посчитать за определенный период количество импульсов. Ну это как идея.
Флюгер , уже предлагали выше – они используются в метеостанциях, очень простое и надежное устройство. Размеры бывают разные от пары сантиметров ну и до метровых гигантских.
На производстве используют датчики разряжения – давления, используется перепад давления(разряжения) воздуха прямой и обратный, чувствительный элементе может быть от простых дифтрансформаторных датчиков до всяких тензопреобразователей и прочих.
То есть при прямом движение воздуха у вас измеряется например давление, а при обратном разряжение.
Ну а если нужен расход воздуха, то с помощью тех же датчиков надо измерять перепад давления.Последнее редактирование: 11 ноя 2015
конструкция:
на плату впаять 2 термистора, и резистор.
разместить так чтобы они были на одной линии, параллельно оси движения воздуха. резистор между двух термисторов с небольшим зазором 3-5 мм
накрыть сверху полкуруглым кожухом, чтобы воздух продувался по кожуху и обдувал резистор с термисторами.как пользоваться:
греем резистор постоянным током, считываем показания с термисторов.
если показания примерно одинаковые, значит воздух не движется.
если один термистор показывает температуру выше другого, значит воздух движется, а направление движения – со стороны холодного термистора в сторону тёплого.по величине разности двух температур можно приблизительно оценить скорость движения воздуха.
Спасибки, прикольная идея.
Подобное решение уже видел, но несколько в другом исполнении: Туба, посредине небольшая лампочка (автомобильная), а с двух сторон по датчику температуры. Алгоритм такое же.
Все таки попробую пока с гироскопом, уже куплен.
Страница 1 из 2
Беспроводная метеостанция
Платформы: Teensy, Arduino Uno
Тэги: метеостанция, погода, температура, влажность, прогноз
Что это такое?
В этой статье мы расскажем о том, как собрать полноценную метеостанцию,
передающую данные о погоде на широко известный сервис
«народный мониторинг».
Наша метеостанция будет состоять из двух устройств: компактного автономного
устройства, измеряющего погодные показатели, и устройства-ретранслятора,
получающего эти показатели и отправляющего их на «народный мониторинг».
Устройства будут связываться по беспроводному каналу связи на частоте 433 МГц.
Автономная часть будет питаться от трёх пальчиковых батареек и сможет
просуществовать на одном комплекте батарей до года при периоде опроса датчиков
в 20 мин.
Такая конструкция позволяет не сверлить стены для прокладки проводов с улицы, где необходимо производить измерения, в помещение, где результатами этих
измерений надо пользоваться.
Что для этого необходимо?
Для изготовления автономного передатчика нам понадобятся:
Держатель пальчиковых батареек на x3 AA
Для изготовления ретранслятора нам понадобятся:
Так же удобно установить два светодиода для индикации процессов:
Для звуковой индикации разряда батареи автономной части удобно использовать
пьезо-пищалку:
Как это собрать?
Сборка автономной части
Сборка ретранслятора
На этом сборка минимально функционального ретранслятора закончена. Если вы хотите установить светодиодную индикацию и звуковую сигнализацию, то выполните пункты ниже.
Исходный код
Код автономной части
- meteo_sensor.ino
#include <Arduino.h> #include <SHT1x.h> #include <LowPower_Teensy3.h> #include <ampline.h> // Таймаут между посылками (не более 65535) #define TIMEOUT 60000 // Количество попыток отправки посылки #define ATTEMPTS 3 // Информационный пин передатчика #define RF_PIN 5 // Пины датчика температуры и влажности #define GND1_PIN 10 #define VCC1_PIN 11 #define GND2_PIN 7 #define VCC2_PIN 8 #define DATA_PIN 12 #define CLK_PIN 9 AmperkaLine rf(RF_PIN); SHT1x sht1x(CLK_PIN, DATA_PIN); void loop(void); // Функция усыпления платы. Каждые TIMEOUT секунд // будет вызываться функция loop_func. TEENSY3_LP LP = TEENSY3_LP(); sleep_block_t* LP_config; void sleep_mode(void) { LP_config = (sleep_block_t*)calloc(1,sizeof(sleep_block_t)); // Просыпаться будем по таймеру LP_config->modules = (LPTMR_WAKE); // Задаём таймаут для таймера LP_config->lptmr_timeout = TIMEOUT; // По истечении таймаута будет вызываться функция loop LP_config->callback = loop; LP.Hibernate(LP_config); } // Функция включения периферии void periferial_start(void) { // Включаем линию передачи данных pinMode(RF_PIN, OUTPUT); // Включаем питания и земли датчиков температуры и влажности pinMode(GND1_PIN, OUTPUT); pinMode(GND2_PIN, OUTPUT); pinMode(VCC1_PIN, OUTPUT); pinMode(VCC2_PIN, OUTPUT); digitalWrite(GND1_PIN, LOW); digitalWrite(GND2_PIN, LOW); digitalWrite(VCC1_PIN, HIGH); digitalWrite(VCC2_PIN, HIGH); // Включаем светодиод для индикации передачи pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, HIGH); // Выбираем в качестве опорного напряжения внутренний analogReference(INTERNAL); } // Функция выключения периферии void periferial_stop(void) { // Выключаем линию передачи данных pinMode(RF_PIN, INPUT); // Выключаем датчик температуры и влажности pinMode(GND1_PIN, INPUT); pinMode(GND2_PIN, INPUT); pinMode(VCC1_PIN, INPUT); pinMode(VCC2_PIN, INPUT); pinMode(18, INPUT_PULLUP); pinMode(19, INPUT_PULLUP); // Выключаем светодиод digitalWrite(LED_BUILTIN, LOW); } void setup(void) { // Ничего не инициализируем, сразу засыпаем sleep_mode(); } // Эта функция выполняется раз в TIMEOUT секунд void loop(void) { unsigned long msg; byte temp, humidity, voltage; // Включаем периферию periferial_start(); // Подождём, пока включится датчик температуры и влажности delay(30); // Получаем входные данные с сенсоров temp = (byte)(sht1x.readTemperatureC() + 40.)*2; humidity = (byte)sht1x.readHumidity(); voltage = analogRead(A0)/4; // Составляем из данных посылку msg = 0; msg |= voltage; msg <<= 8; msg |= humidity; msg <<= 8; msg |= temp; // Отправляем несколько раз посылку for(int i = 0; i < ATTEMPTS; i++) rf.send(msg); // Выключаем периферию periferial_stop(); // После выхода из функции плата снова уснёт }
Код платы, работающей в помещении
- receiver.ino
#include <Arduino.h> #include <SPI.h> #include <Ethernet.h> #include <ampline.h> byte mac[] = { 0x90, 0xA7, 0xDA, 0x0F, 0xBC, 0x75 }; char server[] = "narodmon.ru"; EthernetClient client; const int rfpin = 7; AmperkaLine rf(rfpin); void setup(void) { pinMode(rfpin, INPUT); pinMode(6, OUTPUT); Serial.begin(9600); Serial.println("Started."); } void loop(void) { static unsigned long pushtimeout = 0; static float temp, humidity, voltage; unsigned long msg; int res; if((res = rf.receive(&msg)) == 0) { temp = ((float)(msg&0xFF))/2. - 40.; msg >>= 8; humidity = (float)(msg&0xFF); msg >>= 8; voltage = (float)(msg&0xFF) / 256. * 1.2 * 10 * 1.1; digitalWrite(6, HIGH); Serial.print("Temp: "); Serial.print(temp); Serial.print(", humidity: "); Serial.print(humidity); Serial.print(", voltage: "); Serial.println(voltage); digitalWrite(6, LOW); } else Serial.println('E'); if(millis() - pushtimeout > 60000*5) { pushtimeout = millis(); Serial.println("Starting Ethernet..."); if (Ethernet.begin(mac) == 0) { Serial.println("Failed to configure Ethernet using DHCP"); while(1) { } } delay(1000); Serial.println("connecting..."); if (client.connect(server, 8283)) { Serial.println("connected"); client.println("#90-A7-DA-0F-BC-75#Sensor#55.751775#37.616856#0.0"); client.print("#90A7DA0FBC7501#"); client.print(temp, DEC); client.println("#In"); client.print("#90A7DA0FBC7502#"); client.print(humidity, DEC); client.println("#Humidity"); client.print("#90A7DA0FBC7503#"); client.print(voltage, DEC); client.println("#Voltage"); client.println("##"); } else Serial.println("connection failed"); { unsigned long tm = millis(); while(millis() - tm < 5000) { if (client.available()) { char c = client.read(); Serial.print(c); } } } client.stop(); } }
Регистрация метеостанции в «Народном мониторинге»
Чтобы данные, передаваемые нашим устройством, корректно отображались на народном
мониторинге, необходимо выполнить следующее:
Установить уникальный MAC-адрес устройства.
Зарегистрироваться на сайте «Народного мониторинга».
Авторизоваться.
Открыть список датчиков и установить номиналы передаваемых данных.
Демонстрация работы устройства
Что ещё можно сделать?
Мы установили только сенсор температуры и влажности. Но у Teensy остаётся ещё много свободных ножек, т.ч. можно добавить разных датчиков: освещённости, атмосферного давления, скорости ветра и т.д.
Teensy прямо на борту имеет часы реального времени (RTC). Для их работоспособности не хватает только кварца. Можно купить кварц на 32,768 КГц в любом магазине радиоэлементов и припаять его. Тогда можно пробуждать Teensy по будильнику RTC. Достоинство в том, что можно будить устройство чаще в те часы, когда нужны более точные показания. Например, в рабочее время будить устройство каждые 5 минут, а в остальное — каждые полчаса.
Offline
Зарегистрирован: 28.11.2015
Есть задача мониторить направление ветра и его скорость.
Пока у меня возникли такие идеи.
1. Направление ветра.
Взять токопроводящий круг, разделить его на 8 секторов, к каждому сектору подсоеденить резисторы разных номиналов. С другой стороны завести все их на аналоговый вход. +5V пустить на щетку, которая будет бегать по секторам в зависимости от направления ветра (простой флюгер). Мониторить периодически напряжение на аналоговом входе и в зависимости от того в какой диапазон попадает, значит щетка находится над тем или иным сектором.
2. Скорость ветра.
Пока ничего лучшего не придумал, кроме: вертушка крутит цилиндр с прорезью. Внутри цилиндра светодиод, снаружи – фотодиод или фоторезистор. Необходимо каким-то образом посчитать кол-во срабатываний фотодиода в секунду. Собственно, вопрос: как посчитать?
И в правильном ли вообще направлении я думаю по обоим вопросам? Может есть проверенные боле простые или практичные решения?
Электронный ветроуказатель
Offline
Зарегистрирован: 07.06.2012
Добрый день!
Хочу развить свой проект метеостанции, добавить в неё функцию отображения текущего направления ветра, возможно, впоследствии добавить и анемометр. Но пока речь пойдет о датчике направления ветра. Долго гуглил интернет, искал на ибее, амазоне и прочее, но дешевых датчиков не нашел. Вроде руки откуда надо, поэтому решил сделать самостоятельно и спросить вашего совета, ибо есть сомнения. В качестве ветроуказателя хочу использовать обычный компьютерный кулер, вот картинка.
Я вынул из него все “потроха”. Вместо заводской платы сделаю свою. Лопасти отрежу и сделаю подобие флюгера, ну это уже дело техники. В качестве датчика хочу использовать датчики холла. На внутреннюю обойму приклею магнит. А вот дальше что-то у меня сомнения, и в голове несколько вариантов решения:
1. Использовать униполярные ДХ, разместить их внутри обоймы. Получается, что их нужно минимум 8 штук. Что не есть очень хорошо, т.к. до крыши дома (примерно 12 – 15 метров) придется тянуть минимум 10 проводов. Да и с калибровкой будет не легко.
2. Использовать аналоговые ДХ, тут проще, я так понимаю, можно отделаться двумя датчиками, т.к. одного, думаю, будет мало. Но тут сложность, во-первых: как заранее откалибровать эти датчики, ведь дома это одно, а когда будет стоять на крыше, падение напряжения в кабеле будет точно. Во-вторых: абсолютно не знаю, как себя поведут аналоговые ДХ при разной температуре, от +30 до -50. Наверняка температура будет влиять на выходное значение напряжение у ДХ.
3.Думал использовать герконы, но не нашел подходящие по габаритам, и еще все минусы первого варианта.
4.Может оптический энкодер использовать? Но все что я видел, очень дорого стоит, да и есть ограничение на длину кабеля.
Что посоветуете вы? Какой вариант выбрать? Может, все это чепуха и есть альтернативные решения?
Ранее был сделан прототип анемометра из одного ультразвукового дальномера HC-SR04. Он умел рассчитывать проекцию скорости ветра на линию между приемником и передатчиком. Для получения вектора скорости ветра на плоскости (2D) требуется вторая координата, которую мы получим, если добавим второй датчик перпендикулярно первому. В этом случае можно закрепить анемометр стационарно — отпадает необходимость использовать флюгер и как-то организовывать подвижные контакты.
Первая версия
Сказано — сделано, причем основательно.
Из обрезков полипропиленовых труб сварил крестовину. Все датчики отпаял и удлинил проводами, которые проложил внутри труб. Расстояние между датчиками получилось 70 см.
Код программы такой.
#include <dht.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define Trig 4
#define Echo 2
#define Trig2 8
#define Echo2 12
#define ONE_WIRE_BUS 7
#define Steps
dht DHT;
#define DHT21_PIN 0
static const float defDist = .6985; // m
static const float defDist2 = .713; // m
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
void setup()
{
pinMode(Trig, OUTPUT);
pinMode(Echo, INPUT);
pinMode(Trig2, OUTPUT);
pinMode(Echo2, INPUT);
Serial.begin(57600);
// Start up the library
sensors.begin();
Serial.println("X Distance Tds18820 Tcalc Tdht Hum V");
}
unsigned long impulseTime=0;
void loop()
{
// READ DATA
//Serial.print("DHT21, \t");
int chk = DHT.read21(DHT21_PIN);
float DHTtemp = 10;
float DHThum = 50;
switch (chk)
{
case DHTLIB_OK:
// Serial.print("OK,\t");
DHTtemp =DHT.temperature;
DHThum = DHT.humidity;
break;
default:
Serial.print("DHT Error,\t");
break;
}
// DISPLAY DATA
// Serial.print(DHThum, 1);
// Serial.print(",\t");
//Serial.println(DHTtemp, 1);
sensors.requestTemperatures(); // Send the command to get temperatures DS18820
float dist = 0;
float dist2 = 0;
float temp = sensors.getTempCByIndex(0); //DHTtemp;
unsigned long impulseTime=0;
unsigned long impulseTime2=0;
int N=250;
for (int i = 0; i <N; i++) {
digitalWrite(Trig, HIGH); delayMicroseconds(10); digitalWrite(Trig, LOW);
impulseTime +=pulseIn(Echo, HIGH); delay(50);
digitalWrite(Trig2, HIGH); delayMicroseconds(10); digitalWrite(Trig2, LOW);
impulseTime2 +=pulseIn(Echo2, HIGH); delay(50);
}
//float P = 101325;
float P = 761 * 133.3;
float M = (28.95-10.934*DHT.humidity/100*(133.3*4.579*exp(17.14*temp/(235.3+temp)))/P)/1000;
float R= 8.31447; float X = 1.4 * R/M ; //X = 287;
float c = sqrt( X *(temp+273.15));
dist = impulseTime * c / 1e6 /N;
dist2 = impulseTime2 * c / 1e6 /N;
float Speed_of_sound = defDist*N/impulseTime * 1e6;
float Speed_of_sound2 = defDist2*N/impulseTime2 * 1e6;
float Tcalc = sq(Speed_of_sound)/X - 273.15;
float v = c- Speed_of_sound;
float v2 = c- Speed_of_sound2; float v3 = sqrt(sq(v) + sq(v2));
int wd = int(atan(-v/v2)*180/3.1416);
if (v>0) {wd+=90;} else {wd+=270;}
//Serial.println("X Distance Tds18820 Tcalc Tdht Hum V");
//Serial.println(String(impulseTime) + char(9) + String(impulseTime2));
Serial.println(String(impulseTime) + char(9) + String(impulseTime2) + char(9) + String(dist, 5) + char(9) + String(dist2, 5) + char(9) + String(temp) + char(9) + String(Tcalc) + char(9) + String(DHTtemp)+ char(9) + String(DHThum) + char(9) + String(v) + char(9) + String(v2) + char(9) + String(v3) + char(9) + String(wd));
}
Два последних числа дают искомую горизонтальную скорость и направление ветра. Направление рассчитывается в виде азимута к направлению на север и дается в градусах. Вращение по часовой стрелке.
Увы, результаты меня разочаровали.
При усреднении в 25 измерений, показания в спокойном воздухе прыгают в среднем до 1.5 м/с, при этом измерения выдаются примерно раз в сек. Если усреднить в 10 раз больше показаний ситуация улучшается, но кардинально проблему не решает. К тому же судя по графику скоростей в двух осях, одна пара датчиков фонит существенно больше другой. Скорее всего дело в проводах, которыми я удлинил датчики. Придется переделывать.
Вторая версия
Есть еще одна причина все переделать. Как отмечалось в первой теоретической части, скорость звука изменится на 1 м/с при изменении температуры примерно на 1.5 °С. Погрешности измерений по обоим осям складываются. Нужно понимать, что порывы теплого или холодного воздуха могут существенно исказить показания такого анемометра. Нет смысла в показаниях 4 м/с при легком дуновении теплого ветерка. Из диаграммы натурного эксперимента видно, что даже медленное изменение температуры вызывает дрейф измеренной скорости, а быстрое изменение температуры на 1 градус скачком поменяло измеренную скорость ветра на 1.5 м/с, в то время как датчик температуры медленно отрабатывает это изменение. Важно заметить, что эксперимент этот проходил прямо у меня на столе и изменение температуры было естественным — я ничего не трогал и искусственно ничего не нагревал.
И тут на помощь приходит тот же принцип, что и при измерении расстояния. Если помним, датчики у оригинального HC-SR04 расположены вместе, поэтому результаты не зависят от наличия ветра. Если измерить скорость звука на известном расстоянии сначала в одном направлении, а затем в другом, то разница этих двух показаний, деленная пополам и будет искомой скоростью ветра в проекции на эту ось. При этом, изменение температуры в диапазоне ±25°С дает погрешность ±4%, что абсолютно не критично и мы можем обойтись вообще без термометра. Да и зачем нам термометр? Если мы знаем время прохождения сигнала в обоих направлениях, то по формулам из прошлой статьи мы легко вычислим температуру, а значит сможем уточнить скорость ветра.
Есть лишь одна маленькая загвоздка — придется использовать два HC-SR04 на одной оси. В промышленных образцах датчики попеременно выполняют роль приемника и передатчика. В нашем случае для этого придется подключить пищалки напрямую к arduino и программно генерировать 8 импульсов 40 кГц на одной, после чего вычленять их из другой. Зная про определенные сложности на этом пути, мне представляется проще купить еще 2 датчика по 55 рублей и попытаться обойтись малой кровью. Этим я займусь в следующий раз. А пока на двух датчиках сделаю измерение скорости ветра по одной оси и измерение температуры в такой конфигурации. Главная проблема здесь убрать помехи, которые дают такой большой разброс показаний в спокойном воздухе.
Конструкция
Вооружившись паяльником конструкция была беспощадно распаяна на составляющие. Новую версию решил не делать так основательно, а зря. Никогда не угадаешь, где найдешь, где потеряешь. Получилось как-то так.
Во-первых, приемник расположил как можно ближе к плате, а передатчик удалил всего лишь на 20 см. Второй комплект перевернул на 180 градусов и пищалки скрепил попарно изолентой. Чем точнее соблюсти соосность обоих пар датчиков, тем лучше. В идеале мы должны получить абсолютно идентичные показания скорости прохождения сигнала в обоих направлениях в спокойном воздухе. Натурные испытания подтвердили нашу теорию. В такой конфигурации получается мало помех и весьма точные показания независимо от температуры, что подтверждается графиком ниже.
Вначале я пробовал просто дуть по направлению от синей пары к черной. Моих легких явно недостаточно. Но любопытный факт — воздух в легких успел нагреться на 1°, что раньше вызвало бы скачок скорости на 1.5 м/с, т.к. DS18B20 просто ничего не заметил. Отметим, что мои легкие способны дать всего лишь 0.5 м/с. Дальше я включил большой напольный вентилятор и направил все также от синего к черному. Видно как пошел более прохладный воздух из глубины комнаты и даже DS18B20 начал отрабатывать это снижение, но теперь его значения не используются для расчета скорости. Сделал открытие, что мой вентилятор дует со скоростью около 2 м/с. Дальше в течение паузы видим постепенное увеличение температуры и отличную корреляцию между рассчитанной и измеренной температурой. В конце поставил вентилятор с другой стороны и получил 2 м/с в обратном направлении с падением температуры. Ура, товарищи, это работает!
Программа расчета скорости ветра
#include <dht.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define Trig 4 // HC-SR04 №1
#define Echo 2
#define Trig2 8 // HC-SR04 №2
#define Echo2 12
#define ONE_WIRE_BUS 7 // DS18B20
#define Steps
dht DHT;
#define DHT21_PIN 0 // DHT21
static const float defDist = .2121; // m
static const float defDist2 = .2121; // m
float Tcalc = 0;
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
void setup()
{
pinMode(Trig, OUTPUT);
pinMode(Echo, INPUT);
pinMode(Trig2, OUTPUT);
pinMode(Echo2, INPUT);
Serial.begin(57600);
// Start up the library
sensors.begin();
Serial.println("X Distance Tds18820 Tcalc Tdht Hum V");
}
unsigned long impulseTime=0;
void loop()
{
float temp = 0;
float DHTtemp = 0;
float DHThum = 50;
// READ DHT DATA
int chk = DHT.read21(DHT21_PIN);
if (chk == DHTLIB_OK)
{
DHTtemp =DHT.temperature;
DHThum = DHT.humidity;
}
if (sensors.getDeviceCount() > 0)
{
sensors.requestTemperatures(); // Send the command to get temperatures DS18820
temp = sensors.getTempCByIndex(0); //DHTtemp;
}
float dist = 0;
float dist2 = 0;
unsigned long impulseTime=0;
unsigned long impulseTime2=0;
int N=50;
for (int i = 0; i <N; i++)
{
digitalWrite(Trig, HIGH);
delayMicroseconds(10);
digitalWrite(Trig, LOW);
impulseTime +=pulseIn(Echo, HIGH);
delay(50);
digitalWrite(Trig2, HIGH);
delayMicroseconds(10);
digitalWrite(Trig2, LOW);
impulseTime2 +=pulseIn(Echo2, HIGH);
delay(50);
}
//float P = 101325;
float P = 761 * 133.3;
float M = (28.95-10.934*DHThum/100*(133.3*4.579*exp(17.14*Tcalc/(235.3+Tcalc)))/P)/1000; //M = 0.02895;
float R= 8.31447;
float X = 1.4 * R/M ;
Tcalc = sq((defDist+defDist2)*N/(impulseTime+impulseTime2) * 1e6)/X - 273.15;
float c = sqrt( X *(Tcalc+273.15));
dist = impulseTime * c / 1e6 /N;
dist2 = impulseTime2 * c / 1e6 /N;
float Speed_of_sound = defDist*N/impulseTime * 1e6;
float Speed_of_sound2 = defDist2*N/impulseTime2 * 1e6;
float v = (Speed_of_sound-Speed_of_sound2)/2;
//float v2 = c- Speed_of_sound2;
//float v3 = sqrt(sq(v) + sq(v2));
//int wd = int(atan(-v/v2)*180/3.1416);
//if (v>0) {wd+=90;} else {wd+=270;}
Serial.println(String(impulseTime) + char(9) + String(impulseTime2) + char(9) + String(dist, 5) + char(9) + String(dist2, 5) + char(9)
+ String(temp) + char(9) + String(Tcalc) + char(9) + String(DHTtemp)+ char(9) + String(DHThum)+ char(9) + String(M,5) + char(9) + String(v));
}
Программа будет работать и без датчиков DHT-21 и DS18B20. DS18B20 для вычислений в этом коде нигде не задействован — только выводится в терминал как эталон. Без датчика влажности температура будет рассчитываться как для воздуха с 50% влажностью. На практике это вносит очень маленькую погрешность. На измерения скорости ветра эти датчики вообще не оказывают никакого влияния.
Собственно это все что можно выжать из двух HC-SR04. Для получения вектора скорости ветра на плоскости нужно добавить еще 2 датчика перпендикулярно первым и по формулам первой версии получить полную скорость и направление. Этим займусь как только приедут заказанные дополнительные датчики.
P.S.
Датчики давно приехали, конструкцию переделывал еще 2 раза и в конце концов он заработал как надо, но до крыши этот ультразвуковой анемометр так и не доехал, поэтому до сих пор продолжения и не написал, хотя идея рабочая.
P.P.S. 2018
По многочисленным просьбам выкладываю итоговый скетч, который не требует никаких библиотек (кроме стандартной EEPROM) и работает с 4 датчиками. Код со всякими вкусностями типа встроенной калибровки и сохранением калибровочных значений в энергонезависимую память. И самое главное. Описанная выше проблема с погрешностями по одной из осей была связана не с проводами, а с работающими в одной комнате с датчиками импульсными блоками питания компьютера, монитора и т.п. (их схема преобразования работает на близкой частоте 40 кГц). Я остановился на проблеме выноса датчика на улицу подальше от помех (с передачей данных по блютус). В остальном это работает. Это версия для распаянных датчиков, но есть способ не распаивать. Если вернусь к проекту — реализую.
Для этого кода неважно какое расстояние между датчиками. Нужно поместить устройство в безветренное пространство (и без импульсных помех) и через терминал несколько раз отдать 2 команды:
t21.5
u
Первая — текущая температура по эталонному термометру (любой уличный), вторая — говорит контроллеру что сейчас скорость ветра 0. Согласно этим данным он вычислит расстояние между датчиками и запишет их в EEPROM. Все дальнейшие измерения будут отталкиваться от этих значений.
// WindSpeed v.4 - Анемометр
// Copyright Evgeny Istomin gena@regimov.net, blog.regimov.net
// Используются 4 датчика HC-SR04. Приемник и передатчик разнесены на противоположные концы крестовины
// На схеме изображено положение приемников для правильного расчета направления и силы ветра
// HC-SR04 №1
// Север (0 гр)
// o
// |
// |
// HC-SR04 №2 o-------|---------o HC-SR04 №4
// Запад (270гр) | Восток (90 гр)
// |
// o
// HC-SR04 №3
// Юг (180 гр)
// при выборе материала крестовины руководствоваться http://temperatures.ru/pages/temperaturnyi_koefficient_lineinogo_rasshireniya
// лучший выбор материала - труба инвар 36H, но и обычное железо вполне годится :-)
#define DEFINE_DISTANCE 0.22 // примерное расстояние между датчиками, измеренное линейкой, в метрах.
#define MES_PAUSE 90 // Пауза между измерениями для затухания отражений. В реальности нужно не менее 1, мс.
#define MES_AVERAGE 8 // сколько измерений усреднять для температуры.
#define PRINT_PERIOD 500 // период вывода измерений в терминал, ms
#include <EEPROM.h>
#define FALSE 0
#define TRUE 1
#define Echo1 2
#define Echo2 3
#define Echo3 8
#define Echo4 5
#define Trig1 6 // HC-SR04 №1
#define Trig2 7 // HC-SR04 №2
#define Trig3 4 // HC-SR04 №3
#define Trig4 9 // HC-SR04 №4
#define Pow1 10
#define Pow2 11
#define Pow3 12
#define Pow4 13
#define T_ABS 273.15 // температура абсолютного нуля https://ru.wikipedia.org/wiki/%D0%90%D0%B1%D1%81%D0%BE%D0%BB%D1%8E%D1%82%D0%BD%D1%8B%D0%B9_%D0%BD%D1%83%D0%BB%D1%8C_%D1%82%D0%B5%D0%BC%D0%BF%D0%B5%D1%80%D0%B0%D1%82%D1%83%D1%80%D1%8B
#define PRINT_LOOP PRINT_PERIOD/(4*(MES_PAUSE)) // сколько полных циклов пропустить перед выводом измерений в терминал
float defDist1 = DEFINE_DISTANCE;
float defDist3 = DEFINE_DISTANCE;
float defDist2 = DEFINE_DISTANCE;
float defDist4 = DEFINE_DISTANCE;
float Tcalc = 0; // температура воздуха (расчетная)
const float DHThum = 50; // % влажности
float M = 0.02895; // молярная масса кг/моль https://ru.wikipedia.org/wiki/%D0%9C%D0%BE%D0%BB%D1%8F%D1%80%D0%BD%D0%B0%D1%8F_%D0%BC%D0%B0%D1%81%D1%81%D0%B0
const float R = 8.31447; // Универса́льная га́зовая постоя́нная Дж/(моль*К) https://ru.wikipedia.org/wiki/%D0%A3%D0%BD%D0%B8%D0%B2%D0%B5%D1%80%D1%81%D0%B0%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F_%D0%B3%D0%B0%D0%B7%D0%BE%D0%B2%D0%B0%D1%8F_%D0%BF%D0%BE%D1%81%D1%82%D0%BE%D1%8F%D0%BD%D0%BD%D0%B0%D1%8F
const float P = 761 * 133.3;// давление в Па. 101325 на уровне моря
float X = 1.4 * R / M ;
float c = sqrt( X * (Tcalc + T_ABS)); // скорость звука м/с https://ru.wikipedia.org/wiki/%D0%A1%D0%BA%D0%BE%D1%80%D0%BE%D1%81%D1%82%D1%8C_%D0%B7%D0%B2%D1%83%D0%BA%D0%B0
float impulseTime1 = defDist1 / c;
float impulseTime2 = defDist2 / c;
float impulseTime3 = defDist3 / c;
float impulseTime4 = defDist4 / c;
unsigned char count = 0; // счетчик циклов
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// простой фильтр-усреднитель
float filterA(float y1, float y)
{
return ((MES_AVERAGE - 1) * y1 + y) / MES_AVERAGE;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// измеряем задержку прохождения звука между датчиками, сек
float measument(unsigned char Trig, unsigned char Echo, unsigned char Pow) {
float y;
digitalWrite(Pow, HIGH);
delay(MES_PAUSE);
digitalWrite(Trig, HIGH);
delayMicroseconds(10);
digitalWrite(Trig, LOW);
y = pulseIn(Echo, HIGH);
if (count > PRINT_LOOP) Serial.print(String(y, 0) + char(9));
digitalWrite(Pow, LOW);
return y * 1e-6;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// запоминаем в flash-памяти расстояния между датчиками
void StoreDefDist()
{
EEPROM.put(0, defDist1);
EEPROM.put(1 * sizeof(float), defDist2);
EEPROM.put(2 * sizeof(float), defDist3);
EEPROM.put(3 * sizeof(float), defDist4);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// читаем из flash-памяти расстояния между датчиками
float GetDefDist(int adress)
{
float dd;
EEPROM.get(adress, dd);
if (dd <= 0) dd = DEFINE_DISTANCE;
return dd;
} ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// расчет скорости звука в зависимости от температуры, давления и влажности
void GetC(float t) {
M = (28.95 - 10.934 * DHThum * 0.01 * (133.3 * 4.579 * exp(17.14 * t / (235.3 + t))) / P) / 1000;
X = 1.4 * R / M ;
c = sqrt( X * (t + T_ABS));
} ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() {
pinMode(Pow1, OUTPUT);
pinMode(Pow2, OUTPUT);
pinMode(Pow3, OUTPUT);
pinMode(Pow4, OUTPUT);
pinMode(Trig1, OUTPUT);
pinMode(Trig2, OUTPUT);
pinMode(Trig3, OUTPUT);
pinMode(Trig4, OUTPUT);
pinMode(Echo1, INPUT);
pinMode(Echo2, INPUT);
pinMode(Echo3, INPUT);
pinMode(Echo4, INPUT);
digitalWrite(Pow1, HIGH);
digitalWrite(Pow4, HIGH);
digitalWrite(Pow3, HIGH);
digitalWrite(Pow2, HIGH);
defDist1 = GetDefDist(0); // читаем из flash-памяти расстояния между датчиками
defDist2 = GetDefDist(1 * sizeof(float));
defDist3 = GetDefDist(2 * sizeof(float));
defDist4 = GetDefDist(3 * sizeof(float));
Serial.begin(57600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
Serial.println("impT1\timpT3\timpT2\timpT4\tdist1\tdist3\tdist2\tdist4\tTcalc\tv1\tv2\tWD\tv3 " + String(PRINT_LOOP));
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() {
// период измерений = 1 / ( 4e-3 * (MES_PAUSE + 1))
impulseTime1 = measument(Trig1, Echo1, Pow1);
impulseTime3 = measument(Trig3, Echo3, Pow3);
impulseTime2 = measument(Trig2, Echo2, Pow2);
impulseTime4 = measument(Trig4, Echo4, Pow4);
//if (count > MES_AVERAGE) Serial.print(String(impulseTime1*1e6) + char(9));
Tcalc = filterA(Tcalc, sq((defDist2 + defDist4 + defDist1 + defDist3) /
(impulseTime1 + impulseTime3 + impulseTime2 + impulseTime4) ) / X - T_ABS);
if ((Tcalc > 70) | (Tcalc < -50)) Tcalc = 0;
GetC(Tcalc);
float Speed_of_sound1 = defDist1 / impulseTime1 ;
float Speed_of_sound2 = defDist2 / impulseTime2 ;
float Speed_of_sound3 = defDist3 / impulseTime3 ;
float Speed_of_sound4 = defDist4 / impulseTime4 ;
float v1 = ((Speed_of_sound3 - Speed_of_sound1) / 2);
float v2 = ((Speed_of_sound2 - Speed_of_sound4) / 2);
float v3 = sqrt(sq(v1) + sq(v2));
int wd = int(atan(v2 / v1) * 180 / 3.1416);
if (v1 < 0) {
wd += 180;
} else if (v2 < 0) {
wd += 360;
}
if (count > PRINT_LOOP) {
Serial.println(
String(c, 5) + char(9) + String(Tcalc) + char(9) + String(v1) + char(9)
+ String(v2) + char(9) + String(wd) + char(9) + String(v3)
);
count = 0;
}
while (Serial.available() > 0) {
char inCh = Serial.read();
// установка температуры. формат команды: t21.5
if (inCh == 't') {
String a = Serial.readString();
Tcalc = a.toFloat();
GetC(Tcalc);
}
// u - юстировка (установка на 0). формат команды: u
if ((inCh == 't') | (inCh == 'u')) {
defDist1 = impulseTime1 * c ;
defDist2 = impulseTime2 * c ;
defDist3 = impulseTime3 * c ;
defDist4 = impulseTime4 * c ;
StoreDefDist();
}
}
count++;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
На фото – не фазово-импульсный дезинтегратор и даже не “Либератор”, а именно то, что вынесено в заголовок – анемометр гика.
Это прибор для измерения скорости ветра. Хотите узнать как выглядит анемометр нормального человека и зачем это мне нужо-добро пожаловать под кат!
Сам по себе флюгер донедавна для меня ценности не представлял, да и скорость ветра тоже не особо важна в повседневной жизни.
А вот количественная оценка энергии, переносимой воздушными массами – это интересный показатель.
Зачем? Чтобы знать стоит-ли строить ветряк!
Если честно, то цена компонетов для постройки ультразвукового анемометра приближается к стоимости готового карманного образца:
На фото-анемометр здорового человека 😉
Обычно это крыльчатки той или иной формы, ну или максимум конусы, какие можно увидеть на аэродромах:
И конечно-же, требовалась мобильная версия, а тут еще “охотники за привидениями вышли” с их детектором паранормальной активности:
Поэтому решено было не встраивать анемометр в флюгер, а поступить вовсе даже наоборот 😉
Естественно скетч(программа) был переработан, поскольку добавлен экран LCD1602-i2c и вычисление энергии ветра.
Да, она вопреки ожиданиям зависит от куба скорости: E=(M*V^3)/2 , именно поэтому знать скорость ветра так важно.
На самом деле, медведь межу датчиками, как на заглавном фото мешал работе анемометра, поэтому был сделан “медведь на палочке” 😉
Почему флюгер-медведь?
Все просто – для участия в конкурсе “Учим медведей летать”
К слову, медведи начали летать еще когда матушка-природа даже и не задумывалась о создании человека.
Правда не по своей воле – ураган с силой ветра более 33м/с способен поднять в воздух хоть лося, хоть медведя.
Я ни разу не художник, а потому взял, да и сделал белого медведя черным 😉
Правда первый образец получился уж очень “олимпийским” и сильно походил на пуму:
Моделирование произошло до ужаса банально – приложил лист А4 к экрану, обвел маркером, сфотографировал и загрузил в Paint.
Дальше-проще – преобразовал монохромный битмап в svg онлайн
Конечно, есть 100500 других способов, тот-же 3D Builder, но на вкус все фломастеры разные 😉
А в данной разработке основное – это електроника!
Нам понадобится:
– Arduino Nano
– 2 ультразвуковых датчика расстояния HC-SR04
– экран LCD1602-i2c
– датчик влажности-температуры DHT-11/21 (плотность воздуха растет на треть при охлаждении от +50 до -20 градусов Цельсия)
– держатель батареи “Крона”
– 2-рядная гребенка контактов PLS с шагом 2.54мм длинной 15мм
– линейка 30см
Ах да, еще придется рискуя жизнью пробраться к секретному военному обьекту, снять часового и открутить пистолетную рукоятку автомата.
Шутка 😉
Тепрь о сборке – в Ардуино ВСЕГДА не хватает контнтактов питания, поэтому я запаял/распаралелил контакты питания гребенкой PLS:
Вот так – хватит!
Держатель батареи паяется на контакты Vin(плюс) и Gnd(минус)
Экранчик подключается следующим образом:
Распиновка датчика влажности/температуры:
Кстати, DHT-11 – тормозной, глюкавый и неточный, лучше взять DHT-21 (но дороже 😉
С остальными подключениями справится даже школьник – по маркировке на компонентах и полям #define программы :
#include
#include
#include
#include
LiquidCrystal_I2C lcd(0x27,16,2); // set display
#define Trig 4 // HC-SR04 №1
#define Trig2 8 // HC-SR04 №2
#define Steps
#define DHTPIN 3 // DHT21
// Uncomment whatever type you’re using!
#define DHTTYPE DHT11 // DHT 11
//#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321
//#define DHTTYPE DHT21 // DHT 21 (AM2301)
static const float defDist = .3; // m
static const float defDist2 = .3; // m
float Tcalc = 0;
unsigned int speed1 = 0;
float density[]={1.395, 1.342, 1.293, 1.247, 1.205, 1.165, 1.128, 1.093}; //air density table for teperatures from -20 to +50 Celsius with step 10
float energy = 0;
byte remap;
float squar = 0.333; //square of winf turbine
float efficiency = 0.4; // efficiency of winf turbine
DHT dht(DHTPIN, DHTTYPE);
void setup()
{
pinMode(Trig, OUTPUT);
pinMode(Trig2, OUTPUT);
Serial.begin(57600);
Serial.println(“Tdht Hum Velocity”);
dht.begin();
lcd.init();
lcd.backlight();// turn on lcd backlight
}
unsigned long impulseTime=0;
void loop()
{
float temp = 0;
float DHTtemp = 0;
float DHThum = 50;
// READ DHT DATA
DHTtemp = dht.readTemperature();
DHThum = dht.readHumidity();
float dist = 0;
float dist2 = 0;
unsigned long impulseTime=0;
unsigned long impulseTime2=0;
int N=50;
for (int i = 0; i 0) {wd+=90;} else {wd+=270;}
Serial.println(String(v));
remap=map(DHTtemp, -20, 50, 0, 7);
energy = squar*efficiency*density[remap]*pow(v, 3)/2; //windpower (m*v^3)/2
lcd.setCursor(0, 0);
lcd.print(“Speed:”);
lcd.setCursor(7, 0);
lcd.print(v);
lcd.setCursor(0, 1);
lcd.print(“Power:”);
lcd.setCursor(7, 1);
lcd.print(energy);
}
Да, скетч следует залить в микроконтроллер через Arduino IDE (задача для пятикласника 😉
Кстати, там есть два параметра:
float squar = 0.333; //площадь, ометаемая лопастями ветряка – та которая Пи*D
float efficiency = 0.4; // Эффективность ветряка (Коєфициент Использования Енергии Ветра)
Для ветряной мельницы последний меньше 0.1
Для ротора Савониуса – 0.2
Для современных лопастей на горизонтальной оси – 0.3
Ротор Дарье – 0.4
Это важно для расчета мощности конкретного ветряка при текущей скорости потока.
А то ушлые китайцы продают ветряки площадью 1м с заявленной мощностью 400Вт, что соответствует скорости ветра 10м/с при температуре 20 градусов.
Где,Где вы видели такой ветер – я там мельницы поставлю!
Собственно все – собираем устройство – пользуемся.
Линейку с датчиками следует располагать по ветру.
Особо продвинутые могут поставить кнопку включения вместо курка 😉
Всем удачи, а я пошел лопасти печатать да ветер ловить – и не пытайтесь меня останавливать!