Laserowy anemometr

Laserowy anemometr

Pomiary parametrów wiatru są istotne w wielu dziedzinach – od marynistyki, przez meteorologię a na modelarstwie skończywszy. Klasyczne układy do pomiaru prędkości i kierunku wiatru bazują na dosyć złożonych układach mechanicznych, które mierzą prędkość obrotową specjalnych wiatraków itd. Zaproponowana konstrukcja jest znacznie prostsza – zastępuje cały układ mechaniczny rurką poruszającą się na wietrze. Dodatkowym plusem tego urządzenia jest fakt, że oferuje nie tylko informacje o kierunku, ale także o prędkości wiatru przy tym samym pomiarze, istotnie upraszczając konstrukcję systemu.

W artykule zaprezentujemy opis budowy i omówimy działanie oprogramowania ciekawego rodzaju anemometru, który do działania używa dwóch laserowych dalmierzy typu VL6180X. Zasada działania tego systemu polega na pomiarze zmiany odległości sensorów od poruszającego się na wietrze plastikowego elementu. Dane z dalmierzy są odczytywane z użyciem Arduino a następnie są przekazywane do komputera PC, gdzie oprogramowanie bazujące na Processing3 wyświetla w czasie rzeczywistym kierunek i siłę wiatru.

Ta konstrukcja jest wyjątkowo prosta i tania. Do zbudowania urządzenia wystarczą podstawowe narzędzia, takie jak wiertarka, piła czy pistolet z klejem na gorąco. Same elementy nie są również drogie, w zależności od tego, co mamy ręką, koszt zestawienia takiego anemometru autor wycenia na od 20 do 50 dolarów.

Potrzebne elementy

Do zestawienia anemometru potrzebne są w zasadzie trzy moduły elektroniczne:

  • Arduino UNO R3 (lub podobny moduł),
  • dwie sztuki laserowego dalmierza VL6180X lub podobnego dalmierza z interfejsem I2C.

Oprócz tego potrzebne będą:

  • sekcja (150 mm) plastikowej rury o średnicy wewnętrznej 65 mm,
  • zaślepka do tej rury,
  • rurka aluminiowa o średnicy 10 mm o długości co najmniej 500 mm,
  • fragment sprężynki, pasujący do rurki aluminiowej,
  • śrubka i nakrętka M4,
  • wkręt samogwintujący,
  • przewody do podłączenia sensorów odległości do Arduino (6 fragmentów o długości ok. 500 mm każdy).

Wiele z tych elementów można kreatywnie zastąpić innymi, jakie znajdziemy w naszym warsztacie, co oznacza, że z łatwością można zredukować koszt całego urządzenia do absolutnego minimum.

Zasada działania laserowego anemometru

Anemometr składa się z plastikowej rury, zawieszonej w centralnym punkcie, która rusza się wraz podmuchami wiatru. Jej przekrój jest okręgiem. W jego centralnym punkcie zainstalowane są laserowe dalmierze, które mierzą odległości od centralnego punktu okręgu do ścianek. Punkty, w których promienie lasera dotykają ścianek wewnątrz rury, definiują pewną cięciwę tego łuku. Długość tej cięciwy zmienia się, gdy rura zostaje poruszona przez wiatr – cały proces obrazują fotografie 1a, b i c.

Fotografia 1. Zmieniająca się długość cięciwy przy zmianach położenia rury mierzącej wiatr

Znając średnicę rury oraz przemieszczenia w osi X i Y (pomiary z dalmierzy), możliwe jest wyznaczenie kierunku i siły wiatru, tak jak pokazano na rysunku 1.

Rysunek 1. Algorytm wyznaczania prędkości wiatru

W pierwszej kolejności wyznaczamy przesunięcie rury w osiach X oraz Y – odpowiednio dX oraz dY. Wartości te opisane są funkcjami:

dX = |East – R x cos(\beta)|
dY = |North – R x cos(\alfa)|

gdzie:

North i East to pomiary z dalekomierzy, R to promień rury, \alfa i \beta to kąty pomiędzy promieniami w osiach North i East a cięciwą, jak pokazano na rysunku 1a.

Prędkość wiatru P wyznaczana jest zgodnie ze wzorem:

P = √(dX2 + dY2) x S

gdzie:

S to współczynnik skali, wyznaczany na etapie kalibracji.

Ustalenie kierunku wiatru w pierwszej kolejności wymaga określenia, w której ćwiartce znajduje się ten kierunek (rysunek 1b). Aby to zrobić, podstawiamy obliczone dX i dY pod równania:

North – R x cos (\alfa) – dY = 0
East – R x cos (\alfa) – dX = 0

Jeśli którekolwiek z nich nie będzie spełnione, to oznacza, że skojarzony z nim współczynnik dX lub dY jest ujemny. To pozwala nam znaleźć ćwiartkę, w której jest kierunek wiatru i wyliczyć go, jak pokazano na rysunku 2b. Kąt (Direction) wyrażony jest w stopniach względem północy, zgodnie z kierunkiem obrotów wskazówek zegarka.

Układ elektroniczny

Układ znajdujący się w anemometrze jest bardzo prosty. Sercem systemu jest moduł Arduino – w tym przypadku jest to Arduino UNO R3. Do niego podłączone są dwa laserowe sensory odległości VL6180X. Schemat układu połączeń został pokazany na rysunku 2.

Rysunek 2. Schemat pokazujący połączenia modułu Arduino i sensorów laserowych

Zasada działania laserowego dalmierza nie jest skomplikowana. Układ mierzy czas przelotu impulsu świetlnego – emituje krótkie impulsy promieniowania podczerwonego, które następnie odbijane lub rozpraszane są na jakiejś przeszkodzie. Odbite/rozproszone światło wraca do układu, zatrzymując licznik. Znając prędkość światła w powietrzu oraz czas jego przelotu, bez problemu można obliczyć drogę, jaką pokonało. Natomiast odległość do przeszkody to połowa drogi zmierzonej przez sensor, ponieważ mierzy on czas przelotu światła od emitera w układzie do przeszkody i z powrotem. Używany sensor ma maksymalny zasięg do 100 mm – jest to wartość gwarantowana przez producenta, dalszy pomiar również jest możliwy, ale tylko w sprzyjających warunkach.

Sensor VL6180X jest wyposażony w interfejs I2C, który pozwala na łatwe podłączenie go do mikrokontrolera. Z uwagi na fakt, że sensory te nie mają zmienianego adresu I2C, nie mogą być one dołączone do tej samej magistrali I2C mikrokontrolera jednocześnie. Rozwiązaniem tego problemu jest użycie linii Chip Enable układu, która włącza i wyłącza jego działanie. Po podciągnięciu jej do zasilania układ się aktywuje, dzięki czemu mikrokontroler może kontrolować, z którym sensorem się w danej chwili komunikuje.

Konstrukcja

Mechaniczną konstrukcję anemometru można zestawić w kilku prostych krokach. W pierwszej kolejności należy przygotować sprężynę, odcinając jej jeden koniec tak, aby była zakończona na płasko. Następnie do wnętrza zwiniętej sprężyny wciskamy nakrętkę M4, która pozwoli nam na umocowanie w niej pasującej śruby. Nakrętkę można dodatkowo zamocować w sprężenie za pomocą lutowia lub kleju na gorąco. Drugi koniec sprężyny mocujemy w rurce aluminiowej, dodatkowo ustalając jej pozycję za pomocą wkrętu samogwintującego, wkręconego w niewielki otwór, wykonany na boku rurki aluminiowej (fotografia 2).

Fotografia 2. Montaż sprężyny, do której będzie zawieszona rura

Długość odsłoniętej części sprężyny decyduje o właściwościach tłumienia układu mechanicznego. Jeśli odsłoni się za dużo sprężyny, rura będzie miała tendencję do wpadania w drgania, nawet przy najmniejszym podmuchu wiatru. Jeśli odsłoni się zbyt mało, sensor będzie wymagał dużego przepływu powietrza, zanim się przechyli i wykryje podmuch wiatru.

Kolejnym krokiem jest przygotowanie miejsca dla sensorów odległości. Z fragmentu płaskiego plastiku (może to być stara karta bankomatowa) wycinamy prostokąt wielkości dwukrotnej wysokości sensora VL6180X. Następnie nacinamy go delikatnie na środku i składamy pod kątem 90°. Tak przygotowany kątownik naklejamy na aluminiowej rurce tak, jak pokazano na fotografii 3. Przewody od sensorów wkładamy do wnętrza rurki (na rysunku widoczne są przewody przed przylutowaniem ich do wyprowadzeń sensorów laserowych). Dalmierze muszą być umieszczone na takiej wysokości, aby były zakrywane przez plastikową rurę, która zamontowana zostanie na górze. Na plastikowych elementach można zamontować dalmierze, na przykład za pomocą kleju na gorąco.

Fotografia 3. Montaż sensorów odległości

