Obsah:

Autonomní auto udržující jízdní pruh využívající Raspberry Pi a OpenCV: 7 kroků (s obrázky)
Autonomní auto udržující jízdní pruh využívající Raspberry Pi a OpenCV: 7 kroků (s obrázky)

Video: Autonomní auto udržující jízdní pruh využívající Raspberry Pi a OpenCV: 7 kroků (s obrázky)

Video: Autonomní auto udržující jízdní pruh využívající Raspberry Pi a OpenCV: 7 kroků (s obrázky)
Video: Zcela nový Land Rover Discovery | Funkce a výhody 2024, Listopad
Anonim
Autonomní auto udržující jízdní pruh využívající Raspberry Pi a OpenCV
Autonomní auto udržující jízdní pruh využívající Raspberry Pi a OpenCV

V tomto pokynu bude implementován autonomní robot pro udržování v jízdním pruhu, který projde následujícími kroky:

  • Shromažďování dílů
  • Instalace požadavků na software
  • Montáž hardwaru
  • První test
  • Detekce čar jízdních pruhů a zobrazení vodicí čáry pomocí openCV
  • Implementace PD řadiče
  • Výsledek

Krok 1: Shromažďování komponent

Shromažďování komponent
Shromažďování komponent
Shromažďování komponent
Shromažďování komponent
Shromažďování komponent
Shromažďování komponent
Shromažďování komponent
Shromažďování komponent

Obrázky výše ukazují všechny komponenty použité v tomto projektu:

  • RC auto: Moje jsem dostal z místního obchodu ve své zemi. Je vybaven 3 motory (2 pro škrcení a 1 pro řízení). Hlavní nevýhodou tohoto vozu je, že řízení je omezeno mezi „žádné řízení“a „úplné řízení“. Jinými slovy, nemůže řídit pod určitým úhlem, na rozdíl od RC vozidel se servořízením. Zde najdete podobnou automobilovou soupravu navrženou speciálně pro malinové pi.
  • Raspberry pi 3 model b+: toto je mozek automobilu, který zvládne mnoho fází zpracování. Základem je čtyřjádrový 64bitový procesor s taktem 1,4 GHz. Svůj jsem dostal odsud.
  • Modul kamery Raspberry pi 5 mp: Podporuje nahrávání 1080p @ 30 fps, 720p @ 60 fps a 640x480p 60/90. Podporuje také sériové rozhraní, které lze zapojit přímo do Raspberry Pi. Není to nejlepší volba pro aplikace pro zpracování obrazu, ale pro tento projekt je dostačující a také velmi levná. Svůj jsem dostal odsud.
  • Motor Driver: Používá se k ovládání směrů a rychlostí stejnosměrných motorů. Podporuje ovládání 2 stejnosměrných motorů na 1 desce a vydrží 1,5 A.
  • Power Bank (volitelně): Použil jsem powerbanku (ohodnocenou na 5V, 3A) pro samostatné zapnutí Raspberry Pi. K napájení malinového pi z 1 zdroje by měl být použit převodník s krokem dolů (převodník buck: výstupní proud 3A).
  • 3 s (12 V) LiPo baterie: Lithium polymerové baterie jsou známé svým vynikajícím výkonem v oblasti robotiky. Slouží k napájení ovladače motoru. Koupila jsem si tu svoji.
  • Propojovací vodiče mezi muži a muži a ženy a ženy.
  • Oboustranná páska: Používá se k upevnění součástí na RC auto.
  • Modrá páska: Jedná se o velmi důležitou součást tohoto projektu, která se používá k vytvoření dvou pruhů, mezi nimiž bude vůz jezdit. Můžete si vybrat libovolnou barvu, kterou chcete, ale doporučuji zvolit jiné barvy než v okolním prostředí.
  • Kravaty na zip a dřevěné tyče.
  • Šroubovák.

Krok 2: Instalace OpenCV na Raspberry Pi a nastavení vzdáleného zobrazení

Instalace OpenCV na Raspberry Pi a nastavení vzdáleného zobrazení
Instalace OpenCV na Raspberry Pi a nastavení vzdáleného zobrazení

Tento krok je trochu nepříjemný a bude nějakou dobu trvat.

