Skocz do zawartości

Przeszukaj forum

Pokazywanie wyników dla tagów 'Freestyle'.

  • Szukaj wg tagów

    Wpisz tagi, oddzielając przecinkami.
  • Szukaj wg autora

Typ zawartości


Kategorie forum

  • Elektronika i programowanie
    • Elektronika
    • Arduino, ESP
    • Mikrokontrolery
    • Raspberry Pi
    • Inne komputery jednopłytkowe
    • Układy programowalne
    • Programowanie
    • Zasilanie
  • Artykuły, projekty, DIY
    • Artykuły redakcji (blog)
    • Artykuły użytkowników
    • Projekty - roboty
    • Projekty - DIY
    • Projekty - DIY (początkujący)
    • Projekty - w budowie (worklogi)
    • Wiadomości
  • Pozostałe
    • Oprogramowanie CAD
    • Druk 3D
    • Napędy
    • Mechanika
    • Zawody/Konkursy/Wydarzenia
    • Sprzedam/Kupię/Zamienię/Praca
    • Inne
  • Ogólne
    • Ogłoszenia organizacyjne
    • Dyskusje o FORBOT.pl
    • Na luzie
    • Kosz

Szukaj wyników w...

Znajdź wyniki, które zawierają...


Data utworzenia

  • Rozpocznij

    Koniec


Ostatnia aktualizacja

  • Rozpocznij

    Koniec


Filtruj po ilości...

Data dołączenia

  • Rozpocznij

    Koniec


Grupa