Przez rurkę przeprowadzono 6 przewodów. Można skręcić je w trzy pary – jedna para to zasilanie (VCC i GND), druga para to linie I2C (SDA i SCL), a trzecia to dwie linie Chip Enable do obu sensorów.

Na plastikowej rurce montujemy zaślepkę. Tak powstałą konstrukcję nakładamy na górną stronę aluminiowej rurki (tę ze sprężyną). Przewody wychodzące z układu podłączamy do Arduino zgodnie ze schematem pokazanym na rysunku 2 – układ jest gotowy do działania.

Na czas testów konstrukcję można zamontować np. do nogi stołu, w pionie, jak pokazano na fotografii tytułowej. W docelowym systemie układ należałoby oczywiście zabezpieczyć przed niekorzystnym wpływem czynników otoczenia, głównie wilgoci itp.

Oprogramowanie

W pierwszej kolejności należy przygotować środowisko do uruchomienia oprogramowania, instalując bibliotekę Pololu VL6180X w Arduino IDE. Następnie można otworzyć szkic omawianego systemu, którego treść została pokazana na listingu 1. By zainstalować bibliotekę do dalmierza, wystarczy w IDE wybrać menu zarządzania bibliotekami, a następnie dodawanie biblioteki i w proponowanych bibliotekach wyszukać i wskazać interesującą nas bibliotekę VL6180. Po zainstalowaniu biblioteki można załadować do mikrokontrolera kod programu. Można skopiować go do nowego szkicu lub wgrać plik .ino pobrany ze strony projektu (link na końcu artykułu).

Rysunek 3. Ekran Processing3 prezentujący dane z anemometru

Na komputerze należy zainstalować oprogramowanie Processing3 (można je pobrać ze strony www.processing.org). Następnie należy pobrać załączony do programu plik laser_anemometer_display.pde i jego treść skopiować do nowego szkicu w Processing3 lub wczytać sam plik. Szkic ten posłuży nam do odbierania danych i ich prezentacji na ekranie komputera PC. Ekran prezentujący dane pokazano na rysunku 3.

Kalibracja

Przed finalnym uruchomieniem programu należy skalibrować sensory odległości. Czujniki VL6180X są w stanie mierzyć odległości od 1 mm do 100 mm od czujnika. Z karty katalogowej wynika, że odchyłka pomiaru może wynieść do 15 mm bez kalibracji. Aby pomiar był precyzyjny, dalmierze wymagają kalibracji.

Aby skalibrować sensor, należy zaznaczyć jako komentarz linie odpowiedzialne za komunikację z odbiornikiem danych, a odblokować linię:

East.writeReg(VL6180X::SYSRANGE__PART_TO_PART_RANGE_OFFSET,0);

Następnie umieszczamy przed sensorem, w odległości 50 mm, przeszkodę. Może to być kartka papieru lub cokolwiek innego, do czego sensor zmierzy odległość. Odbieramy średnią odległość zmierzoną przez sensor, a następnie wyliczamy offset = 50 – zmierzona wartość. Jeśli sensor nie wykryje nic przed sobą, zwróci wartość 255. Zastępujemy otrzymaną nową wartością offsetu – X, w odpowiedniej linii w kodzie (listing 1).

East.writeReg(VL6180X::SYSRANGE__PART_TO_PART_RANGE_OFFSET, X);
Listing 1. Kod programu kontrolującego anemometr

#include <Wire.h>
#include <VL6180X.h>
// Osobne obiekty dla każdego z sensorów
VL6180X North;
VL6180X East;
// Adres sensors N
const byte North_address = 0x30;
// Adres sensora E
const byte East_address = 0x31;
// Pin enable sensora N
const int North_enable = 16;
// Pin enable sensora E
const int East_enable = 17;
// Średnica wewnętrzna rury (mm)
const float Radius = 36;
// Odległość od lini środkowej (mm)
// dla sensora N
const float North_offset = -13.0;
// Odległość od linii środkowej (mm)
//dla sensora E
const float East_offset = -13.0 ;
// Współczynnik skali
const float Scale = 4.0;
float North_reading = 0.0;
float East_reading = 0.0;
float Windspeed = 0.0;
float Direction = 0.0;
// ----- Filtr0 (North)
float Array0[40] = {0};
int Index0 = 0;
float Sum0 = 0.0;
float Average0 = 0.0;
// ----- Filtr1 (East)
float Array1[40] = {0};
int Index1 = 0;
float Sum1 = 0.0;
float Average1 = 0.0;
// ----- Filtr2 (Kierunek)
float Array2[40] = {0};
int Index2 = 0;
float Sum2 = 0.0;
float Average2 = 0.0;
// Prędkość interfejsu szeregowego
const long Baudrate = 115200;
char Char;