OpenCV (Open source Computer Vision) je open source knihovna softwaru pro počítačové vidění a strojové učení. Knihovna má více než 2500 optimalizovaných algoritmů. Při instalaci openCV na váš malinový pi stejně jako při instalaci raspberry pi OS postupujte podle TÉTO velmi jednoduché příručky (pokud jste to ještě neudělali). Vezměte prosím na vědomí, že proces budování openCV může trvat přibližně 1,5 hodiny v dobře chlazené místnosti (protože teplota procesoru bude velmi vysoká!), Dejte si čaj a trpělivě čekejte: D.

Pro vzdálený displej také postupujte podle TÉTO příručky pro nastavení vzdáleného přístupu k vašemu malinovému pi ze zařízení Windows/Mac.

Krok 3: Spojení dílů dohromady

Spojení dílů dohromady
Spojení dílů dohromady
Spojení dílů dohromady
Spojení dílů dohromady
Spojení dílů dohromady
Spojení dílů dohromady

Výše uvedené obrázky ukazují spojení mezi Raspberry Pi, kamerovým modulem a ovladačem motoru. Vezměte prosím na vědomí, že motory, které jsem použil, absorbují 0,35 A při 9 V, což řidiči motoru umožňuje provozovat 3 motory současně. A protože chci řídit rychlost 2 škrticích motorů (1 zadní a 1 přední) přesně stejným způsobem, připojil jsem je ke stejnému portu. Namontoval jsem ovladač motoru na pravou stranu auta pomocí dvojité pásky. Pokud jde o modul kamery, vložil jsem mezi otvory pro šrouby zip, jak ukazuje obrázek výše. Poté kameru namontuji na dřevěnou tyč, abych mohl upravit polohu kamery, jak chci. Zkuste kameru co nejvíce nainstalovat doprostřed auta. Doporučuji umístit kameru alespoň 20 cm nad zemí, aby se zlepšilo zorné pole před autem. Schéma Fritzingu je přiloženo níže.

Krok 4: První test

První test
První test
První test
První test

Testování kamery:

Jakmile je kamera nainstalována a je vytvořena knihovna openCV, je čas vyzkoušet náš první obrázek! Pořídíme fotografii z pi cam a uložíme ji jako „original.jpg“. Lze to provést 2 způsoby:

1. Pomocí příkazů terminálu:

Otevřete nové okno terminálu a zadejte následující příkaz:

raspistill -o original.jpg

Tím se pořídí statický obrázek a uloží se do adresáře "/pi/original.jpg".

2. Pomocí libovolného IDE pythonu (používám IDLE):

Otevřete novou skicu a napište následující kód:

importovat cv2

video = cv2. VideoCapture (0) while True: ret, frame = video.read () frame = cv2.flip (frame, -1) # used to turn the image vertically cv2.imshow ('original', frame) cv2. imwrite ('original.jpg', frame) key = cv2.waitKey (1) if key == 27: break video.release () cv2.destroyAllWindows ()

Podívejme se, co se stalo v tomto kódu. První řádek importuje naši knihovnu openCV, aby používala všechny její funkce. funkce VideoCapture (0) začne streamovat živé video ze zdroje určeného touto funkcí, v tomto případě je to 0, což znamená kameru raspi. pokud máte více kamer, měla by být umístěna různá čísla. Video.read () přečte každý snímek pocházející z kamery a uloží jej do proměnné zvané „rámeček“. Funkce flip () převrátí obraz vzhledem k ose y (svisle), protože kameru montuji obráceně. imshow () zobrazí naše rámečky se slovem „originál“a imwrite () uloží naši fotografii jako original.jpg. waitKey (1) počká 1 ms na stisknutí jakéhokoli tlačítka na klávesnici a vrátí jeho kód ASCII. pokud je stisknuto tlačítko Esc (esc), vrátí se desetinná hodnota 27 a podle toho přeruší smyčku. video.release () zastaví nahrávání a zničí AllWindows () zavře každý obrázek otevřený funkcí imshow ().

Doporučuji otestovat vaši fotografii druhou metodou, abyste se seznámili s funkcemi openCV. Obrázek je uložen v adresáři "/pi/original.jpg". Původní fotografie, kterou můj fotoaparát pořídil, je zobrazena výše.

Testování motorů:

Tento krok je nezbytný pro určení směru otáčení každého motoru. Nejprve si pojďme stručně představit pracovní princip řidiče motoru. Obrázek výše ukazuje pin-out ovladače motoru. Povolení A, vstup 1 a vstup 2 jsou spojeny s řízením motoru A. Povolení B, vstup 3 a vstup 4 jsou spojeny s ovládáním motoru B. Řízení směru je určeno částí „Vstup“a řízení rychlosti je určeno částí „Povolit“. Chcete -li například řídit směr motoru A, nastavte vstup 1 na VYSOKÝ (v tomto případě 3,3 V, protože používáme malinový pi) a nastavte vstup 2 na NÍZKÝ, motor se bude točit v určitém směru a nastavením opačných hodnot na vstup 1 a vstup 2 se motor bude točit v opačném směru. Pokud vstup 1 = vstup 2 = (VYSOKÝ nebo NÍZKÝ), motor se neotáčí. Povolte piny, které odebírají vstupní signál PWM (Pulse Width Modulation) z maliny (0 až 3,3 V) a podle toho nechají běžet motory. Například signál 100% PWM znamená, že pracujeme na maximální rychlosti, a signál 0% PWM znamená, že se motor netočí. Následující kód slouží k určení směrů motorů a testování jejich rychlostí.

čas importu

importujte RPi. GPIO jako GPIO GPIO.setwarnings (False) # Kolíky motoru řízení řízení_enable = 22 # Fyzický kolík 15 in1 = 17 # Fyzický kolík 11 in2 = 27 # Fyzický kolík 13 # Motory škrtící klapky kolíky throttle_enable = 25 # Fyzický kolík 22 in3 = 23 # Fyzický pin 16 in4 = 24 # Fyzický pin 18 GPIO.setmode (GPIO. BCM) # Místo fyzického číslování použijte GPIO číslování GPIO.setup (in1, GPIO.out) GPIO.setup (in2, GPIO.out) GPIO. setup (in3, GPIO.out) GPIO.setup (in4, GPIO.out) GPIO.setup (throttle_enable, GPIO.out) GPIO.setup (volant_enable, GPIO.out) # Steering Motor Control GPIO.output (in1, GPIO. VYSOKÉ) GPIO.output (in2, GPIO. LOW) řízení = GPIO. PWM (volant_enable, 1000) # nastavit spínací frekvenci na 1000 Hz.output (in4, GPIO. LOW) throttle = GPIO. PWM (throttle_enable, 1000) # nastavte spínací frekvenci na 1000 Hz throttle.stop () time.sleep (1) throttle.start (25) # spustí motor na 25 % Signálu PWM -> (0,25 * napětí baterie) - ovladač ztráta řízení.start (100) # spustí motor se signálem 100% PWM -> (1 * Napětí baterie) - doba ztráty řidiče. spánek (3) škrticí klapka. zastavení () řízení.zastavení ()

Tento kód spustí škrticí motory a motor řízení po dobu 3 sekund a poté je zastaví. (Ztrátu řidiče) lze určit pomocí voltmetru. Například víme, že 100% signál PWM by měl udávat plné napětí baterie na svorce motoru. Ale nastavením PWM na 100%jsem zjistil, že ovladač způsobuje pokles 3 V a motor dostává 9 V místo 12 V (přesně to, co potřebuji!). Ztráta není lineární, tj. Ztráta na 100% se velmi liší od ztráty na 25%. Po spuštění výše uvedeného kódu byly mé výsledky následující:

Výsledky škrcení: pokud in3 = HIGH a in4 = LOW, škrticí motory budou mít rotaci Clock-Wise (CW), tj. Auto se bude pohybovat vpřed. Jinak se auto pohne dozadu.

Výsledky řízení: pokud je in1 = HIGH a in2 = LOW, motor řízení se bude otáčet maximálně doleva, tj. Auto se bude otáčet doleva. V opačném případě bude auto řídit vpravo. Po několika experimentech jsem zjistil, že se motor řízení neotáčí, pokud signál PWM nebyl 100% (tj. Motor bude řídit buď zcela doprava, nebo zcela doleva).

Krok 5: Detekce čar jízdních pruhů a výpočet linie záhlaví

