Sadržaj:
- Korak 1: Skupljanje komponenti
- Korak 2: Instaliranje OpenCV -a na Raspberry Pi i postavljanje udaljenog zaslona
- Korak 3: Povežite dijelove zajedno
- Korak 4: Prvi test
- Korak 5: Otkrivanje linija prometne trake i izračun linije smjera
- Korak 6: Primjena PD kontrole
- Korak 7: Rezultati
Video: Autonomni automobil za održavanje prometne trake koji koristi Raspberry Pi i OpenCV: 7 koraka (sa slikama)
2024 Autor: John Day | [email protected]. Zadnja promjena: 2024-01-30 09:34
U ovim uputama bit će implementiran autonomni robot za održavanje prometne trake koji će proći kroz sljedeće korake:
- Skupljanje dijelova
- Preduvjeti za instaliranje softvera
- Sklapanje hardvera
- Prvi test
- Otkrivanje linija trake i prikazivanje linije vođenja pomoću openCV -a
- Implementacija PD kontrolera
- Rezultati
Korak 1: Skupljanje komponenti
Gornje slike prikazuju sve komponente korištene u ovom projektu:
- RC auto: Ja sam svoj nabavio u lokalnoj trgovini u mojoj zemlji. Opremljen je s 3 motora (2 za prigušivanje i 1 za upravljanje). Glavni nedostatak ovog automobila je to što je upravljanje ograničeno između "bez upravljanja" i "potpunog upravljanja". Drugim riječima, ne može se upravljati pod određenim kutom, za razliku od RC automobila sa servo upravljačem. Odavde možete pronaći sličan automobilski komplet dizajniran posebno za maline pi.
- Raspberry pi 3 model b+: ovo je mozak automobila koji će obraditi mnoge faze obrade. Temelji se na četverojezgrenom 64-bitnom procesoru takta 1,4 GHz. Ja sam svoje odavde.
- Modul kamere Raspberry pi 5 mp: Podržava 1080p @ 30 fps, 720p @ 60 fps i 640x480p 60/90 snimanje. Također podržava serijsko sučelje koje se može priključiti izravno na malinovo pi. To nije najbolja opcija za aplikacije za obradu slika, ali je dovoljna za ovaj projekt, jer je i vrlo jeftina. Ja sam svoje odavde.
- Pogonitelj motora: Koristi se za kontrolu smjera i brzine istosmjernih motora. Podržava upravljanje 2 dc motora u 1 ploči i može izdržati 1,5 A.
- Power Bank (izborno): Koristio sam power bank (ocijenjen na 5V, 3A) za zasebno napajanje maline pi. Za napajanje maline pi iz 1 izvora trebao bi se koristiti pretvarač s dolje (pretvarač u buck -u: 3A izlazna struja).
- 3s (12 V) LiPo baterija: Litij -polimerne baterije poznate su po izvrsnim performansama na polju robotike. Koristi se za napajanje vozača motora. Ja sam svoj kupio odavde.
- Muški na muški i ženski na ženski kratkospojnik.
- Dvostrana traka: Koristi se za montažu komponenti na RC automobil.
- Plava traka: Ovo je vrlo važna komponenta ovog projekta, koristi se za izradu dviju traka između kojih će automobil voziti. Možete odabrati bilo koju boju koju želite, ali preporučujem da odaberete boje drugačije od onih u okolini.
- Zip kravate i drvene šipke.
- Odvijač.
Korak 2: Instaliranje OpenCV -a na Raspberry Pi i postavljanje udaljenog zaslona
Ovaj korak je pomalo neugodan i potrajat će neko vrijeme.
OpenCV (Open Source Computer Vision) je biblioteka softvera za računalni vid i strojno učenje otvorenog koda. Knjižnica ima više od 2500 optimiziranih algoritama. Slijedite OVAJ vrlo jednostavan vodič za instalaciju openCV -a na vašem malinovom pi, kao i instaliranju malinovog pi OS -a (ako još niste). Imajte na umu da proces izgradnje openCV-a može potrajati oko 1,5 sati u dobro rashlađenoj prostoriji (jer će temperatura procesora postati vrlo visoka!) Pa popijte čaj i strpljivo pričekajte: D.
Za daljinski zaslon također slijedite OVAJ vodič za postavljanje daljinskog pristupa vašem maline pi s vašeg Windows/Mac uređaja.
Korak 3: Povežite dijelove zajedno
Gornje slike prikazuju veze između maline pi, modula kamere i upravljačkog programa motora. Imajte na umu da motori koje sam koristio apsorbiraju 0,35 A na 9 V svaki, što vozaču motora omogućuje sigurno pokretanje 3 motora u isto vrijeme. A budući da želim kontrolirati brzinu 2 motora za prigušivanje (1 straga i 1 sprijeda) na isti način, spojio sam ih na isti priključak. Ugradio sam upravljački program motora s desne strane automobila pomoću dvostruke trake. Što se tiče modula kamere, ja sam umetnuo patentni zatvarač između rupa za vijke kao što prikazuje gornja slika. Zatim sam kameru postavio na drvenu šipku kako bih mogao prilagoditi položaj kamere kako želim. Pokušajte kameru postaviti što je više moguće u sredinu automobila. Preporučujem da kameru postavite najmanje 20 cm iznad tla kako bi se vidno polje ispred automobila poboljšalo. Shema Fritzinga nalazi se u nastavku.
Korak 4: Prvi test
Testiranje kamere:
Nakon što je kamera instalirana i openCV knjižnica izgrađena, vrijeme je za testiranje naše prve slike! Snimit ćemo fotografiju s pi cama i spremiti je kao "original.jpg". To se može učiniti na 2 načina:
1. Korištenje naredbi terminala:
Otvorite novi prozor terminala i upišite sljedeću naredbu:
raspistill -o original.jpg
Ovo će uzeti statičnu sliku i spremiti je u direktorij "/pi/original.jpg".
2. Korištenje bilo kojeg python IDE -a (ja koristim IDLE):
Otvorite novu skicu i napišite sljedeći kod:
uvoz cv2
video = cv2. VideoCapture (0) dok je True: ret, frame = video.read () frame = cv2.flip (frame, -1) # koristi se za okretanje slike okomito cv2.imshow ('izvornik', okvir) cv2. imwrite ('original.jpg', frame) key = cv2.waitKey (1) if key == 27: break video.release () cv2.destroyAllWindows ()
Pogledajmo što se dogodilo u ovom kodu. Prvi redak je uvoz naše openCV knjižnice za korištenje svih njenih funkcija. funkcija VideoCapture (0) započinje strujanje videozapisa uživo s izvora određenog ovom funkcijom, u ovom slučaju to je 0 što znači raspi kamera. ako imate više kamera, potrebno je postaviti različite brojeve. video.read () će pročitati svaki kadar koji dolazi s kamere i spremiti ga u varijablu koja se naziva "frame". flip () funkcija će okrenuti sliku u odnosu na os y (okomito) budući da kameru montiram obrnuto. imshow () prikazat će naše okvire na kojima stoji riječ "original", a imwrite () će našu fotografiju spremiti kao original.jpg. waitKey (1) će čekati 1 ms da se pritisne bilo koja tipka na tipkovnici i vrati svoj ASCII kod. ako se pritisne tipka escape (esc), vraća se decimalna vrijednost 27 i prema tome će prekinuti petlju. video.release () će zaustaviti snimanje i uništiti AllWindows () će zatvoriti svaku sliku koju otvori funkcija imshow ().
Preporučujem testiranje vaše fotografije drugom metodom kako biste se upoznali s funkcijama openCV -a. Slika je spremljena u direktorij "/pi/original.jpg". Izvorna fotografija koju je moja kamera snimila prikazana je gore.
Ispitivanje motora:
Ovaj korak je bitan za određivanje smjera rotacije svakog motora. Prvo, kratki uvod o principu rada vozača motora. Gornja slika prikazuje pin-out upravljačkog programa motora. Omogući A, ulaz 1 i ulaz 2 povezani su s upravljanjem motorom A. Omogući B, ulaz 3 i ulaz 4 povezani su s upravljanjem motorom B. Kontrola smjera uspostavljena je dijelom "Ulaz", a kontrola brzine dijelom "Omogući". Na primjer, za upravljanje smjerom motora A, postavite Ulaz 1 na VISOKO (3,3 V u ovom slučaju budući da koristimo malinu pi) i postavite Ulaz 2 na NISKO, motor će se vrtjeti u određenom smjeru i postavljanjem suprotnih vrijednosti do ulaza 1 i ulaza 2, motor će se vrtjeti u suprotnom smjeru. Ako je ulaz 1 = ulaz 2 = (VISOKO ili NISKO), motor se neće okrenuti. Omogući pinovi uzimaju ulazni signal PWM (Pulse Width Modulation - PWM) signala iz maline (0 do 3,3 V) i u skladu s tim pokreću motore. Na primjer, 100% PWM signal znači da radimo na maksimalnoj brzini, a 0% PWM signal znači da se motor ne okreće. Sljedeći kôd koristi se za određivanje smjerova motora i ispitivanje njihovih brzina.
vrijeme uvoza
uvoz RPi. GPIO kao GPIO GPIO.upozorenja (Netačno) # Igle upravljačkog motora upravljačko_omogućeno = 22 # Fizički pin 15 in1 = 17 # Fizički pin 11 in2 = 27 # Fizički pin 13 # Rotirajući motori pinovi throttle_enable = 25 # Fizički pin 22 in3 = 23 # Fizički pin 16 in4 = 24 # Fizički pin 18 GPIO.način rada (GPIO. BCM) # Koristite GPIO numeriranje umjesto fizičkog numeriranja 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 (enable_nable, GPIO.out) # Upravljanje motorom za upravljanje GPIO.output (in1, GPIO. VISOKO) GPIO.izlazni izlaz (in2, GPIO. LOW) upravljanje = GPIO. PWM (upravljanje_mogući, 1000) # postavite sklopnu frekvenciju na 1000 Hz upravljanje.stop () # Motori za gas Kontrolirajte GPIO.izlaz (in3, GPIO. HIGH) GPIO.izlaz (in4, GPIO. LOW) gas = GPIO. PWM (throttle_enable, 1000) # postavite sklopnu frekvenciju na 1000 Hz throttle.stop () time.sleep (1) throttle.start (25) # pokreće motor na 25 % PWM signal-> (0,25 * napon baterije) - vozačev gubitak upravljanja.pokretanje (100) # pokreće motor pri signalu od 100% PWM-> (1 * Napon baterije) - vrijeme gubitka vozača.spavanje (3) leptir za gas (stop) upravljač.stop ()
Ovaj kôd će pokretati motore prigušivača i motor upravljača 3 sekunde, a zatim će ih zaustaviti. (Gubitak vozača) može se odrediti pomoću voltmetra. Na primjer, znamo da bi 100% PWM signal trebao dati puni napon baterije na priključku motora. No, postavljanjem PWM -a na 100%, otkrio sam da upravljački program uzrokuje pad od 3 V, a motor dobiva 9 V umjesto 12 V (upravo ono što mi treba!). Gubitak nije linearan, tj. Gubitak od 100% se jako razlikuje od gubitka od 25%. Nakon pokretanja gornjeg koda, moji su rezultati sljedeći:
Rezultati prigušivanja: ako je in3 = VISOKO, a in4 = NIZO, motori prigušivanja će imati rotaciju prema satu (CW), tj. Automobil će se kretati naprijed. U suprotnom će se automobil kretati unatrag.
Rezultati upravljanja: ako je in1 = VISOKO i in2 = NISKO, motor upravljača će se okrenuti maksimalno ulijevo, tj. Automobil će krenuti ulijevo. U suprotnom će automobil skrenuti desno. Nakon nekih eksperimenata, otkrio sam da se motor upravljača neće okrenuti ako PWM signal nije 100% (tj. Motor će se usmjeriti ili udesno ili ulijevo).
Korak 5: Otkrivanje linija prometne trake i izračun linije smjera
U ovom koraku bit će objašnjen algoritam koji će kontrolirati kretanje automobila. Prva slika prikazuje cijeli proces. Unos sustava su slike, izlaz je theta (kut upravljanja u stupnjevima). Imajte na umu da se obrada vrši na jednoj slici i da će se ponoviti na svim okvirima.
Fotoaparat:
Kamera će početi snimati video zapis rezolucije (320 x 240). Preporučujem smanjenje rezolucije kako biste dobili bolju brzinu kadrova (fps) jer će do pada fps doći nakon primjene tehnika obrade na svaki okvir. Kod u nastavku bit će glavna petlja programa i dodat će svaki korak preko ovog koda.
uvoz cv2
uvoz numpy kao np video = cv2. VideoCapture (0) video.set (cv2. CAP_PROP_FRAME_WIDTH, 320) # postavi širinu na 320 p video.set (cv2. CAP_PROP_FRAME_HEIGHT, 240) # postavi visinu na 240 p # Petlja dok Istina: 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 ()
Ovdje će kôd pokazati izvornu sliku dobivenu u koraku 4, a prikazan je na gornjim slikama.
Pretvori u HSV prostor boja:
Nakon snimanja video zapisa kao okvira s fotoaparata, sljedeći korak je pretvaranje svakog kadra u prostor boje Hue, Saturation i Value (HSV). Glavna prednost toga je mogućnost razlikovanja boja po razini osvjetljenja. I ovdje je dobro objašnjenje HSV prostora boja. Pretvaranje u HSV vrši se putem sljedeće funkcije:
def convert_to_HSV (okvir):
hsv = cv2.cvtBoja (okvir, cv2. COLOR_BGR2HSV) cv2.imshow ("HSV", hsv) povratak hsv
Ova funkcija će se pozvati iz glavne petlje i vratit će okvir u HSV prostor boja. Okvir koji sam dobio u HSV prostoru boja prikazan je gore.
Otkrijte plavu boju i rubove:
Nakon pretvaranja slike u HSV prostor boja, vrijeme je da otkrijemo samo onu boju koja nas zanima (tj. Plavu boju jer je to boja linija trake). Za izdvajanje plave boje iz HSV okvira potrebno je navesti raspon nijansi, zasićenja i vrijednosti. pogledajte ovdje kako biste bolje razumjeli vrijednosti HSV -a. Nakon nekih pokusa, gornja i donja granica plave boje prikazane su u donjem kodu. A kako bi se smanjilo sveukupno izobličenje u svakom kadru, rubovi se detektiraju samo pomoću detektora rubova. Više o canny edgeu možete pronaći ovdje. Zlatno pravilo je odabir parametara funkcije Canny () u omjeru 1: 2 ili 1: 3.
def detektiranje_rubova (okvir):
lower_blue = np.array ([90, 120, 0], dtype = "uint8") # donja granica plave boje upper_blue = np.array ([150, 255, 255], dtype = "uint8") # gornja granica maska plave boje = cv2.inRange (hsv, lower_blue, upper_blue) # ova će maska filtrirati sve osim plave # detektirati rubove rubova = cv2. Canny (maska, 50, 100) cv2.imshow ("rubovi", rubovi) vratiti rubove
Ova funkcija će se također pozvati iz glavne petlje koja uzima kao parametar okvir prostora boje HSV -a i vraća okvir s rubovima. Rubni okvir koji sam ipak našao nalazi se gore.
Odaberite regiju interesa (ROI):
Odabir područja interesa od ključne je važnosti za fokusiranje samo na 1 područje okvira. U ovom slučaju ne želim da automobil vidi mnogo predmeta u okruženju. Samo želim da se automobil usredotoči na trake i zanemari bilo što drugo. P. S: koordinatni sustav (osi x i y) počinje iz gornjeg lijevog kuta. Drugim riječima, točka (0, 0) počinje iz gornjeg lijevog kuta. os y je visina, a x x širina. Donji kôd odabire područje interesa koje se fokusira samo na donju polovicu kadra.
def region_of_interest (rubovi):
height, width = edge.shape # izdvojite visinu i širinu rubova frame mask = np.zeros_like (bridovi) # napravite praznu matricu s istim dimenzijama okvira # samo fokus donju polovicu zaslona # navedite koordinate 4 točke (donji lijevi, gornji lijevi, gornji desni, donji desni) poligon = np.masa (
Ova funkcija će uzeti rubni okvir kao parametar i nacrtati poligon s 4 unaprijed postavljene točke. Usredotočit će se samo na ono što je unutar poligona i zanemariti sve izvan njega. Okvir moje regije interesa prikazan je gore.
Otkrivanje segmenata linije:
Hough transformacija koristi se za otkrivanje segmenata linije s okvira. Hough transformacija je tehnika otkrivanja bilo kojeg oblika u matematičkom obliku. Može otkriti gotovo svaki objekt čak i ako je iskrivljen prema određenom broju glasova. ovdje je prikazana velika referenca za Hough transformaciju. Za ovu aplikaciju, funkcija cv2. HoughLinesP () koristi se za otkrivanje linija u svakom okviru. Važni parametri koje ova funkcija uzima su:
cv2. HoughLinesP (okvir, rho, theta, min_threshold, minLineLength, maxLineGap)
- Okvir: je okvir u kojem želimo detektirati linije.
- rho: To je preciznost udaljenosti u pikselima (obično je = 1)
- theta: kutna preciznost u radijanima (uvijek = np.pi/180 ~ 1 stupanj)
- min_threshold: minimalni glas koji bi trebao dobiti da bi se smatrao retkom
- minLineLength: minimalna duljina retka u pikselima. Svaka linija kraća od ovog broja ne smatra se linijom.
- maxLineGap: najveći razmak u pikselima između 2 retka tretira se kao 1 redak. (U mom slučaju se ne koristi jer linije traka koje koristim nemaju praznine).
Ova funkcija vraća krajnje točke retka. Sljedeća se funkcija poziva iz moje glavne petlje za otkrivanje linija pomoću Houghove transformacije:
def detektiraj_segmente_line (izrezane_rubove):
rho = 1 theta = np.pi / 180 min_threshold = 10 linija_segmenata = cv2. HoughLinesP (obrezani rubovi, rho, theta, min_threshold, np.array (), minLineLength = 5, maxLineGap = 0) povratni segmenti linije
Prosječni nagib i presjek (m, b):
podsjetimo se da je jednadžba linije dana sa y = mx + b. Gdje je m nagib prave, a b presjek y. U ovom će se dijelu izračunati prosjek nagiba i presjeka segmenata linije otkrivenih Houghovom transformacijom. Prije nego što to učinimo, pogledajmo gornju originalnu fotografiju okvira. Čini se da lijeva traka ide prema gore pa ima negativan nagib (sjećate li se početne točke koordinatnog sustava?). Drugim riječima, lijeva traka ima x1 <x2 i y2 x1 i y2> y1 što će dati pozitivan nagib. Dakle, sve linije s pozitivnim nagibom smatraju se točkama desne trake. U slučaju okomitih linija (x1 = x2), nagib će biti beskonačan. U tom slučaju preskočit ćemo sve okomite crte kako bismo spriječili pojavu pogreške. Kako bi se ovom otkrivanju dodala veća točnost, svaki je okvir podijeljen u dvije regije (desno i lijevo) kroz 2 granične crte. Sve točke širine (točke osi x) veće od desne granične crte povezane su s izračunom desne trake. A ako su sve točke širine manje od lijeve granične crte, one su povezane s izračunom lijeve trake. Sljedeća funkcija uzima okvir u obradu i segmente traka otkrivene pomoću Houghove transformacije te vraća prosječni nagib i presijecanje dviju traka.
def average_slope_intercept (frame, line_segments):
lane_lines = ako line_segments nema None: print ("nije otkriven segment linije") return lane_lines height, width, _ = frame.shape left_fit = right_fit = border = left_region_boundary = width * (1 - border) right_region_boundary = širina * granica za segment_ linije u segmentima linija: za x1, y1, x2, y2 u segmentu_ linije: ako je x1 == x2: ispis ("preskakanje okomitih linija (nagib = beskonačnost)") nastavi fit = np.polyfit ((x1, x2), (y1, y2), 1) nagib = (y2 - y1) / (x2 - x1) presretanje = y1 - (nagib * x1) ako je nagib <0: ako je x1 <lijeva_regija_granična i x2 desna_regija_granična i x2> desna_region_boundary: right_fit. append ((nagib, presretanje)) left_fit_average = np.average (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) ako je len (right_fit)> 0: lane_lines.append (make_points (frame, right_fit_average)) # lane_lines je 2-D niz koji se sastoji od koordinata desne i lijeve linije trake # na primjer: lan e_lines =
make_points () je pomoćna funkcija za funkciju average_slope_intercept () koja će vratiti ograničene koordinate linija trake (od dna do sredine okvira).
def make_points (okvir, linija):
visina, širina, _ = okvir.nagib oblika, presretanje = linija y1 = visina # dno okvira y2 = int (y1 / 2) # napravite točke od sredine okvira prema dolje ako je nagib == 0: nagib = 0,1 x1 = int ((y1 - presretanje) / nagib) x2 = int ((y2 - presretanje) / nagib) return
Da bi se spriječilo dijeljenje s 0, prikazan je uvjet. Ako je nagib = 0, što znači y1 = y2 (vodoravna linija), dajte nagibu vrijednost blizu 0. To neće utjecati na performanse algoritma, kao i spriječiti nemoguće slučajeve (dijeljenje s 0).
Za prikaz linija trake na okvirima koristi se sljedeća funkcija:
def display_lines (frame, lines, line_color = (0, 255, 0), line_width = 6): # boja crte (B, G, R)
line_image = np.zeros_like (frame) ako linije nisu None: za liniju u redovima: za x1, y1, x2, y2 u retku: 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
cv2.addWeighted () funkcija uzima sljedeće parametre i koristi se za kombiniranje dvije slike, ali svakoj daje težinu.
cv2.addPonderirano (slika1, alfa, slika2, beta, gama)
Izračunava izlaznu sliku pomoću sljedeće jednadžbe:
izlaz = alfa * slika1 + beta * slika2 + gama
Više informacija o funkciji cv2.addWeighted () izvedeno je ovdje.
Izračunajte i prikažite liniju zaglavlja:
Ovo je posljednji korak prije nego što primijenimo brzine na naše motore. Linija smjera odgovorna je za davanje motoru upravljača smjera u kojem bi se trebao okretati, a motorima za prigušivanje daje brzinu kojom će raditi. Izračun linije naslova je čista trigonometrija, koriste se trigonometrijske funkcije tan i atan (tan^-1). Neki ekstremni slučajevi su kada kamera detektira samo jednu liniju trake ili kada ne detektira nijednu liniju. Svi ti slučajevi prikazani su u sljedećoj funkciji:
def get_steering_angle (frame, lane_lines):
visina, širina, _ = okvir.oblik ako je len (lane_lines) == 2: # ako se otkriju dvije linije trake _, _, left_x2, _ = lane_lines [0] [0] # izdvojite lijevo x2 iz niza lane_lines _, _, right_x2, _ = lane_lines [1] [0] # izdvoj desno x2 iz niza lane_lines mid = int (width / 2) x_offset = (left_x2 + right_x2) / 2 - mid y_offset = int (height / 2) elif len (lane_lines) == 1: # ako se otkrije samo jedna linija x1, _, x2, _ = lane_lines [0] [0] x_offset = x2 - x1 y_offset = int (height / 2) elif len (lane_lines) == 0: # ako se ne detektira linija x_offset = 0 y_offset = int (height / 2) angle_to_mid_radian = math.atan (x_offset / y_offset) angle_to_mid_deg = int (angle_to_mid_radian * 180.0 / math.pi) upravljački kut = kut_do_mid_deg + 90 return
x_offset u prvom slučaju je koliko se prosjek ((desno x2 + lijevo x2) / 2) razlikuje od sredine ekrana. y_offset uvijek se uzima kao visina / 2. Posljednja gornja slika prikazuje primjer linije naslova. angle_to_mid_radians isto je što i "theta" prikazano na gornjoj zadnjoj slici. Ako je upravljački kut = 90, to znači da automobil ima liniju smjera okomitu na liniju "visina / 2" i da će se automobil kretati naprijed bez upravljanja. Ako je upravljački kut> 90, automobil bi trebao krenuti udesno, u suprotnom bi trebao krenuti ulijevo. Za prikaz linije naslova koristi se sljedeća funkcija:
def display_heading_line (okvir, kut upravljača, linija_boja = (0, 0, 255), širina_ linije = 5)
heading_image = np.zeros_like (okvir) visina, širina, _ = okvir.oblik upravljački_ugao_radian = upravljački_ugao / 180,0 * math.pi x1 = int (širina / 2) y1 = visina x2 = int (x1 - visina / 2 / math.tan (upravljački_ugaoni_radijan)) y2 = int (visina / 2) cv2.line (zaglavlje_slika, (x1, y1), (x2, y2), crta_boja, širina_ linije) zaglavlje_image = cv2.addOdmjereno (okvir, 0,8, zaglavlje_slika, 1, 1) return heading_image
Gornja funkcija uzima okvir u kojem će biti povučena linija smjera i kut upravljanja kao ulaz. Vraća sliku linije naslova. Okvir linije naslova snimljen u mom slučaju prikazan je na gornjoj slici.
Kombiniranje svih kodova zajedno:
Kôd je sada spreman za sastavljanje. Sljedeći kôd prikazuje glavnu petlju programa koja poziva svaku funkciju:
uvoz cv2
uvoz numpy kao np video = cv2. VideoCapture (0) video.set (cv2. CAP_PROP_FRAME_WIDTH, 320) video.set (cv2. CAP_PROP_FRAME_HEIGHT, 240) dok je True: ret, frame = video.read () frame = cv2.flip (okvir, -1) #Pozivanje funkcija hsv = pretvoriti u_HSV (okvir) rubovi = otkriti_rubove (hsv) roi = regija_interesa (rubovi) linije_segmenti = otkriti_linijske_segmente (roi) lane_lines = prosječne_slope_intercept (okvir, segmenti_crta) lane_lines_image = display_line_ frame (okvir) = get_steering_angle (frame, lane_lines) heading_image = display_heading_line (lane_lines_image, upravljački_ugao) ključ = cv2.waitKey (1) if key == 27: break video.release () cv2.destroyAllWindows ()
Korak 6: Primjena PD kontrole
Sada imamo kut upravljanja spreman za napajanje motorima. Kao što je ranije spomenuto, ako je kut upravljanja veći od 90, automobil bi trebao skrenuti desno, u suprotnom bi trebao skrenuti ulijevo. Primijenio sam jednostavan kod koji okreće motor upravljača udesno ako je kut veći od 90 i okreće ga ulijevo ako je kut upravljanja manji od 90 pri konstantnoj brzini prigušivanja (10% PWM), ali dobio sam mnogo pogrešaka. Glavna greška koju sam dobio je kad se automobil približi bilo kojem zavoju, motor upravljača djeluje izravno, ali se motori za prigušivanje zaglave. Pokušao sam povećati brzinu prigušivanja na (20% PWM) u zavojima, ali završio sam s izlaskom robota iz prometnih traka. Trebalo mi je nešto što uvelike povećava brzinu prigušivanja ako je kut upravljanja vrlo velik i malo povećava brzinu ako kut upravljanja nije tako velik, tada smanjuje brzinu na početnu vrijednost dok se automobil približava 90 stupnjeva (kreće se ravno). Rješenje je bilo korištenje PD kontrolera.
PID regulator označava proporcionalni, integralni i izvedeni kontroler. Ova vrsta linearnih kontrolera naširoko se koristi u aplikacijama robotike. Gornja slika prikazuje tipičnu PID upravljačku petlju. Cilj ovog regulatora je postići "zadanu vrijednost" na najučinkovitiji način za razliku od "on -off" regulatora koji uključuju ili isključuju postrojenje prema nekim uvjetima. Neke ključne riječi trebaju biti poznate:
- Zadana vrijednost: je željena vrijednost koju želite da vaš sustav dosegne.
- Stvarna vrijednost: je stvarna vrijednost koju je senzor osjetio.
- Pogreška: razlika je između zadane vrijednosti i stvarne vrijednosti (pogreška = zadana vrijednost - stvarna vrijednost).
- Kontrolirana varijabla: iz naziva varijabla koju želite kontrolirati.
- Kp: Proporcionalna konstanta.
- Ki: Integralna konstanta.
- Kd: Izvedena konstanta.
Ukratko, petlja PID upravljačkog sustava radi na sljedeći način:
- Korisnik definira zadanu vrijednost koju sustav želi doseći.
- Pogreška se izračunava (pogreška = zadana vrijednost - stvarna).
- Regulator P generira radnju proporcionalnu vrijednosti pogreške. (greška se povećava, akcija P se također povećava)
- I kontroler će s vremenom integrirati pogrešku koja eliminira pogrešku sustava u stabilnom stanju, ali povećava njezino prekoračenje.
- D regulator je jednostavno vremenski derivat pogreške. Drugim riječima, to je nagib greške. Čini radnju proporcionalnu izvedenici pogreške. Ovaj regulator povećava stabilnost sustava.
- Izlaz regulatora bit će zbroj tri kontrolera. Izlaz regulatora će postati 0 ako greška postane 0.
Odlično objašnjenje PID kontrolera možete pronaći ovdje.
Vraćajući se do auta za zadržavanje trake, moja kontrolirana varijabla bila je brzina prigušivanja (budući da upravljanje ima samo dva stanja, desno ili lijevo). U tu se svrhu koristi PD kontroler jer D radnja uvelike povećava brzinu prigušivanja ako je promjena pogreške vrlo velika (tj. Veliko odstupanje) i usporava automobil ako se ova promjena pogreške približi 0. Učinio sam sljedeće korake za implementaciju PD -a kontroler:
- Postavite zadanu vrijednost na 90 stupnjeva (uvijek želim da se automobil kreće ravno)
- Izračunati kut odstupanja od sredine
- Odstupanje daje dvije informacije: Kolika je greška (veličina odstupanja) i u kojem smjeru motor upravljača mora ići (znak odstupanja). Ako je odstupanje pozitivno, automobil bi trebao upravljati udesno, u suprotnom bi trebao upravljati ulijevo.
- Budući da je odstupanje negativno ili pozitivno, varijabla "pogreške" je definirana i uvijek jednaka apsolutnoj vrijednosti odstupanja.
- Pogreška se množi s konstantom Kp.
- Pogreška prolazi kroz vremensku diferencijaciju i množi se s konstantom Kd.
- Brzina motora se ažurira i petlja se ponovno pokreće.
Sljedeći kôd se koristi u glavnoj petlji za kontrolu brzine motora prigušivača:
brzina = 10 # radna brzina u % PWM
#Varijable koje se ažuriraju za svaku petlju lastTime = 0 lastError = 0 # PD konstante Kp = 0.4 Kd = Kp * 0.65 Dok je True: now = time.time () # trenutna vremenska varijabla dt = now - odstupanje zadnjeg vremena = upravljački kut - 90 # ekvivalent na angle_to_mid_deg varijabla greška = abs (odstupanje) ako je odstupanje -5: # nemojte upravljati ako postoji odstupanje od 10 stupnjeva pogreške = 0 greška = 0 GPIO.izlaz (in1, GPIO. LOW) GPIO.output (in2, GPIO. LOW) upravljanje.stop () elif odstupanje> 5: # upravljajte desno ako je odstupanje pozitivno GPIO.izlaz (in1, GPIO. LOW) GPIO.izlaz (in2, GPIO. HIGH) upravljanje.pokretanje (100) elif odstupanje < -5: # upravljač lijevo ako je odstupanje negativno GPIO.izlaz (in1, GPIO. HIGH) GPIO.izlaz (in2, GPIO. LOW) upravljanje.start (100) izvedenica = kd * (pogreška - lastError) / dt proporcionalno = kp * pogreška PD = int (brzina + izvedenica + proporcionalna) spd = abs (PD) ako je spd> 25: spd = 25 gas. start (spd) lastError = pogreška lastTime = time.time ()
Ako je pogreška vrlo velika (odstupanje od sredine je veliko), proporcionalne i izvedene radnje su velike što rezultira velikom brzinom prigušivanja. Kad se pogreška približi 0 (odstupanje od sredine je malo), izvedenica djeluje obrnuto (nagib je negativan), a brzina prigušivanja postaje niska kako bi se održala stabilnost sustava. Cijeli kôd nalazi se u nastavku.
Korak 7: Rezultati
Gornji videozapisi prikazuju rezultate koje sam postigao. Potrebno je više ugađanja i daljnjih prilagodbi. Povezivao sam malinu pi sa svojim LCD zaslonom jer je streaming videozapisa preko moje mreže imao veliku latenciju i bio je vrlo frustrirajući za rad, zato u video zapisu postoje žice povezane s malinom pi. Za crtanje staze koristio sam pjenaste ploče.
Čekam vaše preporuke za poboljšanje ovog projekta! Nadam se da su ove upute bile dovoljno dobre da vam daju neke nove informacije.
Preporučeni:
Biometrijski glasački stroj na temelju otisaka prstiju koji koristi Arduino: 4 koraka (sa slikama)
Biometrijski glasački stroj temeljen na otiscima prstiju koji koristi Arduino: Svi smo svjesni postojećeg elektroničkog glasačkog stroja u kojem korisnik mora pritisnuti gumb za glasovanje. No ti su strojevi od početka kritizirani zbog kaljenja. Stoga vlada planira uvesti sustav otisaka prstiju
Hodajući robot koji koristi 1 servo motor: 13 koraka (sa slikama)
Hodajući robot s jednim servo motorom: Želio sam izgraditi ovog robota za hodanje otkad sam ga vidio na YouTubeu. Nakon kratkog pretraživanja pronašao sam još informacija o njemu i odlučio sam napraviti svoj. Cilj koji sam imao izgradnjom ove hodalice bio je pokušati je učiniti što manjom
Raspberry Pi - Autonomni Mars Rover s OpenCV praćenjem objekata: 7 koraka (sa slikama)
Raspberry Pi - Autonomni Mars Rover s OpenCV praćenjem objekata: Pokreće ga Raspberry Pi 3, prepoznavanje otvorenih CV objekata, ultrazvučni senzori i istosmjerni motori. Ovaj rover može pratiti svaki objekt za koji je osposobljen i kretati se po bilo kojem terenu
Arduino Bluetooth RC automobil s pogonom na četiri kotača koji koristi UNO R3, HC-05 i L293D motorni štit s kodiranjem i Android aplikacijom: 8 koraka
Arduino Bluetooth RC automobil s pogonom na četiri kotača koristeći UNO R3, HC-05 i L293D motorni štit s kodiranjem i Android aplikacijom: Danas ću vam reći o tome kako napraviti arduino bluetooth RC automobil s pogonom na četiri kotača koristeći HC 05, L293 motorni štit, 4 DC motor, s kodiranjem i aplikacijom za android za upravljanje automobilom. Korištena komponenta: -1-Arduino UNO R32-Bluetooth HC-053-Motorshield L293
Težina ruku i nogu trake za ljepljive trake: 3 koraka
Težine za ruke i noge od ljepljive trake: Ova instrukcija će vas naučiti kako napraviti pojednostavljene utege ljepljive trake i napuniti ih olovom ili pijeskom. Te se težine mogu zamijeniti između ruke i noge. Ovo je moje prvo uputstvo pa budite ljubazni;) Molimo ostavite komentare