//--------------------------------------------------
void setup() {
 // Inicjalizacja komunikacji przez port szeregowy
 Serial.begin(115200);
 Wire.begin();
 // Konfiguracja linii GPIO
 pinMode(North_enable, OUTPUT);
 pinMode(East_enable, OUTPUT);
 // Wyłączenie sensorów
 digitalWrite(North_enable, LOW);
 digitalWrite(East_enable, LOW);
 // Aktywacjja sensora North
 digitalWrite(North_enable, HIGH);
 delay(50);
 // Konfiguracja sensora
 North.init
 North.configureDefault();
 // Zmiana adresu sensora
 North.setAddress(North_address);
 North.setTimeout(500);
 North.writeReg(
   VL6180X::SYSRANGE__PART_TO_PART_RANGE_OFFSET, 9);
 North.stopContinuous();
 delay(300);
 North.startRangeContinuous(50);
 // Aktywacja sensora East
 digitalWrite(East_enable, HIGH);
 delay(50);
 // Konfiguracja sensora
 East.init();
 East.configureDefault();
 // Zmiana adresu sensora
 East.setAddress(East_address);
 East.setTimeout(500);
 East.writeReg(
   VL6180X::SYSRANGE__PART_TO_PART_RANGE_OFFSET, 22);
 East.stopContinuous();
 delay(300);
 East.startRangeContinuous(50);
 // Połączenie z odbiornikiem danych
 connect_to_display();
}

//--------------------------------------------------
void loop() {
 // Sprawdza, czy są dostępne nowe dane
 if (Serial.available() > 0){
   Char = (char)Serial.read();
   // Jeśli odebrano znak ‘S’ wysyła dane z pomiarów
   if (Char == ‘S’){
     if (!North.timeoutOccurred()) {
       North_reading =
         (float)North.readRangeContinuousMillimeters() -
         North_offset;
       Average0 =
         moving_average(Array0, sizeof(Array0) /
         sizeof(Array0[0]), &Sum0, &Index0, North_reading);
     }
     if (!East.timeoutOccurred()) {
       East_reading =
         (float)East.readRangeContinuousMillimeters() -
         East_offset;
       Average1 =
         moving_average(Array1, sizeof(Array1) /
         sizeof(Array1[0]), &Sum1, &Index1, East_reading);
     }
     calculate_speed_direction(Average0, Average1);
     Average2 =
     moving_average(Array2, sizeof(Array2) /
     sizeof(Array2[0]), &Sum2, &Index2, Direction);
     Serial.print(Windspeed);      // Prędkość wiatru
     Serial.print(‘,’);
     Serial.print(Average2);     // Kierunek wiatru
     Serial.print(‘,’);
     // Zmierzony offset dla sensora N
     // w bezwietrznych warunkach
     Serial.print(Average0 – Radius);
     Serial.print(‘,’);
     // Zmierzony offset dla sensora E
     // w bezwietrznych warunkach
     Serial.println(Average1 – Radius);
   }
 }
}

//--------------------------------------------------
void connect_to_display() {
 // Wysyła znaki ‘S’, aż odbiornik danych odpowie
 while (Serial.available() <= 0) {
   Serial.println("S");
   delay(100);
 }
}

//--------------------------------------------------
float calculate_speed_direction(float north, float east){
 float N = north;    // north reading (adjusted)
 float E = east;     // east reading (adjusted)
 float C;            // chord formed by laser readings
 float R = Radius;   // pipe radius
 float A1;           // angle between radius and chord
 float A2;           // angle between north and chord
 float A3;           // angle between east and chord;
 float A4; // diference angle between north and radius;
 float A5; // difference angle between east and radius;
 float A6;           // arc-tangent dY/dX
 float dX;           // horizontal offset
 float dY;           // vertical offset
 float D;            // wind direction

 // ----- calculations
 C = sqrt(sq(N) + sq(E));
 A1 = acos(C / (2 * R)) * RAD_TO_DEG;
 A2 = acos(N / C) * RAD_TO_DEG;
 A3 = 90 – A2;
 A4 = A1 – A2;
 A5 = A1 – A3;
 dY = R * fabs(cos(A4 * DEG_TO_RAD)) – N;
 dX = R * fabs(cos(A5 * DEG_TO_RAD)) – E;
 if (fabs(dX) == 0)dX = 0.0001;
 A6 = fabs(atan(dY / dX) * RAD_TO_DEG);

 // ----- Apply signs to dY and dX
 if (fabs(N – R * cos(A4 * DEG_TO_RAD) – dY) > 0.001)
   dY = -dY;
 if (fabs(E – R * cos(A5 * DEG_TO_RAD) – dX) > 0.001)
   dX = -dX;

 // ----- Calculate wind direction
 // quadrant 0
 if ((dX >= 0) && (dY >= 0)) Direction = 270 – A6;
 // quadrant 1
 if ((dX < 0) && (dY >= 0)) Direction =  90 + A6;
 // quadrant 2
 if ((dX < 0) && (dY < 0)) Direction =   90 – A6;
 // quadrant 3
 if ((dX >= 0) && (dY < 0)) Direction =  270 + A6;

 // ----- calculate the windspeed
 Windspeed = sqrt(sq(dX) + sq(dY)) * Scale;
}