Detekce čar jízdních pruhů a výpočet záhlaví
Detekce čar jízdních pruhů a výpočet záhlaví
Detekce čar jízdních pruhů a výpočet záhlaví
Detekce čar jízdních pruhů a výpočet záhlaví
Detekce linek a výpočet nadpisu
Detekce linek a výpočet nadpisu

V tomto kroku bude vysvětlen algoritmus, který bude řídit pohyb vozu. První obrázek ukazuje celý proces. Vstupem systému jsou obrázky, výstupem je theta (úhel řízení ve stupních). Pamatujte, že zpracování probíhá na 1 obrázku a bude se opakovat na všech snímcích.

Fotoaparát:

Fotoaparát začne nahrávat video s rozlišením (320 x 240). Doporučuji snížit rozlišení, abyste získali lepší snímkovou frekvenci (fps), protože po použití technik zpracování na každý snímek dojde k poklesu fps. Níže uvedený kód bude hlavní smyčkou programu a přidá každý krok přes tento kód.

importovat cv2

import numpy as np video = cv2. VideoCapture (0) video.set (cv2. CAP_PROP_FRAME_WIDTH, 320) # nastavte šířku na 320 p video.set (cv2. CAP_PROP_FRAME_HEIGHT, 240) # nastavte výšku na 240 p # Smyčka zatímco True: ret, frame = video.read () frame = cv2.flip (frame, -1) cv2.imshow ("original", frame) key = cv2.waitKey (1) if key == 27: break video.release () cv2.destroyAllWindows ()

Zde uvedený kód zobrazí původní obrázek získaný v kroku 4 a je zobrazen na obrázcích výše.

Převést na HSV Color Space:

Nyní po pořízení záznamu videa jako snímků z kamery je dalším krokem převedení každého snímku na barevný prostor Odstín, Sytost a Hodnota (HSV). Hlavní výhodou tohoto postupu je schopnost rozlišovat mezi barvami podle jejich úrovně jasu. A tady je dobré vysvětlení barevného prostoru HSV. Převod na HSV se provádí pomocí následující funkce:

def convert_to_HSV (rámeček):

hsv = cv2.cvtColor (snímek, cv2. COLOR_BGR2HSV) cv2.imshow ("HSV", hsv) návrat hsv

Tato funkce bude volána z hlavní smyčky a vrátí snímek v barevném prostoru HSV. Rámeček získaný mnou v barevném prostoru HSV je uveden výše.

Detekce modré barvy a hran:

Po převedení obrázku do barevného prostoru HSV je čas detekovat pouze barvu, která nás zajímá (tj. Modrá barva, protože je to barva čar pruhu). Chcete -li extrahovat modrou barvu z rámečku HSV, je třeba určit rozsah odstínu, sytosti a hodnoty. zde naleznete lepší představu o hodnotách HSV. Po několika experimentech jsou horní a dolní meze modré barvy zobrazeny v níže uvedeném kódu. A aby se snížilo celkové zkreslení v každém snímku, jsou hrany detekovány pouze pomocí detektoru hran. Více o canny edge najdete zde. Pravidlem je vybrat parametry funkce Canny () v poměru 1: 2 nebo 1: 3.

def detect_edges (rámec):

lower_blue = np.array ([90, 120, 0], dtype = "uint8") # dolní mez modré barvy horní_blue = np.array ([150, 255, 255], dtype = "uint8") # horní hranice modrá barevná maska = cv2.inRange (hsv, lower_blue, upper_blue) # tato maska odfiltruje vše kromě modré # detekuje hrany hran = cv2. Canny (maska, 50, 100) cv2.imshow ("hrany", hrany) vrací hrany

Tato funkce bude také volána z hlavní smyčky, která bere jako parametr rámec barevného prostoru HSV a vrací hranatý rámec. Okrajový rámeček, který jsem získal, se nachází výše.

Vyberte oblast zájmu (ROI):

Výběr oblasti zájmu je zásadní pro zaostření pouze na 1 oblast rámce. V tomto případě nechci, aby auto vidělo spoustu položek v prostředí. Chci jen, aby se auto soustředilo na pruhy a ignorovalo cokoli jiného. P. S: souřadný systém (osy x a y) začíná od levého horního rohu. Jinými slovy, bod (0, 0) začíná od levého horního rohu. Osa y je výška a osa x je šířka. Níže uvedený kód vybírá oblast zájmu, která se má zaměřit pouze na spodní polovinu rámečku.