Znaleziono 145 wyników

  1. Cześć. Chciałbym przedstawić wam mój projekt robota samobalansującego. Jest to mój najbardziej zaawansowany jak dotąd projekt, który pochłonął najwięcej pracy. Pomysł na zbudowanie takiego robota zrodził się w mojej głowie w wakacje po obejrzeniu filmiku przedstawiającego podobną konstrukcję. Pracę nad nim rozpocząłem jeszcze w wakacje, a z przerwami zakończyłem w lutym. Działanie robota jest podobne do dostępnych na rynku Hoverboardów, czyli robot ma za zadanie poruszać się w taki sposób, aby utrzymać się w pionie, oczywiście bez podpierania. Konstrukcję robota zaprojektowałem sam i wykonałem z pręta gwintowanego i plexi. Uznałem że taka konstrukcja zapewni robotowi wymaganą sztywność i niską masę, jednocześnie nie rujnując budżetu. Najpierw wykonałem jej model w Fusion 360, a później przystąpiłem do pracy. Roboty z tym trochę było, bo obróbka plexi do łatwych nie należy. Sporo czasu zajęło przycięcie prostokątów, a jeszcze więcej wywiercenie otworów, które musiały być idealnie rozmieszczone, aby później dało się przełożyć przez nie pręt gwintowany. Po zbudowaniu ramy przyszła pora na elektronikę. Ponieważ robot nie zapewnia dużo miejsca, a jednocześnie środek ciężkości powinien być możliwie wysoko, dla ułatwienia balansu, musiałem się postarać ścisnąć wszystko jak to tylko możliwe. Baterię zasilającą robota (ogniwe Li-Po odzyskane z powerbanka o pojemności 3000 mAh) umieściłem na najwyższej półce. Tam również trafiła przetwornica step-up podnosząca napięcie do 7,4 V. Wiem że lepiej byłoby dać dwie baterie połączone szeregowo, ale w momencie budowania budżet na to nie pozwolił. Szybko okazało się że jedna przetwornica to za mało - Arduino restartowało się przy każdym uruchomieniu silnika, nawet jeśli do układu przyłączyłem bardzo duży kondensator. Dodałem więc drugą - teraz silniki były zasilanie niezależnie od elektroniki sterującej. Pozwoliło to stanąć robotowi po raz pierwszy, jednak wciąż jedna przetwornica zasilająca silniki ograniczała ich moc. Dodałem drugą, co nieco poprawiło sytuację, jednak wciąż nieco ogranicza silniki. Póki co szukam lepszego rozwiązania. Schodząc na niższą półkę. Tam trafiła płytka ze sterownikiem i druga z mostkiem H. Pierwszą płytkę lutowałem sam na płytce uniwersalnej - zajęło to kilka godzin i mnóstwo cyny, ale satysfakcja była nie do opisania, zwłaszcza że wszystkie połączenia wykonałem cyną. Po spędzeniu kolejnej godziny na pozbywaniu się zwarć układ był gotowy do testów Robot aby ustalić swoją pozycję korzysta z modułu żyroskopu i akcelerometru MPU6050 oraz wbudowanych w silniki enkoderów. Dane z tych czujników trafiają do Arduino Nano które poprzez układ L298N steruje dwoma silnikami. Dzięki akcelerometrowi i żyroskopowi robot zna swój kąt przechylenia. W pierwszych wersjach kodu szybko okazało się, że to nie wystarczająco, ponieważ o ile robot stał, to cały czas przesuwał się w jedną stronę. Wynika to z tego że konstrukcja nie jest idealnie wyważona, a robot nie zna swojej pozycji, jedynie kąt nachylenia, więc jeżeli ustawiony na sztywno kąt odbiegał od kąta balansu, robot "dryfował". Aby temu zapobiec dodałem drugie sprzężenie zwrotne, tym razem oparte o enkodery przy silnikach. Enkodery zliczają ilość impulsów które silniki wykonały w każdą ze stron, a oprogramowanie dąży, aby ich różnica była równa 0. Pierwsze próby nie były zbyt udane. Kiedy doprowadziłem kod do stanu w którym robot chociaż próbował się utrzymać, udawało mu się to przez maksymalnie kilkanaście sekund. Jednak wraz z poprawianiem kodu robot stał dłużej i dłużej. Obecnie już się nie wywala, jednak mostek H po dłuższym staniu się przegrzewa, więc czas pracy ograniczony jest do kilku minut. Mimo to robot robi duże wrażenie, chociaż z pewnością nie jest idealny. Zastosowałem tanie chińskie silniki, i jak się okazało, jeden obraca się szybciej niż drugi, więc robot obraca się w jedną stronę. Do tego jak wspomniałem przegrzewa się, a silnikom brakuje momentu, więc robot się trzęsie zamiast stać idealnie prosto. Są to jednak problemy które mam w planach poprawić. Planuję dodać również możliwość sterowania po BT (już nawet na płytce jest miejsce na moduł HC-06), ale na razie nie miałem czasu. Oto filmik prezentujący działanie robota:
  2. "Devastator" O zbudowaniu robota myślałem już dawno. Devastator ma też swojego poprzednika, lecz o wykonaniu conajmniej tragicznym. Po podjęciu decyzji o budowie robota zaczęłem rozglądać się za częściami a jednocześnie zajęłem się wakacyjną pracą, żeby jakoś dorobić się na te części. Zbudowanie tego robota kosztowało mnie jak do tej pory trochę ponad 1000 zł dodając jeszcze do tego masę czasu, kawy i nieprzespanych nocek przy budowie. Głównym problemem był dla mnie program. Programistą nie jestem jakimś dobrym a jeszcze dodatkowo projekt ten jest pierwszym z użyciem raspberry pi. Największym problemem był program. Sczególnie dał mi się we znaki, gdy chciałem zaprogramować serva. Jak na złość żaden program znaleziony w internecie nie chciał działać. Więc musiałem przestudiować zasadę działania serv, i na podstawie wyciągnietych wniosków metodą prób i błędów udało mi się dojść do rozwiązania tego problemu. Tak więc mając mniejsze i większe problemy udało mi się dobrnąć do zbudowania robota. Zamysł projektu jest taki, żeby zbudować takiego robota, który dostanie się w takie miejsca niebezpieczne lub miejsca gdzie człowiek się nie dostanie. Czyli np. budynki grożące zawaleniem, szczeliny, oraz wiele innych. Zamiast podawać teoretyczne zastosowania wolę wspomnieć o sytuacjach gdy Devastator znalazł zastosowanie. Przede wszystkim użyłem go do sprawdzenia stanu podwozia auta. następne zastosowanie znalazł gdy zatkały się przepusty na pod wjazdem na moje podwórko. Dzięki temu robotowi szybko odnalazłem owe zatkane przepusty, dzięki czemu oszczędziłem sobię wiele pracy. Sprzydał się również podczas szukania nieszczelności w instalacji hydraulicznej. Zaczynając od początku: Mózgiem robota jest Raspberry PI 3 b+(link na dole). Malinę wybrałem tylko dlatego, że potrzebowałem odskoczni od arduino. Następnie użyłem sterownik silników(link na dole) do sterowania gąsienicami. Do budowy użyłem również baterii li-ion 18650 , powerbanka , kilku serv, modułu kamery z nadajnikiem radiowym oraz własnej płytki pcb. Do budowy użyłem podwozia gąsienicowego "Devastator"(stąd nazwa robota, link na dole), ramienia wydrukowanego na drukarce 3D oraz wieżyczki z kamerką również drukowaną na drukarce. obecnie pracuję nad dopinanym z przodu spychem/elektromagnesem. Program napisany w Pythonie (z małą pomocą wujka google). Sterowany poprzez klawiaturę bluetooth, natomiast obraz przezyłany radiowo przez moduł bezpośrednio do telefonu. Devastator posiada zasilanie modułowe. Znaczy to, że osobno jest zasilana logika, silniki, serva, oraz kamerka. Devastator przeżył już swój debiut na konkursie Geniusz IT(Dotarł do finału). Jak wiadaomo z każdym projektem jest jakieś ograniczenie budżetowe. W moim przypadku ciągle szukam dodatkowych funduszy na ulepszenie tego projektu, np. muszę wymienić serva na o wiele wytrzymalsze bo na ten moment ramię działa jedynie w wersji pokazowej. Muszę również przerzucić się na komunikację radiową, a wiadomo nic za darmo. NIe będę już więcej przynudzał. wrzucam wam więc kilka zdjęć (sorki że obrócone, pogimnastykujecie się trochę ) : A tu kilka przydatnych linków: raspberry: https://botland.com.pl/pl/moduly-i-zestawy-raspberry-pi-3-b-plus/11142-raspberry-pi-3-model-b-wifi-dual-band-bluetooth-1gb-ram-14ghz-7131796402594.html?search_query=raspberry+pi+3+b+&results=937 podwozie: https://botland.com.pl/pl/podwozia-robotow/6610-dfrobot-devastator-gasienicowe-podwozie-robota-metalowe-silniki.html?search_query=devastator&results=2 sterownik silników: https://botland.com.pl/pl/podwozia-robotow/6610-dfrobot-devastator-gasienicowe-podwozie-robota-metalowe-silniki.html?search_query=devastator&results=2
  3. O mnie Witam, Jestem Maciej - pracuje jako software architect (nie mam wykształcenia elektronicznego dlatego proszę o wyrozumiałość jeżeli chodzi o połączenia i rozwiązania - z tego też powodu w projekcie nie daje gotowego przepisu na zasilanie ) i żeby do końca nie zgnuśnieć po godzinach tworzę platformę RemoteMe. W platformie chodzi głównie o ułatwienie sterowaniem urządzeniami IoT poprzez internet - bez konieczności posiadania VPNa, publicznego IP. Po stronie RemoteMe tworzycie strony internetowe ( RemoteMe posiada hosting na Wasze pliki ) + zestaw bilbiotek (Javascript, RasbeprryPi (python), Arduino ESP ) które w łatwy sposób pozwolą na komunikowanie się z Waszymi urządzeniami. Co do protokołu to opracowałem własny (bardziej jest to konwencja przesyłu paczek niż protokół jako taki ) (działa przez sockety, websockety, wywoływania RESTowe) - umożliwia on przesył wiadomości do określonego urządzenia, i coś w rodzaju topic- subscribera ( u mnie się to nazwa"variables" zmienne ) Wasze urządzenia rejestrują się w RemoteMe po zarejestrowaniu, możecie do nich wysyłać komendy przez stronę internetową albo z innych urządzeń. Jednym z ostatnich featerów są "Out of the box projects" - polega to na tym, że jednym kliknięciem importujecie projekt na Wasze konto - oczywiście możecie potem wszytko zmieniać wedle własnych pomysłów - właśnie ostatnim takim projektem jest Samochód RaspberryPi z kamerką o którym w tym kursie. Projekt jest częściowo openSourcowy - bilbioteki Javascript, Python, api Restowe są openSource - sam kod serwera i program na RasbeprryPi jest zamknięty. Platformę tworzę sam - po godzinach i udostępniam za darmo O kursie Ten kurs – przedstawia budowę samochodu sterowanego przez przeglądarkę z wyświetlaniem obrazu z kamerki. Jest to dość specyficzny kurs (jak pisałem wyżej ) – całość oprogramowanie jest już zrobiona, a dodanie plików do własnego konta w RemoteMe sprowadza się do paru kliknięć. Po tak dodanym projekcie można własnoręcznie i dowolnie edytować wszystkie pliki źródłowe (strona WWW skrypt pythonowy) – zwłaszcza, że same pliki projektu nie są skomplikowane, a kod jest dość czytelny i samo opisujący się (mam przynajmniej taką nadzieję ) Na dole kursu opisana jest bardziej szczegółowo zasada działania samochodu. Jeżeli nie jesteście zainteresowani samą platformą RemoteMe to i tak myślę, że w kursie znajdziecie garść pomysłów na podobny projekt Kurs właściwy Na filmie działanie + krok po kroku wszystko z tego kursu. W poprzednim kursie pokazałem jak sterować pozycją kamerki i przechwytywać obraz na przeglądarkę tutaj i sterowanie kamerką tutaj . Teraz rozbudujemy ten projekt i zbudujemy samochód z napędem na 4 koła ( sterowany podobnie jak czołg – żeby skręcić prawa para kół musi się kręcić z inną prędkością niż lewa). Taki efekt otrzymamy na wideo też całość kursu – można zaglądnąć, gdy gdzieś utkniecie Części RaspberryPi z wifi ( np zeroW) link Podwozie z silnikami link Sterownik serwomechanizmów na I2C link Kamera do Rpi + taśma jeżeli potrzebna link Dwa SerwoMechanizmy kompatybilne z uchwytem kamerki kamery link Uchwyt na kamerkę z serwami link Mostek H TB6612FNG link Zasialnie – np akumlatory podłączone do przetwornicy – żeby uzyskać odpowiednie napięcie link Połączenia RaspberryPI steruje serwami poprzez moduł PWM i napędem przez ustawianie stanu pinów na mostku oraz dostarczając sygnału PWM poprzez ten sam moduł, który wysyła sygnał do serwomechanizmów. (Dzięki modułowi do generowanie sygnału PWM nie musimy tych sygnałów generować przez samo RaspberryPi – co jest dość problematyczne, poprostu przez I2C przesyłamy odpowiednie instrukcje do sterownika serw (poprzez bibliotekę pythonową dostarczoną przez adafruit), a ten generuje odpowiedni sygnał PWM dla serwo mechanizmów i do mostka H) Schemat połączeń: Poprzez magistrale I2C RPi steruje kontrolerem serwo mechanizmów, dwa ostanie wyprowadzenia kontrolera są podłączone do mostka H, gdzie wykorzystując sygnał PWM ustawiamy prędkość silników. Do mostka H są również podłączone piny RPi które stanami wysokim i niskim będą określać kierunek obrotu silników napędowych – po szczegóły odsyłam do dokumentacji układu TB6612FNG, równie dobrze można użyć mostka L298N lub podobnego. Zaprojektowałem płytkę PCB, którą możecie użyć pliki eagle,gerber itd tutaj plik pcb.zip Schemat płytki pokrywa się ze schematem powyżej. Wyprowadzenia płytki: Wejście sygnału PWM z kanałów 15 i 14 modułu PWM Wejście zasilania silników do poruszania się Zasilanie układów (PWM, RPi) koniecznie dokładne +5V Wyjście silników napędu, pierwsze dwa wyjścia do jednej pary silników kolejne dwa do drugiej Zasilanie serw i w tym przypadku silników napędu w moim przypadku ~6V (należy sprawdzić w specyfikacji serw i silników, jakie maksymalne napięcie można podłączyć) ZWORKA gdy zepniemy dwa piny napięcie z 5 będzie podawane też do zasilania silników napędu ZWORKA gdy jest podłączona zasilane jest RaspberryPI z połączenia 3 przed podłączeniem zworki należy dokładnie sprawdzić napięcia, żeby nie uszkodzić Najdroższego komponentu czyli właśnie malinki Wlutowujemy kabelki, bo nie będziemy korzystali z konwertera stanów Wlutowujemy kabelki, bo nie będziemy korzystali z konwertera stanów Oczywiście jest jeszcze potrzebne odpowiednie zasilanie, w moim przypadku 6v jako napięcie silników napędu i serw, oraz 5v dla RasbeprryPi i kontrolerów. Poniżej kilka zdjęć poglądowych całości samochodu: Programowanie Przed utworzeniem projektu skonfigurujcie kamerkę i komunikacje I2C używając raspi-config opisane tutaj. Ten projekt jest jednym z gotowych projektów, które możecie prosto zaimplementować kilkoma kliknięciami: KLIK - po zalogowaniu otworzy się projekt. Przejdźcie do zakładki “Build It” i podążajcie krokami, na końcu klik w “Build Project” i otrzymacie: Po kliknięciu “Get QR” pokaże się kod QR, który możecie zeskanować smartfonem, lub po prostu otworzyć stronę przyciskiem “Open” w przeglądarce na komputerze. Narazie nie radzę zmieniać pozycji kamery dopóki nie ustawimy pozycji serw – w niektórych przypadkach możecie uszkodzić swoje serwomechanizmy. Samochód powinien jeździć jak na filmie – może się zdarzyć, że skręca w złą stronę albo serwa są źle skalibrowane, poniżej w omawianiu kodu napisałem jak to naprawić. Omówienie tego, co się stało Jak zauważyliście, tworzenie projektu było mocno zautomatyzowane. Dlatego omówię teraz, co się dokładnie wydarzyło i jak modyfikować Wasz projekt. Przede wszystkim utworzyły się dwie zmienne (zakładka variables): Zmienna cameraPos przesyła pozycje kamery, drive pozycje joysticka. Obie są typem “Small int x2” oznacza to, że wartoscią zmiennej są dwie liczby integer. Strona internetowa zmienia nasze zmienne, a skrypt pythonowy te zmiany rejestruje i odpowiednio reaguje (jak rozwiniemy zmienne zobaczymy, że urządzeniem nasłuchującym na zmiany jest właśnie skrypt pythonowy). Zobaczmy jak wygląda kod Pythonowy (więcej o zmiennych tutaj) Python Skrypt pythonowy został automatycznie wgrany. Oczywiście możemy go podejrzeć i modyfikować ( żeby stworzyć nowy skrypt pythonowy np dla innych projektów zobacz tutaj) . Z informacji jakie teraz są Ci potrzebne to skrypt pythonowy to kolejne urządzenie w remoteMe jest zarządzalne przez skrypt (uruchomiony przez ./runme.sh) , do tego urządzenia możemy wysłać wiadomości, urządzenie reaguje też na zmiany zmiennych, które obserwuje i może te zmienne zmieniać. Żeby otworzyć skrypt pythonowy kliknij python.py i wybierz Edit : Wygląda on następująco. Poniżej omówię ciekawsze fragmenty import logging import socket import math import struct import sys import os os.chdir(sys.argv[1]) sys.path.append('../base') import remoteme import Adafruit_PCA9685 import time import RPi.GPIO as GPIO motorAIn1 = 25 # GPIO25 motorAIn2 = 8 # GPIO8 motorBIn1 = 24 # 24 motorBIn2 = 23 # 23 motors = [[motorAIn1, motorAIn2], [motorBIn1, motorBIn2]] motorsPWM = [14, 15] pwm = None; def motorForward(motorId): GPIO.output(motors[motorId][0], GPIO.LOW) GPIO.output(motors[motorId][1], GPIO.HIGH) def motorBackward(motorId): GPIO.output(motors[motorId][0], GPIO.HIGH) GPIO.output(motors[motorId][1], GPIO.LOW) def motorSoftStop(motorId): GPIO.output(motors[motorId][0], GPIO.LOW) GPIO.output(motors[motorId][1], GPIO.LOW) def setMotor(motorId, speed): if speed == 0: motorSoftStop(motorId) elif speed > 0: motorForward(motorId) elif speed < 0: motorBackward(motorId) speed=-speed logger.info("set speed {} for motor {} ".format(speed,motorId)) pwm.set_pwm(motorsPWM[motorId], 0, int(speed)) def onCameraPosChange(i1, i2): global pwm logger.info("on camera change {} , {}".format(i1, i2)) pwm.set_pwm(1, 0, i1) pwm.set_pwm(0, 0, i2) pass def onDriveChange(x, y): logger.info("on drive change x {} , y {}".format(x, y)) global pwm left=y right=y left+=x right-=x delta=(left+right)/2 left+=delta right+=delta # when your car doesnt drive as suppose try to swich right and left variable below # or remove add minuses next to 2 # another way is to switch cables conencted to motors setMotor(0, 2*left) setMotor(1, 2*right) pass def setupPWM(): global pwm pwm = Adafruit_PCA9685.PCA9685() pwm.set_pwm_freq(80) def setupPins(): global GPIO GPIO.setmode(GPIO.BCM) # Broadcom pin-numbering scheme for motor in motors: for pinId in motor: GPIO.setup(pinId, GPIO.OUT) try: logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s', datefmt='%d.%m %H:%M', filename="logs.log") logger = logging.getLogger('application') setupPWM() setupPins() remoteMe = remoteme.RemoteMe() remoteMe.startRemoteMe(sys.argv) remoteMe.getVariables().observeSmallInteger2("cameraPos" ,onCameraPosChange); remoteMe.getVariables().observeSmallInteger2("drive" ,onDriveChange); remoteMe.wait() finally: pass Sterowanie silnikami: def motorForward(motorId): GPIO.output(motors[motorId][0], GPIO.LOW) GPIO.output(motors[motorId][1], GPIO.HIGH) def motorBackward(motorId): GPIO.output(motors[motorId][0], GPIO.HIGH) GPIO.output(motors[motorId][1], GPIO.LOW) def motorSoftStop(motorId): GPIO.output(motors[motorId][0], GPIO.LOW) GPIO.output(motors[motorId][1], GPIO.LOW) def setMotor(motorId, speed): if speed == 0: motorSoftStop(motorId) elif speed > 0: motorForward(motorId) elif speed < 0: motorBackward(motorId) speed=-speed logger.info("set speed {} for motor {} ".format(speed,motorId)) pwm.set_pwm(motorsPWM[motorId], 0, int(speed)) Funkcja setMotor dla motorId 1 lub 2 ustawia prędkość speed (może być ujemna). poprostu najperw na odpowiednich pinach ustawiamy odpowiednio stany (ruch do przodu do tyłu, hamowanie), a następnie w zależności od prędkości ustawiamy odpowiednio wypełnienie PWM korzystając ze sterownika serw. def onCameraPosChange(x, y): global pwm logger.info("on camera change {} , {}".format(x, y)) pwm.set_pwm(1, 0, x) pwm.set_pwm(0, 0, y) pass Funkcja setMotor dla motorId 1 lub 2 ustawia prędkość speed (może być ujemna). poprostu najperw na odpowiednich pinach ustawiamy odpowiednio stany (ruch do przodu do tyłu, hamowanie), a następnie w zależności od prędkości ustawiamy odpowiednio wypełnienie PWM korzystając ze sterownika serw. def onDriveChange(x, y): logger.info("on drive change x {} , y {}".format(x, y)) global pwm left=y right=y left+=x right-=x delta=(left+right)/2 left+=delta right+=delta # when your car doesnt drive as suppose try to swich right and left variable below # or remove add minuses next to 2 # another way is to switch cables conencted to motors setMotor(0, 2*left) setMotor(1, 2*right) pass Powyższa funkcja zostanie wywołana jak zmieni się zmienna drive – np po zmianie joysticka na stronie. x,y to po prostu współrzędne wychylenia joysticka (1024,1024) oznacza wychylenie maksymalnie do góry i w prawo. Na podstawie tych zmiennych wyliczamy prędkość lewej i prawej strony samochodu. Jeżeli samochód skręca, zamiast jechać do przodu, jedzie do tyłu zamiast do przodu: setMotor(0, Y2*left) setMotor(1, X2*right) Dajcie minusy w różnych kombinacjach (w miejsca X i Y) do czasu, aż samochód jedzie do przodu – gdy joystick jest wychylony do góry. (będzie to odpowiadać zamianą miejscami przewodów lewej strony dla miejsca Y i prawej strony dla miejsca X). Następnie, jeżeli prawa i lewa strony są zamienione (samochód skręca w złą stronę ), w funkcji powyżej zamieńcie left i right miejscami. def setupPWM(): global pwm pwm = Adafruit_PCA9685.PCA9685() pwm.set_pwm_freq(80) def setupPins(): global GPIO GPIO.setmode(GPIO.BCM) # Broadcom pin-numbering scheme for motor in motors: for pinId in motor: GPIO.setup(pinId, GPIO.OUT) Po prostu ustawiamy odpowiednie piny (te do sterowania mostkiem H) na wyjścia. I tworzymy obiekt do kontrolowania sterowania serw. (Uwaga żeby sterownik serw działał prawidłowo musimy włączyć komunikacje I2C używając raspi-config więcej tutaj ) remoteMe.startRemoteMe(sys.argv) remoteMe.getVariables().observeSmallInteger2("cameraPos" ,onCameraPosChange); remoteMe.getVariables().observeSmallInteger2("drive" ,onDriveChange); remoteMe.wait() Ustawienie RemoteMe i ustawienie jakie funkcję mają zostać wywołane, gdy zmienne do sterowania kamery i napędu zostaną zmienione. To tyle w samym skrypcie pythonowym, jak widzicie, nie jest on zbyt skomplikowany, po więcej informacji zapraszam tutaj Strona WWW Tak naprawdę zostały stworzone dwie strony WWW — jedna do kalibracji druga — strona do sterowania samochodem i wyświetlania obrazu z kamerki. Otwórzmy stronę do kalibracji: Otworzy się strona internetowa z dwoma suwakami. Ustawmy górny i dolny na środkową pozycję – kamera się poruszy- górny suwak powinien poruszać kamerę w osi x, dolny y. Jeżeli się tak nie dzieje – zamieńcie miejscami przewody serwomechanizmu. Następnie za pomocą suwaków ustalcie maksymalne wychylenie osi x i osi y dla mnie jest to: x : 298 – 830 i centralna pozycja. Ważne, żeby centralna pozycja byłą dokładnie pomiędzy przedziałem u mnie ((298+830) /2 = 564) y: 223 – 723 i podobnie centralna pozycja kamery w osi y powinna być w środku przedziału Zapiszmy liczby gdzieś w notatniku i otwórzmy do edycji stronę do sterowania samochodem: <camera autoConnect="true" showInfo="true" class="cameraView"></camera> <connectionstatus webSocket="true" directConnection="false" camera="true"></connectionstatus> <variable component="cameraMouseTrack" type="SMALL_INTEGER_2" style="display:block" name="cameraPos" xMin="298" xMax="830" invertX="true" yMin="223" yMax="723" invertY="true" requiredMouseDown="true" reset="true" onlyDirect="true"></variable> <div class="joystickButtons"> <div class="buttons"> <variable class="gyroscope" component="gyroscope" type="SMALL_INTEGER_2" name="cameraPos" label="Gyroscope Camera" orientationSupport="true" xMin="298" xMax="830" xRange="19" invertX="true" yMin="223" yMax="723" yRange="20" invertY="false" onlyDirect="true"></variable> <variable class="gyroscope" component="gyroscope" type="SMALL_INTEGER_2" name="drive" label="Gyroscope Drive" xMin="-512" xMax="512" xRange="19" invertX="false" yMin="-512" yMax="512" yRange="20" invertY="false" onlyDirect="true"></variable> <button class="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect gyroscope" onClick="toggleFullScreen()">fullscreen </button> </div> <div class="joystickParent"> <variable class="joystick" component="joystick_simple" type="SMALL_INTEGER_2" name="drive" xRange="1024" yRange="1024" onlyDirect="true"></variable> </div> <div style="clear: both;"/> </div> Są to automatyczne komponenty do sterowania samochodem i wyświetlaniem obrazu wideo. Strona, którą otworzyliście zawiera już wszystkie komponenty potrzebne do sterowania waszym samochodem. Jedyne co trzeba zrobić to zmienić zakres ruchów serwo mechanizmów. xMin,xMax,yMin,yMax, zamieńcie na wartości jakie otrzymaliście na poprzedniej stronie z suwakami. Jeżeli chcecie stworzyć własną stronę ze swoimi komponentami najlepiej utworzyć ją od początku pokazane tutaj – pozwoli Wam to dodawać komponenty w przy pomocy kreatora, gdzie ustalicie potrzebne parametry, albo po prostu edytować źródła tej już utworzonej strony – wcześniej warto utworzyć kopię, gdyby coś poszło nie tak (albo skasować pliki i utworzyć projekt jeszcze raz – wtedy nie zapomnijcie wcześniej wykasować też zmienne) Po zmianie wartości x/y/Min/Max możemy otworzyć naszą stronę np w smartfonie, klikamy na index.html, ale tym razem wybieramy opcje get anymous link Następnie, klikamy ikonkę kodu QR, a kod, który się pojawi skanujemy smarfonem. Oczywiście sterowanie działa również poprzez internet – nie tylko w sieci lokalnej, jednak w niektórych przypadkach jest potrzebna dodatkowa konfiguracja więcej o niej tutaj Trochę szczegółów technicznych ( nie obowiązkowe ) RemoteMe serwuję stronę WWW do sterowania Waszym samochodem ( a dodatkowo Was loguje na Wasze konto – stąd token w linku otwieranym przez smartfon ) i uczestniczy w negocjowaniu tworzenia połączenia WebRTC. Połączenie webRTC jest to połączenie bezpośrednie (RaspberryPi – przeglądarka ( w niektórych przypadkach np za NATem jest potrzebny dodatkowo stun sewer)). Po stworzeniu połączenia webRTC stan zmiennych nie jest w ogóle wysyłany do remoteMe (bo pole “onlyDirect” w komponentach jest ustawione na true). Protokołem webRTC przesyłany jest też obraz, a że webRTC tworzy połaczenie point to point opóźnienie jest znikome. Program na RaspberryPi który odpalacie poleceniem ./runme.sh tworzy połączenie websocketowe z platformą RemoteMe oraz zarządza skryptem pythonowym (wysyła do niego wiadomości, przesyła wiadomości ze skryptu dalej do platformy etc ). Działanie skryptu pythonowego jest możliwe dzięki dodatkowym bilbiotekom RemoteMe (znajdują sie w folderze leafDevices/base/ ). Sama strona internetowa po websocketach łączy się do platformy RemoteMe (pozwalają na to skrypty javascriptowe zaimportowane w headerze pliku index.html ze ścieżek /libs/). Ułatwiają i ustanawiają komunikacje z platformą RemoteMe. Same komponenty wstawione w index.html typu : <variable component="**" W funkcjach pliku remoteMeComponents.js są zastępowane na “standardowe” i “bootstrapowe” komponenty htmlowe, dodatkowo do komponentów przypinane są eventy reagujące na akcje użytkownika i wysyłające odpowiednie komunikaty do skryptu pythonowego. Można podejrzeć jak remoteMeComponents.js zamienia i tworzy nowe komponenty – może to być interesujące gdy macie potrzebę stworzenia własnych komponentów, które RemoteMe nie pozwala dodać z kreatora. W większości przypadków akcje Waszych komponentów będą wykonywać zapis zmiennych w postaci RemoteMe.getInstance().getVariables() .setSmallInteger2("cameraPos",123,456,true); która wyśle do skryptu pythonowego informacje o zmianie zmiennej, podobnie sterujemy silnikami ustawiając odpowiednią zmienną. Podsumowanie Tworząc tej projekt chciałem pokazać Wam jak w łatwy sposób sterować Waszym samochodem z widokiem FPV. Projekt można rozbudowywać, lub zmieniać np, gdy korzystanie z innego mostka H niż ja. Zachęcam zatem do eksperymentowania ze źródłami projektu . Gdy jest to Wasz pierwszy projekt, zachęcam do zrobienia na początek projektu z mrugającą diodą i poczytanie dokumentacji na www.remoteme.org Pozdrawiam, Maciej
  4. Trudne początki Tak naprawdę to jest chyba mój pierwszy projekt w świecie Arduino! Zamarzyłem sobie zbudowanie własnego, terenowego pojazdu zdalnie sterowanego - takiego, na którym można potem zamontować jakiś chwytak, ramię albo kamerkę z przekaźnikiem FPV. Kontroler Tu akurat nie miałem większego wyboru, bo wtedy pod ręką miałem akurat Arduino Leonardo. Zaletą tej płytki jest kompatybilność z popularnymi shieldami do Uno a także złącze microUSB typu B (zamiast mało popularnego złącza "drukarkowego" w Uno). Na potrzeby tego niezbyt skomplikowanego projektu moc obliczeniowa tej płytki jest również całkowicie wystarczająca. Podwozie Moim planem było zbudowanie definitywnego i niepokonanego łazika marsjańskiego, więc zwykłe podwozie nie wchodziło w grę - koniecznie musiało być terenowe. Przegrzebałem naprawdę połowę Internetu w poszukiwaniu tego idealnego podwozia (ale - nie ukrywajmy - mieszczącego się również w moim budżecie) i w końcu mój wybór padł na podwozie Dagu DG012-ATV z napędem na cztery koła. Nieco podwyższony prześwit w stosunku do innych podwozi (dający nadzieję na pokonywanie niewielkich przeszkód), napęd na cztery koła - wszystko to brzmiało bardzo zachęcająco. Czterema silnikami coś oczywiście musi obracać, razem z podwoziem nabyłem więc również czterokanałowy sterownik silników DFRobota (w postaci shieldu dla Arduino). Serwo i czujnik Żeby urozmaicić nieco projekt, dodałem do niego serwo modelarskie, na którym zamontowałem ultradźwiękowy czujnik odległości z założeniem, że spróbuję kiedyś napisać program do autonomicznego poruszania się. RC Od długiego czasu używam do zdalnego sterowania aparatury FrSky Taranis, więc oczywiście musiałem skorzystać z kompatybilnego odbiornika - w tym przypadku X8R. Zasilanie Projekt oczywiście musiał być mobilny, więc zdecydowałem się na zasilenie go dwucelowym akumulatorem Lipo; konieczne okazało się też zastosowanie układu BEC, który obniżył napięcie akumulatora do 5V. Teraz pozostało już tylko zmontować wszystko w całość. Montaż podwozia Tu obyło się bez niespodzianek i problemów, po prostu skręciłem wszystko zgodnie z instrukcją i wyprowadziłem na zewnątrz przewody, którymi zasilane miały być silniki. Potem sprawy nieco się skomplikowały. Wszystko rozbiło się generalnie o to, że jak bym nie ułożył elementów na podwoziu, po prostu nie było takiego ułożenia, żeby wszystko się zmieściło. Sprawy utrudniał również fakt zastosowania Leonardo, które - umówmy się - jest raczej kobylaste i znacznie lepiej sprawdziłoby się tu kompatybilne z tą płytką Arduino Micro. Do tego dochodził BEC, odbiornik, serwo (którego nota bene nie miałem jak zamocować, bo w wersji 4WD podwozia miejsce na serwo zajmowane było przez dwa dodatkowe silniki) no i oczywiście akumulator. Dlatego zdecydowałem się na umieszczenie wszystkiego ponad podwoziem, pozostawiając na dole sam akumulator. Przykleiłem więc na dolnym pokładzie rzep, na którym mocowany jest akumulator - przeciążenia podczas poruszania robota są tak znikome, że jest to naprawdę pewny i sprawdzony sposób montażu (pozwalający też szybko zamontować albo zdemontować akumulator w razie potrzeby). Oprócz tego przykręciłem w narożnikach podwozia długie dystanse (kupione kiedyś w Chinach na potrzeby projektu quadrokoptera) i zabrałem się za przygotowywanie górnej części pojazdu. Górne podwozie wykonałem z fragmentu płytki aluminiowej, którą dociąłem tak, by znalazła się dokładnie ponad górną częścią podwozia - i jednocześnie dzięki temu przykryła koła, z których pył mógł się dostawać do elektroniki. W płytce wyciąłem otwór na serwo; ponieważ nie dysponuję żadnym sprzętem CNC, który pomógłby mi wyciąć równy, parametryczny otwór, rad nierad wziąłem do ręki wiertarkę, najpierw nawierciłem otwory, potem zamontowałem w niej frez i zacząłem ręcznie wycinać aluminium, a na końcu doszlifowałem wszystko pilnikami o zmniejszającej się ziarnistości. Cały proces poniżej: Teraz można było powoli przystąpić do montażu. Na pierwszy ogień poszło serwo, które na szczęście wpasowało się w wycięty przeze mnie otwór po prostu idealnie. Następnym krokiem było zamontowanie BECa, którego umieściłem pod górnym pokładem. Przewód zasilający (zakończony złączem T-Dean) musiałem rozgałęzić, ponieważ jedna para przewodów musiała zostać połączona z BECem, który obniży napięcie do 5V dla części elektroniki, zaś druga para - do sterownika silników, który będzie potem je zasilał. Szczęśliwie silniki akceptują napięcie dwucelowego akumulatora LiPo - trzeba to koniecznie sprawdzić przed zakupem/montażem! Arduino Leonardo można zasilić bezpośrednio z akumulatora, natomiast konieczne było przylutowanie odpowiedniej wtyczki (na zdjęciu po prawej stronie). Na koniec pozostało podłączenie wszystkich komponentów i otrzymujemy następujący efekt: Programowanie Pierwszym programikiem, który napisałem, był tester silników, który uruchamiał każdy z nich na pół sekundy. Kod wygląda następująco: const int E1 = 3; // Motor1 Speed const int E2 = 11; // Motor2 Speed const int E3 = 5; // Motor3 Speed const int E4 = 6; // Motor4 Speed const int M1 = 4; // Motor1 Direction const int M2 = 12; // Motor2 Direction const int M3 = 8; // Motor3 Direction const int M4 = 7; // Motor4 Direction void M1_advance(char Speed) { digitalWrite(M1, HIGH); analogWrite(E1, Speed); } void M2_advance(char Speed) { digitalWrite(M2, LOW); analogWrite(E2, Speed); } void M3_advance(char Speed) { digitalWrite(M3, LOW); analogWrite(E3, Speed); } void M4_advance(char Speed) { digitalWrite(M4, HIGH); analogWrite(E4, Speed); } void M1_back(char Speed) { digitalWrite(M1, LOW); analogWrite(E1, Speed); } void M2_back(char Speed) { digitalWrite(M2, HIGH); analogWrite(E2, Speed); } void M3_back(char Speed) { digitalWrite(M3, HIGH); analogWrite(E3, Speed); } void M4_back(char Speed) { digitalWrite(M4, LOW); analogWrite(E4, Speed); } void setup() { for (int i = 3; i < 9; i++) pinMode(i, OUTPUT); for (int i = 11; i < 13; i++) pinMode(i, OUTPUT); pinMode(LED_BUILTIN, OUTPUT); } void loop() { digitalWrite(LED_BUILTIN, HIGH); M1_advance(100); delay(500); M1_advance(0); M2_advance(100); delay(500); M2_advance(0); M3_advance(100); delay(500); M3_advance(0); M4_advance(100); delay(500); M4_advance(0); digitalWrite(LED_BUILTIN, LOW); delay(2000); // Delay 2S } Jak widać, sterowanie silnikami odbywa się poprzez podawanie kierunku poprzez piny cyfrowe i prędkości poprzez piny analogowe - proste, jak konstrukcja cepa. Teraz przyszła kolej na odbiornik RC i tu zaczęły się schody. Odbiorniki klasycznie podają stan każdego kanału poprzez sygnał PWM. W praktyce jest to seria naprzemiennych zer i jedynek, z których każda para 1+0 trwa 1/55 sekundy. Wartość możemy odczytać mierząc czas trwania sygnału 1: jeżeli jest to 1 milisekunda, przyjmujemy wartość minimalną ("-1"), jeżeli 1.5 milisekundy, to wartość środkową ("0"), zaś jeśli 2 milisekundy, to wartość maksymalną ("1"). Niektóre odbiorniki pozwalają na nieco szerszy zakres - od 0.5ms do 2.5ms, X8R domyślnie podaje wartości z tego pierwszego zakresu. Ponieważ musiałem mierzyć wartości na dwóch różnych kanałach, zdecydowałem się skorzystać z mechanizmu przerwań. Działa on mniej więcej następująco: gdy zajdzie wybrane zdarzenie (na przykład zmiana stanu danego pinu z niskiego na wysoki), wykonanie programu jest przerywane, zostaje wykonana funkcja oznaczona jako tzw. handler przerwania, a po jej zakończeniu program wznawia wykonanie w miejscu, w którym został przerwany. Na Arduino można znaleźć bardzo wygodną bibliotekę EnableInterrupt, która uogólnia sposób dodawania i usuwania handlerów przerwań pomiędzy różnymi wersjami Arduino, a korzysta się z niej w następujący sposób: #include "EnableInterrupt.h" volatile int microsStart = 0; void pin0Rising() { microsStart = micros(); disableInterrupt(0); enableInterrupt(0, pin0Falling, FALLING); } void pin0Falling() { int microsEnd = micros(); int diff = microsEnd - microsStart; if (diff > 1500) { digitalWrite(LED_BUILTIN, HIGH); } else { digitalWrite(LED_BUILTIN, LOW); } disableInterrupt(0); enableInterrupt(0, pin0Rising, RISING); } void setup() { enableInterrupt(0, pin0Rising, RISING); pinMode(LED_BUILTIN, OUTPUT); } void loop() { } Po wpięciu przewodu sygnałowego do pinu 0 i uruchomieniu programiku na kontrolerze, wbudowana dioda powinna się zapalić w momencie, gdy ustawimy drążek w położeniu większym niż połowa. Zwrócę jeszcze uwagę na magiczne słówko "volatile" przy deklaracji zmiennej - informuje ono kompilator, że zmienna ta nie może zostać zoptymalizowana (kompilator, a dokładniej optymalizator w niektórych przypadkach może w locie usunąć zmienną, na przykład jeżeli nie jest ona używana lub przez cały czas trwania programu ma zawsze tę samą wartość). Dodam tu jeszcze jedną ważną informację: program obsługi przerwania powinien być tak krótki, jak to tylko możliwe! Ma to sporo sensu jeżeli się nad tym nieco dłużej zastanowić, ale ja na to nie wpadłem i w pierwotnej wersji programu cała obsługa silników umieszczona była właśnie w programie obsługi przerwania. I ku mojemu zdziwieniu, po uruchomieniu programu, pomimo tego, że drążki były w położeniu zerowym, dwa silniki zaczęły się obracać. Okazało się, że obsługa przerwania obliczającego czas trwania PWM na pierwszym kanale trwała tak długo, że sztucznie opóźniała wywołanie drugiego przerwania wykonującego te same obliczenia dla drugiego kanału, przez co podawało ono zawyżone wartości. Wystarczyło przebudować program w taki sposób, by obsługa silników znalazła się poza programami obsługi przerwań i wszystko wróciło do normy. Pamiętajmy - to może oczywiste, ale mimo wszystko warto to powiedzieć - że mikrokontrolery nie są wielowątkowe, a przerwania nie są wątkami: wykonują się tylko jedno na raz. Drugie przerwanie musi czekać, aż pierwsze zostanie do końca obsłużone. Przed napisaniem końcowego programu pozostało mi już tylko przetestować obsługę czujnika ruchu, programik wygląda następująco: #include <NewPing.h> #define ULTRASONIC_TRIGGER_PIN 9 #define ULTRASONIC_ECHO_PIN 10 #define MAX_DISTANCE 400 NewPing sonar(ULTRASONIC_TRIGGER_PIN, ULTRASONIC_ECHO_PIN, MAX_DISTANCE); void setup() { pinMode(LED_BUILTIN, OUTPUT); } void loop() { digitalWrite(LED_BUILTIN, HIGH); delay(50); digitalWrite(LED_BUILTIN, LOW); delay(50); int ping = sonar.ping_cm(); if (ping < 30) digitalWrite(LED_BUILTIN, HIGH); else digitalWrite(LED_BUILTIN, LOW); delay(200); } Również i tu korzystam z wbudowanej diody, która powinna zapalić się, gdy zmierzona przez czujnik odległość będzie mniejsza niż 30 cm. Wreszcie program obsługujący całego robota: #include <NewPing.h> #include "EnableInterrupt.h" #include "NewPing.h" // Motor constants // Motor1 Speed #define MOTOR_1_SPEED_PIN 3 // Motor2 Speed #define MOTOR_2_SPEED_PIN 11 // Motor3 Speed #define MOTOR_3_SPEED_PIN 5 // Motor4 Speed #define MOTOR_4_SPEED_PIN 6 // Motor1 Direction #define MOTOR_1_DIR_PIN 4 // Motor2 Direction #define MOTOR_2_DIR_PIN 12 // Motor3 Direction #define MOTOR_3_DIR_PIN 8 // Motor4 Direction #define MOTOR_4_DIR_PIN 7 // Ultrasonic constants #define ULTRASONIC_TRIGGER_PIN 9 #define ULTRASONIC_ECHO_PIN 10 #define MAX_DISTANCE 400 // Servo constants #define SERVO_PIN 13 // AI constants #define DISTANCE_THRESHOLD_2 80 #define DISTANCE_THRESHOLD_1 40 // Ultrasonic control NewPing sonar(ULTRASONIC_TRIGGER_PIN, ULTRASONIC_ECHO_PIN, MAX_DISTANCE); // Motor control functions void M1_advance(byte Speed) ///<Motor1 Advance { digitalWrite(MOTOR_1_DIR_PIN, HIGH); analogWrite(MOTOR_1_SPEED_PIN, Speed); } void M2_advance(byte Speed) ///<Motor2 Advance { digitalWrite(MOTOR_2_DIR_PIN, LOW); analogWrite(MOTOR_2_SPEED_PIN, Speed); } void M3_advance(byte Speed) ///<Motor3 Advance { digitalWrite(MOTOR_3_DIR_PIN, LOW); analogWrite(MOTOR_3_SPEED_PIN, Speed); } void M4_advance(byte Speed) ///<Motor4 Advance { digitalWrite(MOTOR_4_DIR_PIN, HIGH); analogWrite(MOTOR_4_SPEED_PIN, Speed); } void M1_back(byte Speed) ///<Motor1 Back off { digitalWrite(MOTOR_1_DIR_PIN, LOW); analogWrite(MOTOR_1_SPEED_PIN, Speed); } void M2_back(byte Speed) ///<Motor2 Back off { digitalWrite(MOTOR_2_DIR_PIN, HIGH); analogWrite(MOTOR_2_SPEED_PIN, Speed); } void M3_back(byte Speed) ///<Motor3 Back off { digitalWrite(MOTOR_3_DIR_PIN, HIGH); analogWrite(MOTOR_3_SPEED_PIN, Speed); } void M4_back(byte Speed) ///<Motor4 Back off { digitalWrite(MOTOR_4_DIR_PIN, LOW); analogWrite(MOTOR_4_SPEED_PIN, Speed); } // PWM control volatile int microsYStart = 0; volatile int microsXStart = 0; volatile int microsZStart = 0; volatile int yMicros = 0; volatile int xMicros = 0; volatile int zMicros = 0; int UScounter = 0; int USlock = 0; // Pin 0 interrupt handling void pin0Rising() { microsYStart = micros(); disableInterrupt(0); enableInterrupt(0, pin0Falling, FALLING); } void pin0Falling() { yMicros = micros() - microsYStart; disableInterrupt(0); enableInterrupt(0, pin0Rising, RISING); } // Pin 1 interrupt handling void pin1Rising() { microsXStart = micros(); disableInterrupt(1); enableInterrupt(1, pin1Falling, FALLING); } void pin1Falling() { xMicros = micros() - microsXStart; disableInterrupt(1); enableInterrupt(1, pin1Rising, RISING); } // Pin2 interrupt handling void pin2Rising() { microsZStart = micros(); disableInterrupt(2); enableInterrupt(2, pin2Falling, FALLING); } void pin2Falling() { zMicros = micros() - microsZStart; disableInterrupt(2); enableInterrupt(2, pin2Rising, RISING); } void setup() { for (int i = 3; i < 9; i++) pinMode(i, OUTPUT); for (int i = 11; i < 13; i++) pinMode(i, OUTPUT); pinMode(ULTRASONIC_TRIGGER_PIN, OUTPUT); pinMode(ULTRASONIC_ECHO_PIN, INPUT); pinMode(SERVO_PIN, OUTPUT); enableInterrupt(0, pin0Rising, RISING); enableInterrupt(1, pin1Rising, RISING); enableInterrupt(2, pin2Rising, RISING); } void loop() { // Eval motor signals int yValue = (yMicros - 1500) / 2; int xValue = (xMicros - 1500) / 2; if (yValue > 260 || yValue < -260) yValue = 0; if (xValue > 260 || xValue < -260) xValue = 0; int leftEngines = constrain(xValue + yValue, -250, 250); int rightEngines = constrain(yValue - xValue, -250, 250); // Check for obstacles every 10th iteration UScounter++; if (UScounter >= 10) { UScounter = 0; int frontDistance = sonar.convert_cm(sonar.ping_median(5)); if (frontDistance != 0 && frontDistance < DISTANCE_THRESHOLD_2) { if (frontDistance > DISTANCE_THRESHOLD_1) USlock = 1; else USlock = 2; } else USlock = 0; } if (USlock == 1) { leftEngines = constrain(leftEngines, -250, 128); rightEngines = constrain(rightEngines, -250, 128); } if (USlock == 2) { leftEngines = constrain(leftEngines, -250, 0); rightEngines = constrain(rightEngines, -250, 0); } if (abs(leftEngines) < 20) { M3_advance(0); M4_advance(0); } else if (leftEngines > 0) { M3_advance(leftEngines); M4_advance(leftEngines); } else { M3_back(-leftEngines); M4_back(-leftEngines); } if (abs(rightEngines) < 20) { M1_advance(0); M2_advance(0); } else if (rightEngines > 0) { M1_advance(rightEngines); M2_advance(rightEngines); } else { M1_back(-rightEngines); M2_back(-rightEngines); } } Pozwala on na kontrolowanie robota przy pomocy jednego drążka aparatury (dwóch kanałów). Oprócz tego program cyklicznie sprawdza odległość przed robotem i zabezpiecza przed wjechaniem w ścianę: w przypadku przeszkody znajdującej się bliżej niż 80 cm od robota, zostanie ograniczona jego maksymalna prędkość, natomiast jeżeli odległość ta będzie mniejsza niż 40cm, robot zatrzyma się całkowicie i niemożliwe będzie ruszenie nim do przodu. Wnioski To była prawdziwa frajda zobaczyć, jak robot rusza i jeździ zgodnie z instrukcjami z aparatury! Pierwszy skończony projekt. Nauczyłem się na nim dużo, bo okazało się, że w trakcie pracy podjąłem bardzo dużo nietrafnych decyzji. Robot tak naprawdę nigdy nie wyjechał z domu, ma bardzo otwartą konstrukcję, która sprzyja dostawaniu się do obudowy pyłu i piachu. W domowych warunkach wystarczyłby natomiast napęd na dwa koła - w ten sposób miałbym też trochę miejsca wewnątrz obudowy. Arduino Leonardo jest świetne, ale wielkie. Znacznie lepiej sprawdziłoby się Arduino Micro albo Teensy. To drugie nawet bardziej, bo shield do sterowania silnikami pożera dużo pinów i niewiele zostaje na odbiór sygnału z odbiornika RC. Udało mi się jeszcze podłączyć czujnik odległości, ale serwo wpiąłem już bezpośrednio w odbiornik, bo po prostu zabrakło mi pinów. Nie ma większego sensu robić żadnych projektów (innych niż wstępne prototypy) na przewodzikach połączeniowych. Lepiej kupić sobie płytkę prototypową, złącza goldpinowe, przewodziki kydexowe i polutować wszystko na płytce - układ zajmuje znacznie mniej miejsce i jest znacznie mniej podatny np. na przypadkowe wyjęcie przewodu. Chodzi mi po głowie wskrzeszenie projektu - właśnie przy pomocy Teensy oraz drukarki 3D, przy pomocy której mogę wydrukować całe nadwozie szyte na miarę. Ale podejrzewam, że zajmę się tym dopiero za jakiś czas...
  5. Cześć! Skończyłem budowę mojego pierwszego robota. Jest to też mój pierwszy większy projekt, więc proszę o wyrozumiałość, komentarze, porady mile widziane. Z racji tego, że posiadam jeszcze dwa komplety lego, postanowiłem je wykorzystać do budowy pojazdu. Początkowo miały być silniki lego, ale stwierdziłem, że lepiej będzie zrobić to na zwykłych, uniwersalnych częściach. Konstrukcja miała być mała, zwinna, sterowana przez WIFI. Przednia oś, jak widać, sterowana za pomocą micro serwa. Nie było większych oporów, serwo bez problemów sobie radziło ze sterowaniem. Zacząłem szukać jakiegoś ciekawego i małego silnika DC. Postanowiłem wybrać silnik z podwójnym wałem. Kolejnym zadaniem było przebudowanie konstrukcji tak, żeby silnik się zmieścił i nie wadził w poruszaniu się robota. Z racji tego, że wolałem zaoszczędzić kilkanaście złotych na przejściówkę lego-wał, rozwierciłem otwory w częściach które miałem. Zacząłem myśleć jak wyglądałoby połączenie iPhone - ESP, ale w międzyczasie na uczelni dziekan zapowiedział nam dodatkowy projekt na zajęciach z mikrokontrolerów ( pierwsze takie zajęcia na drugim roku studiów ) - dowolny robot na platformie Arduino lub STM. Chłopaki na Facebookowej grupie Arduino uświadomili mi, że nie ma sensu robić projektu na ESP, bo musiałbym się łączyć tylko przez sieć i lepszym wyborem byłby bluetooth. Tak też się stało, zakupiłem moduł HM-10, który współpracuje z używanym przeze mnie iOS. Do tego całość przeniosłem na klona płytki Arduino. Jako aplikacji sterującej użyłem ArduinoBlue, wraz z biblioteką. Inne aplikacje nie chciały działać. W dodatku albo na iOS nie ma żadnych popularnych aplikacji do sterowania przez BLE albo nie udało mi się znaleźć. Możecie polecić ciekawe aplikacje na iOS, na pewno sprawdzę! Można zauważyć, że na breadbordzie zainstalowałem jakąś płytkę. Jest to sterownik silników DC, polecany, łatwy w użyciu. Dobra, silnik jest, działa, serwo jest, łączność przez BLE również. Wypadało by odpiąć wszystko od zasilania z gniazdka i zastosować akumulatory, baterie. Z początku była to dla mnie czarna magia, większe napięcie, jakieś ampery, przetwornice. Czytałem różne artykuły, oglądałem poradniki, pytałem na Facebookowej grupie. Ostatecznie, zgodnie z zasadami: Arduino + sekcja logiczna zasilana z powerbanka + wyprowadzenie zasilania bezpośrednio do serwa, silnik DC zasilany przez dwa ogniwa litowo-jonowe połączone szeregowo z BMS, napięcie zmniejszane przez przetwornicę Żeby szybko podpinać ogniwa do robota albo ładować, przylutowałem wtyki/gniazda DC 5.5mm. BTW. Bardzo długo męczyłem się z lutowaniem ogniw na 30-watowej lutownicy kolbowej. Metodą prób i błędów wszystko się złączyło. Przed podłączeniem każdego elementu lutowanego, sprawdzałem miernikiem czy nie ma zwarcia! Dodatkowo pokusiłem się o popularny czujnik odległości oraz mała prowizorka - dwie diody z opornikami schowane w obudowie po serwie (spaliło się), informujące o przeszkodzie w danej odległości. Wersja finalna, kilkukrotnie większa i cięższa niż pierwotna wersja. Wzmocniony układ kierowniczy. Jeździ, skręca, hamuje, cofa. Trzymany pod kocem Wszelkie komentarze mile widziane! A tutaj krótki filmik (musiałem zdemontować czujnik odległości, ponieważ powodował zakłócenia całego układu: Tak wygląda sterowanie za pomocą joysticka:
  6. bigthomas

    Odkurzacz na Bluetooth

    Witam, jest to mój pierwszy projekt, na którym uczyłem się nieco programowania ... a że w piwnicy leżał mi popsuty odkurzacz to postanowiłem go ożywić po swojemu. Odkurzacz który notabene dostałem jako gratis działał dosłownie 10 minut po czym nie dawał oznak życia. 1.Podwozie jest wykorzystane w 100% z oryginału, nie zmieniałem nic oprócz zrobienia miejsca na elektronikę. 2. Z oryginału wykorzystałem również zasilanie (czyli ogniwa Li-lon) wraz z ładowarką. Zasilanie było oryginalne 7.2 V 3. Elektronika - wykorzystałem Arduino UNO wraz z shield sterownika L293D do 4x silników DC lub 2x krokowych w sumie wykorzystałem taki bo taki miałem, trochę nad wyrost bo zostają nie wykorzystane (a może jeszcze nie wykorzystane) dwa wejścia pod silniki DC. Jako że zaczynałem od podstaw programowanie, przysporzyło mi to trochę problemów. Ale od czego jest forum Na początku udało mi się zrobić aby pojazd sam się poruszał i odbijając od przeszkód (za pomocą dwóch umieszczonych wyłączników krańcowych umieszczonych z przodu odkurzacza) zmieniał kierunek jazdy, nie działało to w 100% tak jak sobie to na początku założyłem, ze względu na ogromny brak wiedzy w programowaniu, ale jednak pierwsze efekty pracy zainspirowały mnie do dalszej pracy nad robotem. #include <AFMotor.h> AF_DCMotor motorP(1); // silnik prawy AF_DCMotor motorL(2); // silnik lewy #define zdL 9 #define zdP 10 void setup() { motorP.setSpeed(255); motorL.setSpeed(255); pinMode(zdP, INPUT_PULLUP); pinMode(zdL, INPUT_PULLUP); } void loop() { bool zderzakL = digitalRead(zdL) == HIGH; bool zderzakP = digitalRead(zdP) == HIGH; // jazda do tyłu if (zderzakL == LOW && zderzakP == LOW) { motorP.run(BACKWARD); motorL.run(BACKWARD); } // // skręt w prawo else if (zderzakL == LOW) { motorP.run(BACKWARD); motorL.run(FORWARD); } // skręt w lewo else if (zderzakP == LOW) { // delay(200); motorP.run(FORWARD); motorL.run(BACKWARD); } // jazda do przodu else { motorP.run(FORWARD); motorL.run(FORWARD); } } Z shelda wykorzystałem piny 9 oraz 10 do serwa jako sterowanie do krańcówek. Kolejną rzecz jaką chciałem zrobić i pobawić się było stworzenie możliwości sterowania odkurzaczem za pomocą bluetooth oraz telefonu z androidem. A więc jak tylko paczuszka ze sklepu pojawiła się w moim domu wraz z modułem bluetooth (2.1 XM-15B 3,3V/5V) postanowiłem działać dalej. Pierwszy problem to połączenie modułu bluetooth z płytką, musiałem dolutować w odpowiednie miejsca przewody aby móc komunikować się z arduino (Rx, Tx) jak również doprowadzenie zasilania. Jednak nie stanowiło to większego wyzwania, udało się za pierwszym razem. Następnie przyszedł czas na połączenie bluetooth z telefonem. Udało mi się to zrealizować również w dość szybkim czasie (wcześniej oczywiście przeglądałem różnego rodzaju poradniki, czy posty kolegów z forum). Przyszedł czas na aplikację do telefonu, jako że gotowe rozwiązania nie podobały się (a może bardziej ambicja wzięła górę) postanowiłem stworzyć coś własnego. Z pomocą przyszła stronka http://ai2.appinventor.mit.edu. Gdzie w sposób prawie że obrazkowy udało mi się zrobił własny interfejs z własna logiką. Przyszedł czas na oprogramowanie w Arduino wszystkich funkcji które chciałem uzyskać tj: możliwość ręcznego sterowania przełączania na tryb automatyczny sterowania prędkością silniczków Udało mi się to za pomocą kodu: #include <AFMotor.h> AF_DCMotor motorP(1); // silnik prawy AF_DCMotor motorL(2); // silnik lewy #define zdL 9 #define zdP 10 String data; void setup() { Serial.begin(9600); Serial.println("Test portu"); pinMode(zdP, INPUT_PULLUP); pinMode(zdL, INPUT_PULLUP); bool zderzakL = digitalRead(zdL) == HIGH; bool zderzakP = digitalRead(zdP) == HIGH; } uint8_t oP = 255; uint8_t oL = 255; int pierwszyStart = 1; void loop() { if (Serial.available() > 0) { delay(1); char znak = Serial.read(); data += znak; pierwszyStart = 2; ///////////// Prędkość silników ///////////// if (data == "X") { oP = oP + 1; } if (data == "x") { oP = oP - 1; } if (data == "Y") { oL = oL + 1; } if (data == "y") { oL = oL - 1; } ///////////// Prędkość silników ///////////// Serial.print("Prędkość silnika prawego: "); Serial.println(oL); Serial.print("Prędkość silnika lewego: "); Serial.println(oP); if (data == "G") { motorP.setSpeed(oP); motorL.setSpeed(oL); motorP.run(FORWARD); motorL.run(FORWARD); } if (data == "B") { motorP.setSpeed(oP); motorL.setSpeed(oL); motorP.run(BACKWARD); motorL.run(BACKWARD); } if (data == "L") { motorP.setSpeed(oP); motorL.setSpeed(oL); motorP.run(BACKWARD); motorL.run(FORWARD); } if (data == "R") { motorP.setSpeed(oP); motorL.setSpeed(oL); motorP.run(FORWARD); motorL.run(BACKWARD); } if (data == "S") { motorP.setSpeed(0); motorL.setSpeed(0); } if (data == "A") { bool zderzakL = digitalRead(zdL) == HIGH; bool zderzakP = digitalRead(zdP) == HIGH; motorP.setSpeed(oP); motorL.setSpeed(oL); // jeżeli oba zderzaki if (zderzakL == LOW && zderzakP == LOW) { motorP.run(BACKWARD); motorL.run(BACKWARD); delay(250); motorP.run(FORWARD); motorL.run(BACKWARD); delay(1150); } // skręt w prawo else if (zderzakL == LOW) { motorP.run(BACKWARD); motorL.run(BACKWARD); delay(100); motorP.run(FORWARD); motorL.run(BACKWARD); delay(100); } // skręt w lewo else if (zderzakP == LOW) { motorP.run(BACKWARD); motorL.run(BACKWARD); delay(100); motorP.run(BACKWARD); motorL.run(FORWARD); delay(100); } // jazda do przodu else { motorP.run(FORWARD); motorL.run(FORWARD); } } data = ""; } else { if (pierwszyStart == 1) { bool zderzakL = digitalRead(zdL) == HIGH; bool zderzakP = digitalRead(zdP) == HIGH; motorP.setSpeed(oP); motorL.setSpeed(oL); // jeżeli oba zderzaki if (zderzakL == LOW && zderzakP == LOW) { motorP.run(BACKWARD); motorL.run(BACKWARD); delay(250); motorP.run(FORWARD); motorL.run(BACKWARD); delay(1150); } // skręt w prawo else if (zderzakL == LOW) { motorP.run(BACKWARD); motorL.run(BACKWARD); delay(100); motorP.run(FORWARD); motorL.run(BACKWARD); delay(100); } // skręt w lewo else if (zderzakP == LOW) { motorP.run(BACKWARD); motorL.run(BACKWARD); delay(100); motorP.run(BACKWARD); motorL.run(FORWARD); delay(100); } // jazda do przodu else { motorP.run(FORWARD); motorL.run(FORWARD); } } } delay(50); } Na pewno nie jest on w 100% zgodny ze sztuką, ale nic dziwnego bo programowania się nie uczyłem. Jest to zlepek funkcji odnalezionych w internecie i przystosowanych do moich potrzeb. Szczerze chciałbym zobaczyć prawidłowy wygląd kodu Na tym chyba zakończę podsumowując że obiekt spełnił moje oczekiwania, a to jest chyba najważniejsze: mogę sterować robotem/odkurzaczem z telefonu przy włączeniu uruchamia się tryb automatyczny bez potrzeby uruchamiania aplikacji w telefonie możliwość włączania/wyłączania na tryb automatyczny z telefonu sterowanie robotem w trybie automatycznym (w przypadku chęci korekty kierunku jazdy) i poza nim odbijanie od przedmiotów Filmik prezentujący funkcjonalność automatycznej jazdy.
  7. Witam, jako, iż jest to pierwszy opis mojego projektu na forum krótko się przedstawię. Mam na imię Marek, niedługo skończę 15 lat a elektroniką interesuję się od około roku. Chciałbym wam dzisiaj przedstawić mojego właściwie drugiego robota, wcześniej był światłolub, ale stwierdziłem, że chciałbym coś czym mógłbym wygodnie sterować używając np telefonu.Nazwa robota oznacza "Bluetooth Pojazd Jeżdżący 1". Na początku użyłem zamówionego z chin Wemos D1 Mini, który potem zmieniłem na połączenie klona Arduino Uno + HC-05 gdyż uznałem to jako lepszą opcję, oraz w moje ręce wpadł ten właśnie moduł bluetooth, następnie po ukazaniu projektu w szkole, zamieniłem Arduino Uno na Arduino Nano, również klona, głównie z powodu rozmiarów. Początkowo zasilanie było zrobione z 4 paluszków AA, co było złym pomysłem, silniki słabo działały, jeżeli w ogóle, chyba, że baterie były nowe. Baterie zostały zamienione na 2 Ogniwa Li-Ion od Panasonica NCR18650B o pojemności 3400mAh od sztuki które są połączone równolegle.Dwoma silnikami steruje sterownik L293D, wszystko znajduje się na podwoziu 2WD RT-5.Umieściłem dodatkowo diodę led RGB, z poziomu aplikacji można wybierać jej kolor, a dodatkowo, jej kolor jest zależny on tego w jakim kierunku porusza się robot. Komunikacja z modułem Bluetooth odbywa się przez aplikacje na telefon. To tak w skrócie, poniżej opiszę poszczególne "sekcje" robota. 1.Zasilanie: Zasilanie, tak jak wyżej napisałem są to 2 Akumulatorki Li-Ion, połączyłem je równolegle, ponieważ chce oba ładować jedną ładowarką, bez potrzeby ich wyjmowania z koszyczka (balancera nie posiadam) . Dlatego iż ogniwa nie mają żadnych zabezpieczeń, ładowarka jest wymagana ponieważ posiada wbudowane już zabezpieczenia. Ogniwa podłączone są do ładowarki TP4056, na wyjściu z niej jest zamontowany Dip Switch, jeden przełącznik do + zasilania, drugi do -. Następnie jest przetwornica step-up MT3608, która podwyższa mi napięcie z 3.6V, na 5V. Następnie poprzez kolejny przełącznik zasilanie idzie do płytki stykowej skąd jest rozprowadzane do wszystkich urządzeń (Silniki, sterownik, arduino, moduł Bluetooth). Praktycznie cały układ zasilania jest polutowany, na uniwersalnej płytce do lutowania 5cm na 7cm. 2.Komunikacja przez Bluetooth: Komunikacja z robotem jest wykonywana poprzez dosyć popularny Bluetooth, Aplikacja na telefon została wykonana przeze mnie, wykorzystując ten poradnik. Wykonałem ją w Mit App Inventor 2. Sama aplikacja wygląda tak: Na samej górze widzimy przycisk by połączyć się z HC-05, niżej widać przyciski do sterowania diodą RGB, a na samym dole są przyciski do sterowania silnikami. 3.Połączenia poszczególnych modułów, silniki, i koła Większość połączeń wykonałem prostymi przewodami jak te albo te, co się dało zamieniłem na ręcznie robione przeze mnie zworki wykonane z skrętki telefonicznej, a reszta jest polutowana. Sterownik silników znajduje się w podstawce na przeciętej na pół płytce do lutowania, ponieważ jest za długa a ja potrzebowałem tylko kawałka na ten sterownik (same zasilanie przez ogniwa było dodane dużo później więc dlatego 2 płytki) Silniki to dosyć tanie, w pakiecie z podwoziem TT D65, zasilane mogą być do 6V, oraz zawierają już wbudowaną przekładnie 1:48. Koła były w pakiecie z silnikami, wiele o nich nie mogę powiedzieć. Oprócz 2 kół na silnikach mam jedno małe z tyłu, dosyć popularne w światłolubach 4.Program w Arduino Program został również przeze mnie, myślę, iż jest raczej na podstawowym poziomie i nie ma czym się chwalić, na początku odczytuje informację otrzymane z modułu Bluetooth, z którym jest połączony przez TX i RX. Zależnie od otrzymanej liczby wykonywany jest konkretny warunek. char t; void setup() { pinMode(9,OUTPUT); //Lewy silnik przód pinMode(10,OUTPUT); //Lewy silnik tył pinMode(11,OUTPUT); //Prawy silnik przód pinMode(12,OUTPUT); //Prawy silnik tył pinMode(5,OUTPUT); //RGB Czerwony pinMode(6,OUTPUT); //RGB Zielony pinMode(7,OUTPUT); //RGB Niebieski Serial.begin(9600); } void loop() { if(Serial.available()){ t = Serial.read(); Serial.println(t); } if(t == '5') { //Do przodu digitalWrite(9,HIGH); digitalWrite(10,LOW); digitalWrite(11,HIGH); digitalWrite(12,LOW); digitalWrite(6,HIGH); //Zielony ON digitalWrite(5,LOW); //Czerwony OFF digitalWrite(7,LOW); //Niebieski OFF } else if(t == '6') { //Do tyłu digitalWrite(9,LOW); digitalWrite(10,HIGH); digitalWrite(11,LOW); digitalWrite(12,HIGH); digitalWrite(5,HIGH); //Czerwony ON digitalWrite(6,LOW); //Zielony OFF digitalWrite(7,LOW); //Niebieski OFF } else if(t == '7') { //W prawo digitalWrite(9,LOW); digitalWrite(10,LOW); digitalWrite(11,HIGH); digitalWrite(12,LOW); digitalWrite(7,HIGH); //Niebieski ON digitalWrite(5,LOW); //Czerwony OFF digitalWrite(6,LOW); //Zielony OFF } else if(t == '8') { //W lewo digitalWrite(9,HIGH); digitalWrite(10,LOW); digitalWrite(11,LOW); digitalWrite(12,LOW); digitalWrite(7,HIGH); //Niebieski ON digitalWrite(5,LOW); //Czerwony OFF digitalWrite(6,LOW); //Zielony OFF } else if(t == '9') { //STOP digitalWrite(9,LOW); digitalWrite(10,LOW); digitalWrite(11,LOW); digitalWrite(12,LOW); digitalWrite(5,HIGH); //Czerwony ON digitalWrite(6,LOW); //Zielony OFF digitalWrite(7,LOW); //Niebieski OFF } else if(t == '1') digitalWrite(5,HIGH); //Czerwony ON else if(t == '2') digitalWrite(6,HIGH); //Zielony ON else if(t == '3') digitalWrite(7,HIGH); //Niebieski ON else if(t == '4') { //RGB OFF digitalWrite(5,LOW); digitalWrite(6,LOW); digitalWrite(7,LOW); } delay(100); } 5.Prezentacja działania Testy wykonałem na profesjonalnej wykładzinie, na panelach jeździ wolniej, bo trochę się ślizga ale problemów większych nie ma, poniżej jest widoczny filmik: Proszę o rady co można zmienić od bardziej doświadczonych kolegów, oraz mam nadzieję, iż ten opis się komuś przyda.
  8. Witam chciałem opisać wam mój szybki i drobny projekt. Spektral - tak został nazwany mały robot do wyścigów na kategorię deathrace. 100x100x80mm oraz 300gr to ograniczenia które narzucił w tej kategorii organizator Robomaticonu 2019. Robot był składany dosłownie dzień przed wyścigami od 10 rano do 2 w nocy następnego dnia. Najmniejsza pomyłka albo uszkodzona część niestety uniemożliwiłaby mi start. Na szczęście części z botlandu i od chińczyka nie zawiodły^^ Robot był napędzany silnikiem 3000rpm z kołem o średnicy 37mm potrafił się naprawdę nieźle rozpędzić ale to było zdecydowanie za dużo. Miał napęd na jedno koło dla uproszczenia konstrukcji, zmniejszenia wagi oraz dla polepszenia zwrotności. Tylne koła mają dość sporą szerokość oraz dużą przyczepność obawiałem się że jak zamontuje je na jednej sztywnej osi auto będzie zbyt podsterowne. Co ciekawe Spektral był jednym startującym pojazdem z układem skrętnym. Niżej zostawiam spis części: Rama oraz felgi zostały wydrukowane na drukarce 3D materiałem PLA Łożyska użyte w 3 kołach Silnik pololu 3000rpm - polecam jednak zamiast niego zastosować 1000rpm Sterownik do silnika szczotkowego 20A (jest idealny, nie grzeje się i nie spalił silnika tylko lekko go podgrzał ) 4 kanałowy odbiornik Kosztuje około 25zł ma naprawdę ładny zasięg i waży tylko 2gr! Serwo 9gr tutaj nie ma co wiele pisać zwykłe serwo sterowane PWM, 180st. Step down obniża napięcia z lipo 2s na 6v To chyba tyle, do tego potrzebujecie garść śrubek M3 oraz jedną M2 do zamocowania cięgna serwa z mechanizmem skrętu. Jakby komuś się bardzo nudziło to radzę dać silnik 1000rpm, w zupełności wystarczy i kamerę FPV - świetna zabawa xD Jeżeli interesuje Cie moja działalność w internecie zapraszam na mojego facebooka wydrukuje oraz koło naukowe politechniki opolskiej SPEKTRUM
  9. Witam, przedstawiam mój pierwszy projekt DIY opisany na Forbocie. Robota nazwałem Maxi-Brzydal, ponieważ podwozie i nadwozie na którym wykonałem robota jest wizualnie zniszczone i nie wygląda ciekawie. Robot może być sterowany za pomocą Bluetooth i posiada funkcję omijania przeszkód, którą można włączyć i wyłączyć z poziomu aplikacji. Robot posiada sterowanie "jak czołg", regulację prędkości, sterowanie chwytakiem (trzema serwami), włącznik lamp i włącznik trybu omijania przeszkód. Panel sterowania zrobiłem w aplikacji Bluetooth Electronic od keuwl. Sama aplikacja nie potrzebuję żadnych dodatkowych bibliotek i wszystko odbywa się za pomocą komend monitora szeregowego, czyli Serial.read itd. MECHANIKA i ZASILANIE: Robot został zbudowany za starym podwoziu od jakiegoś pojazdu RC(Podwozie znalazłem w piwnicy bez baterii silników i z uszkodzoną elektroniką). Podwozie jest bardzo fajne, ponieważ posiada pompowane, gumowe opony, które świetnie sprawują się na powierzchniach wszystkich typów. Całość napędzają dwa silniki 12V, które są w stanie uciągnąć około 2-kilogramową konstrukcję. W przedniej części znajduję się chwytak sterowany za pomocą 3 serw TowerPro MG-995 wykonany z aluminium. Co do zasilania zwykłe "laptopówki" nie dawały wystarczająco mocy więc wybór padł na akumulator żelowy 12V 1.3Ah pozwalający wykorzystać potencjał silników w 100%. Taki akumulator kosztował mnie jakieś 20zł. ELEKTRONIKA: Mózgiem całego robota jest klon bardzo popularnego Arduino NANO z procesorem Atmega328 na pokładzie, który w zupełności wystarcza do tego typu robota. Kod zabiera jakieś 45% pamięci. Do komunikacji z telefonem lub komputerem wykorzystałem moduł BT o nazwie XM-15 . Moduł ten ma większy zasięg od popularnych HC-05 i HC-06, a jest tak samo łatwy w obsłudze. do sterowania silnikami posłużyłem się dwoma sterownikami VNH2SP30 osadzonymi na shildzie do Arduino UNO. Użyłem tych sterowników ponieważ silniki potrzebują aż 5A, a ten sterownik może dać 30A. Płytkę PCB wytrawiłem sam w domu rysując odpowiednie ścieżki i wyszła całkiem dobrze. Na płytce oprócz arduino, sterownika silników i modułu BT znajduję się kilka dodatkowych złączy zasilania, wyjścia do podłączenia serw oraz dość duży kondensator (chodzi o to, że przy maksymalnej mocy silników przy ruszaniu bez niego potrafiło zrestartować arduino i rozłączyć moduł BT, teraz jest Soft Start, ale kondensator został). Na czerwonym nadwoziu zamontowane są trzy czujniki ultradźwiękowe HC-SR04 do wykrywania przeszkód, dwie lampy LED 12V i mały woltomierz do sprawdzania naładowania akumulatora. Jest to mój pierwszy wpis na forum więc proszę o wyrozumiałość dla młodego, dopiero uczącego się, pasjonata robotyki i programowania. Liczę na konstruktywną krytykę od tych bardziej doświadczonych i wskazówki co mogę zrobić lepiej. Na wszystkie pytania postaram się odpowiedzieć. Pozdrawiam wszystkich czytelników, Technowsky!
  10. Witam, Chciałbym przedstawić zbudowany ostatnio pojazd inspekcyjny. Założenia były następujące: dobra mobilność w nierównym terenie, sterowanie za pomocą aplikacji na Android'a oraz podgląd z wbudowanej kamery w czasie rzeczywistym. Mechanika W pojeździe zastosowano uproszczoną, 4-kołową wersję zawieszenia rocker-bogie stosowaną m.in. w łazikach marsjańskich. Główną zaletą tego rozwiązania jest niemal równomierny nacisk wszystkich kół na podłoże oraz możliwość uniesienia koła na przeszkodzie. Zastosowane koła pochodzą od "jakiejś" zabawki (znalezione na strychu ) i są zamocowane adapterem hex 12 mm (z małymi przeróbkami, aby schować przekładnię wewnątrz koła). Każde koło posiada własny silnik DC z przekładnią - prędkość wyjściowa: ok. 120 obr/min przy zasilaniu 12V. Silniki zostały zamocowane do aluminiowego profilu kwadratowego 10 mm za pomocą opasek zaciskowych. Profil ten stanowi część wahacza przymocowanego do osi kadłuba przez łożyska z wiertarek (średnica wewnętrzna 6 mm). Z tyłu pojazdu widoczna jest belka różnicowa łącząca wahacze po obu stronach. Dzięki niej kadłub utrzymywany jest w swojej pozycji a wychylenie jednego wahacza powoduje odchylenie drugiego o taki sam kąt przeciwnie skierowany. Jako kadłub wykorzystano obudowę z ABS. Do jej wieczka przymocowano również maszt z kamerą sterowany w dwóch osiach. Elektronika Komputerem sterującym w pojeździe jest Raspberry Pi Zero W z systemem Raspbian w wersji Jessie. Zastosowano ten model z powodu małych rozmiarów, stosunkowo niskiej ceny i małego poboru mocy. Z racji braku przetwornika ADC, zastosowano również arduino w wersji Pro Mini o napięciu 3.3V (aby było zgodne ze standardem w Raspberry). Są również 2 sterowniki silników na bazie modułu L298N (Sterownik ten ma dwa kanały i można było zastosować tylko jeden sterownik, jednak z powodu niewystarczającej wydajności prądowej zastosowano dwa), 2 przetwornice step-down 5V (osobno dla logiki, i osobno dla serwomechanizmów), dwa serwomechanizmy TowerPro SG90, kamera, oraz pakiet 3S ogniw li-ion w rozmiarze 18650. Z racji tego, że kamera jest podłączana przez taśmę FFC, zastosowano również przejściówki z FFC na goldpin, aby nie uszkodzić taśmy podczas obracania kamerą. Oprogramowanie Arduino w tym pojeździe odpowiedzialne jest za odczyt aktualnego napięcia zasilania oraz generowanie sygnałów PWM dla prędkości silników oraz serwomechanizmów pozycjonowania kamery. To jaki sygnał ma być generowany, jest wiadome dzięki połączeniu z Raspberry poprzez UART. Dodatkową funkcją Arduino jest wyłączenie PWM dla silników w przypadku braku komunikacji z Raspberry co zapobiega niekontrolowanej jeździe pojazdu w przypadku np. zerwania zasięgu. Raspberry komunikuje się z użytkownikiem poprzez sieć WiFi (Malinka działa w trybie hot-spot'u). Program działający na Raspberry został napisany w Python'ie i wykorzystuje również biblioteki Flask, w celu utworzenia serwera. Odpowiednie fragmenty kodu są wykonywane po wywołaniu przypisanego do niego adresu. Do transmisji wideo wykorzystano platformę Gstreamer, która pozwala na strumieniowanie w formacie H.264. Dzięki temu udało się uzyskać płynny obraz przy 30 FPS i rozdzielczości 800x600 cechujący się niewielkim opóźnieniem (ok. 300 ms). Powstała również dedykowana aplikacja na system Android, gdzie widoczny jest podgląd z kamery oraz sterowanie pojazdem. Podsumowanie Powstały pojazd zgodnie z założeniami dobrze radzi sobie w terenie, jednak pozostawia również spore możliwości rozbudowy. Można np. dodać zewnętrzną antenę WiFi aby poprawić zasięg (obecnie jest to ok 50m na otwartej przestrzeni), diodę doświetlającą, czy też różne czujniki. Najprawdopodobniej następnym krokiem będzie dodanie przetwarzania obrazów, aby pojazd był w stanie podążać za danym obiektem i być może omijać przeszkody. Na koniec krótka prezentacja działania:
  11. Witam, chciałbym przedstawić swoją konstrukcję, a mianowicie robota mobilnego o nazwie Bluebot – od połączenia słów bluetooth oraz robot . Jak można się domyślić, konstrukcja jest sterowana przez bluetooth z poziomu aplikacji, co było głównym założeniem. Ponadto chciałem, aby robocik miał jak najbardziej estetyczny wygląd. Pozwolę sobie przejść teraz do szczegółowego opisu. Podwozie Podwozie (a właściwie korpus) zostało wydrukowane na drukarce 3d. Składa się z górnej części – głównej, oraz dolnej – pokrywki przymocowanej do pierwszej części za pomocą trzech wkrętów. Na pierwszej warstwie bardzo mocno są widoczne „paski” nanoszonego filamentu, ale zmniejszając temperaturę głowicy przy kolejnych wydrukach udało mi się trochę zmniejszyć widoczność tego defektu (ktoś ma jakieś pomysły co jeszcze można zrobić?). Zdjęcia pierwsze i drugie przedstawiają model korpusu, natomiast trzecie wspomnianą „wadę” wydruków. Warto jeszcze dopisać, że podwozie jest kołem o średnicy 100mm. Elektronika Elektronika robocika nie jest skomplikowana. „Sektor sterujący” składający się z arduino micro (akurat takie wykorzystałem, równie dobrze można było użyć każdego innego), sterownika silników L293D (nie zdecydowałem się na gotowy moduł TB6612 ze względu na oszczędność miejsca ) i modułu bluetooth HC-05 (zmieściła się jeszcze dioda LED, kondensator ceramiczny i rezystor) znajduje się na płytce PCB, którą sam wykonałem metodą termotransferu. Do narysowania projektu płytki wykorzystałem program Eagle, do trawienia użyłem wytrawiacza B327. Płytka cechuje się nietypowym kształtem widocznym na zdjęciu. Druga część elektroniki, a mianowicie stabilizator L7805 z parą kondensatorów, znajduje się w korpusie. Tam „ułożyłem” także wszystkie przewody, tak, że po zamknięciu obudowy żaden kabelek nie jest widoczny. Zastosowałem taki przełącznik suwakowy, który pełni rolę włącznika. Zastosowany akumulator to pakiet Dualsky 2S 7,4V 550mAh 45C, mieści się idealnie pomiędzy kołami, został przymocowany do podwozia za pomocą rzepu. Mechanika Zastosowałem znane silniczki Pololu z przekładnią 50:1. Jak już wcześniej wspomniałem, są sterowane przez układ L293D. Nie miałem jeszcze problemów z taką kombinacją. Mocowania Pololu, koła także Pololu – 40mm, czerwone (są wciskana na D-kształtny wał). Trzecim punktem podparcia jest dioda Led 10mm, nie świeci. W pierwotnej wersji miały być dwie – z przodu i z tyłu, ale jedna wystarczyła (robot jest delikatnie przechylony do przodu, poza tym dodając czwarty punkt podparcia jedno z kół mogłoby nie dotykać podłoża). Algorytm Sterowanie odbywa się z poziomu RoboRemo Free – aplikacji na urządzenia z systemem Android. Darmowa wersja pozwala na korzystanie z pięciu elementów jednocześnie. Działanie aplikacji zostało przystępnie wyjaśnione w tym filmie. Kod napisałem w Arduino IDE. Sterowanie pojazdem wygląda następująco: przesuwając lewy suwak zwiększa się prędkość lewego silnika, analogicznie prawy suwak. Fragment kodu (gdzie wartość ‘p’ to wartość suwaka, która jest wysyłana do arduino): if (cmd[0] == 'p') { unsigned int prawy = atof(cmd + 2); Serial.println(prawy); analogWrite(PWM_B, prawy);} Dodatkowo podczas przytrzymywania przycisku ‘LED’ zapala się żółta dioda na płytce PCB w robocie. Odpowiada za to ten fragment kodu: if (strcmp(cmd, "led 1")==0) { digitalWrite(ledPin, HIGH);} if (strcmp(cmd, "led 0")==0) { digitalWrite(ledPin, LOW);} Film To byłoby na tyle, dziękuję Wam za przeczytanie mojego opisu, zachęcam do zadawania pytań, na wszystkie postaram się odpowiedzieć .
  12. WSTĘP Mój projekt składa się z dwóch współpracujących układów działających dzięki mikrokontrolerowi Arduino Uno: pojazdu oraz pilota do sterowania. Pojazd posiada silnik DC napędzający wał z tylnymi kołami oraz serwomechanizm odpowiadający za skręcanie. Urządzenie jest wyposażone w akumulator li-pol zasilający mikrokontroler i silniki. Pilot powstał z użyciem modułu joysticka, który umożliwia analogowe sterowanie prędkością i kierunkiem jazdy pojazdu. Urządzenia komunikują się z wykorzystaniem podczerwieni, pilot wyposażony jest w nadajnik IR, a pojazd w odbiornik IR. MECHANIKA Mechaniczna konstrukcja pojazdu została wykonana z plastikowej butelki. Skrętne koło zostało wymontowane z starego krzesła obrotowego. Układ pilota znajduje się w obudowie z odpowiednio wyciętego kartonowego pudełka. ELEKTRONIKA Oba układy są zlutowane na uniwersalnych płytkach. Płytki zostały wyposażone w listwę goldpinów, które wtyka się w Arduino. Dzięki temu rozwiązaniu możemy wyciągnąć Arduino i użyć go w innym projekcie bez potrzeby niszczenia trwałych połączeń. Pojazd jest wyposażony w jednokanałowy sterownik silnika. Schemat układu pojazdu: Schemat układu pilota: Schematy połączeń stworzono z użyciem programu do projektowania i symulowania obwodów elektronicznych EasyEDA. OPROGRAMOWANIE Najważniejsze fragmenty kodu pilota: valueX = analogRead(joyX) / 100; valueY = analogRead(joyY) / 100; isPress = !digitalRead(button); data0 = String(isPress, HEX); data1 = String(valueX, HEX); data2 = String(valueY, HEX); if (isPress == 0) dataSend += "1"; else dataSend += "2"; dataSend += data1 + data2; for (int i = 0; i < 3; i++) { irsend.sendSony(StrToHex(dataSend.c_str()), 12); delay(40); } Program odczytuje pozycję X oraz Y joysticka oraz czy jest on wciśnięty. Następnie pilot wysyła komunikaty zapisane w systemie szesnastkowym. Są to trzy cyfry: pierwsza stan przycisku (0x1 nie wciśnięty, 0x2 wciśnięty), druga kąt ustawienia serwomechanizmu (od 0x0 do 0xA, 0x0 to ustawienie serwomechanizmu maksymalnie w lewo, 0x5 ustawienie serwomechanizmu prosto, 0xA ustawienie serwomechanizmu maksymalnie w prawo) i trzecia prędkość obrotów silnika (od 0x0 do 0xA, 0x0 to maksymalne obroty do tyłu, 0x5 silnik nie pracuje, 0xA maksymalne obroty do przodu). Przykładowy sygnał 0x171 oznacza serwomechanizm ustawiony delikatnie w prawo oraz prawie maksymalna prędkość w tył. Wszystkie dłuższe sygnały są ignorowane, dzięki czemu ograniczony zostaje wpływ zakłóceń na układ. Stan przycisku nie jest używany przez pojazd ale nic nie stoi na przeszkodzie, aby rozbudować projekt o nową funkcjonalność, jak na przykład zapalanie świateł czy sygnał dźwiękowy. Najważniejsze fragmenty kodu pojazdu: if (irrecv.decode(&results)) { IRcommand = String(results.value, HEX); if (IRcommand.length() == 3) { tmp = IRcommand.charAt(1); setTurn(hexChar2Int(tmp)); tmp = IRcommand.charAt(2); setSpeed(hexChar2Int(tmp)); } irrecv.resume(); } Program używa drugiego i trzeciego znaku do ustawienia kolejno odpowiedniej prędkości oraz kąta obrotu serwomechanizmu. Oba programy wykorzystują bibliotekę <IRremote.h> do komunikacji z użyciem podczerwieni. Dodatkowo program pojazdu korzysta z biblioteki <Servo.h>. Program użyty do napisania programowania mikrokontrolerów to Arduino Software.
  13. Cześć wszystkim, chciałbym zaprezentować Wam konstrukcję, która stała się tematem mojej pracy dyplomowej. Działanie: Pojazd opiera się o Raspberry Pi 2 (bo akurat ten model posiadam), a dalmierz wykorzystuje dedykowaną kamerę do Maliny. W projekcie chciałem skupić się na wykrywaniu przeszkód, w związku z czym pominąłem pewne kwestie techniczne, jak np. zasilanie z akumulatorów (robot musi być podłączony do zasilacza kablem) albo kwestie zdalnego sterowania (robot wykonuje z góry zdefiniowane instrukcje ruchu). Najważniejszym elementem tego projektu jest własnoręcznie wykonany dalmierz laserowy, który opisuję dokładniej poniżej. Podstawowym zadaniem robota jest skanowanie przestrzeni wokół niego. Wygenerowana mapa wygląda tak: Jest ona przedstawiona w formie tablicy dwuwymiarowej, w której każda komórka odpowiada kwadratowi o boku 10 cm. Zdecydowałem się na taki sposób zapisania mapy, ponieważ można ją łatwo przetworzyć algorytmami wykrywania drogi. Konstrukcja mechaniczna: Do budowy użyłem gotowego podwozia z dwoma kołami i kółkiem podpierającym z tyłu. Podwozie te wymusza poruszanie się pojazdu analogicznie do poruszania się czołgu, a ma to tę zaletę, że robot może obracać się w miejscu. Do gotowego podwozia przykręciłem drugą płytę, którą ręcznie wyciąłem z płyty MDF. Do tej płyty przymocowana jest cała elektronika wraz z serwomechanizmem, na którym znajduje się głowica dalmierza. Głowica ta również została ręcznie wykonana z płyty pilśniowej. Składają się na nią trzy płytki, z których jedna jest przeznaczona na umocowanie lasera, druga na umocowanie kamery, a trzecia tworzy podstawę i miejsce mocowania do serwomechanizmu. Dwie pierwsze płytki są ułożone względem siebie pod kątem 9,3°. Kąt ten wynika z niedoskonałości ręcznej obróbki materiału, docelowo miał on wynosić 15° (niestety nie dysponuję drukarką 3D). Jego zmniejszenie powoduje, że dalmierz może wykonywać pomiary w większym zakresie (nawet do kilku metrów), jednak pomiary te są mniej precyzyjne, ponieważ na jeden piksel przesunięcia punktu lasera przypada większa różnica odległości. Przestrzeń pomiędzy obydwoma płytami pojazdu ma wysokość około 4 cm i jest zajmowana jedynie przez wiązki przewodów. Przestrzeń ta jest tak duża aby można było, przy przyszłej rozbudowie projektu, umieścić tam 4 cylindryczne akumulatory Li-ion wraz z towarzyszącą im elektroniką. Elektronika: Jak napisałem wcześniej głównym elementem sterującym jest Raspberry Pi, jednak niezbędne są też odpowiednie układy np. do sterowania silnikami. W tym celu stworzyłemukład, który zawiera sterownik silników L293D oraz całą niezbędna elektronikę potrzebną do m.in. sterowania laserem czy serwomechanizmem. Układ ten służy też do rozdzielenia zasilania na wszystkie komponenty. W kwestii zasilania zdecydowałem się na użycie dwóch zasilaczy 5 V, gdzie jeden odpowiada za zasilanie Maliny, a drugi za zasilanie wszystkich silników. Przy jednym zasilaczu zakłócenia powodowane przez silniki były tak duże, że często powodowały resetowanie się Raspberry Pi. Dalmierz: Dalmierz zbudowałem na podstawie poradnika Forbota, w związku z czym pominę tutaj opis metody triangulacji i niezbędne wzory, ponieważ to wszystko możecie przeczytać w wymienionym artykule. Podstawowym problemem przy korzystaniu z tak skonstruowanego dalmierza jest wyznaczenie pozycji plamki lasera na obrazie z kamery. W projekcie zaimplementowałem dwa różne sposoby osiągnięcia tego celu. Pierwszym z nich jest znalezienie najjaśniejszego puntu na obrazie. Przy użyciu biblioteki OpenCV metoda ta jest bardzo łatwa w implementacji. Jednak ja użyłem trochę bardziej rozbudowanej metody używającej maski na obrazie. Maska jest obszarem achromatycznym (1-bitowym), który wyznacza obszar na obrazie, który powinien być wyłączony z obliczeń. W projekcie maskę użyto, aby wyszukiwać najjaśniejszy punkt jedynie w wąskim poziomym pasie obrazu. Innymi słowy, maska obrazu wyłącza z przetwarzania górną i dolną część klatki. Użyłem tej metody ze względu na to, że w trakcie testów często maksimum na obrazie było wykrywane nie w miejscu plamki lasera, a np. w miejscu odbicia światła dziennego od błyszczących przedmiotów w pomieszczeniu. Dzięki ograniczeniu interesującego nas obszaru obrazu udało się znacząco zminimalizować ten efekt. Wysokość tych obszarów dobrałem eksperymentalnie, wiedząc, że ze względu na konstrukcję dalmierza, plamka lasera w oku kamery zawsze „porusza się” w linii poziomej, na stałej wysokości. Wyszukiwanie najjaśniejszego punktu jest metodą bardzo łatwą w implementacji i dobrze sprawdzają się w praktyce. Ma ona jednak jedną poważną wadę. W momencie gdy odległość do przeszkody jest tak duża, że plamka lasera znajduje się poza kadrem, metoda ta w dalszym ciągu odnajdzie najjaśniejszy punkt na obrazie, który błędnie zostanie zinterpretowany jako światło lasera. Używając tej metody nie ma możliwości sprawdzenia czy punkt lasera znajduje się w kadrze. Z tego względu spróbowałem też drugiej metody. Procedura w tym przypadku składa się z kilku kroków: pobranie klatki obrazu przy wyłączonym laserze, włączenie lasera, pobranie drugiej klatki obrazu, odjęcie dwóch pobranych klatek od siebie, wyznaczenie obszaru, w którym obie klatki różnią się od siebie. Jak widać metoda ta już w swoich założeniach jest bardziej skomplikowana niż wcześniejsza. Poza trudniejszą implementacją programową, problemy sprawiają tu też kwestie mechaniczne. Aby odjęte od siebie obrazy w wyniku dały obszar oświetlony laserem cała reszta kadru musi być na obu zdjęciach taka sama. Wymaga to, aby kamera nie poruszała się w trakcie pomiaru. Z tego względu pomiar jest też dłuższy niż przy wyszukiwaniu najjaśniejszego punktu, ponieważ należy poczekać z pobraniem kolejnych klatek aż drgania spowodowane ruchem serwomechanizmu ustaną. W projekcie metoda ta została zaimplementowana w taki sposób: każda z pobranych klatek jest konwertowana na obraz czarno-biały, 8-bitowy, gdzie wartość 255 odpowiada bieli, a 0 odpowiada czerni. Wszystkie wartości pomiędzy to odcienie szarości. Następnie obrazy te są od siebie odejmowane, w wyniku czemu uzyskujemy trzeci czarno-biały obraz. Obraz różnicy jest wtedy konwertowany na mapę 1-bitową z ustaloną wartością progową, tj. wartością, powyżej której piksel jest uznawany za biały, a poniżej za czarny. Do wszystkich tych przekształceń obrazu używane są narzędzia z biblioteki OpenCV. Na tak przetworzonym obrazie są następnie wyszukiwane białe obszary. Obszarów tych zazwyczaj jest więcej niż jeden, często też widoczne są tu krawędzie różnych obiektów, które znajdowały się w kadrze, jednak krawędzie te mają zazwyczaj 1-2 px grubości. Są to niedoskonałości obrazu, których nie udało się wyeliminować nawet przez wyeliminowanie drgań kamery. Aby krawędzie te nie wpływały na wynik, z przetwarzania wyłączane są wszystkie obszary, których wysokość lub szerokość jest mniejsza niż 3 px. W wyniku tego na obrazie różnicy pozostaje obszar światła lasera oraz kilka mniejszych obszarów, które są rożnymi zakłóceniami. Aby ostatecznie znaleźć obszar plamki lasera, szukany jest największy biały obszar na obrazie różnicy i wyznaczany jest jego środek. Obliczony punkt jest pozycją plamki lasera na obrazie. Jak widać, metoda ta jest dużo bardziej skomplikowana i dużo trudniejsza w praktycznej implementacji niż szukanie najjaśniejszego punktu. Nie ma ona jednak wady poprzedniej metody, tj. gdy w kadrze nie znajduje się światło lasera, metoda ta w większości przypadków wykryje to. Wymaga to jednak małych zakłóceń na obrazie różnicy, gdzie po odjęciu zakłóceń do 3 pikseli otrzymamy pusty obraz. Taką sytuację należy zinterpretować jako pomiar poza zakresem.
  14. Projekt powstał jako rozwinięcie prostego jeździka solarnego ( dwa panele słoneczne, dwa silniki rama z dużego klocka ala duplo) który miał problem z pokonywaniem nierówności. Założenia Stworzenie budżetowej platformy jezdnej mogącej poruszać się swobodnie po typowym mieszkaniu - pokonywać przeszkody typu próg czy gruby dywan. Walidacją założenia będzie możliwość pokonywania przeszkód o wysokości około 1 cm. Układ mechaniczny Aby było możliwe pokonywanie nierówności, koła muszą być maksymalnie niezależne - amortyzowane. Próby [teoretyczne] opracowania zawieszenia trwały w sumie kilka miesięcy. Żaden z pomysłów nie był tani a jednocześnie obiecujący (prosty). Natomiast podczas spożywania ptysi z biedronki (francuskie ptysie nadziewane kremem o smaku waniliowym z sosem z czekoladowym) zauważyłem że pudełko jest wytrzymałe ale jego rogi da się dość elastycznie wyginać. Po nawierceniu 8 dziur i przykręceniu silników z kołami okazało się że efekt jest obiecujący. Elektronika Sercem układu jest Arduino Pro Mini 328 3V3 (3V3 bo docelowo będzie zasilane z starej baterii od telefonu) poza tym jest wystarczające. Silnikami steruje DRV8833 - pierwszy kanał na dwa silniki z prawej strony i drugi kanał na dwa silniki z lewej strony. UWAGA trzeba pamiętać o polach lutowniczych pozwalających ograniczyć prąd! Komunikacja odbywa się jednokierunkowo - z telefonu do arduino. Ja użyłem Bluetooth BLE HM-10 bo taki miałem ale może być jakiś inny. Program Jako bazy użyłem przykładu SerialEvent https://www.arduino.cc/en/Tutorial/SerialEvent Dodałem obsługę przycisku włączającego i wyłączającego pojazd (ruch pojazdu). Obsługa sterowania na podstawie akcelerometru: Oś y - prawo lewo ( 123 na wprost [110-136]; 250 max prawo; 0 max lewo) Oś z - speed (0-255) wsteczny max 140; przód max 255 - środek 195, bezład [ 200-230 ] /* akcelerometr: 1 - (x) 2 - (y) prawo lewo ( 123 na wprost [110-136]; 250 max prawo; 0 max lewo ) 3 - (z) speed (0-255) wsteczny max 140; przód max 255 - srodek 195, bezład [ 200-230 ] PWM 9 i 6 */ //PWM int BIN_1 = 9; int BIN_2 = 8; //PWM int AIN_1 = 6; int AIN_2 = 5; int MAX_PWM_VOLTAGE = 240; float MAX_PWM_VOLTAGE_FLOAT = 240.00; float PWM_VOLTAGE_PERCENT = MAX_PWM_VOLTAGE_FLOAT/100; float PWM_VOLTAGE_A; float PWM_VOLTAGE_B; String inputString = ""; // a String to hold incoming data bool stringComplete = false; // whether the string is complete String speed = ""; String direction = ""; int speed_int = 215; int direction_int = 123; int tmp_speed_int = 0; int tmp_direction_int = 0; bool remote = false; void setup() { // initialize serial: Serial.begin(9600); // reserve 200 bytes for the inputString: inputString.reserve(200); // initialize digital pin LED_BUILTIN as an output. pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, HIGH); delay(1000); digitalWrite(LED_BUILTIN, LOW); delay(1000); pinMode(BIN_1, OUTPUT); pinMode(BIN_2, OUTPUT); pinMode(AIN_1, OUTPUT); pinMode(AIN_2, OUTPUT); // delay just in case bluetooth module needs time to "get ready" //delay(100); //Serial.println("setup complete"); //--prevMillis = millis(); digitalWrite(BIN_2, LOW); digitalWrite(AIN_2, LOW); analogWrite(BIN_1, 0); analogWrite(AIN_1, 0); } void loop() { // print the string when a newline arrives: if (stringComplete) { if (inputString.substring(0,6) == "remote"){ if(remote == true){ remote = false; digitalWrite(LED_BUILTIN, LOW); } else { remote = true; digitalWrite(LED_BUILTIN, HIGH); } } if (inputString.substring(0,1) == "2"){ direction = inputString.substring(2); direction_int = direction.toInt(); } if (inputString.substring(0,1) == "3"){ speed = inputString.substring(2); speed_int = speed.toInt(); } ] if((remote == true) && (speed_int > 230)){ //26-50 pomnozone razy dwa daje ponad 50%, przy niższej mocy silniki nie pracują tmp_speed_int = speed_int-205; tmp_speed_int = tmp_speed_int*2; PWM_VOLTAGE_A = PWM_VOLTAGE_PERCENT*tmp_speed_int; PWM_VOLTAGE_B = PWM_VOLTAGE_PERCENT*tmp_speed_int; if((direction_int >= 110 ) && (direction_int <= 136 )){ digitalWrite(BIN_2, LOW); digitalWrite(AIN_2, LOW); } else if (direction_int < 110){ digitalWrite(BIN_2, LOW); digitalWrite(AIN_2, HIGH); } else if (direction_int > 136){ digitalWrite(BIN_2, HIGH); digitalWrite(AIN_2, LOW); } analogWrite(BIN_1, (int)PWM_VOLTAGE_B); analogWrite(AIN_1, (int)PWM_VOLTAGE_A); } else if((remote == true) && (speed_int < 200)){ //26-50 pomnozne razy dwa daje ponad 50%, przy niższej mocy silniki nie pracują tmp_speed_int = speed_int-230; tmp_speed_int = tmp_speed_int*-2; if((direction_int >= 110 ) && (direction_int <= 136 )){ PWM_VOLTAGE_A = PWM_VOLTAGE_PERCENT*tmp_speed_int; PWM_VOLTAGE_B = PWM_VOLTAGE_PERCENT*tmp_speed_int; } else if (direction_int < 110){ PWM_VOLTAGE_A = 0; PWM_VOLTAGE_B = PWM_VOLTAGE_PERCENT*tmp_speed_int; } else if (direction_int > 136){ PWM_VOLTAGE_A = PWM_VOLTAGE_PERCENT*tmp_speed_int; PWM_VOLTAGE_B = 0; } digitalWrite(BIN_2, HIGH); digitalWrite(AIN_2, HIGH); analogWrite(BIN_1, (int)PWM_VOLTAGE_B); analogWrite(AIN_1, (int)PWM_VOLTAGE_A); } else { digitalWrite(BIN_2, LOW); digitalWrite(AIN_2, LOW); analogWrite(BIN_1, 0); analogWrite(AIN_1, 0); } // clear the string: inputString = ""; stringComplete = false; } } /* Serial Event example When new serial data arrives, this sketch adds it to a String. When a newline is received, the loop prints the string and clears it. A good test for this is to try it with a GPS receiver that sends out NMEA 0183 sentences. NOTE: The serialEvent() feature is not available on the Leonardo, Micro, or other ATmega32U4 based boards. created 9 May 2011 by Tom Igoe This example code is in the public domain. http://www.arduino.cc/en/Tutorial/SerialEvent */ /* SerialEvent occurs whenever a new data comes in the hardware serial RX. This routine is run between each time loop() runs, so using delay inside loop can delay response. Multiple bytes of data may be available. */ void serialEvent() { while (Serial.available()) { // get the new byte: char inChar = (char)Serial.read(); //Serial.println(inChar); // add it to the inputString: inputString += inChar; // if the incoming character is a newline, set a flag so the main loop can // do something about it: if (inChar == '\n') { stringComplete = true; } } } Podsumowanie Pojazd pokonuje przeszkody o wysokości ponad 1 centymetra - więc cel został osiągnięty. Natomiast sterowanie nie jest optymalne - docelowo będę zmieniał na skręt realizowany jako obrót wokół własnej osi (naprzemienny kierunek silników z prawej i lewej strony). Do budowy platformy wykorzystano: 4 * silnik DC + koło 1 * sterownik silników DC DRV8833 1 * Arduino Pro Mini 328 3V3 1 * Bluetooth BLE HM-10 (może być każdy BT [slave]) 2 * koszyczek na cztery AA 8 * akumulator AA (najlepsze IMHO enleopy) 1 * Breadboard 170 1 * zestaw kabli 1 * śrubki z nakrętkami z LeroyMerlin 1 * pudełko po francuskich ptysiach nadziewanych kremem o smaku waniliowym z sosem z czekoladowym - na wszelki wypadek zaopatrzyłem się w 3 dodatkowe pudełka Sterowanie odbywa się z smartfonu przy użyciu aplikacji RoboRemoFree. Do programowania Arduino Pro Mini konieczne jest użycie konwertera USB do RS232TTL.
  15. Chciałbym przedstawić wam mój pierwszy projekt na Raspberry Pi – pojazd gąsiennicowy z kamerą i czujnikiem odległości sterowany przez przeglądarkę przy użyciu Bottle. Do tej pory używałem tylko Arduino i postanowiłem spróbować czegoś nowego. Przewagą pojazdu gąsienicowego nad kołowym jest możliwość poruszania się w trudnych warunkach. Podwozie jest amortyzowane co sprawia, że lepiej radzi sobie z nierównościami terenu. Robot bez problemu jeździ w ogrodzie i po śniegu. Podstawowe elementy wykorzystane do budowy robota: podwozie gąsiennicowe Raspberry Pi Zero W (ze względu na wbudowane wifi) sterownik silników L298N servo hat Sparkfun kamera do Raspberry Pi (z adapterem do Pi zero) przetwornica napięcia step down uchwyt do kamery + 2 serwomechanizmy czujnik ultradźwiękowy HC-SR 04 konwenter poziomów logicznych akumulator 7.4 V Budowa: Raspberry, sterownik silników, przetwornica i uchwyt kamery przykręcone są do postawy. Akumulator znajduje się pomiędzy podstawą a podwoziem. Raspberry i servo hat zasilane są kablem USB z przetwornicy podłączonym do hat’a. Sterownik silników i przetwornica podłączone są do akumulatora przez włącznik zasilania. Kamera i czujnik odległości są przymocowane do uchwytu z serwomechanizmami dzięki czemu można sterować ich położeniem. Czujnik odległości wysyła sygnał 5V, więc musi być podłączony do Raspberry przez konwenter stanów logicznych. Oprogramowanie: Do sterowania pojazdem przez przeglądarkę wykorzystałem projekt Bottle przy użyciu portu 8080. Obraz transmitowany jest przy użyciu pakietu Motion. Po wpisaniu w przeglądarkę: http://[ip_Raspberry]:8080/robocik/ pokazuje się panel do sterowania. Sterujemy robotem przy użyciu myszki wciskając odpowiednie przyciski. Możemy sterować kierunkiem jazdy, prędkością, ustawieniem uchwytu, a także włączyć i wyłączyć kamerę i Raspberry oraz zmierzyć odległość od przeszkody. Oprogramowanie składa się z dwóch części – programu w Pythonie i szablonu strony internetowej w html z rozszerzeniem .tpl. W szablonie możemy ustawić wygląd strony i funkcje przycisków, a program w Pythonie odpowiada za sterowanie GPIO. Pojazd_gasiennicowy_Raspberry_Bottle.zip
  16. Cześć, tym razem chciałbym się z Wami podzielić moim pierwszym jeżdżącym robotem - światłolubem. Wybrałem ten typ robota ze względu na jego prostą konstrukcję i łatwy w napisaniu program do sterowania. Do stworzenia podwozia postanowiłem wykorzystać płytę HDF. Jest ona lekka ale wystarczająco sztywna żeby utrzymać robota i co ważne łatwo dostępna i tania. Konstrukcja pod względem mechanicznym jest dosyć duża i niezgrabna, jednak było to zaplanowane. Na dosyć sporym kawałku HDFu zmieściłem 2 koszyki na baterie, jeden na 6 baterii AA, drugi na 2, dzięki czemu mam do dyspozycji 9 i 12V, Arduino Uno oraz płytkę stykową - dzięki takiemu rozwiązaniu mogę w łatwy sposób przerobić robota na innego. Koszyki na baterie przykleiłem do podwozia za pomocą kleju na ciepło, żeby nie mogły się one przemieszczać, Arduino przykręciłem za pomocą 4 długich śrub w taki sposób, że nie przylega ono do powierzchni płyty (jest to spowodowane sposobem montażu tylnego koła) a płytkę stykową przykleiłem na taśmie dwustronnej, która zabezpiecza jej spód. Silniki przymocowałem w taki sposób, jaki został przedstawiony w kursie budowy robotów. Do styków przylutowałem przewody, które następnie wyprowadziłem przez wcześniej nawiercone otwory. Tylne koło (obrotowe) zamocowałem za pomocą 4 śrub, niestety dysponowałem tylko jednym rodzajem więc mocno wystają one ponad powierzchnię podwozia. Kolejnym krokiem było stworzenie elektroniki, która będzie odpowiedzialna za ruch robota i znajdywanie najmocniejszego źródła światła. Do sterowania silnikami wykorzystałem sterownik silników L293D, który podłączyłem tak jak zostało to przedstawione w kursie programowania Arduino. W podwoziu zrobiłem 3 nacięcia (2 z przodu i 1 z tyłu, żeby robot mógł także cofać) do których włożyłem, a następnie zalałem klejem na ciepło fotorezystory 20-30k, które następnie podłączyłem do płytki stykowej i stworzyłem dzielnik z rezystorami 4k7 na których za pomocą pinów analogowych Arduino mierzony jest spadek napięcia. Dzielnik zasiliłem z wyjścia 5V Arduino. Na koniec zostało napisanie programu, który będzie wszystko koordynował. Było to najbardziej pracochłonne zajęcie i wymagało zdecydowanie najwięcej czasu. Program nie jest szczególnie skomplikowany, jednak żeby robot jeździł tak jak trzeba musiałem określić np. wartości różnicy między napięciami na fotorezystorach, żeby nie skręcał on w przypadku, gdy jeden z czujników jest minimalnie mocniej oświetlony. #define L_MOTOR_F 4 //definiowanie pinów #define L_MOTOR_B 5 #define L_MOTOR_PWM 6 #define R_MOTOR_F 2 #define R_MOTOR_B 7 #define R_MOTOR_PWM 3 #define L_O A4 #define R_O A5 #define B_O A3 #define ROZNICA_MIN -200 //okreslenie maksymalnej i minimalnej roznicy miedzy odczytanymi wartosciami napiecia #define ROZNICA_MAX 200 #define ROZNICA_PROG_G 10 //okreslenie roznicy, ktora nie bedzie powodowala skretu #define ROZNICA_PROG_D 10 void setup() { pinMode(L_MOTOR_F, OUTPUT); //deklaracja pinow na wyjscia pinMode(L_MOTOR_B, OUTPUT); pinMode(R_MOTOR_F, OUTPUT); pinMode(R_MOTOR_B, OUTPUT); pinMode(L_MOTOR_PWM, OUTPUT); pinMode(R_MOTOR_PWM, OUTPUT); } void loop() { int lewy=analogRead(L_O); //odczyt wartosci napiec z fotorezystorow int prawy=analogRead(R_O); int tyl=analogRead(B_O); int roznica=lewy-prawy; //obliczenie roznicy miedzy wartosciami przednich fotorezystorow int srednia=(lewy+prawy)/2; //obliczenie sredniej wartosci spadkow napiec na przednich fotorezystorach if (roznica < ROZNICA_MIN) roznica = ROZNICA_MIN; //ograniczenie roznicy else if (roznica > ROZNICA_MAX) roznica = ROZNICA_MAX; else if (roznica<=ROZNICA_PROG_G && roznica>=ROZNICA_PROG_D) //jezeli roznica jest mniejsza od progu, jedzie prosto roznica=0; if(srednia>tyl){ //jezeli natezenie swiatla z przodu jest wieksze niz z tylu - jazda do przodu int zmianaPredkosci = map(roznica, ROZNICA_MIN, ROZNICA_MAX, -40, 40); L_MOTOR(60-zmianaPredkosci); R_MOTOR(60+zmianaPredkosci); } else{ //w przeciwnym wypadku jazda w tyl L_MOTOR(-60); R_MOTOR(-60); } } void L_MOTOR(int V){ //funkcja sterujaca predkoscia lewego silnika if(V>0){ V=map(V,0,100,0,255); digitalWrite(L_MOTOR_F,HIGH); digitalWrite(L_MOTOR_B,LOW); analogWrite(L_MOTOR_PWM,V); } else{ V=abs(V); V=map(V,0,100,0,255); digitalWrite(L_MOTOR_B,HIGH); digitalWrite(L_MOTOR_F,LOW); analogWrite(L_MOTOR_PWM,V); } } void R_MOTOR(int V){ //funkcja sterujaca predkoscia prawego silnika if(V>0){ V=map(V,0,100,0,255); digitalWrite(R_MOTOR_F,HIGH); digitalWrite(R_MOTOR_B,LOW); analogWrite(R_MOTOR_PWM,V); } else{ V=abs(V); V=map(V,0,100,0,255); digitalWrite(R_MOTOR_B,HIGH); digitalWrite(R_MOTOR_F,LOW); analogWrite(R_MOTOR_PWM,V); } } void STOP(){ //zatrzymanie silnikow analogWrite(R_MOTOR_PWM,0); analogWrite(L_MOTOR_PWM,0); } W ten sposób robot został ukończony. Projekt ten bez wątpienia dużo mnie nauczył. Może nie ze strony elektroniki, ale na pewno ze strony programowania. I co najważniejsze miałem dużo zabawy tworząc go Pozdrawiam ~Usohaki
  17. Przedstawiam mój pierwszy projekt DIY na forum Forbota, jest to pojazd o nazwie Wall-E kontrolowany przez bluetooth, którego zadaniem jest tworzenie mapy przeszkód w pomieszczeniu, w którym się znajduje. MECHANIKA Wall-E został zbudowany na ładnej zielonej sklejce, która niestety utraciła część swego uroku wskutek wiercenia kiedyś używanych otworów na kable i śrubki, które obecnie nie pełnią żadnej funkcji. Napęd robota został przymocowany do podwozia przy pomocy drewnianych klocków. Silniki krokowe 28BYJ-48 z przekładnią pracują pod napięciem 5V, posiadają wystarczający moment obrotowy 0,03Nm, lecz ich wadą jest dość niska prędkość. Do silników przymocowane są koła. Z tyłu znajduje się kółko obrotowe. Do mechaniki należy też doliczyć Serwo TowerPro SG-90, które pozwala regulować kąt widzenia przyklejonego do niego czujnika odległości bez konieczności obracania pojazdu. HARDWARE Sercem pojazdu jest klon Arduino Uno. Kontroluje ono dwa silniki za pośrednictwem dedykowanych sterowników, które zakupiłem razem z silnikami. Wyświetlacz tekstowy JHD162A-B-W w kolorze niebieskim wyświetla nazwę robota, jego prędkość, kierunek ruchu i kąt patrzenia. Czujnik odległości HC-SR04 zapewnia dane o przeszkodach w otoczeniu i odległości od nich. Posiada zadowalającą dokładność przy niskiej cenie, choć doświadczenie nauczyło mnie, aby kierować go zawsze na przeszkodę pod kątem prostym. Komunikację bluetooth umożliwia moduł bluetooth HC-06. Jest on chyba najpopularniejszy obok modułu 05, interfejs UART pozwala na proste podłączenie, go do pinów Arduino. Od oferty z linku różni się tylko tym, że nie posiada wyprowadzeń STATE i EN, co jednak nie ogranicza jego możliwości. Na pokładzie Wall-Ego umieściłem także płytkę wylutowaną ze starej zabawki RC. Stanowi ona węzeł, który łączy pin zasilania 5V Arduno z zasilaniem dodatnim układów peryferyjnych. Wychodzą z niego przewody męskie, a za nimi tam, gdzie zaszła taka potrzeba również żeńskie (przyznam, jedna wielka plątanina kabli), taką samą funkcje pełni drugi węzeł GND. Na płytce ulokowałem też podstawkę pod układ scalony, która stanowi gniazdo na moduł bluetooth, gdyż nie chciałem go wlutowywać na stałe (przy wgrywaniu programu na płytkę Arduino należy go wyciągnąć). Znajduje się tam też dzielnik napięcia zbudowany z rezystorów 1kOhm i 2kOhm, który podaje na pin RX modułu napięcie 3,3V. Zapobiega to uszkodzeniu układu, który pracuje w logice 3,3V, a Arduino w 5V. Napięcia wychodzącego z pinu TX nie trzeba podnosić, co byłoby bardziej kłopotliwe, gdyż Arduino rozpoznaje 3,3V jako logiczne 1. Na płytce umieściłem także potencjometr 10kOhm, który służy do ustawienia kontrastu wyświetlacza. Aby umożliwić komunikację z notebookiem, który nie posiada wbudowanego modułu BT potrzebny jest adapter podłączany do niego przez USB. SOFTWARE Program Arduino napisany został w środowisku Arduino IDE, czyli standardowym środowisku. Program na PC powstał w środowisku Processing. Przy wyborze zdecydowało kryterium języka - operuję tylko C++ i Java - oraz interfejs graficzny. Zrealizowałem też identyczną komunikację korzystając z C++ i CodeBlocks, lecz program konsolowy mnie nie satysfakcjonował. Na screenie przedstawiłem, gdzie znaleźć numer portu, do którego przypisany jest moduł HC-06 oraz interfejs programu wraz z przykładowym fragmentem mapy, którą Wall-E stworzył. Kod Arduino: /* 1 - stop 2 - do przodu 3 - do tyłu 4 - lewo 5 - prawo 6 - żądanie trasy 7 - żądanie pomiaru 81...86 - zmiana prędkośćci 101...118 - pozycja serwa */ #include <SoftwareSerial.h> //dodanie bibliotek #include <Servo.h> #include <Stepper.h> #include <LiquidCrystal.h> #define echo 11 //podłączenie czujnika odległości #define trig 12 LiquidCrystal lcd(14, 15, 16, 17, 18, 19); //tworzenie obiektów SoftwareSerial bt (0,1); Stepper left(64, 2, 4, 3, 5); Stepper right(64, 6, 8, 7, 9); Servo serwo; char state; //zmienna przechowująca odczyt z bluetooth long czas; //zmienne używane przy pomiarze odległości int dystans; int prawy=0, lewy=0; //koła: do tyłu/stop/do przódu int pom; //zmienna pomocnicza przy nadawaniu wyniku pomiaru int steps; //przebyte kroki void setup() { pinMode(echo, INPUT); //deklaracje OUTPUT/INPUT czujnika odległości pinMode(trig, OUTPUT); Serial.begin(9600); //ustanowienie komunikacji przez bluetooth serwo.attach(10); //podłączenie serwa right.setSpeed(300); //domyślna prędkość silników left.setSpeed(300); lcd.begin(16, 2); //ustannowienie komunikacji z wyświetlaczem lcd.setCursor(0, 0); //początkowe dane do wyświetlenia lcd.print("STOP"); lcd.setCursor(8, 0); lcd.print("SPEED: 6"); lcd.setCursor(0, 1); lcd.print("Wall-E"); lcd.setCursor(8, 1); lcd.print("SERVO: 9"); } void loop() { if(Serial.available() > 0){ //jeżeli istnieją dane do odebrania state = Serial.read(); //odbierz switch (state) { case '1': //stop lewy = 0; prawy = 0; lcd.setCursor(0, 0); lcd.print("STOP "); break; case '2': //do przodu lewy = 1; prawy = 1; lcd.setCursor(0, 0); lcd.print("FORW. "); break; case '3': //do tyłu lewy = -1; prawy = -1; lcd.setCursor(0, 0); lcd.print("BACKW."); break; case '4': //wokół własnej osi w lewo lewy=-1; prawy=1; lcd.setCursor(0, 0); lcd.print("LEFT "); break; case '5': //wokół własnej osi w prawo lewy=1; prawy=-1; lcd.setCursor(0, 0); lcd.print("RIGHT "); break; case '6': //żądanie przebytych kroków Serial.print(char(steps/10+115)); steps=0; break; case '7': //żądanie pomiaru z czujnika odległości delay(200); pom = pomiar(); if(pom < 115) Serial.print(char(pom)); else Serial.print(char(115)); break; case 'Q': //zmiana prędkości case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': left.setSpeed(int(state-80)*50); right.setSpeed(int(state-80)*50); lcd.setCursor(15, 0); lcd.print(int(state-80)); break; default: //zmiana pozycji serwa serwo.write(int(state-100)*10); if(int(state-100) < 10){ if(int(state-100) == 9){ lcd.setCursor(14, 1); lcd.print(" ");} lcd.setCursor(15, 1); lcd.print(int(state-100));} else {lcd.setCursor(14, 1); lcd.print(int(state-100));} break; } } if(lewy == 1) {left.step(-1); steps++;} //ruch i odnotowanie do zmiennej steps else if(lewy == -1) {left.step(1); steps++;} if(prawy == 1) right.step(-1); else if(prawy == -1) right.step(1); if(steps == 100){ //automatyczne wysłanie ilości kroków po wykonaniu 100 Serial.print(char(steps/10+115)); steps=0; } } int pomiar() //funkcja pomiar z czujnika odległości { digitalWrite(trig, LOW); delayMicroseconds(2); digitalWrite(trig, HIGH); delayMicroseconds(10); digitalWrite(trig, LOW); czas = pulseIn(echo, HIGH); dystans = czas / 58; return dystans; } Kod Processing: import processing.serial.*; //dodanie biblioteki Serial bt; //obiekt - port szeregowy int odleglosc = 0; //zmienna przechowująca odczyt z czujnika odległości int pozycja=9; //pozycja serwa boolean flag_up=false, flag_down=false, flag_lewa=false, flag_prawa=false; //flagi kierunku boolean pomiar = false; //flaga mówiąca czy robot ma wykonywać pomiar int speed = 6; //prędkość int licznik = 0; //wartość używana przy żądaniu przebytej odleglości float ang = 0; //odchylenie robota od położenia wyjściowego float x_co, y_co; //koordynaty x, y int steps=0; //odebrana ilośc przebytych kroków float[][] dots = new float[1000][2]; //tablica na przeszkody int odczyt; //dane odebrane z bluetooth int i; //zmienna pomocnicza przy rysowaniu przeszkód void setup(){ size(1000,500); //rozmiar okna bt=new Serial(this, "COM13", 9600); //tworzenie obiektu bt.buffer(1); //ilośc bajtów do buforowania } void serialEvent (Serial bt){ //SerialEvent odczyt = bt.read(); if(odczyt >= 115) {steps = (odczyt-115)*10; //informacja o przebytych krokach pozycja(); //odświeżenie pozycji } else {odleglosc = odczyt; //informacja o nowej przeszkodzie dots[i][0]=x_co+odleglosc*2.5*sin(ang+((float)(9-pozycja)/18)*PI); //OX dots[i][1]=-y_co-odleglosc*2.5*cos(ang+((float)(9-pozycja)/18)*PI); //OY i++;} } void draw(){ background(100); fill(255, 255, 255); rect(500, 0, 500, 500); for(int i = 0; i<21; i++) //tworzenie siatki line(500, i*25+y_co%25, 1000, i*25+y_co%25); for(int i = 0; i<21; i++){ if(i*25-x_co%25>0) line(500+i*25-x_co%25, 0, 500+i*25-x_co%25, 500);} textSize(10); fill(255, 255, 255); text("10cm", 470, 50+y_co%25); //jedna kratka 10x10cm fill(1); for(int j=0; j<=i; j++){ //wyswietlenie przeszkód if(dots[j][0] < 250-x_co && dots[j][1] < 250-y_co && dots[j][0] > -250+x_co && dots[j][1] > -250+x_co) rect(750+dots[j][0]-x_co, 250+dots[j][1]+y_co, 5, 5);} fill(0, 200, 0); //wyswietlenie robota triangle(750+10*sin(ang), 250-10*cos(ang), 750+10*sin(ang+PI*3/4), 250-10*cos(ang+PI*3/4),750+10*sin(ang+PI*5/4), 250-10*cos(ang+PI*5/4)); fill(150); //napis serwo i wskaźnik pozycji rect(50, 50, 200, 200); textSize(30); fill(255, 255, 255); text("Serwo", 60, 40); line(150, 200, 150-90*sin((float)(pozycja*10-90)/57), 200-90*cos((float)(pozycja*10-90)/57)); fill(150); //napis odległość i odczyt z czujnika odległości rect(300,50,150,50); fill(255, 255, 255); textSize(30); text("Odległość", 310, 40); text(odleglosc, 310, 90); fill(150); //przyciski do sterowania serwem rect(190,400,50,50); rect(260,400,50,50); fill(255, 0, 0); triangle(230, 440, 230, 410, 200, 425); triangle(270, 440, 270, 410, 300, 425); if(flag_up) fill(120); //sterowanie kołami else fill(150); rect(300, 150, 150, 50); if(flag_down) fill(120); else fill(150); rect(300, 300, 150, 50); if(flag_lewa) fill(120); else fill(150); rect(300, 225, 50, 50); if(flag_prawa) fill(120); else fill(150); rect(400, 225, 50, 50); if(flag_up) fill(150); else fill(255, 0, 0); triangle(350, 190, 375, 160, 400, 190); if(flag_down) fill(150); else fill(255, 0, 0); triangle(350, 310, 375, 340, 400, 310); if(flag_lewa) fill(150); else fill(255, 0, 0); triangle(340, 230, 310, 250, 340, 270); if(flag_prawa) fill(150); else fill(255, 0, 0); triangle(410, 230, 440, 250, 410, 270); fill(150); //przyciski do regulowania prędkości rect(50, 300, 50, 50); rect(50, 400, 50, 50); fill(255, 0, 0); triangle(60, 340, 75, 310, 90, 340); triangle(60, 410, 75, 440, 90, 410); fill(5); line(60, 390 - (speed*5), 90, 390 - (speed*5)); fill(150); //przycisk włącz/wyłącz autopomiar rect(150, 300, 100, 50); fill(255, 255, 255); textSize(20); if(pomiar) text("Pom. ON", 157, 340); else text("Pom. OFF", 155, 340); sterowanie(); } void sterowanie(){ //funkcja obsługi przycisków if(mousePressed && mouseX<250 && mouseX>150 && mouseY<350 && mouseY>300){ pomiar=!pomiar; //przycisk pomiar ON/OFF if(!pomiar) odleglosc=0; delay(100);} if(pomiar) licznik++; //automatyczne żądanie informacji o przeszkodach if(licznik == 50) { bt.write('7'); i++; licznik = 0;} if(mousePressed && mouseX<100 && mouseX>50 && mouseY<350 && mouseY>300 && speed<6){ speed++; //zwiększ prędkość bt.write(char(speed+80)); delay(100);} if(mousePressed && mouseX<100 && mouseX>50 && mouseY<450 && mouseY>400 && speed>1){ speed--; //zmniejsz prędkość bt.write(char(speed+80)); delay(100);} if(mousePressed && mouseX<240 && mouseX>190 && mouseY<450 && mouseY>400 && pozycja<18){ pozycja++; //obsługa strzałek do serwa bt.write(char(pozycja+100)); delay(100);} else if(mousePressed && mouseX<310 && mouseX>260 && mouseY<450 && mouseY>400 && pozycja>0){ pozycja--; bt.write(char(pozycja+100)); delay(100);} if(mousePressed && mouseX<450 && mouseX>300 && mouseY<200 && mouseY>150){ flag_up=!flag_up; //do przodu flag_down=false; flag_prawa=false; flag_lewa=false; if(flag_up) bt.write('2'); else bt.write('1'); delay(100);} if(mousePressed && mouseX<450 && mouseX>300 && mouseY<350 && mouseY>300){ flag_down=!flag_down; //do tyłu flag_up=false; flag_prawa=false; flag_lewa=false; if(flag_down) bt.write('3'); else bt.write('1'); delay(100);} if(mousePressed && mouseX<350 && mouseX>300 && mouseY<275 && mouseY>225) {flag_lewa=!flag_lewa; //obrót wokół własnej osi w lewo if(flag_lewa) bt.write('4'); else bt.write('1'); flag_up=false; flag_down=false; flag_prawa=false; delay(100); bt.write('6'); delay(100);} if(mousePressed && mouseX<450 && mouseX>400 && mouseY<275 && mouseY>225){ flag_prawa=!flag_prawa; //obrót wokół własnej osi w prawo if(flag_prawa) bt.write('5'); else bt.write('1'); flag_up=false; flag_down=false; flag_lewa=false; delay(100); bt.write('6'); delay(100);} } void pozycja() //funkcja odświeżania pozycji robota { if(flag_lewa) ang-=(float)(steps*TWO_PI)/5600; else if(flag_prawa) ang+=(float)(steps*TWO_PI)/5600; else if(flag_up){ x_co+=((float)steps*sin(ang))/40; y_co+=((float)steps*cos(ang))/40;} else if(flag_down){ x_co-=((float)steps*sin(ang))/40; y_co-=((float)steps*cos(ang))/40;} } ZASILANIE Robot zasilany jest z powerbanka umieszczonego pod sklejką. Planowałem wykorzystanie zwykłej baterii, lecz silniki krokowy pobierają razem prąd 600mA, co powodowało przerwy w zasilaniu z czterech paluszków AA. Mam nadzieję, że Wall-E spodoba się forumowiczom. Z przyjemnością publikuję jego opis na Forbocie. Mam 17 lat i rok temu zacząłem swoją przygodę z elektroniką i programowaniem, a mój pojazd jest jej efektem. W przyszłości planuję rozszerzyć jego możliwości dodając chociażby układ z rodziny ESP w miejsce Arduino, co otworzy go na IoT i zwiększy jego autonomię. Zachęcam do komentowania, jest to bezcenna możliwość do wymiany doświadczeń i opinii.
  18. Wstęp Globalizacja światowej gospodarki oraz gwałtowny rozwój techniczny w XX wieku spowodował bardzo duże udoskonalenie metod produkcji, gdzie przemysłowe innowacje pozwoliłyby na produkcję wysokiej jakości dóbr przy dążeniu do jak najniższej ceny wyrobu końcowego. Jednym z owoców tego postępu jest CNC - computerized numerical control / komputerowe sterowanie urządzeń numerycznych, opracowane w MIT w USA w roku 1949. Podstawową różnicą między obróbką ręczną a CNC jest zastąpienie pracownika sterującego maszyną, komputerem, który z wykorzystaniem czujników (indukcyjne liniały pomiarowe, przełączniki krańcowe, elementy optoelektroniczne) i urządzeń wykonawczych (silniki krokowe / serwomechanizmy / serwonapędy) będzie na bieżąco kontrolował przemieszczanie narzędzia (na przykład frezu, noża tokarskiego czy palnika plazmowego/laserowego) zgodnie z przygotowanym wcześniej na podstawie rysunku technicznego zestawem instrukcji sterujących, pozwalając, w porównaniu do metod konwencjonalnych, na uzyskanie większej wydajności, wyższej dokładności i powtarzalności przy mniejszej ilości pracowników (park maszynowy składający się z kilku obrabiarek może obsługiwać jeden programista) oraz redukcji kosztów. Założenia projektu i dane techniczne Celem projektu było zbudowanie sterowanego numerycznie plotera rysującego, który: jako końcówkę wykonawczą wykorzystywałby długopis o średnicy 10mm z możliwością wykorzystywania wkładów o różnych kolorach; w osiach X i Y, napędzanych przez silniki krokowe, posiadał możliwość przesuwu o 120mm; w osi Z, gdzie długopis poruszany przez serwomechanizm modelarski stanowiłby jednocześnie prowadnicę, posiadałby skok kilku milimetrów; wykorzystywałby w osiach X i Y innowacyjne, bezsmarowne moduły liniowe firmy Igus® DryLin®; byłby niski dzięki konstrukcji opartej o stół krzyżowy z wysięgnikiem; był względnie dokładny, z ostateczną dokładnością pozycjonowania na poziomie +/- 0,5mm. Dane techniczne: konstrukcja stołu krzyżowego z wysięgnikiem, oparta o moduły liniowe wykorzystujące prowadnice o średnicy 10mm i śrubie trapezowej o średnicy 10mm i skoku 2mm; moduły liniowe napędzane silnikami krokowymi NEMA16; śruby modułów liniowych połączone z osiami silników krokowych poprzez sprzęgła elastyczne; pole robocze – kwadrat o boku 120mm; uproszczona budowa osi Z - długopis bez możliwości precyzyjnego przesunięcia – podniesienie / opuszczenie dzięki zastosowaniu serwomechanizmu i gumki recepturki; możliwość zerowania (homing) dzięki wykorzystaniu przełączników krańcowych; własnoręcznie wykonany sterownik oparty o Arduino Nano i open-source’owe oprogramowanie GRBL; całość zasilana zasilaczem 12V o maksymalnej wydajności prądowej 4A. Mechanika i oprogramowanie Mechanika maszyny sterowanej numerycznie, poza koniecznością stosowania napędów, w których możliwe będzie zadawanie ściśle określonego przesunięcia, nie różni się wiele od tej stosowanej w konwencjonalnych maszynach. Pierwszym krokiem w przypadku „Pioneer’a” było wybranie modułów liniowych (SLW o maksymalnej długości przejazdu wózka 150mm) firmy Igus®, które pozwalają zamienić ruch obrotowy pokrętła na ruch liniowy wózka dzięki śrubie trapezowej i odpowiedniej nakrętki, zamocowanej wewnątrz wózka. Standardowo nakrętki są wykonywane ze stali nierdzewnej bądź brązu, dla których koniecznością jest smarowanie, ponadto są stosunkowo ciężkie i z biegiem czasu zużywają się. Igus® opracował innowacyjne tworzywo sztuczne iglidur®, które jest doskonałe dla nakrętek, łożysk ślizgowych i panewek pracujących przy małych i średnich obciążeniach dzięki eliminacji wspomnianych wad. Dwa takie moduły zostały ze sobą połączone w stół krzyżowy za pomocą aluminiowego elementu z blachy o grubości 1,5mm – najpierw wycięto odpowiedni prostokąt na gilotynie, następnie otwory nawiercano wiertarką kolumnową, korzystając z rysunku technicznego stworzonego w programie Solid Edge. Drugim programem CAD wykorzystanym do budowy plotera, był Google SketchUp, w którym zaprojektowane zostały wszystkie elementy drukowane później na drukarce 3D W niskobudżetowych konstrukcjach CNC stosuje się silniki krokowe, ze względu na to, że jest to najtańsza w porównaniu do prostoty sterowania opcja napędu, który pozwalałby na precyzyjne zadawanie kąta, o jaki obrócić ma się wał – wykorzystane silniki NEMA16 firmy MicroStep pobierają prąd rzędu 800mA i posiadają rozdzielczość 200 kroków na obrót – zatem pojedynczy impuls obraca wał o 1,8° (teoretycznie zatem, jeżeli skok śruby wynosi 2mm, to dokładność pozycjonowania wózka wyniesie 0,01mm). Osie silnika krokowego (średnica 5mm) i śrub (średnica 10mm) połączone są aluminiowymi sprzęgłami elastycznymi. Wykorzystane sterowniki silników krokowych to A4988 – aby wysterować silnik krokowy, potrzebne są dwa piny – DIR (kierunek obrotów) i STEP (ilość impulsów podanych na to złącze jest równa ilości kroków, o jakie przesunie się wał silnika). Pozwalają one również na tak zwane mikrokroki – w zamian za mniejszy moment obrotowy pozwalają na nawet 16-krotne zwiększenie rozdzielczości, jednak ze względu na bardzo małą odległość przesuwu wózka w osi X bądź Y po podaniu jednego impulsu na wejście STEP (wspomniane 0,01mm) nie wykorzystano tej opcji w tym projekcie (na zdjęciu sterownik wraz z radiatorem). W początkach CNC wysterowaniem step-stick’ów zajmował się bezpośrednio komputer PC, gdzie do pinów portu LPT podłączone były piny sterowników silników krokowych – nie jest to dobre rozwiązanie, gdyż komputer PC musi jednocześnie obsłużyć wiele procesów, a zatem mogą pojawić się błędy w rysowaniu krzywych (wówczas ruch osi X oraz Y musi ze sobą korelować). Wady te można wyeliminować poprzez zainstalowanie systemu operacyjnego czasu rzeczywistego, na przykład LinuxCNC, jednak w zastosowaniach niskobudżetowych optymalne jest wykorzystanie Arduino – oprogramowanie sterujące (GRBL) przesyła paczkami poprzez USB instrukcje do niego właśnie, a ono, pełniąc funkcję buforującą, wysterowuje silniki w sposób ciągły. GRBL to open-source’owe darmowe oprogramowanie rozwijane przez grupę hobbystów z całego świata, oferujące gotowy do wgrania wsad dla płytek Arduino oraz gotowy program sterujący, dostępny dla systemów Windows, Linux i Mac OS, GRBL Controller, który pozwala na zmianę ustawień sterownika, ręczny przesuw końcówki roboczej, wyzerowanie maszyny (jeżeli takowa posiada taką opcję („Pioneer” posiada), na przykład w postaci czujników krańcowych – po włączeniu plotera program nie wie, gdzie znajduje się końcówka wykonawcza, musi więc przesuwać wózki od poszczególnych osi tak długo, aż zareagują na ich obecność krańcówki – to sygnał, że wózek dojechał do początku osi), podgląd pliku G-Code oraz rzecz jasna przesłanie go do sterownika. G-Code dla prostych kształtów napisać można samodzielnie, bądź poprzez program graficzny (stosuję Inkscape z wtyczką MIGRBL – najpierw z grafiki rastrowej program pozyskuje kontur, który jest wektoryzowany). Następnie wtyczka zbiór taki konwertuje do listy punktów i zapisuje w postaci tekstowego pliku o rozszerzeniu .gcode Do mocowania kartki papieru (format A4) wykorzystano taśmę malarską – sprawdziła się w tej roli bardzo dobrze, kartka jest zamocowana pewnie i nie przesuwa się, a po zakończonym rysowaniu łatwo zdjąć ją ze stołu. Program GRBL jest przeznaczony przede wszystkim dla frezarek CNC, ale nie stanowi większego problemu wykorzystanie jako końcówki roboczej, zamiast wrzeciona ze zamontowanym frezem, długopisu. Przed pierwszym użyciem należy go skonfigurować, wprowadzając ustawienia, które są indywidualne dla każdej konstrukcji. Schemat Kilka zdjęć i rysunków Robot przeszedł lifting związany z zastąpieniem ciężkiej podstawy ze sklejki płytą ze spienionego PCV Podsumowanie Jestem bardzo zadowolony z konstrukcji, mimo niewielkich prędkości stanowi świetny model edukacyjny, doceniony został na I Edycji Konkursu "Elektronika - by żyło się łatwiej" - III miejsce oraz Konkursie Innowacji Technicznych w roku szkolnym 2017/18 - I miejsce na etapie rejonowym i wyróżnienie na ogólnopolskim Pozdrawiam, wn2001
  19. Wstęp O projekcie myślałem od czerwca poprzedniego roku, to jest 2018. Postępy prac opisywałem tu - cel projektu stanowiła budowa robota klasy SCARA - dwuosiowego ramienia robotycznego manipulującego efektorem w płaszczyźnie XY, z funkcją grawerowania laserowego oraz mini- wrzecionem modelarskim, rysowania mazakiem i pick&place realizowanym techniką próżniową. SCARA to akronim słów Selective Compliance Articulated Robot Arm, co oznacza, że robot w osiach X i Y porusza się obrotowo względem siebie i liniowo w osi Z. Dzięki temu, SCARA jest szybsza (w porównaniu do maszyny pracującej w układzie kartezjańskim), pozwala na osiągnięcie zadanego w obszarze roboczym punktu dwoma trajektoriami, a także umożliwia łatwy montaż połączony z niewielkimi rozmiarami w porównaniu do pola roboczego, który oferuje (klasyczna konfiguracja XYZ cechuje się faktem, że pole robocze musi być mniejsze od rozmiarów samej konstrukcji). Nie może natomiast przenosić dużych sił, a samo sterowanie wymaga zastosowania równań trygonometrycznych oraz interpolowania w momencie, kiedy końcówka ma wykonać ruch po linii prostej. Ponadto, roboty tej klasy cechują się mniejszą sztywnością. Całość sprawia, że ramiona robotyczne tego typu są idealne dla lekkich aplikacji, gdzie często wymagana jest szybkość, higieniczność (małe natężenie hałasu) oraz łatwość instalacji połączona z niewielką ilością miejsca, czyli w zastosowaniach "podnieś i przenieś" lub operacjach montażowych, chociaż z powodzeniem może posiadać koncówkę roboczą typową dla tradycyjnych maszyn CNC. Mechanika i elektronika Prostokątna podstawa robota o wymiarach 320x240mm została numerycznie wyfrezowana, z plexi o grubości 16mm. Otwory, służące zamocowaniu silnika oraz dysku łożyskującego I stopień swobody zostały nagwintowane gwintem M5. Wszystkie elementy 2D, które osobiście frezowałem, projektowałem w Solid Edge 2019. Najwięcej problemów miałem z przekładniami (zwiększenie momentów obrotowych silników oraz rozdzielczości (stosunek ilość kroków/obrót) oraz konieczność przenoszenia dużych sił, zgodnie z równaniem dźwigni jednostronnej) - właściwe ramię jest przymocowane do koła zębatego, które łożyskowane jest przez dysk z poliamidu (przeniesienie sił osiowych) oraz wciskane łożyska 6008RS (przeniesienie sił promieniowych). Oś koła stanowi imbusowa śruba M10, przykręcona nakrętką samohamowną z podkładką. W obydwóch stopniach swobody, przekładnie pasowe działają w oparciu o zamknięte paski zębate o module HTD 3mm, które pochodzą ze znanych robotów kuchennych "KASIA". Koła zębate, podobnie jak inne wydruki 3D, wykonano przy pomocy drukarki Zortrax M200. Wykorzystałem bardzo dobry filament ABS firmy Spectrum. Drugi stopień swobody działa i założyskowany jest identycznie z tą różnicą, iż wykorzystano jedno łożysko kulkowe, a dysk wykonano z ABS-u. Warto zaznaczyć, że każdy z uchwytów silników krokowych posiada podłużne otwory, tak zwane "fasolki", które pozwalają na regulację naprężenia paska. Średnice osi silników krokowych to odpowiednio 6,35mm oraz 5mm, niezawodne połączenie małych zębatek z gładkim wałem uzyskano poprzez wcisk na gorąco oraz ścisk dwoma śrubkami imbusowymi M3. Drugie z ramion można łatwo zmienić, w zależności od tego, jaką funkcję ma pełnić robot (na zdjęciu koncówka z modułem lasera IR 500mW). Każde z ramion ma długość 200mm, zatem maksymalny obszar roboczy konstrukcji (bez uwzględnienia faktu ograniczenia go przez wieże silników i podstawę) to koło o średnicy 800mm. Wymiana ramienia (a co za tym idzie - funkcji) jest łatwa i przyjemna, zajmuje mniej niż 5 minut. W robocie nie zastosowano czujników krańcowych, pozycję zerową ustawiam ręcznie w linii prostej. W precyzyjnym ustawieniu pozycji zerowej pomocne są specjalne znaczniki (zdjęcie poniżej), zakładane tylko na czas zerowania. Drugie zdjęcie przedstawia budowę, a trzecie - mosiężne emblematy, jakimi ozdobiłem podstawę Wykorzystałem silniki krokowe, NEMA23 i NEMA17 Osobny blok funkcjonalny robota stanowi sterownik, którego zdjęcie przedstawiono poniżej - połączenia z urządzeniami zewnętrznymi (silniki krokowe oraz efektor) zrealizowane zostały złączami JST-BEC (bądź 3-pinowym złączem 0,1" jeżeli efektorem jest serwomechanizm modelarski). Do zasilacza sterownika (1) podłączany jest przewód zasilający sieciowy. Napięcie wyjściowe wynosi 12V DC, a wydajność prądowa zasilacza to 5A. Celem sterowania robotem (kiedy nie jest wgrana zaprogramowana sekwencja ruchów) należy podłączyć przewodem USB typu B do komputera PC płytkę Arduino UNO (6), która stanowi "mózg" sterownika - podaje ona sygnały sterujące pracą silników krokowych (HY-DIV268N oraz TB6560 - odpowiednio 2 i 3), serwomechanizmu i/lub przekaźnika (7), który może załączać palnik laserowy lub elektrozawór. Płytka (5) posiada bezpiecznik, diodę - wskaźnik napięcia (na płycie znajduje się również woltomierz (9)), kondensatory chroniące przed chwilowym spadkiem napięcia zasilania oraz umożliwia podłączenie każdego modułu odpowiednio pod linię 12V DC lub 5V DC (dla logiki), za którą odpowiedzialny jest moduł stabilizatora szeregowego (8) - LM7805. Zadaniem wentylatora (4) jest chłodzenie sterowników silników krokowych. Sterownik przeszedł drobny lifting i obecnie wygląda tak, jak na II zdjęciu Software Dla funkcji rysowania, palenia laserem oraz grawerowania wykorzystano udostępniane na zasadach open-source oprogramowanie firmy Makeblock - mDraw, rozszerzony o funkcję sterowania przekaźnikiem. Natomiast dla aplikacja pick&place napisałem własny program, z funkcją odwrotnego liczenia kinematyki, oraz zamykania/otwierania elektrozaworu, co pozwala na zaprogramowanie pełnego cyklu "podnieś i przenieś". Składa się on z prostych procedur, typu PrzejdzDoPunktu(x,y), Chwyc(), Pusc(), SilownikZ(pozycja) i tak dalej. Trzecią oś swobody stanowi bowiem dla rysowania i grawerowania niewielka prowadnica podnoszona za pomocą linki przez serwo, natomiast przy chwytaniu podciśnieniowym wspomogłem się https://www.thingiverse.com/thing:3170748 Tak wygląda moduł generujący podciśnienie, wykorzystałem pompę próżniową Film - podsumowanie zawierające ujęcia z budowy oraz działania konstrukcji Robot otrzymał wyróżnienie na tegorocznych zawodach Robotic Arena oraz został zgłoszony do konkursu "Elektronika, by żyło się łatwiej". Przy okazji, pragnę podziękować mojemu sponsorowi - firmie MONDI Polska, która umożliwiła realizację całości projektu. Pozdrawiam, Wiktor Nowacki wn2001 (dla ścisłości - spostrzegawczy z pewnością zauważą rozbieżności w detalach pomiędzy różnymi zdjęciami oraz ujęciami z filmu - wykonałem je po prostu w różnym czasie, kiedy udoskonalałem jeszcze i poprawiałem konstrukcję )
  20. Witam serdecznie Chciałbym przedstawić Państwu robota mobilnego, o wdzięcznej nazwie "Drewniak". Praca ta została wykonana na potrzeby projektu "Roboty Mobilne" na Politechnice Opolskiej. Poniżej krótka prezentacja robota na filmie, w dalszej części szczegółowy opis. 1. Cel projektu. Celem projektu było stworzenie robota mobilnego zdolnego do pokonania labiryntu. Postawione wymagania przed realizacją projektu to: całkowita autonomiczność robota, brak możliwości wpływu na trajektorię podczas jazdy robota, pokonanie labiryntu w obie strony w czasie poniżej dwóch minut. Zakres prac koniecznych do wykonania w celu realizacji projektu obejmuje: zaprojektowanie konstrukcji mechanicznej oraz elektronicznej, budowa robota, stworzenie oprogramowania robota, wykonanie testów potwierdzających poprawność działania konstrukcji. Na poniższym rysunku przedstawiono zwymiarowany schemat labiryntu, który musi zostać pokonany przez projektowanego robota. 2. Budowa układu mechanicznego, napędy Do stworzenia platformy jezdnej robota zdecydowano się na użycie materiałów drewnianych. Podwozie wykonane zostało z płyty pilśniowej oraz przymocowanych do nich drewnianych listew. Rzeczywiste wymiary platformy jezdnej robota to: 18 cm długości, 12 cm szerokości, oraz 5,5 cm wysokości, mierząc od podłoża do platformy podwozia. Robot napędzamy jest dwoma silnikami DC o następujących parametrach: napięcie zasilania od 5 V do 7 V, pobór prądu w stanie „bez obciążenia” około 180 mA, prędkość obrotowa za przekładnią: ok. 80 obr/min, moment obrotowy za przekładnią: ok. 0,5 kg*cm (0,049 Nm). Dodatkowo, kompletny zespół napędowy wyposażony jest w przekładnię o przełożeniu 48:1, a także koła wykonane z materiałów sztucznych o średnicy 65 mm oraz szerokości 26 mm. Ostatnim elementem zestawu napędowego robota jest prototypowe koło samonastawne, stworzone z zestawu klocków „Lego”, zapewniające trzeci punkt podparcia robota. Na poniższych rysunkach ukazano podwozie robota wraz z przymocowanymi napędami. 3. Budowa układu elektronicznego 3.1. Układ zasilania Na układ zasilania konstrukcji robota składają się cztery ogniwa litowo-jonowe, pozyskane ze starej baterii laptopa. Pojemność jednego ogniwa wynosi 2200 mAh. Ogniwa połączono równolegle. Uzyskano w ten sposób źródło zasilania o napięciu równym od 3 do 4,2 V, w zależności od stanu naładowania ogniw, oraz pojemności ponad 8000 mAh. W celu zabezpieczenia ogniw przed nadmiernym rozładowaniem oraz możliwości ich ładowania, zastosowano układ ładowarki akumulatorów jedno-celowych z zabezpieczeniem o oznaczeniu TP4056. Napięcie ładowania ogniw wynosi 4,2 V, maksymalny prąd ładowania to 1000 mA. Zabezpieczenie przed rozładowaniem ogniw poniżej napięcia równego 2,5 V, oraz przed poborem prądu ponad 3 A. Zastosowane rozwiązanie pozwala na ciągłe pobieranie prądu równego 3 A przez niespełna 3 godziny, bez uwzględniania strat. Aby podnieść napięcie zasilania do poziomu napięcia równego 7 V (maksymalne napięcie zasilania zastosowanych silników), użyto regulowanej przetwornicy impulsowej Step-Up o oznaczeniu XL6009E1. Jej napięcie wejściowe wynosi od 3 do 30 V, natomiast możliwe do regulacji napięcie wyjściowe od 5 do 35 V. Maksymalny prąd wyjściowy równa się 3 A, a sprawność układu zawiera się na poziomie 80-94%. Napięcie wyjściowe z przetwornicy zostało doprowadzone do sterownika silników oraz układu z mikroprocesorem. 3.2. Sterownik silników W celu precyzyjnej kontroli prędkości oraz kierunku obrotu silników napędowych, zastosowano dwukanałowy sterownik silników prądu stałego o oznaczeniu L298N. Pozwala on na pobór prądu maksymalnego przez silniki do 2 A na kanał, przy maksymalnym napięciu zasilania równym 12 V. Sterownik posiada wbudowany regulator napięcia 5 V, do zasilania części logicznej. 3.3. Czujniki odległości Aby możliwe było określenie położenia robota mobilnego, zdecydowano się na wykorzystanie dwóch analogowych czujników odległości firmy Sharp. Pierwszy z nich, o oznaczeniu GP2Y0A41SK0F i zakresie pracy od 4 do 30 cm, został umieszczony na prawym boku platformy jezdnej, pozwalając tym samym na określenie jej odległości od prawej ściany. Drugi czujnik, o oznaczeniu GP2Y0A21YK0F i zakresie pracy od 10 do 80 cm, został umieszczony na przodzie platformy jezdnej. Jego zadaniem jest wykrywanie przeszkody w postaci ściany przez robotem w momencie, gdy tunel zakręca w lewo pod kątem większym bądź równym 90 stopni. Czujniki zasilane są napięciem z zakresu od 4,5 do 5,5 V, ich średni pobór prądu to 30 mA. Wyjściem jest sygnał analogowy, którego wartość zależna jest od odległości pomiędzy wykrytym obiektem a sensorem. Im obiekt znajduje się bliżej, tym napięcie na wyjściu jest wyższe. 3.4. Mikrokontroler sterujący Jako jednostkę sterującą układem wybrano mikrokontroler AVR Atmega328 w obudowie do montażu przewlekanego DIP. Jest to ośmiobitowy mikrokontroler, posiadający 23 programowalne układy wejścia-wyjścia. Oferuje on 32 KB programowalnej pamięci Flash, 1 KB pamięci EEPROM, a także 2 KB pamięci SRAM, natomiast maksymalna częstotliwość taktowania wynosi 20 MHz przy użyciu zewnętrznego rezonatora kwarcowego lub 8 MHz przy użyciu wbudowanego. Na potrzeby projektu stworzono płytkę PCB metoda termotransferu, zawierającą opisywany mikrokontroler, wraz z niezbędnymi do jego poprawnej pracy elementami, tj. stabilizator napięcia 5 V, kondensatory i rezystory filtrujące zasilanie, rezonator kwarcowy o częstotliwości 16 MHz, dwie kontrolne diody LED, złącza na moduł Bluetooth, złącza na czujniki odległości, złącza do wyprowadzeń sterownika silnika. 4. Oprogramowanie mikrokontrolera Program sterujący mikrokontrolerem napisany został w języku C++ z użyciem środowiska Arduino. Następnie, po jego skompilowaniu, wgrano wsad do pamięci mikroprocesora. Użycie środowiska Arduino pozwoliło na łatwiejsze zaprojektowanie oprogramowania z racji dostępności wielu bibliotek, które w łatwy sposób można zaimportować do projektu. Działanie programu można zobrazować za pomocą poniższego schematu blokowego. W kodzie programu, na samym początku zadeklarowano odpowiednie pliki nagłówkowe, zdefiniowano stałe oraz zmienne globalne, które wykorzystywane są podczas działania oprogramowania. Zadeklarowano również obiekt FastPID, odpowiedzialny za użycie biblioteki regulatora PID. W funkcji setup() znalazły się inicjalizacje kolejnych modułów mikrokontrolera, tj. modułu ADC, mierzącego analogowe napięcie, oraz modułu PWM, pozwalającego wygenerować sygnał o zmiennym wypełnieniu. Ustalono również stany na pinach wyjściowych oraz zainicjalizowano moduł obsługujący komunikację szeregową UART, w celu przesyłania podstawowych informacji o pracy mikrokontrolera. W funkcji loop(), czyli w głównej pętli programu, na samym początku algorytmu sprawdzany jest czas, w celu odmierzenia 25 milisekund, za pomocą wbudowanej funkcji millis(). Następnie, po jego upływie, dokonuje się odczyt wartości analogowej napięcia z czujników Sharp. Wyznaczana jest odległość w milimetrach dla czujnika umiejscowionego z prawej strony robota, za pomocą własnej funkcji. Kolejno obliczany jest uchyb, a następnie dane przekazywane są do funkcji regulatora PID. W kolejnej części funkcji loop() sprawdzane jest, czy przed robotem nie ma przeszkody w postaci ściany. Odległość z przodu robota nie została przeliczona na jednostki miary, a jedynie ustalono pewną stałą „granicę”, po której przekroczeniu platforma jezdna skręca maksymalnie w lewo. Jeśli „granica” nie została przekroczona, wykonuje się regulacja za pomocą PID. Dodatkowo zadeklarowano przesyłanie podstawowych informacji, m.in. wartości z obu modułów ADC, wyznaczonej odległości, uchybu, za pomocą interfejsu UART, w celu kontrolowania działania programu mikrokontrolera. Wlutowane w płytkę diody również sygnalizują w odpowiedni sposób o poprawnym działaniu programu. Program mikrokontrolera nie może się zakończyć. Działa nieprzerwanie, aż do zaniku zasilania. Dzięki takiemu rozwiązaniu, robot jest w pełni autonomiczny. 5. Wnioski Celem projektu było stworzenie robota mobilnego zdolnego do pokonania labiryntu bez ingerencji użytkownika w tor jazdy, podczas jego pokonywania. Cel ten został osiągnięty, jednak podczas pracy natknięto się na kilka problemów. Przede wszystkim użyte silniki napędowe okazały się być średniej jakości. Po ustawieniu identycznego wypełnienia dla sygnału PWM dla obu silników, ich prędkości obrotowe znacznie się różniły. Jednak zastosowanie regulatora PID pozwoliło na odpowiednie kontrolowanie toru jazdy platformy robota mobilnego. Parametry regulatora PID zostały dobrane podczas przeprowadzanych testów. Wzmocnienie członu proporcjonalnego ustalono na wartość 1.30, wzmocnienie członu różniczkującego na wartość 2.15, natomiast wzmocnienie członu całkującego na wartość 0. W konstrukcji tego typu, gdzie zachodzi potrzeba szybkiego działania regulatora, człon całkujący mógłby wprowadzić niechciane opóźnienie w układzie regulacji. Robot pokonuje labirynt w czasie niecałych 30 sekund, co jest bardzo dobrym wynikiem. Stworzenie własnej konstrukcji, układu elektronicznego oraz oprogramowania wymagało dużego nakładu pracy, jednak końcowy efekt daje wiele satysfakcji. Ostateczna forma robota mobilnego została przedstawiona na poniższym rysunku. Projekt i wykonanie: Jakub Kinder / Politechnika Opolska 2019. Wszelkie prawa zastrzeżone! Kopiowanie, powielanie i wykorzystywanie zdjęć bez pisemnej zgody autora zabronione!
  21. Jest to mój pierwszy projekt opisany na tym forum, ale także pierwszy projekt oparty na Arduino. Projekt został stworzony w czerwcu ubiegłego roku. Celem tego projektu było stworzenie prostego pojazdu sterowanego za pośrednictwem modułu Bluetooth za pomocą telefonu. Elektronika Projekt został oparty o płytkę Arduino Nano, wybrałem tą płytkę ponieważ jej klony są tanie i nie wymaga dodatkowego programatora. Komunikacja z pojazdem jest prowadzona za pośrednictwem modułu HC-06, przy wyborze zastanawiałem się między modułem HC-06 a HC-05 ale wybrałem ten pierwszy ze względu że nie ma specjalnie różnicy w cenie i daje teoretycznie więcej możliwości (których i tak nie wykorzystałem). Moduł Bluetooth działa w logice 3,3V, więc potrzebny jest konwerter poziomów logicznych (link), ponieważ Arduino działa w logice 5V. Podłączenie bezpośrednio modułu do Arduino mogło by skutkować jego uszkodzeniem. Do sterowania silnikami wykorzystuje sterownik oparty o układ L298n , jest to podwójny mostek „H” który pozwala na sterowanie dwoma silnikami , zasilonymi napięciem max. 12V i pobierającymi prąd max. 2A, pozwala także na sterowanie prędkością za pomocą sygnału PWM. Zupełności mi to wystarczy i w przypadku chęci zastosowania mocniejszych silników jest taka możliwość, z racji chęci maksymalnego uproszenia programu nie zastosowałem tu modulacji PWM do sterowania prędkością. Pojazd jest zasilany z jednej baterii Li-pol o napięciu znamionowym 7,4V i pojemności 2000mAh. Mechanika Zastosowałem silniki z przekładnią kątową w raz z kołami . I teraz mała dygresja i porada dla początkujących, nie kupujcie klonów oryginalnych kuł Pololu, ponieważ może się to skończyć tym że będą one krzywe. Osobiście kupiłem zestaw taki jak w linku powyżej, ale nie oryginalny Pololu. Felgi i opony były obdzielone od siebie podczas transporcie. Opony przyszły do mnie zgniecione co po założeniu je na felgi powoduje że nie są idealnie okrągłe i uniemożliwia to jechania prosto ponieważ pojazd samoistnie skręca. Podwozie pojazdu zostało wydrukowane na drukarce 3d z PLA w mojej szkole. Aby podczas druku nie było potrzeby stosowania podpór, podwozie zostało wydrukowane z dwóch części, a następnie skręcone śrubami i nakrętkami M3. Podwozie było projektowane za pomocą strony Tinkercad od Autodesku. Przednie koło to koło obrotowe z marketu budowlanego, generalnie sprawuje się dobrze, ale przy większych nierównościach zdarzyło mi się że pojazd się przewrócił. Oprogramowanie Do komunikacji z modułem Bluetooth nie jest wymagana implementacja żadnej biblioteki, ponieważ jest ona realizowana poprzez piny UART Rx i Tx. Na płytce podłączyłem piny Rx i Tx ale do komunikacji jednostronnej wystarczy poda łącznie pinu Rx Arduino do Pinu Tx modułu. Kiedy pisałem ten kod nie miałem specjalnie wiedzy na temat programowania więc program nie jest zoptymalizowany i zawiera trochę błędów, ale działa. Podstawowym błędem jest to że gdy gdzieś na drodze sygnału między Arduino a telefonem pojawi się błąd lub przerwa to dochodzi do „zacięcia” i pojazd wykonuje ostatnią zadaną czynność więc jeżeli będzie to np.: jazda do przodu to będzie on cały czas jechać do przodu. char Data = 0; void setup() { Serial.begin(9600); pinMode(8,OUTPUT); pinMode(9,OUTPUT); pinMode(10,OUTPUT); pinMode(11,OUTPUT); } void loop() { Data=Serial.read(); //odbiór danych z BT if (Data == 'n') { // jezeli wcisniete "przod" to do przodu digitalWrite(8, HIGH); //prawy silnik przod ON digitalWrite(10, HIGH); //lewy silnik przod ON } if (Data == 's') { //jezeli tył digitalWrite(9, HIGH); // prawy silnik tył ON digitalWrite(11, HIGH);// lewy silnik tył ON } if (Data == 'w') { // jezeli lewo digitalWrite(8, HIGH); // prawy silnik przod ON digitalWrite(11, HIGH); // to lewy silnik tył ON } if (Data == 'e') { // jezeli prawo digitalWrite(9, HIGH); // prawy silnik tył ON digitalWrite(10, HIGH); // lewy silnik przod ON } if (Data == '0') { // jezeli nic nie wcisnięte to stoj digitalWrite(8, LOW); digitalWrite(9, LOW); digitalWrite(10, LOW); digitalWrite(11, LOW); } } Aplikacja Do sterowania pojazdem używam aplikacji stworzonej za pomocą strony App Inventor. W Internecie można znaleźć wiele poradników jak stworzyć za pomocą niej aplikacje. Program tworzy się za pomocą łączenia ze sobą odpowiednich bloków. Podsumowanie Jak na mój pierwszy projekt na Arduino i pierwszy pojazd sterowany przez Bluetootha i nie zbudowany z klocków Lego to jestem z niego bardo zadowolony. Najważniejsze że działa. Na otwartej przestrzeni udało mi się uzyskać zasięg powyżej 50m. Nie mierzyłem poboru prądu więc ciężko jest mi oszacować jaki ma czas działania na jednym ładowaniu baterii. Pozdrawiam i zachęcam do zadawania pytań i chętnie usłyszę jakąś konstruktywną krytykę i porady na przyszłość. Na koniec jeszcze jedno zdjęcie całego pojazdu:
  22. Cześć wszystkim! Chciałbym przedstawić swój pierwszy projekt DIY - Szymek V1. Sam projekt powstał w celach poszerzenia horyzontów i mogę szczerze powiedzieć, że faktycznie wiele się z niego nauczyłem. Kilka słów wstępu o samym projekcie: Szymek V1 jest pojazdem RC opartym o arduino nano. Jak do tej pory posługiwałem się arduino jednakże nigdy nie używałem go do komunikacji między dwoma mikrokontrolerami, więc projekt nie mógł obejść się bez stworzenia odpowiedniego pilota. Od niedawna zacząłem przygodę z drukiem 3D, wobec tego postanowiłem, że większość elementów musi być drukowana. Zaprojektowałem układ w programie Eagle, jednakże stwierdziłem, że nie będę wytrawiał płytki PCB a wykonam ją w technice montażu przewlekanego THT. Wykonałem płytki zarówno dla pojazdu jak i pilota. Podstawę na której opierała się cała konstrukcja pojazdu wykonałem z plexy, którą wyciąłem laserem. Do komunikacji między pilotem a pojazdem posłużyły mi moduły radiowe NRF24L01, które mimo swojej niskiej ceny zadziwiały mnie swoją efektywnością i zasięgiem. Do zasilania natomiast użyłem 2li-jonów które zasilały silniki i serwo służące do skręcania przednią osią pojazdu, kontroler był zasilany z koszyka czterech zwykłych paluszków 1,5V. Do sterowania silnikami posłużyłem się gotowym sterownikiem l298n, którego z pewnością wykorzystam w kolejnych projektach. Jak wspomniałem, położyłem nacisk na druk 3D, wobec tego większość elementów została wydrukowana: Do wykonania projektu użyłem następujących elementów: 2x Arduino nano 2x Silnik DC z enkoderem Serwo Sterownik silników l298n 2x Moduł radiowy NRF24L01 Joystick ze starej maszyny pomiarowej 2 akumulatorki li-jon 8x paluszki 1,5V Czujnik odległości HC-SR04 Wyświetlacz 4x20 Buzzer Stabilizator liniowy 3,3V, oraz 5V Użyłem silników z enkoderami ze względu na to, że chciałem aby był dokonywany pomiar prędkości. Jednakże jakość użytych enkoderów nie pozwalała na dokładny pomiar, ponieważ wkradały się szumy. Wobec tego zastosowałem w kodzie filtr uśredniający uzyskane pomiary. Poza tym wykorzystałem czujnik ultradźwiękowy do pomiaru odległości aby pojazd miał możliwość jazdy "autonomicznej". I tak: stworzyłem interfejs wyświetlający na ekranie pilota prędkość pojazdu, oraz odległość do najbliższej przeszkody. Z racji tego, że impulsy enkodera wywoływały przerwania w arduino, dodałem także możliwość wyłączenia trybu monitorującego prędkość. Menu było obsługiwane z poziomu dwóch tactswitchów umieszczonych na pilocie, a wciśnięcie któregokolwiek powodowało, że buzzer generował charakterystyczny dźwięk dla danego guzika. W rezultacie Szymek V1 prezentuje się następująco: SzymekV1 w akcji Link do kodu Niestety los chciał, że jestem na wyjeźdze a pojazd zostawiłem domu, więc więcej bardziej szczegółowych (szczególnie z finalnej wersji pojazdu i pilota) zdjęć dodam na dniach.
  23. Witam! Chciałbym przedstawić wam moją konstrukcję, która stała się przedmiotem mojej pracy inżynierskiej. Mechanika: Konstrukcja mechaniczna w zasadzie oparta jest na 2 płytkach PCB. Do płytki głównej zamontowane są dwie kulki podporowe, a także silniki pololu o przekładni 1:10 co stanowi napęd robota. Z przodu zamontowana jest płytka z podstawą zawierająca uchwyty do czujników ultradźwiękowych. Taki sam uchwyt pod czujnik znajduje się również na 'ogonie' robota - jest on nie używany i został zamontowany eksperymentalnie. Na przedłużonej osi silników zostały zamontowane magnesy enkoderów magnetycznych co ilustruje poniższa fotografia. Elektronika: Sercem robota jest mikrokontroler AVR ATmega162, którego zadaniem jest sterowanie robotem w tym: obsługa enkoderów, sterowanie silnikami, odbiór informacji z mikrokontrolera slave nt. odległości mierzonych przez czujniki, realizację algorytmów sterowania, realizacja połączenia bluetooth, obsługa wyświetlacza LCD hd44780. Drugi mikrokontroler również AVR, ATmega328 realizuje tylko i wyłącznie obsługę czujników odległości HC-SR04. Pomiary normalizuje i wysyła interfejsem SPI do jednostki głównej ATmega162. Na pokładzie robota znajdują się również dwa enkodery magnetyczne AS5040 pracujące w pętli sterowania regulatora PI silników. Enkodery te pracują w trybie defaultowym czyli wyjście kwadraturowe, rozdzielczość 2x256. Silniki sterowane są poprzez mostek H L293. Komunikacją z robotem zajmuje się moduł bluetooth bt222 - czyli komunikacja jest przez UART mikrokontrolera. Główny mikrokontroler jest taktowany zewnętrznym kwarcem 16Mhz co przy takiej ilości obsługiwanych urządzeń i wykorzystywanych interfejsów było po prostu konieczne, z kolei mikrokontroler atmega328 jest taktowany zewnętrznym kwarcem jednak z powodu lepszej podstawy czasowej, która jest konieczna do dokładnych odczytów z czujników odległości. Na wyświetlaczu LCD są wyświetlane aktualnie mierzone wartości odległości czujników. Automatyka: Zostało wspomniane, że silnikami steruje algorytm regulatora PI. Aby obliczyć jego nastawy została przeprowadzona identyfikacja transmitancji. W tym celu wykorzystałem UART do przesyłania aktualnej prędkości silników oraz środowisko Matlab do wizualizacji danych na wykresie. Z wyliczeń wyszło, że silniki z zastosowanymi kołami mają transmitancję: G(s)=107/(0.19s+1) Po obliczeniu nastaw regulatora i zastosowaniu w praktyce okazało się, że można jeszcze troszkę dopieścić nastawy i ostatecznie wykresy odpowiedzi skokowej bez i z regulatorem wyglądają następująco: Software: Napisane w C w środowisku Eclipse. Umożliwia robotowi 3 tryby. Tryb avoid. W trybie tym robot ma za zadanie omijać przeszkody wykorzystując regulator rozmyty Takagi-Sugeno. Wykorzystuje w tym celu odczyty z czujników odległości. Tryb goal seeking. Robot podąża do celu czyli do odebranych przez bluetooth współrzędnych kartezjańskich podanych w [mm], zakładając, że miejsce od którego zaczyna lub dostał nowy zestaw współrzędnych, ma współrzędne 0,0. W trybie tym regulator Takagi-Sugeno ma za zadanie na podstawie zaimplementowanej odometrii oraz współrzędnych końcowych sterować robotem w celu osiągnięcia zadanego położenia. Problem algorytmu przedstawia ilustracja: Tryb avoid + goal seeking. Jest to połączenie dwóch wcześniej opisanych trybów. W trybie tym działają równocześnie obydwa wcześniej opisane algorytmy, jednak na wejście regulatorów PI sterujących silnikami jest podawany zbalansowany sygnał z obu algorytmów. Tzn w zależności od najmniejszej odległości od przeszkody mierzonej przez któryś z czujników jest obliczany procentowy udział wartości sterowania od dwóch algorytmów. Brzmi skomplikowanie ale takie nie jest. Najlepiej zobrazuje to wzór: V=K*Vg+(1-K)*Va gdzie V jest prędkością zadaną na regulator PI silnika, Vg jest prędkością wynikającą z algorytmu goal seeking, Va jest prędkością wynikającą z algorytmu avoid, K jest parametrem, który przyjmuje wartość z przedziału 0-1 w zależności od mierzonej minimalnej odległości do przeszkody. Robota wprowadza się w odpowiedni tryb za pomocą dwóch przycisków lub poprzez interfejs bluetooth. Odpowiednie tryby sygnalizują diody LED. W celu przesłania komendy zawierającej współrzędne celu najpierw należy wprowadzić robota w odpowiedni tryb, a następnie wysłać do niego wg stworzonego prze zemnie protokołu dane. Protokół wysyłania danych jest następujący: X±⌴⌴⌴Y±⌴⌴⌴& gdzie +- – znak współrzędnej, _ – wartość współrzędnej. Testy. Konstrukcja została przetestowana pod względem dokładności odometrii. Robot podczas licznych testów na bieżąco wysyłał swoje współrzędne, które w dalszej kolejności były obrabiane w środowisku Octave do przyjemnych w analizie wykresów. Przykładowy wykres drogi, którą pokonał robot na 'placu manewrowym' w trybie avoid: ... oraz rzut z góry na 'plac manewrowy': U góry pozycja początkowa, na dole końcowa robota. Cały ten obszar był dookoła ogrodzony ścianką. Słowa samokrytyki Co bym zmienił ? Czujniki. Ze względu na problematyczność wykrywania małych przeszkód lub gdy płaszczyzna przedmiotu uniemożliwia odbicie się fali ultradźwiękowej w stronę odbiornika. Zdarza się, że z powodu gubienia przeszkód robot po prostu w nie wpada. Najciekawsze fragmenty programu: Regulatory PI: //######################################## REGULATOR PRĘDKOŚCI ############################################ erra = vl-Va;//liczenie błedu prędkości errb = vp-Vb; if(ua<1023&&ua>-1023)Ca = Ca+(erra*dt);//całka błędu ua = kp*(erra + Ca/Ti);//regulator PI //P I if(ub<1023&&ub>-1023)Cb = Cb+(errb*dt);//całka błędu ub = kp*(errb + Cb/Ti);//regulator PI //P I if((ua<10)&&(ua>-10))ua=0; if((ub<10)&&(ub>-10))ub=0; motor_set(ua,ub);//ustawia sterowanie silników Regulator rozmyty Takagi-Sugeno trybu goal seeking: inline void PsiZ2Vlr(float *Psi, float *z, int16_t *vl,int16_t *vp) { float PSI[3]; float XL[6],XR[6]; float NR,FR,L,S,P,VL=0,VP=0,m=0; uint8_t i,k; ///////////////////////////////LICZENIE PRZYNALEŻNOŚCI////////////////////////////////// if(*z<=100)NR=-0.01*(*z)+1;else NR=0;//jak bardzo blisko jest cel if(*z<=100)FR=0.01*(*z);else FR=1;//jak bardzo daleko jest cel if(*Psi<=0)L=-0.3183*(*Psi);else if(*Psi<-M_PI)L=1;else L=0; if(*Psi<=0)S=0.3183*(*Psi)+1;else if(*Psi<-M_PI)S=0; else if(*Psi>M_PI)S=0;else S=-0.3183*(*Psi)+1; if(*Psi>=0)P=0.3183*(*Psi);else if(*Psi>M_PI)P=1;else P=0; /////////////////////////////////////TABLICA REGUŁ////////////////////////////////////// PSI[0]=L; PSI[1]=S; PSI[2]=P; //NR; XL[0]=-4000;XR[0]=4000; XL[1]=0;XR[1]=0; XL[2]=4000;XR[2]=-4000; //FR; XL[3]=-4000;XR[3]=4000; XL[4]=4000;XR[4]=4000; XL[5]=4000;XR[5]=-4000; /////////////////////////////obliczanie prędkości silników////////////////////////////// for(k=0,i=0;k<3;k++,i++)//pierwszy wiersz tabeli { VL+=NR*PSI[k]*XL[i]; VP+=NR*PSI[k]*XR[i]; m+=NR*PSI[k]; } for(k=0;i<6;k++,i++)//drugi wiersz tabeli { VL+=FR*PSI[k]*XL[i]; VP+=FR*PSI[k]*XR[i]; m+=FR*PSI[k]; } *vl=(int16_t)VL/m; *vp=(int16_t)VP/m; } Obsługa czujników odległości: //PRZERWANIE OD CAPTURE PIN ISR(TIMER1_CAPT_vect) { if( (TCCR1B & (1<<ICES1)) ) { LastCapture = ICR1;//jesli zbocze narastajace, zlap ICR1 } else { PulseWidth = ICR1 - LastCapture;//Jeśli zbocze opadajace oblicz PW pomiar=0;//wyzeruj flagę pomiaru } TCCR1B ^= (1<<ICES1);//Zmiana zbocza wyw. przerwanie } Mam nadzieję że robocik się podoba. W razie pytań proszę śmiało. Całości kodu nie udostępniam ze względu na prawa autorskie niektórych funkcji bibliotecznych. Co mogłem udostępniłem. Pozdrawiam was wszystkich !
  24. Ponad dwa lata temu opisałem projekt moich uczniów, wtedy gimnazjalistów o nazwie TankGim. Obecnie chłopcy są w klasie maturalnej i dalej bawią się Arduino. W klasie pierwszej LO powstał pojazd „Jamnik”, a w drugiej projekt edukacyjny „EduBoty”. A co to te EduBoty? Głównym założeniem projektu było zrobienie pomocy dydaktycznej – robotów, które można wykorzystać na różnych lekcjach. Wybór padł na geografię, ale w planach są plansze do innych przedmiotów. Używanie nowoczesnych technologii uatrakcyjnia lekcje i wzbudza ciekawość uczniów. Dodatkowym czynnikiem motywującym do nauki przy korzystaniu z EduBotów jest rywalizacja uczniów o zwycięstwo. Łączenie zabawy i nauki prowadzi do szybkiego rozwoju młodych ludzi. Na czym polega zabawa? Na mapie świata trzeba wskazać wylosowaną stolicę. Za wskaźnik służą małe roboty sterowane przez uczniów. Wyścig odbywać się może w trzech trybach: uczeń vs uczeń, uczeń vs czas, uczeń vs robot autonomiczny (ta opcja jeszcze nie działa). Model robota EduBot to pojazd gąsienicowy zbudowany na bazie podwozia robota Zumo firmy Pololu. Nadwozie i dodatkowe elementy zaprojektowaliśmy w SkechUp i wydrukowaliśmy. Komunikacja robot - plansza W mapie umieszczone są fotorezystory i elektromagnesy, a w robocie dioda laserowa i kontaktron. Zaświecenie w odpowiedni fotorezystor powoduje włączenie elektromagnesu, a pole magnetyczne zamyka kontaktron i robot otrzymuje punkt, co sygnalizują diody umieszczone na robocie. Komunikacja robot – uczeń Do komunikacji z EduBotem postanowiliśmy postawić na dobrze sprawdzającą się w tego typu projektach drogę radiową. W tym celu zastosowaliśmy zestaw GamePad który jest łatwym rozwiązaniem, a przy okazji podkreśla rozrywkowo-edukacyjny charakter robotów. Dzieci w szkołach podstawowych znają ten kontroler i nauczyciel nie musi poświęcać dużo czasu na tłumaczenie zasad działania. Zasilanie i elektronika EduBota Zasilanie standard – akumulator Li-Pol 2s + przetwornica. W padzie dwie baterie AAA. Robot to Arduino Nano, dwukanałowy sterownik silników TB6612FNG oraz wcześniej wspomniane dioda laserowa, kontaktron, 6 diod led i odbiornik od GamePada. Mapa „Pożyczyliśmy” mapę świata z sali od geografii (mam nadzieję że geograf się o nią nie upomni), umieściliśmy w niej czujniki i elektromagnesy, połączyliśmy to z Arduino Mega i wyświetlaczem LCD. Gdzieś po drodze były też przekaźniki. Wnioski i zmiany w projekcie – ewaluacja w belferskim żargonie Są dwa główne problemy. Trafienie światłem diody w fotorezystor wymaga dużej precyzji, zbyt dużej dla uczniów, którzy stoją nad mapą i widzą wszystko z odległości około 2 metrów. Mapa musi być mobilna, trzeba ją zwinąć i schować do szafy po lekcji, a elektromagnesy umieszczone pod nią to uniemożliwiają. Obecnie projekt jest przerabiany. Zamiast diody i kontaktronu użyjemy czytników RFID i tagów. Natomiast elektromagnesy zastąpi jeden nadajnik radiowy i odbiorniki w robotach. Kasa na takie projekty Realizacja takich projektów wymaga środków finansowych. Nawet jeśli dyrektor je znajdzie i przyzna, to nie chce później słyszeć, że coś trzeba zmienić lub że się popsuło (kupić jeszcze raz - chyba żart). Mamy to szczęście, że w województwie podlaskim działa Stowarzyszenie Odkrywców Diamentów, które dwa razy w roku przyznaje środki na realizację ciekawych projektów uczniowskich. Dla zainteresowanych : http://odkrywcydiamentow.com.pl/aktualnosci/ Osiągnięcia - tytuł laureatów eliminacji okręgowych XI edycji Ogólnopolskiego Konkursu o Tytuł Młodego Innowatora; - III miejsce w Międzynarodowych Zawodach Robomotion w Rzeszowie - kategoria freestyle; - tytuł laureatów eliminacji okręgowych w Olimpiadzie Innowacji Technicznych i Wynalazczości w kategorii pomoc dydaktyczna; - Nagroda Bydgoskiego Parku Naukowo – Technologicznego oraz tytuł Młodego Naukowca w konkursie E(x)plory; - Stypendium Prezydenta Miasta Białegostoku za innowacyjną myśl techniczną. Więcej o projekcie: https://eduboty.wixsite.com/home/realizacja-projektu
  25. Witam, przedstawiam wam projekt, nad którym pracowałem przez ostatni rok. Jest to manipulator 5-osiowy zbudowany w oparciu o płytkę Arduino Uno. Mechanika Podstawę wykonałem ze sklejki oraz dwóch desek przykręconych wkrętami. Reszta ramienia jest zrobiona z plexi o grubości 3mm. Przy podstawie zamontowałem również trzy małe kółka dla stabilizacji. Serwa jakich użyłem to TowerPro MG946R oraz Redox S90. Elektronika Mózgiem robota jest płytka Arduino Uno z napisanym przeze mnie programem. Ramieniem steruje się za pomocą płytki z potencjometrami 1k, którą samodzielnie zaprojektowałem i wykonałem. W przyszłości planuję na pewno udoskonalić chwytak i być może dodać kolejne serwo, żeby się obracał. Zdjęcia: Filmik:
×