//--------------------------------------------------
float moving_average(
 float *array_name, int array_length,
 float *array_sum, int *array_index,
   float new_value) {
   // subtract earliest value; add latest value
   *array_sum =
     *array_sum -
     array_name[*array_index] +
     new_value;
   // store latest value in vacant position
   array_name[*array_index] = new_value;
   // point to next earliest value
   (*array_index)++;
   if (*array_index >= array_length) {
     // wrap around
     *array_index = 0;
 }
 // moving average
 return *array_sum / array_length;
}

Ujemne offsety muszą być wyrażone w postaci liczby zapisanej w postaci kodu uzupełnienia do dwóch. Kalibrację należy oczywiście powtórzyć dla każdego z sensorów (North i East). Po zapisaniu nowego offset można cofnąć zmiany w kodzie wykonane na czas kalibracji oraz skompilować szkic i wgrać do Arduino. Po kalibracji każdy czujnik jest w stanie mierzyć odległości do 1 mm od czoła czujnika.

Następnym krokiem jest konwersja fizycznie zmierzonych odległości na prędkość wiatru. W pierwszej kolejności zerujemy offsety w liniach kodu:

const float North_offset = 0.0;
const float East_offset = 0.0;

Po ponownym skompilowaniu programu wgrywamy go do Arduino i sprawdzamy w Processing3 offsety. Następnie zmierzone offsety wprowadzamy do szkicu Arduino. Ponownie kompilujemy i wgrywamy kod.

Ostatnim krokiem jest określenie parametru tzw. skali. Pozwala on przeliczyć milimetry przesunięcia plastikowej rury na prędkość wiatru np. w kilometrach na godzinę. Bez tunelu aerodynamicznego, czy też innego anemometru do testów, może nie być to trywialne. Jednak autor proponuje prostą i całkiem dokładną metodę. Należy w bezwietrzny dzień zabrać anemometr na przejażdżkę i notować odchylenia przy różnych prędkościach na drodze. Najlepiej będzie to działało na płaskiej i prostej drodze. Po zebraniu tych danych wyliczenie skali jest już prostą arytmetyką. Finalnie można przyjrzeć się lokalnej prognozie pogody i zanotować prędkości wiatru i porównywać je z dystansami, jakie mierzy nasz dalmierz.

Po skalibrowaniu czujników wystarczy ustawić czujnik North na północ za pomocą kompasu. Należy pamiętać, że prawdziwa północ to nie to samo co północ magnetyczna, ale w przypadku tego rodzaju pomiarów nie jest to tak istotne.

Nikodem Czechowski, EP

Źródła:
https://www.instructables.com/Laser-Anemometer/
https://processing.org/download

Artykuł ukazał się w
Elektronika Praktyczna
marzec 2022
Elektronika Praktyczna Plus lipiec - grudzień 2012

Elektronika Praktyczna Plus

Monograficzne wydania specjalne

Elektronik grudzień 2024

Elektronik

Magazyn elektroniki profesjonalnej

Raspberry Pi 2015

Raspberry Pi

Wykorzystaj wszystkie możliwości wyjątkowego minikomputera

Świat Radio listopad - grudzień 2024

Świat Radio

Magazyn krótkofalowców i amatorów CB

Automatyka, Podzespoły, Aplikacje listopad - grudzień 2024

Automatyka, Podzespoły, Aplikacje

Technika i rynek systemów automatyki

Elektronika Praktyczna grudzień 2024

Elektronika Praktyczna

Międzynarodowy magazyn elektroników konstruktorów

Elektronika dla Wszystkich grudzień 2024

Elektronika dla Wszystkich

Interesująca elektronika dla pasjonatów