def region_of_interest (hrany):

výška, šířka = hrany. tvar # extrahujte výšku a šířku okrajů maska rámečku = np.zeros_like (hrany) # vytvořte prázdnou matici se stejnými rozměry rámce hran # zaměřte pouze spodní polovinu obrazovky # určete souřadnice 4 body (vlevo dole, vlevo nahoře, vpravo nahoře, vpravo dole) polygon = np.array (

Tato funkce převezme hranatý rámec jako parametr a nakreslí mnohoúhelník se 4 přednastavenými body. Bude se soustředit pouze na to, co je uvnitř mnohoúhelníku, a ignorovat vše mimo něj. Rámeček mého zájmu je uveden výše.

Rozpoznat řádkové segmenty:

Houghova transformace se používá k detekci úseček z hranovaného rámce. Houghova transformace je technika k detekci jakéhokoli tvaru v matematické formě. Může detekovat téměř jakýkoli objekt, i když je zkreslený podle určitého počtu hlasů. je zde ukázána skvělá reference pro Houghovu transformaci. Pro tuto aplikaci slouží funkce cv2. HoughLinesP () k detekci čar v každém rámci. Důležité parametry, které tato funkce má, jsou:

cv2. HoughLinesP (frame, rho, theta, min_threshold, minLineLength, maxLineGap)

  • Rámeček: je rámec, ve kterém chceme detekovat čáry.
  • rho: Je to přesnost vzdálenosti v pixelech (obvykle je = 1)
  • theta: úhlová přesnost v radiánech (vždy = np.pi/180 ~ 1 stupeň)
  • min_threshold: minimální počet hlasů, který by měl být považován za řádek
  • minLineLength: minimální délka řádku v pixelech. Jakýkoli řádek kratší než toto číslo není považován za řádek.
  • maxLineGap: maximální mezera v pixelech mezi 2 řádky bude považována za 1 řádek. (V mém případě se nepoužívá, protože jízdní pruhy, které používám, nemají mezeru).

Tato funkce vrací koncové body řádku. Následující funkce je volána z mé hlavní smyčky pro detekci linek pomocí Houghovy transformace:

def detect_line_segments (cropped_edges):

rho = 1 theta = np.pi / 180 min_threshold = 10 řádků_segmentů = cv2. HoughLinesP (cropped_edges, rho, theta, min_threshold, np.array (), minLineLength = 5, maxLineGap = 0) návrat line_segmentů

Průměrný sklon a zachycení (m, b):

připomeňme, že rovnicová přímka je dána y = mx + b. Kde m je sklon přímky a b je y-průsečík. V této části bude vypočítán průměr sklonů a průsečíků úseček detekovaných pomocí Houghovy transformace. Než tak učiníme, podívejme se na výše uvedenou fotografii původního rámečku. Levý pruh vypadá, že jde nahoru, takže má negativní sklon (pamatujete na počáteční bod souřadnicového systému?). Jinými slovy, linie levého pruhu má x1 <x2 a y2 x1 a y2> y1, což poskytne kladný sklon. Všechny čáry s kladným sklonem jsou tedy považovány za body pravého jízdního pruhu. V případě svislých čar (x1 = x2) bude sklon nekonečný. V tomto případě přeskočíme všechny svislé čáry, abychom předešli chybám. Aby byla detekce ještě přesnější, je každý snímek rozdělen na dvě oblasti (pravou a levou) pomocí 2 hraničních čar. Všechny body šířky (body osy x) větší než pravá hraniční čára jsou spojeny s výpočtem pravého pruhu. A pokud jsou všechny body šířky menší než levá hraniční čára, jsou spojeny s výpočtem levého pruhu. Následující funkce převezme zpracování snímku a segmenty jízdních pruhů detekované pomocí Houghovy transformace a vrátí průměrný sklon a průsečík dvou liniových pruhů.

def average_slope_intercept (rámeček, řádky_segmenty):

lane_lines = pokud line_segments je None: print ("no line segment identified") return lane_lines height, width, _ = frame.shape left_fit = right_fit = boundary = left_region_boundary = width * (1 - boundary) right_region_boundary = width * boundary for line_segment in line_segments: for x1, y1, x2, y2 in line_segment: if x1 == x2: print ("skipping vertical lines (lope = infinity)") continue fit = np.polyfit ((x1, x2), (y1, y2), 1) sklon = (y2 - y1) / (x2 - x1) intercept = y1 - (sklon * x1) pokud sklon <0: if x1 <left_region_boundary a x2 right_region_boundary a x2> right_region_boundary: right_fit. append ((sklon, intercept)) left_fit_average = np.průměr (left_fit, axis = 0) if len (left_fit)> 0: lane_lines.append (make_points (frame, left_fit_average)) right_fit_average = np.average (right_fit, axis = 0) if len (right_fit)> 0: lane_lines.append (make_points (frame, right_fit_average)) # lane_lines je 2-D pole skládající se ze souřadnic linek pravého a levého pruhu # například: lan e_lines =

make_points () je pomocná funkce pro funkci average_slope_intercept (), která vrátí ohraničené souřadnice liniových pruhů (zdola do středu rámečku).

def make_points (rámeček, čára):

výška, šířka, _ = rámeček. sklon svahu, průsečík = přímka y1 = výška # spodní část rámce y2 = int (y1 / 2) # dělat body od středu rámečku dolů, pokud sklon == 0: sklon = 0,1 x1 = int ((y1 - intercept) / sklon) x2 = int ((y2 - intercept) / sklon) návrat

Aby se zabránilo dělení 0, je předložena podmínka. Pokud sklon = 0, což znamená y1 = y2 (vodorovná čára), dejte sklonu hodnotu blízkou 0. To neovlivní výkonnost algoritmu, stejně jako zabrání nemožnému případu (dělení 0).

K zobrazení čar jízdních pruhů na rámech se používá následující funkce:

def display_lines (frame, lines, line_color = (0, 255, 0), line_width = 6): # line color (B, G, R)

line_image = np.zeros_like (frame) if lines is not None: for line in lines: for x1, y1, x2, y2 in line: cv2.line (line_image, (x1, y1), (x2, y2), line_color, line_width) line_image = cv2.addWeighted (frame, 0.8, line_image, 1, 1) return line_image

Funkce cv2.addWeighted () přebírá následující parametry a používá se ke zkombinování dvou obrázků, přičemž každému z nich je přidělena váha.

cv2.addWeighted (image1, alpha, image2, beta, gamma)

A vypočítá výstupní obrázek pomocí následující rovnice:

výstup = alpha * image1 + beta * image2 + gama

Další informace o funkci cv2.addWeighted () jsou odvozeny zde.

Vypočítat a zobrazit záhlaví:

Toto je poslední krok, než na naše motory použijeme otáčky. Směrová čára je zodpovědná za to, že dává motoru řízení směr, ve kterém by se měl otáčet, a dává škrticím motorům rychlost, jakou budou pracovat. Výpočet záhlaví je čistá trigonometrie, používají se goniometrické funkce tan a atan (tan^-1). Extrémní případy jsou, když kamera detekuje pouze jednu jízdní pruh nebo když nezjistí žádnou čáru. Všechny tyto případy jsou uvedeny v následující funkci:

def get_steering_angle (rám, lane_lines):

výška, šířka, _ = rámeček. tvar, pokud len (lane_lines) == 2: # pokud jsou detekovány dvě čáry pruhu _, _, left_x2, _ = lane_lines [0] [0] # extrahovat vlevo x2 z pole lane_lines _, _, right_x2, _ = lane_lines [1] [0] # extrahovat vpravo x2 z pole lane_lines mid = int (width / 2) x_offset = (left_x2 + right_x2) / 2 - mid y_offset = int (výška / 2) elif len (lane_lines) == 1: # pokud je detekován pouze jeden řádek x1, _, x2, _ = lane_lines [0] [0] x_offset = x2 - x1 y_offset = int (výška / 2) elif len (lane_lines) == 0: # pokud není detekován žádný řádek x_offset = 0 y_offset = int (výška / 2) angle_to_mid_radian = math.atan (x_offset / y_offset) angle_to_mid_deg = int (angle_to_mid_radian * 180,0 / math.pi) volant_angle = úhel_to_mid_deg + 90 zpět

x_offset v prvním případě je, jak moc se průměr ((vpravo x2 + vlevo x2) / 2) liší od středu obrazovky. y_offset je vždy považován za výšku / 2. Poslední obrázek nahoře ukazuje příklad nadpisové čáry. angle_to_mid_radians je stejný jako „theta“zobrazený na posledním obrázku výše. Je -li úhel řízení = 90, znamená to, že auto má směrovou čáru kolmou na čáru „výška / 2“a auto se bude pohybovat vpřed bez řízení. Pokud je úhel natočení volantu> 90, auto by mělo řídit doprava, jinak by mělo řídit doleva. K zobrazení záhlaví se používá následující funkce:

def display_heading_line (rám, úhel řízení, barva čáry = (0, 0, 255), šířka čáry = 5)

direction_image = np.zeros_like (frame) výška, šířka, _ = frame.shape (úhlový_radník_radián)) y2 = int (výška / 2) cv2.line (nadpis_obraz, (x1, y1), (x2, y2), barva_řádku, šířka_řádku) nadpis_obraz = cv2.addVáha vrátit záhlaví_obraz

Funkce výše vezme jako vstup rámeček, ve kterém bude nakreslena záhlaví a úhel řízení. Vrátí obrázek záhlaví řádku. Rámeček záhlaví pořízený v mém případě je zobrazen na obrázku výše.

Kombinace veškerého kódu dohromady:

Kód je nyní připraven k sestavení. Následující kód ukazuje hlavní smyčku programu, která volá každou funkci:

importovat cv2

import numpy as np video = cv2. VideoCapture (0) video.set (cv2. CAP_PROP_FRAME_WIDTH, 320) video.set (cv2. CAP_PROP_FRAME_HEIGHT, 240) while True: ret, frame = video.read () frame = cv2.flip (rámec, -1) #Volání funkcí hsv = převést_ na_HSV (rám) hrany = detekovat okraje = get_steering_angle (frame, lane_lines) direction_image = display_heading_line (lane_lines_image, volant_angle) key = cv2.waitKey (1) if key == 27: break video.release () cv2.destroyAllWindows ()

Krok 6: Použití ovládání PD

Aplikace PD Control
Aplikace PD Control

Nyní máme úhel řízení připraven k podávání do motorů. Jak již bylo zmíněno dříve, pokud je úhel řízení větší než 90, auto by mělo odbočit vpravo, jinak by mělo odbočit doleva. Použil jsem jednoduchý kód, který otočí motor řízení doprava, pokud je úhel vyšší než 90, a otočí jej doleva, pokud je úhel řízení menší než 90 při konstantní rychlosti škrcení (10% PWM), ale dostal jsem spoustu chyb. Hlavní chybou, kterou jsem udělal, je, že když se vůz přiblíží k jakékoli zatáčce, motor řízení působí přímo, ale škrticí motory se zasekávají. Pokusil jsem se zvýšit rychlost škrcení na (20% PWM) v zatáčkách, ale skončil jsem tím, že se robot dostal z pruhů. Potřeboval jsem něco, co hodně zvyšuje rychlost škrcení, pokud je úhel řízení velmi velký, a trochu zvyšuje rychlost, pokud úhel řízení není tak velký, pak sníží rychlost na počáteční hodnotu, když se auto přiblíží k 90 stupňům (jede rovně). Řešením bylo použít PD řadič.

PID regulátor je zkratka pro proporcionální, integrální a derivační regulátor. Tento typ lineárních regulátorů je široce používán v robotických aplikacích. Obrázek výše ukazuje typickou regulační smyčku zpětné vazby PID. Cílem tohoto regulátoru je dosáhnout „požadované hodnoty“nejefektivnějším způsobem na rozdíl od regulátorů „zapnuto - vypnuto“, které zapínají nebo vypínají zařízení podle určitých podmínek. Některá klíčová slova by měla být známa:

  • Setpoint: je požadovaná hodnota, které má váš systém dosáhnout.
  • Skutečná hodnota: je skutečná hodnota snímaná senzorem.
  • Chyba: je rozdíl mezi požadovanou a skutečnou hodnotou (chyba = žádaná hodnota - skutečná hodnota).
  • Řízená proměnná: z jejího názvu je proměnná, kterou chcete ovládat.
  • Kp: Proporcionální konstanta.
  • Ki: Integrální konstanta.
  • Kd: Derivační konstanta.

Stručně řečeno, smyčka řídicího systému PID funguje následovně:

  • Uživatel definuje požadovanou hodnotu potřebnou k dosažení systému.
  • Chyba se vypočítá (chyba = požadovaná hodnota - skutečná).
  • Regulátor P generuje akci úměrnou hodnotě chyby. (chyba se zvyšuje, akce P se také zvyšuje)
  • Řadič integruje chybu v průběhu času, což eliminuje chybu ustáleného stavu systému, ale zvyšuje jeho překročení.
  • Řadič D je jednoduše časový derivát chyby. Jinými slovy, je to sklon chyby. Provádí akci úměrnou derivaci chyby. Tento ovladač zvyšuje stabilitu systému.
  • Výstupem regulátoru bude součet tří regulátorů. Pokud se chyba stane 0, výstup regulátoru se změní na 0.

Skvělé vysvětlení PID regulátoru najdete zde.

Když jsem se vrátil do auta udržujícího jízdní pruh, moje kontrolovaná proměnná byla rychlost škrcení (protože řízení má pouze dva stavy buď vpravo, nebo vlevo). K tomuto účelu se používá řadič PD, protože akce D výrazně zvyšuje rychlost škrcení, pokud je změna chyby velmi velká (tj. Velká odchylka) a zpomalí auto, pokud se tato změna chyb přiblíží 0. Pro implementaci PD jsem provedl následující kroky ovladač:

  • Nastavte požadovanou hodnotu na 90 stupňů (vždy chci, aby se auto pohybovalo rovně)
  • Vypočítán úhel odchylky od středu
  • Odchylka poskytuje dvě informace: Jak velká je chyba (velikost odchylky) a jakým směrem se musí pohybovat motor řízení (známka odchylky). Pokud je odchylka kladná, auto by mělo řídit vpravo, jinak by mělo řídit vlevo.
  • Protože je odchylka buď záporná, nebo kladná, je definována proměnná „chyba“, která se vždy rovná absolutní hodnotě odchylky.
  • Chyba se vynásobí konstantou Kp.
  • Chyba podléhá časové diferenciaci a je vynásobena konstantou Kd.
  • Rychlost motorů se aktualizuje a smyčka začne znovu.

Následující kód se používá v hlavní smyčce k řízení otáček škrticích motorů:

speed = 10 # provozní rychlost v % PWM

# Proměnné, které mají být aktualizovány v každé smyčce lastTime = 0 lastError = 0 # PD konstanty Kp = 0,4 Kd = Kp * 0,65 While True: now = time.time () # aktuální časová proměnná dt = nyní - odchylka lastTime = úhel řízení - 90 # ekvivalent to angle_to_mid_deg variabilní chyba = abs (odchylka), pokud je odchylka -5: # neřiďte, pokud existuje 10stupňová odchylka rozsahu chyby = 0 chyba = 0 GPIO.output (in1, GPIO. LOW) GPIO.output (in2, GPIO. LOW) -5: # řízení vlevo, pokud je odchylka záporná GPIO.output (in1, GPIO. HIGH) GPIO.output (in2, GPIO. LOW) * chyba PD = int (rychlost + derivace + proporcionální) spd = abs (PD) pokud spd> 25: spd = 25 throttle.start (spd) lastError = chyba lastTime = time.time ()

Pokud je chyba velmi velká (odchylka od středu je vysoká), proporcionální a derivační akce jsou vysoké, což má za následek vysokou rychlost škrcení. Když se chyba přiblíží k 0 (odchylka od středu je nízká), derivační akce působí opačně (sklon je záporný) a rychlost škrcení se sníží, aby byla zachována stabilita systému. Celý kód je přiložen níže.

Krok 7: Výsledky

Výše uvedená videa ukazují výsledky, kterých jsem dosáhl. Potřebuje více ladění a další úpravy. Připojoval jsem Raspberry Pi k mému displeji LCD, protože streamování videa po mé síti mělo vysokou latenci a práce s ním byla velmi frustrující, proto jsou ve videu připojeny vodiče k Raspberry Pi. Pěnové desky jsem nakreslil na dráhu.

Čekám na vaše doporučení, jak tento projekt vylepšit! Doufám, že tento návod byl dost dobrý na to, aby vám poskytl nějaké nové informace.

Doporučuje: