Przeszukaj forum
Pokazywanie wyników dla tagów 'robot'.
Znaleziono 37 wyników
-
- kilka razy w tygodniu jestem napastowany tym komunikatem. - wcześniej pojawia się komunikat " potwierdz że nie jesteś robotem" i jakiś obrazek do wykonania. - jednak obecnie cześciej jestem blokowany. - wysyłam jakieś wyjaśnienia do alegro i zwykle mnie po czasie odblokują. - przeglądarka to Avast Browser, czyszczenie komputera realizuje program Fortect., system to Win 10 Pro SP2. - czy jednym wyjściem jest zrezygnować z alegro i przejść na amazon ?
- 6 odpowiedzi
-
- robot
- blokada alegro
-
(i 1 więcej)
Tagi:
-
Niejednokrotnie tworząc różne roboty, maszyny oraz platformy terenowe, miałem do czynienia z łączeniem wielu modułów lub tworzenia prowizorycznych układów na płytkach uniwersalnych. Problem pojawiał się na tyle regularnie, że postanowiłem wykonać układ umożliwiający w zasadzie bezpośrednie podłączenie napędu oraz jego obsługę za pomocą modułu NRF24L01. Uniwersalny sterownik robotów to płytka oparta na Atmega328AU, która umożliwia sterowanie radiowe dwoma silnikami DC oraz 6 portami IO. Układ jest rozpoznawany przez komputer jako Arduino Nano, dzięki czemu jest wygodny w obsłudze oraz kompatybilny ze środowiskiem Arduino IDE. W PROJEKCIE WYKORZYSTANO MIĘDZY INNYMI: Mikrokontroler Atmega328P-AU, Złącze USB B SMD, Diody LED statusowe zielone 0603, Moduł radiowy NRF24L01, Złącza XT30 M, Złącza ARK 2pin 5mm, Oscylator 12MHz, Oscylator 16MHz, Stabilizator 3V3, Stabilizator 5V, PEŁNA LISTA KOMPONENTÓW BOM: FUNKCJE SPRZĘTOWE STEROWNIKA: ⦁ Wbudowane złącze zasilania XT30 przyjmujące maksymalnie 28V DC, ⦁ Złącze włącznika, ⦁ Wbudowane statusowe diody zasilania, ⦁ Konwertery napięcia 5V oraz 3,3V, ⦁ Listwę zasilającą 5V, ⦁ Przycisk reset, ⦁ Wbudowane dwa mostki H - BD62130AEFJ-E2, ⦁ Wyprowadzenie pod moduł nrf24l01, ⦁ 6 portów IO (2x PWM, 4x ADC, 1xI2C), ⦁ Komunikacja przez mini USB B, ⦁ Komunikacja przez SPI, ⦁ Komunikacja przez I2C, STEROWANIE SILNIKA DC: Obsługa silników szczotkowych odbywa się za pomocą dwóch zintegrowanych z PCB mostków H BD62130AEFJ-E2. Umożliwiają one pracę silników do 28V oraz 3A. Ich obsługa odbywa się po przez piny: ⦁ PD2 (Arduino port 2) – M1A, ⦁ PD3 (Arduino port 3) – M1B, ⦁ PD4 (Arduino port 4) – M2A, ⦁ PD7 (Arduino port 7) – M2B, PEŁEN SCHEMAT ELEKTRYCZNY: ZDJĘCIA ZMONTOWANEJ PCB: PODSUMOWANIE: Ten projekt bardzo usprawnił moją pracę oraz przyspieszył postępy nad innymi projektami. Głównie przez oszczędność czasu oraz wygodę w obsłudze i debbugowaniu problemów. W przyszłości planuję ponownie pochylić się nad tym sterownikiem, próbując zmniejszyć jego gabaryty oraz wyprowadzając więcej pinów mikrokontrolera.
- 4 odpowiedzi
-
- 6
-
-
- arduino nano
- Arduino IDE
- (i 3 więcej)
-
Mam problem z robotem 2WD. NRF działa, jak dam zamiast v wartość bezpośrednio 255 to też jedzie do przodu i do tyłu. Nie działa w momencie gdy wstawiam v, czytane z NRFa. Na razie chcę żeby chociaż to działało, potem będę się głowił nad skrętami. Jest tam trochę śmieci, gdyż usuwałem kod związany ze skręcaniem (chciałbym zmieniać prędkość każdego z kół w zależności od kierunku skrętu) Prosiłbym o pomoc. Zakres joysticka wynosi ok. 0-675. Środek w pkt ok. X:336, Y:335 Robot na arduino nano, nadajnik na uno. #include <SPI.h> #include <RF24.h> RF24 radio(9,8); const byte adres[6]="00001"; int v; //predkosc do przodu/tyłu int a; //predkosc obrotu struct Data{ int x; int y; }; void setup() { Serial.begin(9600); radio.begin(); radio.setPALevel(RF24_PA_HIGH); radio.setDataRate(RF24_250KBPS); radio.openReadingPipe(0, adres); radio.startListening(); pinMode(10, OUTPUT); //IN 1 pinMode(6, OUTPUT); //IN 2 pinMode(7, OUTPUT); //IN 3 pinMode(4, OUTPUT); //IN 4 pinMode(3, OUTPUT); //EN 1 2 pinMode(5, OUTPUT); //EN 3 4 } void loop() { bool kierunek=true; //true dla przodu, false dla tyłu bool zwrot=false; //true że zmienia kierunek, false że nie float v2, a2; int pwm1=0, pwm2=0; Data data; bool zwrot2=false; //true dla prawo, false dla lewo if(radio.available()) { radio.read(&data, sizeof(data)); v=data.x-338; if(v<0) { kierunek=false; v=-1*v; } a=data.y-338; if(a<-10) //skręt w lewo { zwrot=true; zwrot2=false; a=-1*a; } else if(a>10) //skręt w prawo { zwrot=true; zwrot2=true; } else { a=0; } int a2=map(a, 0, 350, 0, 250); int v2=map(v, 0, 350, 0, 255); pwm1=min(255, a); if(v<10) { analogWrite(3, 0); analogWrite(5, 0); digitalWrite(10, LOW); digitalWrite(6, LOW); digitalWrite(7, LOW); digitalWrite(4, LOW); } else if(kierunek==true) { analogWrite(3, v2); analogWrite(5, v2); digitalWrite(10, HIGH); digitalWrite(6, LOW); digitalWrite(7, HIGH); digitalWrite(4, LOW); } else if(kierunek==false) { analogWrite(3, v2); analogWrite(5, v2); digitalWrite(10, LOW); digitalWrite(6, HIGH); digitalWrite(7, LOW); digitalWrite(4, HIGH); } } else if(radio.available()==false) { pwm1=0; pwm2=0; analogWrite(3, pwm2); analogWrite(5, pwm1); digitalWrite(10, LOW); digitalWrite(6, LOW); digitalWrite(7, LOW); digitalWrite(4, LOW); Serial.print("Nie połączono"); } }
-
Na wstępie muszę wyjaśnić co kryje się za imieniem Demostenes. Demostenes to największy grecki mówca. W młodości posiadający wadę wymowy. Ćwiczył on dykcję chodząc po plaży i mówiąc z kamieniami w ustach. Co Demostenes ma wspólnego z elektroniką? Oczywiście mowę, a opis ten dotyczy rozpoznawania ludzkiej mowy za pomocą urządzeń elektronicznych. Dlatego swój projekt postanowiłem nazwać imieniem tego słynnego greckiego oratora i jego podobiznę umieścić na warstwie opisowej płytki drukowanej. Z zagadnieniem sterowania ludzkim głosem zetknąłem się na początku lat osiemdziesiątych ubiegłego wieku. Wówczas to w Młodym Techniku zostało opisane tego rodzaju sterowanie. Dziś patrząc z perspektywy czasu urządzenie zbudowane na dwóch układach scalonych audio i kilku tranzystorach nie miało prawa działać. Przynajmniej nie tak jak sobie to wyobrażamy. Działanie tego sterownika można porównać do działania iluminofonii. O ile w ogóle opisane urządzenie działało. Moduł SpeakUpTM Dziewięć lat temu przeglądając ofertę firmy TME znalazłem interesujący moduł do rozpoznawania mowy o oznaczeniu MIKROE-1534. Jego cena dziewięć lat temu wynosiła około 200 zł i nie trzeba było robić zakupów za granicą oraz ponosić kosztów celno skarbowych. Moduł MIKROE-1534 to produkt firmy MikroElektronika rozpowszechniany pod nazwą SpeakUpTM. Moduł ten to niewielka płytka drukowana o wymiarach 57x25 mm, którą możemy na poniższych fotografiach. Schemat elektryczny płytki umieszczony jest na ulotce dostarczonej wraz z tym modułem, jak również na stronie jego producenta w pliku PDF „user manual”. Moduł ten zbudowany jest w oparciu o 32 bitowy mikrokontroler z rdzeniem ARM Cortex-M4 STM32F415RG. Na płytce drukowanej modułu zostało wyprowadzone dwanaście programowalnych linii wejścia – wyjścia (I/O). Mogą być one wykorzystane do sterowania przekaźnikami. Do budowy tego modułu użyty został popularny kodek audio stereo VS1053 i mikrofon elektretowy o dobrych parametrach. Uzupełnieniem modułu są trzy diody LED sygnalizujące stan pracy oraz dwa mikroprzyciski. Dostępne jest też miniaturowe gniazdo USB typu B pozwalające na połączenie modułu z komputerem. Na płytce znajduje się również gniazdo mikrofonu typu Jack 3,5 mm pozwalające na podłączenie zewnętrznego mikrofonu. Umieszczone są również złącza JTAG, mikrobus oraz UART. Moduł ten można łatwo konfigurować za pomocą darmowego oprogramowania dostępnego na stronie producenta płytki. Płytka SpeakUpTM potrafi rozpoznać dwieście komend o czasie trwania do pięciu sekund, niezależnie od języka mowy w jakim są one wydawane. Cechuje się ona też dużą szybkością przetwarzania i może pracować on jako samodzielne urządzenie lub część większego systemu. O prostocie stosowania modułu SpeakUpTM stanowi zawarte w mikrokontrolerze oprogramowanie. Mianowicie rozpoznawanie komend głosowych zostało zrealizowane w oparciu o algorytm Dynamic Time Warping (DTW). Sygnał akustyczny po odebraniu przez mikrofon i przekształceniu na sygnał elektryczny jest wstępnie przekształcany przez kodek VS1053. Następnie sygnał ten jest interpretowany przez algorytm DTW zawarty w mikrokontrolerze. Po tym procesie mikrokontroler w zależności od wybranego trybu pracy może zmienić stan jednego w dwunastu wyjść. Jest to praca samodzielna modułu. Możliwe jest również przesłanie po poprawnym rozpoznaniu komendy słownej sygnału dalej za pomocą interfejsu USB lub UART. Aplikacja SpeakUpTM Do korzystania z modułu MIKROE-1534 potrzebna jest aplikacja SpeakUp widoczna na zrzucie ekranu poniżej. Aplikację tą możemy pobrać z tego linku w postaci archiwum 5,5 MB. Instalacja tej aplikacji nie odbiega od instalacji programów dla systemu Windows. Pomimo niepozornego wyglądu ma ona duże możliwości i pozwala ustalić zachowanie modułu SpeakUpTM po poprawnym rozpoznaniu wydanej komendy. Aplikacja ta jest w zasadzie niezbędna do konfiguracji modułu SpeakUpTM. Po jego podłączeniu do komputera system Windows 7 (projekt powstał dziewięć lat temu stąd Windows 7) bez problemu wykrył i zainstalował niezbędne sterowniki. Na tym etapie nie jest też wymagane zewnętrze zasilanie modułu SpeakUpTM. Po uruchomieniu aplikacji SpeakUpTM tworzymy nowy projekt ikonką pokazaną poniżej. Podobnie jak w aplikacjach systemu Windows podajemy nazwę i lokalizację naszego projektu i zatwierdzamy je przyciskiem Create. W następnej kolejności klikamy ikonkę START HERE widoczną na kolejnym zrzucie ekranu. Otworzy się okno nagrywania dźwięku widoczne na poniżej. Po kliknięciu przycisku RECORD rozpocznie się rejestrowanie za pośrednictwem mikrofonu wzorca polecenia. Pod przyciskiem RECORD pojawi się licznik upływającego czasu liczący od pięciu sekund do zera. Zarejestrowane polecenie zostanie od razu odtworzone za pośrednictwem karty muzycznej i głośników komputera. Odsłuch zarejestrowanego polecenia możliwy jest też przyciskiem PLAY. Jeśli zarejestrowane polecenie jest poprawne w polu Enter voice command name podajemy nazwę zarejestrowanego polecenia i zapisujemy je przyciskiem Save & Close. Analogicznie rejestrujemy kolejne polecenia. Po zarejestrowaniu potrzebnych nam poleceń pojawią się one w górnej części okna aplikacji SpeakUpTM w formie zakładek widocznych na poniższym rysunku. Klikając na zakładce z tymi poleceniami mamy możliwość przełączania się między nimi. Na końcu listy zakładek z prawej strony aplikacji SpeakUpTM znajduje się mały przycisk z trójkątem oferujący bezpośredni dostęp do zarejestrowanych poleceń. Pod zakładką z poleceniami dostępne są przyciski odtwarzania, edycji i usuwania zarejestrowanych poleceń. Poniżej tych przycisków znajduje się pole w którym mamy możliwość wprowadzenia opisu dla poszczególnych poleceń. Pod tym polem mamy listę dwunastu wyjść modułu SpeakUpTM. Na tej liście mamy możliwość przypisania wybranego polecenia do określonego wyjścia modułu SpeakUpTM. Oprócz przypisania zarejestrowanych poleceń do poszczególnych wyjść modułu SpeakUpTM, mamy także możliwość ustalenia zachowania się tych wyjść. Dostępne ustawienia widoczne są na powyższym i są to: 1. NONE – bez zmian na wyjściu 2. ON – wyjście załączone (wysoki poziom logiczny H) 3. OFF – wyłączenie wyjścia (niski poziom logiczny L) 4. TOGGLE – przełączenie stanu na wyjściu (z niskiego na wysoki lub odwrotnie) 5. PULSE – wygenerowany zostanie na wyjściu impuls lub ciąg impulsów o określonych parametrach Możliwe jest przypisanie jednemu poleceniu głosowemu zmiany stanu więcej niż jednego wyjścia modułu SpeakUpTM. W przypadku wybrania na wyjściu jako sygnału wyjściowego „pulse” pojawi się ikonka edycji parametrów generowanego impulsu lub ciągu impulsów widoczna na z lewej strony. Prawy rysunek to okno ustawień parametrów generowanego impulsu lub ciągu impulsów. W oknie tym można ustawić czas trwania impulsu – parametr T, współczynnik wypełnienia – parametr D i ilość powtórzeń wygenerowanego impulsu – parametr N. Jeśli ilość powtórzeń impulsów na wyjściu będzie miała wartość zero to impulsy będą generowane w sposób ciągły. Po kliknięciu na ikonce ustawień aplikacji SpeakUpTM (przycisk z kołem zębatym) mamy możliwość wybrania dodatkowych ustawień modułu SpeakUpTM. Ustawienia te możemy zobaczyć na rysunku poniżej i tak: 1. Acceptance threshold – to krótko pisząc poziom akceptacji błędów. Parametr ten decyduje o tym jak precyzyjnie moduł SpeakUpTM będzie rozpoznawał wydawane polecenia. Zbyt niski poziom akceptacji błędów może utrudnić poprawne rozpoznawanie wydawanych poleceń głosowych. 2. Recording timeout – maksymalny czas (ramy czasowe) w jakim rejestrowane są rejestrowane polecenia. Można wybrać czas o długości 5, 10 i 15 sekund. 3. Word Length – maksymalna długość zarejestrowanego polecenia. Dostępne są następujące długości czasu rejestrowanych poleceń, 1, 1.5, 2, 2.5 i 3 sekundy według dokumentacji. U mnie jak widać na rysunku 8 parametr ten jest nieaktywny. 4. Noise level - poziom hałasu. Niski poziom dźwięku może spowodować przypadkowe zadziałanie modułu. Niższe wartości wymagają też cichszego wydawania poleceń, co powoduje wzrost podatności na zakłócenia hałasem i wyższym poziomem szumów. Wyższy poziom dźwięku wymaga głośniejszego wydawania poleceń, dzięki czemu moduł jest mniej wrażliwy na zakłócenia hałasem i poziom szumów sygnału. 5. Notify master – wybór interfejsu (UART lub USB) do komunikacji z nadrzędnym systemem. 6. Data rate – szybkość transmisji danych do nadrzędnego systemu Sekcja Initial Pin States widoczna na powyższym zrzucie ekranu pozwala na ustawienie stanu spoczynkowego wyjść modułu MIKROE-1534. Może być to stan wysoki H lub niski L. Do zmiany stanu służą wirtualne przełączniki przypisane każdemu wyjściu. Natomiast przycisk podwójnej strzałki wskazany na tym rysunku pozwala na zdefiniowanie własnych nazw poszczególnych wyjść modułu SpeakUpTM - Pin Aliases. Widoczne jest to na poniżej. Po zakończeniu nagrywania i konfigurowania poleceń utworzony projekt zapisujemy na dysku komputera, a następnie przesyłamy do modułu SpekUp przyciskiem Upload project co możemy zobaczyć poniżej. Pora na omówienie zastosowania przycisków Push-button 1 i 2 na płytce oraz diod LED, które możemy zobaczyć na fotografiach modułu MIKROE-1534. Przycisk Push-button 1 służy do nagrywania poleceń głosowych. Po naciśnięciu i przytrzymaniu przycisku należy wypowiedzieć żądane polecenie do zarejestrowania. Domyślny czas polecenia to jedna sekunda. Można nagrywać więcej poleceń trzymając wciśnięty przyciski Push-button 1. Przy tej rejestracji poleceń głosowych należy się upewnić, że pomiędzy wypowiadanymi poszczególnymi poleceniami do zarejestrowania wystąpi błysk czerwonej diody LED. Jednoczesne wciśnięcie obydwóch przycisków na dłużej niż dwie sekundy zresetuje moduł SpeakUpTM. Rejestracja i zarządzanie poleceniami głosowymi za pomocą przycisków na płytce nie jest najwygodniejsze. Zielona dioda LED sygnalizuje zasilanie modułu SpeakUpTM. Świecenie bursztynowej diody LD1 sygnalizuje gotowość modułu SpeakUpTM do nagrywania i rozpoznawania poleceń głosowych. Czerwona dioda LD2 sygnalizuje iż moduł SpeakUpTM jest zajęty rozpoznawaniem lub rejestrowaniem poleceń głosowych. Poprawne rozpoznanie polecenia głosowego sygnalizowane jest zaświeceniem obydwóch diod LD1 i LD2 na pół sekundy. Do przycisków Push-button 1 i 2 i diod LD1, LD2 i PWR mogły zostać doprowadzone złącza goldpin umożliwiające umieszczenie ich na obudowie urządzenia, co w niektórych przypadkach mogło by być dużym ułatwieniem w korzystaniu z modułu SpeakUpTM z użyciem tych przycisków. Uwagi praktyczne 1. Aby uzyskać najlepsze wyniki nagrywania poleceń głosowych konieczne jest zapewnienie warunków nagrywania przy niskim poziome hałasu otoczenia. Mikrofon nie może być zbyt blisko głośników komputera z uwagi na możliwość powstania szkodliwych sprzężeń. Mikrofon powinien znajdować się w odległości około 10 – 20 cm od ust osoby nagrywającej komendy – wydającej polecenia. 2. Jeśli występują problemy z rozpoznaniem określonego polecenia głosowego, należy zapisać je kilka razy z uwzględnieniem różnorodności w wymowie. 3. Obowiązkowo należy odtworzyć zarejestrowane polecenie głosowe, aby usłyszeć czy oprócz polecenia nie został zarejestrowany hałas otoczenia lub przypadkowy dźwięk. 4. Z tego powodu zaleca się umieszczenie modułu SpeakUpTM na powierzchni, która nie przenosi drgań mechanicznych, ewentualnie korzystanie z zewnętrznego mikrofonu. 5. Jeśli jest więcej użytkowników, każdy z nich powinien nagrać polecenia głosowe oddzielnie z uwagi na różnorodność wymowy. 6. Liczba poleceń głosowych, które można zapisać zależy od ich długości. Zazwyczaj jest to ponad dwieście poleceń głosowych o długości od jednej sekundy. 7. Nagrywane polecenia głosowe są rejestrowane za pomocą mikrofonu znajdującego na płytce modułu SpeakUpTM, więc nie ma potrzeby podłączania zewnętrznego mikrofonu do komputera. Praktyczne zastosowanie SpeakUpTM Po zapoznaniu się z możliwościami modułu SpeakUpTM pora na jego praktyczne i efektowne zastosowanie. Spośród wielu pomysłów jakie przyszły mi do głowy zdecydowałem się na użycie modułu SpeakUpTM do sterowania ramieniem robota KSR10 dostępnym w sklepie Botlandu, które możemy zobaczyć na fotografii tytułowej. Po poprawnym złożeniu tego ramienia zgodnie z załączoną instrukcją, można przystąpić do połączenia ramienia robota i modułu SpeakUpTM. Oczywiście nie jest możliwe to bezpośrednio. Słaby sygnał z wyjść modułu SpeakUpTM trzeba wzmocnić, aby mógł on sterować silnikami ramienia robota. Zanim do tego przystąpimy spójrzmy na schemat elektryczny ramienia robota widoczny poniżej. Oczywiście przełączniki SW1-SW5 w stanie spoczynku muszą być rozwarte. Jak widzimy schemat elektryczny tego ramienia jest bardzo prosty. Do napędu ramienia wykorzystanych jest pięć silniczków, które zasilane są napięciem 2 x 3V symetrycznym względem masy. Tego rodzaju rozwiązanie ma na celu uproszenie schematu elektrycznego ramienia robota. Nie trzeba stosować podwójnych dwubiegunowych przełączników. Minusem tego rozwiązania jest konieczność stosowania dwóch zestawów baterii zasilających. Dodatkowo w chwytaku ramienia robota zastosowana jest dioda LED oświetlająca pole robocze ramienia. Całość podzielona jest na dwie części elektryczne. Pierwsza część to zespół pięciu silniczków elektrycznych, dioda LED, płytka połączeniowa oraz zespół baterii zasilających typu R20, które są umieszczone w podstawie robota. Druga część to zespół pięciu pojedynczych przełączników dwubiegunowych i przełącznik włączający diodę LED. Całość połączona jest za pomocą wielożyłowego przewodu i ośmiostykowego złącza. Przełączniki SW1 – SW5 można łatwo zastąpić przekaźnikami. Do sterowania ramieniem robota można wykorzystać przekaźniki załączane za pośrednictwem układów ULN2803. Wadą tego rozwiązania jest to iż oryginalne przełączniki pulpitu sterującego muszą zostać zastąpione dwoma przekaźnikami, aby w stanie spoczynku ramię robota nie pracowało. Czyli potrzebujemy dziesięć przekaźników. Dioda LED może być włączona bezpośrednio z układu ULN2803. Jednak zdecydowałem się na zastosowanie dwunastu przekaźników co pozwala na wykorzystanie wszystkich dwunastu wyjść modułu SpeakUpTM. Dzięki temu łatwo możemy wykorzystać całość do sterowania innym urządzeniem lub mechanizmem niż ramię robota. Wybierając to rozwiązanie nie trzeba też ingerować w obwody elektryczne ramienia KSR10. Gotowy moduł sterujący można po prostu podłączyć do złącza sterującego robota, zamiast oryginalnego pulpitu sterującego. Schemat elektroniczny całego sterownika ramienia robota możemy zobaczyć poniżej. Nie jest to skomplikowane urządzenie elektroniczne. W zasadzie jest to karta przekaźników z zasilaczem i możliwością podłączenia płytki SpeakUpTM. Sygnały pojawiające się na wyjściach IO1- IO12 modułu SpeakUpTM wzmacniane są w układach ULN2803, które włączają poszczególne przekaźniki. Diody LED dołączone do przekaźników pełnią rolę sygnalizacyjną, który przekaźnik jest w danej chwili załączony. Zasilacz to tradycyjne rozwiązanie oparte na stabilizatorach LM7805 i LM33CV. Zastosowana została nieco większa ilość kondensatorów filtrujących. Ich zadaniem jest nie tylko filtracja napięcia zasilającego, ale również ograniczenie i filtracja przepięć powstających w cewkach przekaźników. Mogło by to spowodować niekontrolowane działanie całego urządzenia. Montaż i uruchomienie Płytka sterownika zaprojektowana jest z użyciem elementów SMD i przewlekanych. Elementy te są montowane po obu stronach płytki drukowanej. Schemat montażowy płytki sterownika, jej widok 3D oraz fotografie możemy zobaczyć poniżej. Montaż płytki sterownika przeprowadzamy w tradycyjny sposób zaczynając od elementów najmniejszych czyli SMD, na końcu montujemy duże elementy czyli przekaźniki i kondensatory elektrolityczne. Jako złącze pod moduł SpeakUpTM można zastosować goldpiny typu żeńskiego 1x8 pinów. Jeżeli napięcie wyjściowe transformatora zasilającego sterownik nie będzie zbyt wysokie to stabilizatory napięcia nie wymagają radiatora, ale warto go zastosować. Pobór prądu w stanie spoczynku to około 72 mA i 142mA przy włączonym jednym przekaźniku. Pobór prądu wzrasta o około 70 mA przy każdym kolejnym włączonym jednocześnie przekaźniku. Uwzględniając najbardziej niekorzystny przypadek włączenia wszystkich przekaźników i zasilanie części elektronicznej, pobór prądu może przekroczyć 910 mA. Wówczas radiator będzie potrzebny. Silniki serwomechanizmów są zasilane z osobnego źródła zasilania jakim są baterie R20. Przed zamontowaniem na płytce sterownika kosztownego modułu SpeakUpTM należy sprawdzić poprawność montażu płytki i jej działanie. Sprawdzamy napięcia 5V i 3,3V oraz działanie przekaźników podając na piny IO1-IO12 złącz płytki MIKROE-1534 napięcie 3,3V co powinno spowodować załączenie kolejnych przekaźników. Wymagana jest ostrożność i staranność montażu zarówno płytki sterownika jak i płytki SpeakUpTM, aby nie uszkodzić kosztownej płytki SpeakUpTM. Uwaga! Na płytce drukowanej sterownika nie ma gotowych połączeń styków przekaźników do sterowania ramieniem robota. Wykonanie tych połączeń na płytce ograniczyło by jej zastosowanie tylko do sterowania ramieniem KSR10. Odpowiednie połączenia należy wykonać przewodami na podstawie rysunku przedstawiającego połączenia manipulatora robota. Do wykonanych przewodami połączeń należy dołączyć za pośrednictwem taśmy przewodów ośmiostykowe żeńskie złącze typu 402. Do połączenia z płytą drukowaną Demostenesa użyłem żeńskich dwupinowych złącz z przewodami z odzysku z obudów komputerowych. Taśmę ze złączem typu 402 i przewody ze złączami do płytki drukowanej połączyłem razem na małej uniwersalnej płytce drukowanej. Rozwiązanie to jest widoczne na poniżej. Może to nie jest elegancie rozwiązanie, ale taka jest natura połączeń kablowych. Wspomniałem wcześniej, że ramię robota KSR10 zasilane jest z czterech baterii typu R20. Ze zrozumiałych względów baterie te powinny być dobrej jakości. Przy intensywnym korzystaniu z ramienia warto rozważyć zastąpienie ich odpowiednimi akumulatorkami. Jeszcze jedna możliwość to zbudowanie zasilacza do zasilania zarówno ramienia robota jak i sterującej nim części elektronicznej. Odpowiedni do tego rozwiązania jest transformator o oznaczeniu TS25/9, którego napięcia wyjściowe są niemal idealne do wykorzystania i wynoszą 10,5V – 1,2A, 2x 2V – 1,2A oraz 3V – 1,2A – niewykorzystane. Według starszego katalogu transformator ten miał inne napięcia, co należy uwzględnić przy ewentualnym jego zakupie. Zasilanie części elektronicznej z tego transformatora nie wymaga modyfikacji poza ewentualnym zastosowaniem radiatora dla stabilizatorów napięcia. Natomiast do zasilania ramienia robota należy wówczas wykonać prosty zasilacz według poniższego schematu. Napięcia na kondensatorach filtrujących napięcia wyniosą 2V (AC) * 1,41 = 2,82V (DC). Zastosowanie zasilacza zamiast baterii wiąże z niewielkimi przeróbkami ramienia robota i każdy musi sam zdecydować jakie rozwiązanie wybierze. Należy też pamiętać, że duże i ciężkie baterie R20 umieszczone w podstawie ramienia robota stanowią jego obciążenie i zapewniają jego stabilność. Bez baterii w podstawie ramię robota może być podane na przewrócenie. Programowanie modułu SpeakUpTM Korzystając z aplikacji SpeakUp i wcześniejszego opisu należy zaprogramować odpowiednie komendy sterujące ramieniem robota. Zaprogramowanie potrzebnych komend może wymagać trochę treningu, zarówno w czasie programowania komend jak i późniejszego wydawania poleceń, tak aby ramię robota pewnie reagowało na nasze polecenia. Do programowania możemy wykorzystać mikrofon znajdujący się na płytce SpeakUpTM, jak również możemy dołączyć mikrofon zewnętrzny. Podczas programowania komend należy uwzględnić wcześniej podane uwagi praktyczne. Ramię KSR10 ma pięć stopni swobody czyli możliwych do wykonania kierunków ruchu. Na każdy z tych stopni składa się dwa przeciwstawne ruchy. Dla każdego z nich trzeba wybrać i zaprogramować odpowiednie komendy. Najprościej będzie te stopnie swobody opisać za pomocą poniższej fotografii. Literka „M” wraz z cyfrą oznacza dany silniczek serwomechanizmu. Oznaczenia te są zgodne z rysunkiem z punktu 8 na stronie 41 oryginalnej dokumentacji montażowej ramienia KSR10. 1. M1 – sterowanie szczękami chwytaka 2. M2 – pochylanie chwytaka góra – dół 3. M3 – pochylanie połowy ramienia góra – dół 4. M4 – pochylanie całego ramienia góra - dół 5. M5 – obrót ramienia prawo – lewo 6. Włączanie światła Poniżej znajduje się zastosowany przeze mnie wykaz komend sterujących ruchem ramienia. Komendy te powinny być w miarę możliwości krótkie i proste w wymowie. 1. M1 – chwyć – zwolnij – chwytanie i puszczanie przedmiotu szczęką chwytaka 2. M2 – pochyl – unieś – podnoszenie i opuszczanie chwytaka 3. M3 – góra – dół – podnoszenie i opuszczanie połowy ramienia 4. M4 – podnieś – opuść – podnoszenie i opuszczanie całego ramienia 5. M5 – prawo – lewo – ruch ramienia w prawo i lewo 6. Lampa – włącza światło 7. Stop – wyłącza wszystkie komendy Podczas programowania modułu SpeakUpTM odpowiednie jego wyjścia musimy przypisać do odpowiednich przekaźników sterujących poszczególnymi silnikami ramienia. Uwaga! Programując na przykład wyjście IO9 jako komendę „prawo” pozostałe wyjścia dla tej komendy należy ustawić jako OFF czyli wyłączone. Jeśli tego nie zrobimy to wydanie przeciwstawnej komendy „lewo” spowoduje aktywację wyjścia IO10 bez wyłączenia drugiego przekaźnika z wyjścia IO9 i zwarcie elektryczne! Natomiast wydanie innej komendy np. „unieś” spowoduje, że będą wykonywane dwa ruchy ramienia jednocześnie. Drugi przypadek nie jest szkodliwy, ale przez nieuwagę może być jak to wyżej opisałem powodem zwarcia, jak również trudności w kontrolowaniu kilku ruchów ramienia jednocześnie. Dla komendy „stop” przypisujemy wszystkim wyjściom parametr OFF. Przy prawidłowym zaprogramowaniu komend wydanie jednej komendy ma spowodować wyłączenie komendy uprzednio wydanej. Nie dotyczy to jedynie komendy włączania lampki oświetlającej chwytak, która po włączeniu powinna świecić ciągle oświetlając pole robocze chwytaka. Komendzie „stop” możemy przypisać generowanie impulsów na wyjściu, co może sygnalizować zatrzymanie ramienia poprzez klikanie przekaźnika i błyskanie diody LED. Może być to na przykład trzy impulsy o czasie trwania 1s. Ewentualne błędy w przypisaniu serwomechanizmom komend możemy wygodnie skorygować poprzez przeprogramowanie wyjść IO modułu, lub mniej wygodnie poprzez zmianę okablowania w obrębie przekaźników sterujących ramieniem. W tym miejscu należy wspomnieć, że serwomechanizmy ramienia posiadają proste sprzęgła przeciążeniowe i kiedy dany segment ramienia osiągnie skrajne położenie to sprzęgło to zapobiega uszkodzeniu serwomechanizmu. Dłuższe trzymanie włączonego silnika ramienia w skrajnym jego położeniu może spowodować trwałe uszkodzenie lub przedwczesne zużycie tego sprzęgła. Z tego też powodu kiedy element ramienia osiągnie skrajne wychylenie i zadziała sprzęgło, co objawi się głośniejszą pracą serwomechanizmu, należy bezwzględnie wyłączyć silnik komendą „stop”. Lub wyłączyć zasilanie ponieważ hałas generowany przez serwomechanizmy zakłóca wydawane komendy! W przypadku sterownia modułem SpeakUpTM mamy możliwość ustawienia czasu na jaki będą włączane silniki serwomechanizmu. Ustalenie odpowiedniej wartości czasu włączenia danego silnika pozwoli na osiągnięcie jego skrajnego położenia i jednocześnie jego wyłączenie bez konieczności wypowiadania komendy „stop”. Może być to pewien rodzaj wyłącznika bezpieczeństwa i warto rozważyć skorzystanie z niego, aby nie uszkodzić serwomechanizmów kosztownego ramienia KSR10. Teoretycznie możliwe jest wcześniejsze wyłączenie silnika serwomechanizmu komendą „stop”. Jednak hałas serwomechanizmów nakłada się na wydawane komendy i moduł MIKROE-1534 nie reaguje na wydawane polecenia. Po zaprogramowaniu modułu SpeakUpTM i podłączeniu do ramienia robota można zacząć próby sterowania nim za pomocą głosu. Wbrew pozorom nie jest to na początku tak proste jak się wydaje i wymaga prób zarówno wydawania poleceń i rejestracji komend, tak aby były one poprawnie rozpoznawane. Może być konieczna zmiana poziomu akceptowalnych błędów jak i poziomu hałasu. Również treningu wymaga wydawanie poleceń, tak aby ramię reagowało na nasze polecenia zgodnie z naszymi oczekiwaniami. Czyli aby segmenty ramienia KSR10 ustawiały się i zatrzymywały w położeniach, których wymagamy. Nie jest to łatwe, ponieważ ramię cechuje się pewną bezwładnością i po wyłączeniu serwomechanizmu jeszcze się przemieszcza przez krótki czasu. Serwomechanizmy ramienia KSR-10 nie mają sprzężenia zwrotnego co utrudnia kontrolowanie jego ruchów za pomocą głosu. Wrażenia z testów Podczas korzystania z modułu SpeakUpTM komendy i polecenia należy wymawiać głośno, zdecydowanie i wyraźnie szeroko otwierając usta. Nie można niewyraźnie „mruczeć” pod nosem. Zalecane jest nagranie wszystkich komend za jednym razem i przesłanie ich do modułu. Kiedy modyfikujemy ustawienia i ponownie je przesyłamy do modułu SpeakUpTM to odniosłem wrażenie, że z niektóre z modyfikowanych komend są jakby „gubione” podczas ich aktualizacji. Przed wgraniem nowego zestawu komend można zresetować moduł SpeakUpTM wciskając jego przyciski na co najmniej 2 sekundy. Także zdarza się, że moduł SpeakUpTM pomimo poprawnego zaprogramowania komend i przypisania im poszczególnych wyjść myli się i po rozpoznaniu komendy przypisuje jej inne wyjście niż zaprogramowane. Sporadycznie zdarza się, że komendy są błędnie rozpoznawane, na co może wpływać wiele czynników począwszy od niedoskonałości algorytmu zapisanego w mikrokontrolerze, inne akcentowanie poleceń oraz wypowiadanie komend poprzez hałas i dźwięki postronne, a skończywszy na zmianie akustyki pomieszczenia. Zdarzyło się, że moduł przypadkowo zareagował na głos innej osoby, trzaśnięcie drzwiami, dmuchnięcie w mikrofon, a także włączył dwa serwomechanizmy jednocześnie. To były jednak pojedyncze przypadki. Głównym powodem błędnego rozpoznawania komend i błędnego włączania innych wyjść modułu SpeakUpTM, w mojej ocenie jest szybkie wydawanie komend w odstępach kilku – kilkunastu sekundowych. Tak jak w przypadku sterowania ramieniem KSR10. Wówczas moduł SpeakUpTM czasami działa niezgodnie z ustawieniami. W takim przypadku pomaga ponowne jego uruchomienie. Największy problem podczas testów sprawiło ramię KSR10. Odgłos pracy jego serwomechanizmów zakłócał rozpoznawanie komend przez moduł SpeakUpTM. O ile rozpoznanie wydanej komendy nie stanowiło problemu, to jej zmiana lub zatrzymanie ramienia KSR10 po jego uruchomieniu było w zasadzie niemożliwe. Odgłos pracy serwomechanizmu skutecznie utrudniał rozpoznanie wydawanych komend. Sporadycznie udawało się zatrzymać ramię komendą „stop”. W zdecydowanej większości przypadków do zatrzymania ramienia trzeba było wyłączyć zasilanie układu elektronicznego. To z kolei wymagało odczekania kilkunastu sekund na ponowne uruchomienie modułu SpeakUpTM co sygnalizowane jest przez jego diody LED. Nie pomogło nawet oddalenie zewnętrznego mikrofonu od ramienia KRS10 na odległość około trzech metrów. Również zmiana czułości jak i poziomu akceptowalnych błędów przez moduł SpeakUpTM nie przyniosła poprawy. Zadowalające rezultaty osiągnąłem dopiero umieszczając ramię KSR10 na balkonie za zamkniętymi drzwiami. Sterownik Demostenesa w tym czasie znajdował się po drugiej stronie drzwi w salonie. Przechodzący przez drzwi cichy odgłos pracy serwomechanizmów nie zakłócał już wydawanych komend i były one rozpoznawane poprawnie. Jeszcze innym rozwiązaniem, aczkolwiek niewygodnym może być zastosowanie mikrofonu mocowanego jak w hełmofonie czołgisty na krtani operatora. W związku z zakłóceniami dźwięku generowanymi przez serwomechanizmy ramienia KSR10 zaprogramowałem moduł SpeakUpTM, tak aby po rozpoznaniu komendy nie włączał silniczków serwomechanizmów na stałe. Generowany jest jeden impuls o czasie trwania dwóch sekund. Wówczas po załączeniu silniczka jest on automatycznie wyłączany po zaprogramowanym czasie bez konieczności wypowiadania komendy „stop”. W takich warunkach powstał krótki film obrazujący działanie samego układu elektronicznego jak i w połączeniu z ramieniem KSR10. Wybierając ramię KSR10 do sterowania głosem liczyłem się z zakłóceniami. Nie przypuszczałem jednak, że hałas generowany przez jego serwomechanizmy w zasadzie uniemożliwi rozpoznawanie wydawanych komend. Przykładowy film z działania ramienia KSR10 sterowanego głosem możemy zobaczyć w poniższym linku: Film składa się on z trzech części. Test samego modułu elektronicznego. Sterowanie poprzez szybę w drzwiach oraz sterowanie z zatrzymaniem silniczków po upływie dwóch sekund. Poniżej fotografia zmontowanego Demostenesa podczas testów z wykorzystaniem zewnętrznego mikrofonu. Na tym kończę ten obszerny opis. Załączniki: 1. Demostens KiCad9.zip - pliki z programu KiCad 9 ze schematem i rysunkiem płytki drukowanej. Pliki pochodzą z systemu Linux w związku z tym w systemie Windows niektóre ścieżki do bibliotek trzeba skorygować. Docztyczy to w szczególności bibliotek modeli 3D. 2. Demostenes wsad.zip - plik z nagranymi komendami i ustawieniami aplikacji SpeakUp. Plik ten raczej nie zadziała z innym głosem niż mój. Jednak po otwarciu w aplikacji SpeakUp można zobaczyć jak płytka MIKROE-1534 została skonfigurowana dla robota. 3. Mikroe-1534_3D.zip - zmodyfikowany model płytki MIKROE-1534 w programie FreeCAD do wykorzystania w programie KiCad. 4. W tym linku ze strony producenta płytki MIKROE-1534 pobierzmy dokumentację płytki w PDF, aplikację SpeakUP oraz nie modyfikowany model 3D tej płytki. Demostenes KiCad9.zip Demostenes wsad.zip Mikroe-1534_3D.zip
-
Już od jakiegoś czasu interesowały mnie walki robotów, dlatego chciałem podjąć wyzwanie i zbudować swoją własną maszynkę destrukcji. Określenie maszynka nie została użyta bez powodu, gdyż waga robota zamyka się w 150 gramach. Celem robotów combat nie jest żadne skomplikowane zadanie, muszą się ze sobą mierzyć w dosłownej walce na arenie. Są to w zasadzie proste, zdalnie sterowane roboty, nad którymi należy sprawować osobiście kontrolę. Nie należy jednak zapominać, że w tej niby prostej dziedzinie jest ukryta ogromna trudność. Mianowicie należy zbudować robota o dużej sile, wytrzymałości i prędkości - a to wszystko w malutkim gabarycie. Zaprojektowanie maszyny, która zmieści się w tak małej wadze i jednocześnie będzie groźnym przeciwnikiem nie jest łatwe. Należy dokładnie zaprojektować całą konstrukcję, liczyć się z każdą zmianą, szukać kompromisów i dobrze balansować z parametrami maszyny. Cały ten proces sprawił, że praca nad NEONem była niezwykle ciekawa oraz satysfakcjonująca. Konstrukcja jest w zasadzie w całości drukowana na BambuLab A1 z użyciem PA12+CF15 oraz TPU95. Użycie wydruków znacząco zredukowało wagę, a użycie odpowiednich materiałów pozwala na pochłanianie pewnej ilości energii kinetycznej ataków wrogów oraz zapewnia wytrzymały pancerz. Bronią jest tutaj bębęn wyposażony w 2 rzędy bolców, które mają za zadanie zahaczyć o oponenta i wyrzucić go w powietrze. Za napęd służy w nim silnik BLDC 1800kV. Napędem jezdnym robota są dwa silniki N20. Koła zostały wykonane z tego samego materiału co rama. Dodatkowo w celu lepszego styku z powierzchnią, koła posiadają opony z o-ringów. Elektronika była tutaj równie ciekawym wyzwaniem. Większość twórców robotów combat posługuje się gotowymi rozwiązaniami. Używa się najczęściej aparatury modelarskiej (nadajnik i odbiornik), sterownik ESC silnika bezszczotkowego oraz sterownik ESC silnika szczotkowego. Dla wielu wystarczającym wyzwaniem będzie wykonanie stosownej konstrukcji, ja jednak postanowiłem pójść o krok dalej i opracować własną elektronikę. NEONa napędza własny sterownik, komunikujący się drogą radiową za pomocą NRF24L01. Sercem sterownika jest dobrze znana Atmega328P-AU. Sterownik ma wyprowadzone pady pod przyłączenie złącz modułu USB-UART z CH340, który również powstał z myślą o robocie oraz jego wygodnym programowaniu. Układ posiada również zintegrowane sterowniki silników jezdnych, zapewniających prace przy prądzie dochodzącym nawet do 4A. Włącznik robota również jest własnym produktem, gdyż na rynku ciężko o lekki przełącznik o dużej wytrzymałości prądowej. Jedynym w pełni zewnętrznym układem jest ESC do silnika broni. NEON nie przeszedł jeszcze chrztu bojowego. Jednak walka jest już na horyzoncie i po odbytej bitwie chętnie umieszczę tutaj więcej, bardziej treściwych szczegółów tej konstrukcji. Po walkach przyjdzie także pora na wnioski oraz potencjalne ulepszenia. Poniżej zostawiam linki do materiałów użytych do budowy robota. Filament PA12+CF15 1.75mm, Filament TPU 1.7mm, Silniki N20 100RPM 6V, Mikrokontroler Atmega328P-AU, Moduł radiowy NRF24L01.
- 1 odpowiedź
-
- 8
-
-
- robot
- arduino nano
-
(i 1 więcej)
Tagi:
-
ESPoBOT czyli robot mobilny RC z chwytakiem i kamerą FPV
marcinus opublikował temat w Projekty - DIY roboty
No cześć, kilka miesięcy wzlotów i upadków, kłótni z żoną i w końcu jest .... ESPoBOT Robot gąsienicowy RC z kamerą FPV i chwytakiem. Sterowanie oparte o ESP32-wroom 32D. Zacząłem od Arduino, ale z uwagi na problemy z komunikacją dwustronną NRF24L01, przesiadłem się na ESP32. Napędem są 2 silniki 9Vdc z przekładnią 87:1 na podwoziu gąsienicowym z regulacją prześwitu, kontrolowane przez sterownik oparty o układ TB6612. Prędkość silników regulowana płynnie w zakresie 0-30cm/s (1km/h). Robot wyposażony w chwytak umożliwiający chwycenie detalu, podniesienie/opuszczenie z użyciem 3 serw. Kontrola zaciśnięcia chwytaka zrealizowana poprzez pomiar prądu serwa. Regulacja prędkości serw. Zainstalowana kamera 1200TVL do przekazywania obrazu fpv 5.8GHz na telefon, PC lub wyświetlacz AV. Zasięg nadajnika do 500m. Robot wyposażony w oświetlenie LED RGB. Całość zasilana z akumulatora LiPo 1800mAh 11,1V 20C i zabezpieczona bezpiecznikiem polimerowym 4A. Dodatkowo akumulator zabezpieczony programowo przed rozładowaniem. Komunikacja dwustronna z padem na częstotliwości 2.4GHz (ESP-NOW) i zasięgu do 250m. Pad wyposażony w 2 joysticki, 6 guzików, potencjometr, enkoder oraz wyświetlacz OLED 128x64 do wyświetlania parametrów urządzenia. Zasilany z akumulatora 9V 650mAh USB. -
Witam Witam. Do sprzedania nowy, nierozpakowany zestaw do tworzenia modułowych robotów firmy UGOT. Informacje ze strony producenta. UGOT to wszechstronny i innowacyjny zestaw robotyczny oferujący szeroki zakres możliwości i trybów pracy. Dzięki potężnym funkcjom sztucznej inteligencji, dużej mocy obliczeniowej i modułowej konstrukcji UGOT zapewnia użytkownikom prosty i wciągający sposób na poznanie zaawansowanej technologii robotyki. UGOT oferuje szereg udogodnień technologicznych, w tym wizualne rozpoznawanie znaczników, FPV zsynchronizowane z aplikacją, śledzenie pieszych/ruchu, rozpoznawanie postawy, rozpoznawanie mowy, integrację z ChatGPT, niestandardowe szkolenia, szybki montaż, szybkie sterowanie i zasięg 360 stopni -rozpoznawanie mowy w terenie itp. Link do prezentacji produktu: CENA: 2450 zł + przesyłka Posiadam drugi zestaw zostawiony dla siebie więc jak by ktoś chciał zobaczyć jak działają roboty to mogę przesłać filmik Zestaw dostępny od ręki - natychmiastowa wysyłka.
-
Cześć, chcemy przedstawić wam projekt robota kroczącego Honey Badger. Na początek powiemy krótko o tym kim jesteśmy, naszej historii i czym się zajmujemy, następnie przedstawimy naszą najnowszą konstrukcję. Od razu dodamy, że jeśli będziecie mieli jakieś pytania to śmiało zadawajcie je w komentarzach - postaramy się na wszystkie odpowiedzieć MAB Robotics założyliśmy z myślą o komercjalizacji technologii robotów mobilnych i technologii napędowych dla robotyki w 2019. Sam pomysł i prace nad budową robotów kroczących rozpoczęliśmy już w trakcie studiów na Politechnice Poznańskiej gdy byliśmy członkami koła naukowego KN Mechatron. Pierwszy prototyp robota pokazał, że tego typu konstrukcje, w niektórych warunkach mają lepsze możliwości ruchowe niż dotychczas najpopularniejsze na lądzie roboty jeżdżące. Z pomocą dr inż. Krzysztofa Walasa (wykładowcy robotyki na Politechnice Poznańskiej), zdobyliśmy finansowanie z Akademickiego Inkubatora PP i w efekcie w 2019 roku powstała spółka MAB Robotics. Rok później zainwestował w nas fundusz inwestycyjny YouNick Mint co pozwoliło na przejście ze studenckiego projektu w firmę zajmującą się zaawansowanymi pracami badawczo rozwojowymi w obszarze robotyki i rozpoczęcie działań związanych z komercjalizacją opracowanych technologii. Dużą motywacją do działań był udział i nagrody jakie zdobywaliśmy w zawodach robotycznych w Polsce i za granicą - głównie w kategorii freestyle. Z naszymi robotami byliśmy m.in. na RoboticArena we Wrocławiu, Trójmiejskim Turnieju Robotów w Gdańsku, Sumo Challenge w Łodzi, Robomaticon w Warszawie, ROBOCOMP w Krakowie czy Robot Challenge w Pekinie. Niemal wszędzie zdobywaliśmy nagrody, zawsze poznawaliśmy ciekawych ludzi i gromadziliśmy bezcenne doświadczenie. Dziś pracujemy nad systemem inspekcyjnym, którego jedną z części jest robot Honey Badger. System rozwijany jest z myślą o prowadzeniu prac inspekcyjnychi serwisowych wewnątrz podziemnych sieci jakie występują pod ulicami każdego miasta. Obecnie wykorzystywane technologie, oparte najczęściej o jeżdżące platformy nie pozwalają dostać się wszędzie, mają stosunkowo niewielki zasięg i są drogie w użyciu. Dzięki przejściu z kół na nogi roboty MAB Robotics będą w stanie wejść niemal w każde miejsce, niosąc na grzbiecie sensory analizujące stan techniczny instalacji oraz narzędzia umożliwiające wykonywanie drobnych prac naprawczych od wewnątrz - pozwala to ograniczyć wykopy i prace drogowe w na ulicach miast. Teraz ta, pewnie ciekawsza część dotycząca technologii, którą zaczniemy od krótkiej prezentacji najnowszego robota: Zaprezentowany robot Honey Badger posiada 12 stopni swobody - po 3 na każdą z nóg. Napędy zbudowane są z silnika bezszczotkowego, przekładni planetarnej i sterownika silnika MD80. Taki rodzaj napędu dostarcza wystarczającego momentu obrotowego aby unieść robota i jednocześnie zapewnia wysoką dynamikę umożliwiającą np. podskoki. Istotnym aspektem jest wirtualna podatność napędu realizowana przez sterowanie impedancyjne. Dzięki odpowiedniemu sterowaniu, silnik symuluje dynamikę sprężyny. Korpus robota jest wodo i pyłoszczelny, dzięki czemu robot może pracować w trudnym środowisku nieprzyjaznym dla elektroniki - utrudnia to jednak chłodzenie układów. Wewnątrz znajduje się komputer sterujący lokomocją robota oraz dodatkowa jednostka umożliwiająca przetwarzanie danych z sensorów takich jak np. kamera głębi lub lidar. W korpus wbudowana jest również bateria, moduł komunikacyjny, moduł zarządzania energią i AHRS. Cała konstrukcja mechaniczna i wszystkie moduły elektroniczne zostały zaprojektowane przez zespół MAB. Elementy mechaniczne wykonane są metodami obróbki CNC aluminium i włókna węglowego dla elementów przenoszących obciążenia oraz druku 3D dla elementów stylistycznych oraz nieprzynoszących dużych obciążeń jak np. prowadniki przewodów wewnątrz korpusu. Wymiary robota to 0.25-0.5x0.4x0.6 [m] (HxWxL), a jego masa to 10kg. Robot ma gabaryty niewielkiego psa lub dużego kota, zależnie od preferencji Robot do swojej pracy wykorzystuje kilka sensorów. W napędy wbudowane są enkodery zwracające pozycję kątową napędu oraz elektronika, która pozwala na estymację momentu obrotowego generowanego przez napęd - wiemy dzięki temu z jaką siłą stopa robota naciska na podłoże. Dodatkowo, moduł AHRS wewnątrz korpusu wskazuje pozycję kątową oraz pozwala określić przemieszczenia i prędkości korpusu względem świata. Podstawą oprogramowania jest firmware mikrokontrolerów we wszystkich modułach robota. Odpowiada m.in. za sterowanie silnikami, kontrolę zasilania oraz komunikację między układami - napisany jest w języku C, na platformie STM32. Następny poziom to software sterujący pracą robota - tutaj liczone jest jak robot ma poruszać nogami by podążać w wyznaczonym kierunku z zadaną prędkością zachowując równowagę. Najwyższy poziom to oprogramowania wyznacza ścieżkę ruchu robota, analizuje otoczenie i interpretuje polecenia operatora. Dwa ostatnie poziomy wykorzystują ROS2 co bardzo ułatwia pracę i daje wiele możliwości, wykorzystujemy tutaj C++. Na zakończenie ostatni filmik Mamy nadzieję, że temat jest dla was ciekawy, trochę dowiedzieliście się z tego krótkiego wpisu i zmotywowaliśmy was do dalszej (lub rozpoczęcia) pracy z robotami. Jeśli macie pytania to chętnie na nie odpowiemy! Serdecznie zapraszamy: - do zwiedzenia naszej strony internetowej: MAB Robotics, - na nasz kanał na YouTube, gdzie wrzucamy dłuższe filmy, - na nasze social media: instagram, facebook i twitter.
- 7 odpowiedzi
-
- 19
-
-
-
Dzień dobry, Sprzedam platformę jezdną pod robota Dagu Wild Thumper 6WD wraz z silnikami z przekładnią 75:1. Do tego dorzucam sterownik do silników MDD20A od firmy Cytron. Również załączam w zestawie ramię zasilane dwoma serwami 9g sg90 i czujnik ultradźwiękowy HC-SR04. Idealna podstawa pod programowanie jezdnego robota, wystarczy dorzucić rasberry czy inną płytkę oraz zasilanie i mamy gotowego robota. Wszystko jest porzadnie podłączone i połączone. Wyprowadziłem również opcje montażu baterii LiPo poprzez zwykły Plug-In. Dorzucam również GRATIS dwa dodatkowe koła. Cena jaka mnie interesuje to 1400 zł. Mogę wystawić poprzez platformę sprzedażową. W innym wypadku płatność tylko i wyłącznie z góry. Pozdrawiam!
-
Cześć. Przedstawiam wam Small Autonomous Amateur Rover "Romek" - czyli owoc mojej, z założenia kosmetycznej, metamorfozy robota, którego można poznać w jednym z forbotowych kursów. (A ponieważ robiłem tylko w wolnych chwilach, których wielu nie mam, to niczym ciąża - zacząłem z końcem listopada, mamy narodziny z końcem sierpnia). Krótki zarys historyczny: Kilka lat temu miałem fazę, zakupiłem w Botlandzie kilka zestawów do kursów oraz tu i ówdzie trochę rzeczy do szuflady "przydasiów". Życie jednak weryfikuje i przez kilka lat zbierało kurz, aż w zeszłym roku przeszedłem w końcu kurs budowy robotów i kurs Arduino poziom I. Jednak chciałem przede wszystkim sterować robotem przez BT, do tego chciałem pozbyć się w jakiś sposób wężykowania. Odnalazłem info, że komunikacja z BT to w zasadzie komunikacja przez port szeregowy - zapiąłem HC-05, zainstalowałem aplikację Bluetooth RC Car i napisałem switch case pod dane wysyłane z tej apki. Pierwsza rozbudowa "forbociaka" - moduł HC-05 i konwerter poziomów logicznych. Robot jeździł sterowany przez BT i tyle. Podjąłem decyzję, że dokonam modyfikacji zarówno w kodzie, jak i wyglądzie - z tym ostatnim poszedł też warunek, tylko rzeczy z szuflady, żadnych nowych inwestycji - własny czelendż ruszył. Posiadałem podwozie typu T100, które miało silniki z enkoderami - pomyślałem, że super, bo te silniczki z kursu to mogłyby mieć problem z ruszeniem cięższej konstrukcji, ponadto różny typ osi sprawił, że nawet nie próbowałem z nimi rzeźbić. Początkowa radość minęła wraz z przeczytaniem specyfikacji - maksymalny prąd pracy dołączonych silników to 4,5A, zdecydowanie za dużo na shield od Forbota. Przekopywałem szufladę dalej, znalazłem w niej silniczki N20, ale to maluszki, no i oś za mała. Znalazłem także silniki DFRobot o odpowiedniej osi i punktach montażowych. Przeczytałem notę - 7,5V, prąd pracy 50mA, maks. prąd 600 mA, przekładnia 99:1 - zostały wybrane. Nie chciałem mieć elektroniki na zewnątrz, więc potrzeba było też obudowy. Na wstępie wybrałem Kradex Z125 na body i Kradex Z130 na czujnik odległości. Jednak wraz z rozbudową, wybrana obudowa okazała się za ciasna - ledwo się zamykała, a nie założyłem jeszcze wszystkiego, co chciałem. Dodatkowo chciałem odzyskać pewne piny Arduino, które zajmował shield, a których nie potrzebowałem (przycisk i odbiornik IR). Podjąłem decyzję o zmianie obudowy - miałem jeszcze Kradex Z112, która była szersza i nieco wyższa. Poprzednia obudowa wchodziła pomiędzy gąsienice, przy tej musiałem zastosować dystanse, żeby zamocować budę do podwozia i nie kolidować z gąsienicami. Dodałem płaski koszyk na 6 baterii AA, krańcówki dla jazdy autonomicznej, połączone po dwie równolegle - żeby pokryć jak najwięcej czoła i jednocześnie nie odchylać blaszek pod dużym kątem i nie dodawać wąsów z trytytek - i wyłącznik kołyskowy, żeby załączać zasilanie z zewnątrz. Kanapkę Arduino+shield rozdzieliłem i połączyłem je przewodami, odzyskując wspomniane wcześniej piny cyfrowe 2 i 3 oraz uzyskując dostęp do pinu 3,3 V. Obudowę przed dalszymi pracami pomalowałem. Żeby robot nie był tylko sterowanym autkiem, dodałem oczywiście czujnik odległości HC04-SR, czujnik temperatury i wilgotności DHT22 oraz dzielnik napięcia - zbudowany z rezystora 510k i dwóch 68k - dla pomiaru napięcia baterii. Profesjonalny dzielnik amatorski. Na koniec dodałem LED-y w oprawkach. 4 białe jako światła czołowe, każdy z rezystorem 1k. 2 zielone i 2 czerwone jako światła pozycyjne/nawigacyjne - również z rezystorami 1k. 2 żółte drogowe (już nie żółte, jeszcze nie pomarańczowe) jako światła ostrzegawcze, oczywiście z rezystorami 1k. 1 niebieski jako światło sygnalizujące jazdę autonomiczną, z rezystorem 330 Ohm. Niebieski LED jest zasilany i załączany bezpośrednio z Arduino. Pozostałe LED-y zasilane są z baterii i załączane przez tranzystory NPN BC548. Ostatecznie wyszło trochę makaronu z przewodów, ale nie jest ciasno, obudowa zamyka się dobrze, a ja mam w razie W spis przewodów, a te z górnej części, które są wpięte w Arduino UNO są także opisane na wtykach. :) Ponieważ żółte ledy miałem tylko typu clear i ich światło było widoczne tylko na wprost soczewki, dodałem dyfuzory zrobione ze... słomki. Romek po montażu waży ok. 1290 g i prezentuje się tak: Oprogramowanie: Założyłem, że chcę się pozbyć delay(), żeby nie kolidować z DHT oraz żeby robot reagował natychmiast na polecenia. Czasami musiałem się naklikać zanim robot zareagował. Czujnik odległości był jedną z prostszych rzeczy. Zastosowałem bibliotekę New Ping, dla której utworzyłem obiekt: NewPing sonar(trigPin, echoPin, MAX_DISTANCE); Sama funkcja wygląda tak: int sonarDystans() { int dystans = sonar.ping_cm(); // Wykonanie pomiaru i zapisanie wyniku w zmiennej distance w centymetrach return dystans; } A jej wykorzystanie na przykład tak: if (sonarDystans() <= doPrzeszkody) { //Jeżeli w zadanej odległości jest przeszkoda obecnyStan = ZATRZYMAJ; //Przejdź do zatrzymania czasStanu = millis(); //Ustaw czas dla timera serwo.attach(SERWO_PIN); //Podłącz serwo } Najwięcej problemów miałem z przepisaniem logiki jazdy autonomicznej. Poziom mojej wiedzy to kurs robota, kurs Arduino I i na coś tam liźnięte o DHT i millisach. Tutaj nawet zatrudniłem forumowiczów do pomocy: Ostatecznie oryginalną logikę wymieniłem na maszynę stanów, gdzie w danym stanie wywołuję funkcję, a dopiero w funkcji mam opisane zachowanie robota. switch (obecnyStan) { case PROSTO: prosto(); break; case ZATRZYMAJ: zatrzymaj(); break; void zatrzymaj() { zatrzymajSilniki(); if (millis() - czasStanu >= 500UL) { //Odczekaj zadany czas obecnyStan = PATRZ_PRAWO; //Przejdź do wykrywania przeszkody po prawej czasStanu = millis(); } } W przypadku krańcówek musiałem dodać flagę dla kolizji, gdyż bez tego po wjechaniu w przeszkodę robot się zatrzymywał. Zapewne zanim zdążył przejść dalej program ponownie docierał do miejsca, gdzie natrafiał co zrobić po załączeniu krańcówki. Dodanie flagi sprawiło, że problem zniknął. boolean kolizjaPrawo = false; if (digitalRead(prawySensor) == LOW && kolizjaPrawo==0) { //Jeżeli przeszkoda po prawej kolizjaPrawo = 1; obecnyStan = COFAJ_PRAWY; czasStanu = millis(); } void cofajPrawy() { lewySilnik(-70); prawySilnik(-70); if (millis() - czasStanu >= 800UL) { obecnyStan = ZATRZYMAJ2; //Przejdź do wykrywania przeszkody po prawej czasStanu = millis(); kolizjaPrawo = 0; } } Samo wejście w jazdę autonomiczną również realizowane jest zmianą flagi. W switch case dle odczytu z seriala/BT poczyniłem toggleswitch. case 'A': jazdaAutonomiczna = !jazdaAutonomiczna; if (!jazdaAutonomiczna) { zatrzymajSilniki(); ekspander.digitalWrite(LEDjazda, 0); serwo.detach(); } break; Nie ukrywam, że obsługę DHT podejrzałem w drugiej części kursu do Arduino, zanim tam dotrę, ale jak już wiemy, unikam delay(). Na podstawie obsługi czujnika z kursu i tego co wiem o millisach, napisałem funkcję po swojemu. Dodałem też korektę odczytów, gdyż względem czujnika referencyjnego temperatura była zawyżana o wilgotność zaniżana. Najpierw próbowałem korekty procentowej, ale ostatecznie wprowadziłem sztywną korektę. Względem czujnika referencyjnego odczyty nie odbiegają o więcej niż 0,5 stopnia i 0,5%. W tym miejscu dodałem także odczyt z ADC, gdzie doprowadziłem wyjście z dzielnika napięcia dla baterii. Dla napięcia baterii 9,66 V napięcie doprowadzone z dzielnika wynosiło ok. 0,95 V. Po wstępnym obliczeniu mnożnika, ostateczną wartość dobrałem empirycznie. Rozbieżność nie przekracza 0,1 V, średnio jest to 0,06 V. W funkcji tej następuje także wysyłanie danych na serial. void humitemp () { //Funkcja czujnika DHT22 i pomiar napięcia float wilgotnosc = dht.getHumidity(); //Pobierz info o wilgotności do zmiennej float temperatura = dht.getTemperature(); //Pobierz info o temperaturze do zmiennej float wilgKorekta = wilgotnosc + 1.11; //Korekta dla odczytu wilgotności float tempKorekta = temperatura - 2.35; //Korekta odczytu temperatury int adc_val = analogRead(bateria); //Odczytaj wartość ADC float Ubat = adc_val * 0.0485340314; //Wylicz wartość napięcia czasDHT = millis(); //Pobierz aktualny czas Arduino roznicaDHT = czasDHT - odmierzDHT; if (roznicaDHT >= 2000UL) { //Jeżeli różnica wyniesie 2000 ms lub więcej odmierzDHT = czasDHT; //Zapisz aktualny czas arduino do zmiennej if (dht.getStatusString() == "OK") { //Jeżeli czujnik zwróci wartość ok, wykonaj poniższe Serial.print(tempKorekta); Serial.print(" °C"); Serial.print("|"); Serial.print(wilgKorekta); Serial.print(" %"); Serial.print("|"); Serial.print(Ubat); Serial.println(" V"); } } } Wspomniałem wcześniej, że odzyskałem niektóre piny z Arduino. Zależało mi zwłaszcza na pinie PWM dla świateł pozycyjnych. W prototypie używałem pinu ekspandera w trybie włącz-wyłącz, a pulsowanie osiągałem przez zastosowany kondensator, jednak nie dawało to pełnej kontroli. Uwolniony pin PWM wykorzystałem właśnie do świateł pozycyjnych. Zmienna kierunek ma wartość 1 lub -1, zatem wartość PWM jest zwiększana lub zmniejszana. Kiedy wartość PWM osiąga 0 lub 255 wartość zmiennej kierunek zostaje przemnożona przez -1 powodując zmianę jej wartości na przeciwną. void swiatlaPuls() { aktualnyCzasPWM = millis(); // Obsługa narastania i opadania PWM if (aktualnyCzasPWM - poprzedniCzasPWM >= interwalZmianyPWM) { poprzedniCzasPWM = aktualnyCzasPWM; wartoscPWM += kierunek; //Zmniana wartości PWM zależna od wartości kiereunku if (wartoscPWM >= 255 || wartoscPWM <= 0) { if (aktualnyCzasPWM - poprzedniCzasAnimacji >= interwalZmianyKierunku) { poprzedniCzasAnimacji = aktualnyCzasPWM; kierunek *= -1; // Zmiana kierunku narastania/opadania } } analogWrite(pulsLED, wartoscPWM); } } Dla świateł ostrzegawczych chciałem osiągnąć efekt szybkich mignięć wplecionych we włączanie i wyłączanie (włącz, zapulsuj, wyłącz, powtórz). Pożądane zachowanie uzyskałem stosując switch case i zmienną dla licznika i zmieniając zachowanie świateł w zależności od jej wartości. void swiatlaStrobo() { czasLEDstrobo = millis(); switch(licznikStrobo) { case 0: digitalWrite(stroboLED, 1); if (czasLEDstrobo - czasStrobo >= 700UL) { digitalWrite(stroboLED, 0); czasStrobo = czasLEDstrobo; licznikStrobo ++; } break; case 13: digitalWrite(stroboLED, 0); if (czasLEDstrobo - czasStrobo >= 500UL) { digitalWrite(stroboLED, 0); licznikStrobo ++; } break; default: if (czasLEDstrobo - czasStrobo >= 50UL) { czasStrobo = czasLEDstrobo; stanStrobo = !stanStrobo; digitalWrite(stroboLED, stanStrobo); licznikStrobo ++; } break; } if (licznikStrobo > 13) { licznikStrobo = 0; } } Na koniec moja świeżynka. Poznałem operator trójargumentowy, zauważyłem, że dla mnie - tego amatora przed monitorem - działa podobnie do if else, zatem przepisałem logikę odpowiedzialną za silniki. Dotychczas używałem oryginalnej z kursu, po poznaniu tego operatora powstało coś takiego: void lewySilnik (int VL) { if (VL == 0) return; //Jeżeli wartość VL jest równa zero to nie wykonuj funkcji int kierunekLewySilnik = (VL > 0) ? 0 : 1; //Jeżeli wartość VL jest większa od 0 to ustaw wartość 0 (jazda do przodu), jeżeli mniej to ustaw 1 (do tyłu) int vlMap = map(abs(VL), 0, 100, 0, PWM_MAX); //Przemapuj zakres PWM do zakresu 0-100, dla ujemnego VL zwróć wartość absolutną digitalWrite(L_DIR, kierunekLewySilnik); //Jazda do przodu, albo do tyłu :) analogWrite(L_PWM, vlMap); //Ustaw zadaną prędkość } Komunikacja - software: Robot jest częściowo zgodny z aplikacją o której wspomniałem na początku (sterowanie, załączanie świateł co drugi kllik), ale gotowa apka nie do końca spełnia moje oczekiwania. Można też sterować przez aplikację typu BT serial monitor, ale to też nie do końca to - choć tutaj już odbieram dane. Postanowiłem wyrzeźbić - to dobre słowo - aplikację w APP Inventorze. O ile w sekcji bloczkowej jakoś to poszło, to graficznie naprawdę była to rzeźba. Predefiniowane rozdzielczości są przedpotopowe, a i responsive nie do końca daje to, czego człowiek oczekuje. Ale, potrzebowałem jednej apki, więc postanowiłem się przemęczyć, zamiast podejmować naukę tworzenia od podstaw w jakimś ludzkim środowisku. W pierwszej wersji odbierałem temperaturę i wilgotność, napis "connect" był tylko etykietą. W drugiej odbieram jeszcze wartość napięcia. Przyciski kierunkowe to przód, tyłu, obroty w miejscu w prawo, w lewo. Dodatkowo w narożnikach przyciski przywołują jazdę po łuku w daną stronę (prawy przód, lewy tył itp). Przycisk H wyzwala impuls buzzerem. Przycisk Światła uruchamia światła. Zmienna w robocie sprawia, że po kolei uruchamiane są: światła pozycyjne i ostrzegawcze, z drugim wywołaniem dochodzą światła frontowe, z trzecim wywołaniem gaszone są pozycyjne i ostrzegawcze, pozostają frontowe. Czwarte wywołanie resetuje zmienną i gasi wszystkie światła. Przycisk Auto włącza lub wyłącza tryb jazdy autonomicznej. Podsumowanie Zdaję sobie sprawę, że kod nie jest idealny, zwłaszcza, że wiele rzeczy znałem po łebkach, niektórych uczyłem się w trakcie. Ale jestem zadowolony - coś, co miało być tylko dodaniem sterowania BT zmieniło się w duży jak dla mnie projekt, który robiony po godzinach ostatecznie działa. Co dalej? Wyciągnę zasilanie jakoś zasilanie na zewnątrz. Zastosowana obudowa sprawia, że aby ją odkręcić, muszę ściągać gąsienice w celu uzyskania dostępu do śrub. To ze zwykłej wymiany baterii, czy przyszłych zmian w oprogramowaniu, zamienia rutynę w procedurę. W drugiej części kursu Arduino widziałem czujnik ruchu, więc pewnie też go jakoś zatrudnię - zamysł taki, że w trybie auto będzie sobie oczekiwał i uruchamiał jazdę po wykryciu ruchu. A ponieważ szuflada zawiera jeszcze jednego HC-05, jakiegoś klona Nano i wyświetlacz OLED, mam w planie zrobić sprzętowy kontroler dla tego robota. Co to za antenka? To tylko ozdoba - zabieram Romka ze sobą na ERC w tym roku - będzie maskotką. Jaki koszt konwersji? Dla mnie żaden, jeżeli uznajemy, że co w szufladzie to 0 zł. Jeżeli ktoś by chciał iść w moje ślady, to myślę, że kilka stówek. Podwozie jest najdroższe. Ale jak już ktoś ma wydawać pieniądze na konwersję, to lepiej na budowę od podstaw i zrezygnować z tego shielda, na rzecz sterownika, który uciągnie silniki 4,5A - wtedy nie trzeba szukać silników, które ogarnie shield i parę zł zostaje. Osobiście, gdyby nie postanowienie zrobienia tego bez dodatkowych nakładów, to pewnie też bym dokupił kilka rzeczy, rezygnując z shielda forbotowego, ale czelendż to czelendż. Dotarłeś tutaj? No to zobacz krótki filmik. Podjazd miał nachylenie ok. 30 stopni. A tutaj cały potworek //Załączenie bibliotek #include "DHT.h" //Czujnik temperatury i wilgotności #include "Servo.h" #include "Adafruit_MCP23008.h" //Ekspander portów #include <NewPing.h> //Obsługa HC-SR04 //Ekspander Adafruit_MCP23008 ekspander; //Deklaracje i zmienne dla DHT i pomiaru napięcia #define DHT22_PIN 7 //Pin sygnału z DHT DHT dht; //Utworzenie obiektu dla czujnika #define bateria A3 unsigned long czasDHT = 0; unsigned long odmierzDHT = 0; unsigned long roznicaDHT = 0; //Deklaracje serwomechanizmu Servo serwo; #define SERWO_PIN 11 //Pin sygnału sterującego PWM int idle = 84; //Neutralna pozycja dla serwa //Deklaracje mostek H #define L_PWM 5 //Pin prędkości lewego silnika #define L_DIR 4 //Pin kierunku lewego silnika #define R_PWM 6 //Pin prędkości prawego silnika #define R_DIR 9 //Pin kierunku prawego silnika #define PWM_MAX 210 //Maksymalne wypełnienie dla silnika 7,5V przy zasilaniu 9V //Deklaracje i definicje do obsługi buzzera #define BUZZER 10 unsigned long aktualnyCzasBuzzer = 0; unsigned long czasStartuBuzzer = 0; unsigned long czasTrwaniaBuzzer = 200; // Czas trwania impulsu w milisekundach boolean buzzerON = false; //Deklaracje i zmienne czujnika odległości i wykrywania przeszkód #define LEDjazda 0 //LED informujący o jeździe autonomicznej na 0 pinie ekspandera!!! #define lewySensor A0 //Krańcówka po lewej #define prawySensor A1 //Krańcówka po prawej #define trigPin 12 //Pin nadawczy (szary) #define echoPin 13 //Pin odbiorczy (biały) #define MAX_DISTANCE 200 // Maksymalny zasięg w centymetrach NewPing sonar(trigPin, echoPin, MAX_DISTANCE); //Inicjalizacja obiektu sonar z użyciem biblioteki NewPing const int doPrzeszkody = 25; //Odległość wykrywania przeszkody w cm //Wyliczenie stanów dla jazdy autonomicznej enum States { PROSTO, PATRZ_PRAWO, OBROT_PRAWO, PATRZ_LEWO, OBROT_LEWO, ZATRZYMAJ, ZATRZYMAJ2, COFAJ, COFAJ_LEWY, COFAJ_PRAWY, }; boolean jazdaAutonomiczna = false; boolean kolizjaPrawo = false; boolean kolizjaLewo = false; static States obecnyStan = PROSTO; //Domyślny stan unsigned long czasStanu = 0; //Zmienna dla timera stanu unsigned long czasDotyku = 0; //Zmienna dla timera krańcówek static unsigned long czasObrotu = 1100; //Zmienna dla czasu trwania obrotu //Definicje i zmienne dla świateł #define frontLED 1 //LEDy frontowe na 1 pinie ekspandera!!! #define stroboLED 2 #define pulsLED 3 int trybLED = 0; unsigned long czasStrobo = 0; unsigned long czasLEDstrobo = 0; int stanStrobo = 0; int licznikStrobo = 0; int stanPuls = 0; unsigned long poprzedniCzasPWM = 0; unsigned long poprzedniCzasAnimacji = 0; int wartoscPWM = 0; int kierunek = 1; // 1 - narastanie, -1 - opadanie unsigned long interwalZmianyPWM = 10; unsigned long interwalZmianyKierunku = 750; unsigned long aktualnyCzasPWM = 0; void setup() { //Konfiguracja ekspandera ekspander.begin(); ekspander.pinMode(LEDjazda, OUTPUT); //Konfiguracja świateł ekspander.digitalWrite(LEDjazda, LOW); pinMode(stroboLED, OUTPUT); digitalWrite(stroboLED, stanStrobo); pinMode(pulsLED, OUTPUT); analogWrite(pulsLED, stanPuls); ekspander.pinMode(frontLED, OUTPUT); ekspander.digitalWrite(frontLED, LOW); //Konfiguracja pinów mostka H pinMode(L_DIR, OUTPUT); pinMode(L_PWM, OUTPUT); pinMode(R_DIR, OUTPUT); pinMode(R_PWM, OUTPUT); //Konfiguracja pozostałych elementów pinMode(bateria, INPUT); //Odczyt ADC dla pomiaru napięcia baterii pinMode(lewySensor, INPUT_PULLUP); pinMode(prawySensor, INPUT_PULLUP); Serial.begin(9600); //Uruchomienie sprzętowej komunikacji UART dht.setup(DHT22_PIN); //Podłączenie czujnika do zadeklarowanego pinu serwo.attach(SERWO_PIN); //Podłączenie serwa do zadeklarowanego pinu serwo.write(idle); //Ustawienie serwa w domyślnej pozycji delay(200); //Opóźnienie dla ustabilizowania i przeczekania stanów nieustalonych serwo.detach(); //Odłączenie serwa //Konfiguracja buzzera i info o zakończeniu setupu pinMode(BUZZER, OUTPUT); digitalWrite(BUZZER, 1); ekspander.digitalWrite(LEDjazda, 1); delay(100); digitalWrite(BUZZER, 0); ekspander.digitalWrite(LEDjazda, 0); delay(100); digitalWrite(BUZZER, 1); ekspander.digitalWrite(LEDjazda, 1); delay(100); digitalWrite(BUZZER, 0); ekspander.digitalWrite(LEDjazda, 0); delay(100); } void loop() { humitemp(); //Wykonuj funkcje DHT if(jazdaAutonomiczna) { jazdaAuto(); } switch (trybLED) { case 0: analogWrite(pulsLED, 0); digitalWrite(stroboLED, 0); ekspander.digitalWrite(frontLED, 0); break; case 1: swiatlaPuls(); swiatlaStrobo(); ekspander.digitalWrite(frontLED, 0); break; case 2: swiatlaPuls(); swiatlaStrobo(); swiatlaFront(); break; case 3: analogWrite(pulsLED, 0); digitalWrite(stroboLED, 0); swiatlaFront(); break; case 4: trybLED = 0; break; } if (buzzerON) { klakson(); } if (Serial.available() > 0) { //Jeżeli są dostępne dane BT char jazda = Serial.read(); //Odczytaj te dane i przypisz do zmiennej switch(jazda) { //Wykonaj case zgodnie z odebranymi danymi case 'F': //Do przodu lewySilnik(95); prawySilnik(95); break; case 'B': //Do tyłu lewySilnik(-95); prawySilnik(-95); break; case 'S': //Zatrzymaj zatrzymajSilniki(); break; case 'L': //Obrót w lewo lewySilnik(-80); prawySilnik(80); break; case 'R': //Obrót w prawo lewySilnik(80); prawySilnik(-80); break; case 'G': //Lewy łuk do przodu lewySilnik(60); prawySilnik(95); break; case 'I': //Prawy łuk do przodu lewySilnik(95); prawySilnik(60); break; case 'H': //Lewy łuk do tyłu lewySilnik(-60); prawySilnik(-95); break; case 'J': //Prawy łuk do tyłu lewySilnik(-95); prawySilnik(-60); break; case 'V': //Impuls buzzerem buzzerON = !buzzerON; czasStartuBuzzer = millis(); break; case 'X': trybLED++; break; case 'A': jazdaAutonomiczna = !jazdaAutonomiczna; if (!jazdaAutonomiczna) { zatrzymajSilniki(); ekspander.digitalWrite(LEDjazda, 0); serwo.detach(); } break; } } } void lewySilnik (int VL) { if (VL == 0) return; //Jeżeli wartość VL jest równa zero to nie wykonuj funkcji int kierunekLewySilnik = (VL > 0) ? 0 : 1; //Jeżeli wartość VL jest większa od 0 to ustaw wartość 0 (jazda do przodu), jeżeli mniej to ustaw 1 (do tyłu) int vlMap = map(abs(VL), 0, 100, 0, PWM_MAX); //Przemapuj zakres PWM do zakresu 0-100, dla ujemnego VL zwróć wartość absolutną digitalWrite(L_DIR, kierunekLewySilnik); //Jazda do przodu, albo do tyłu :) analogWrite(L_PWM, vlMap); //Ustaw zadaną prędkość } void prawySilnik (int VR) { if (VR == 0) return; //Jeżeli wartość VL jest równa zero to nie wykonuj funkcji int kierunekLewySilnik = (VR > 0) ? 1 : 0; //Jeżeli wartość VR jest większa od 0 to ustaw wartość 1 (jazda do przodu), jeżeli mniej to ustaw 0 (do tyłu) int vrMap = map(abs(VR), 0, 100, 0, PWM_MAX); //Przemapuj zakres PWM do zakresu 0-100 digitalWrite(R_DIR, kierunekLewySilnik); //Jazda do przodu, albo do tyłu :) analogWrite(R_PWM, vrMap); //Ustaw zadaną prędkość } void zatrzymajSilniki() { analogWrite(L_PWM, 0); //Zatrzymaj lewy silnik analogWrite(R_PWM, 0); //Zatrzymaj prawy silnik } void humitemp () { //Funkcja czujnika DHT22 i pomiar napięcia float wilgotnosc = dht.getHumidity(); //Pobierz info o wilgotności do zmiennej float temperatura = dht.getTemperature(); //Pobierz info o temperaturze do zmiennej float wilgKorekta = wilgotnosc + 1.11; //Procentowa korekta dla odczytu wilgotności float tempKorekta = temperatura - 2.35; //Korekta odczytu temperatury int adc_val = analogRead(bateria); //Odczytaj wartość ADC float Ubat = adc_val * 0.0485340314; //Wylicz wartość napięcia czasDHT = millis(); //Pobierz aktualny czas Arduino roznicaDHT = czasDHT - odmierzDHT; if (roznicaDHT >= 2000UL) { //Jeżeli różnica wyniesie 2000 ms lub więcej odmierzDHT = czasDHT; //Zapisz aktualny czas arduino do zmiennej if (dht.getStatusString() == "OK") { //Jeżeli czujnik zwróci wartość ok, wykonaj poniższe Serial.print(tempKorekta); Serial.print(" °C"); Serial.print("|"); Serial.print(wilgKorekta); Serial.print(" %"); Serial.print("|"); Serial.print(Ubat); Serial.println(" V"); } } } int sonarDystans() { int dystans = sonar.ping_cm(); // Wykonanie pomiaru i zapisanie wyniku w zmiennej distance w centymetrach return dystans; } void swiatlaPuls() { aktualnyCzasPWM = millis(); // Obsługa narastania i opadania PWM if (aktualnyCzasPWM - poprzedniCzasPWM >= interwalZmianyPWM) { poprzedniCzasPWM = aktualnyCzasPWM; wartoscPWM += kierunek; //Zmniana wartości PWM zależna od wartości kiereunku if (wartoscPWM >= 255 || wartoscPWM <= 0) { if (aktualnyCzasPWM - poprzedniCzasAnimacji >= interwalZmianyKierunku) { poprzedniCzasAnimacji = aktualnyCzasPWM; kierunek *= -1; // Zmiana kierunku narastania/opadania } } analogWrite(pulsLED, wartoscPWM); } } void swiatlaStrobo() { czasLEDstrobo = millis(); switch(licznikStrobo) { case 0: digitalWrite(stroboLED, 1); if (czasLEDstrobo - czasStrobo >= 700UL) { digitalWrite(stroboLED, 0); czasStrobo = czasLEDstrobo; licznikStrobo ++; } break; case 13: digitalWrite(stroboLED, 0); if (czasLEDstrobo - czasStrobo >= 500UL) { digitalWrite(stroboLED, 0); licznikStrobo ++; } break; default: if (czasLEDstrobo - czasStrobo >= 50UL) { czasStrobo = czasLEDstrobo; stanStrobo = !stanStrobo; digitalWrite(stroboLED, stanStrobo); licznikStrobo ++; } break; } if (licznikStrobo > 13) { licznikStrobo = 0; } } void swiatlaFront() { ekspander.digitalWrite(frontLED, 1); } void jazdaAuto() { //Funkcja jazdy autonomicznej ekspander.digitalWrite(LEDjazda, 1); //Włącz LED informujący o jeździe autonomicznej switch (obecnyStan) { case PROSTO: prosto(); break; case ZATRZYMAJ: zatrzymaj(); break; case ZATRZYMAJ2: zatrzymaj2(); break; case PATRZ_PRAWO: //Wykrywanie przeszkód po prawej patrzPrawo(); break; case OBROT_PRAWO: //Skręt w prawo obrotPrawo(); break; case PATRZ_LEWO: //Wykrywanie przeszkód po lewej patrzLewo(); break; case OBROT_LEWO: //Skręt w lewo obrotLewo(); break; case COFAJ: cofaj(); break; case COFAJ_LEWY: cofajLewy(); break; case COFAJ_PRAWY: cofajPrawy(); break; } if (digitalRead(lewySensor) == LOW && kolizjaLewo==0) { //Jeżeli przeszkoda po lewej kolizjaLewo = 1; obecnyStan = COFAJ_LEWY; czasStanu = millis(); } if (digitalRead(prawySensor) == LOW && kolizjaPrawo==0) { //Jeżeli przeszkoda po prawej kolizjaPrawo = 1; obecnyStan = COFAJ_PRAWY; czasStanu = millis(); } } void prosto() { if (sonarDystans() <= doPrzeszkody) { //Jeżeli w zadanej odległości jest przeszkoda obecnyStan = ZATRZYMAJ; //Przejdź do zatrzymania czasStanu = millis(); //Ustaw czas dla timera serwo.attach(SERWO_PIN); //Podłącz serwo } else { //Jedź prosto lewySilnik(90); prawySilnik(90); } } void zatrzymaj() { zatrzymajSilniki(); if (millis() - czasStanu >= 500UL) { //Odczekaj zadany czas obecnyStan = PATRZ_PRAWO; //Przejdź do wykrywania przeszkody po prawej czasStanu = millis(); } } void zatrzymaj2() { zatrzymajSilniki(); if (millis() - czasStanu >= 500UL) { obecnyStan = PATRZ_LEWO; //Przejdź do wykrywania przeszkody po prawej czasStanu = millis(); } } void patrzPrawo() { serwo.write(25); //Ustw serwo w prawo if (millis() - czasStanu >= 400UL) { //Patrz przez zadany czas dla ustabilizowania serwa if (sonarDystans() > doPrzeszkody) { //Jeżeli nie ma przeszkód bliżej niż zadana odległość obecnyStan = OBROT_PRAWO; //Skręć w prawo czasStanu = millis(); //Ustaw czas dla timera } else { //Jeżeli jest przeszkoda obecnyStan = PATRZ_LEWO; //Przejdź do wykrywania przeszkody po lewej czasStanu = millis(); //Ustaw czas dla timera } } } void obrotPrawo() { lewySilnik(70); prawySilnik(-70); serwo.write(idle); //Ustaw serwo na wprost if (millis() - czasStanu >= czasObrotu) { //Skręcaj przez zadany czas serwo.detach(); obecnyStan = PROSTO; //Przejdź do jazdy na prosto czasStanu = millis(); //Ustaw czas dla timera } } void patrzLewo() { serwo.write(155); //Obróć serwo w lewo if (millis() - czasStanu >= 450UL) { //Patrz przez zadany czas dla ustabilizowania serwa if (sonarDystans() > doPrzeszkody) { //Jeżeli nie ma przeszkody w zadanej odległości obecnyStan = OBROT_LEWO; //Skręć w lewo czasStanu = millis(); //Ustaw czas dla timera } else { //Jeżeli jest przeszkoda obecnyStan = COFAJ; //Włącz alarm czasStanu = millis(); //Ustaw czas dla timera } } } void obrotLewo() { lewySilnik(-70); prawySilnik(70); serwo.write(idle); //Ustaw serwo na wprost if (millis() - czasStanu >= czasObrotu) { //Skręcaj przez zadany czas serwo.detach(); obecnyStan = PROSTO; //Przejdź do jazdy prosto czasStanu = millis(); //Ustaw czas dla timera } } void cofaj() { serwo.write(idle); //Ustaw serwo na wprost lewySilnik(-80); //cofaj prawySilnik(-80); if (millis() - czasStanu >= 800UL) { //Po upływie zadanego czasu zatrzymajSilniki(); //Zatrzymaj się obecnyStan = ZATRZYMAJ; //Przejdź do jazdy prosto czasStanu = millis(); //Ustaw czas dla timera } } void cofajLewy() { lewySilnik(-70); prawySilnik(-70); if (millis() - czasStanu >= 800UL) { obecnyStan = ZATRZYMAJ; //Przejdź do wykrywania przeszkody po prawej czasStanu = millis(); kolizjaLewo = 0; } } void cofajPrawy() { lewySilnik(-70); prawySilnik(-70); if (millis() - czasStanu >= 800UL) { obecnyStan = ZATRZYMAJ2; //Przejdź do wykrywania przeszkody po prawej czasStanu = millis(); kolizjaPrawo = 0; } } void klakson() { aktualnyCzasBuzzer = millis(); if (aktualnyCzasBuzzer - czasStartuBuzzer < czasTrwaniaBuzzer) { digitalWrite(BUZZER, HIGH); } else { digitalWrite(BUZZER, LOW); buzzerON = false; } }
- 3 odpowiedzi
-
- 13
-
-
Hej! Jeszcze jestem zielony, ale walczę. Moja wiedza to na razie kurs Arduino I i coś tam echem o millis. Jestem w trakcie modyfikacji robota z forbotowego kursu, oprócz zmian w budowie, wprowadzam też zmiany w programie. Jednym z założeń jest eliminacja wstrzymujących program delayów. Aktualnie pracuję nad sekcją jazdy autonomicznej. Popełniłem działający program z millisami, ale kolega @ethanak wskazał mi, że no nie do końca. Zatem, na początku kody z kursu (żeby w jednym miejscu było): Kontaktowe wykrywania/omijanie przeszkód: if (digitalRead(L_SIDE_SENSOR) == LOW) { //Jesli przeszkoda po lewej stronie //Jedz wstecz i wydawaj dzwiek leftMotor(-40); rightMotor(-40); digitalWrite(BUZZER, 1); delay(800); //Obrot w miejscu w prawo leftMotor(40); rightMotor(-40); digitalWrite(BUZZER, 0); delay(140); //Koniec warunku wracamy do jazdy prosto } if (digitalRead(R_SIDE_SENSOR) == LOW) { //Jesli przeszkoda po prawej stronie //Jedz wstecz i wydawaj dzwiek leftMotor(-40); rightMotor(-40); digitalWrite(BUZZER, 1); delay(800); //Obrot w miejscu w lewo leftMotor(-40); rightMotor(40); digitalWrite(BUZZER, 0); delay(140); //Koniec warunku wracamy do jazdy prosto } Wykrywanie przeszkód czujnikiem ultradźwiękowym: void loop() { //Czy wykryto przeszkode w zakresie 0-40 cm if (zmierzOdleglosc() > 40) { leftMotor(40); //Jesli nie, to jedz prosto rightMotor(40); } else { //Jesli przeszkoda stopMotors(); //Zatrzymaj robota serwo.write(20); //Skrec czujnikiem w prawo delay(800); //Poczekaj 800ms dla ustabilizowania konstrukcji //Sprawdz, czy po prawej stronie jest przeszkoda if (zmierzOdleglosc() > 40) { //Jesli jest pusto leftMotor(40); rightMotor(-40); delay(400); //Obracaj w prawo przez 400 ms } else { //Jeśli po prawej jest przeszkoda serwo.write(160); //Obroc czujnik w lewo delay(800); //Poczekaj 800ms dla ustabilizowania konstrukcji //Sprawdz, czy po lowej stronie jest przeszkoda if (zmierzOdleglosc() > 40) { //Jesli jest pusto leftMotor(-40); rightMotor(40); delay(400); //Obracaj w lewo przez 400 ms } else { //Jesli z przodu, z lewej i prawej jest przeszkoda digitalWrite(BUZZER, 1); delay(500); digitalWrite(BUZZER, 0); //Daj sygnal buzzerem } } //Po sprawdzeniu przeszkod po bokach //Ustaw czujnik prosto serwo.write(90); } //Opoznienie 100ms, ponieważ nie ma potrzeby sprawdzać przeszkod czesciej delay(100); } Aktualnie popełniłem taką funkcję, łączącą wykrywanie przeszkód przez krańcówki i sonar: void jazdaAuto() { //Funkcja jazdy autonomicznej ekspander.digitalWrite(LEDjazda, 1); unsigned long kontakt = 0; //Zmienne przechowująca czas startu unsigned long przeszkoda = 0; if (digitalRead(lewySensor) == LOW) { //Jeżeli przeszkoda po lewej zatrzymajSilniki(); kontakt = millis(); //Aktualizuj czas startu while (millis() - kontakt < 100) {} //Poczekaj 100 ms lewySilnik(-80); //Cofnij kawałek prawySilnik(-80); kontakt = millis(); //Aktualizuj czas startu while (millis() - kontakt < 800) {} //Cofaj przez 800 ms lewySilnik(80); //Skręć w prawo prawySilnik(-80); kontakt = millis(); //Aktualizuj czas startu while (millis() - kontakt < 800) {} //Skręcaj przez 800 ms zatrzymajSilniki(); kontakt = millis(); //Aktualizuj czas startu while (millis() - kontakt < 100) {} //Poczekaj 100 ms } if (digitalRead(prawySensor) == LOW) { //Jeżeli przeszkoda po prawej zatrzymajSilniki(); kontakt = millis(); //Aktualizuj czas startu while (millis() - kontakt < 100) {} //Poczekaj 100 ms lewySilnik(-80); //Cofnij kawałek prawySilnik(-80); kontakt = millis(); //Aktualizuj czas startu while (millis() - kontakt < 800) {} //Cofaj przez 800 ms lewySilnik(-80); //Skręć w lewo prawySilnik(80); kontakt = millis(); //Aktualizuj czas startu while (millis() - kontakt < 800) {} //Skręć w lewo przez 800 ms zatrzymajSilniki(); kontakt = millis(); //Aktualizuj czas startu while (millis() - kontakt < 100) {} //Poczekaj 100 milisekund } if (sonarDystans() > 30) { // Jeżeli w odległości 30 cm nie ma przeszkody lewySilnik(90); // To jedź prosto prawySilnik(90); } else { // Jeżeli wykryłeś przeszkodę serwo.attach(SERWO_PIN); // Podłącz serwo zatrzymajSilniki(); serwo.write(700); // Skręć czujnikiem w prawo przeszkoda = millis(); while(millis() - przeszkoda < 800) {}; //Poczekaj 800 ms if (sonarDystans() > 30) { // Jeżeli w odległości 30 cm nie ma przeszkody lewySilnik(70); // Skręcaj w prawo prawySilnik(-70); serwo.write(1400); // Ustaw serwo do pozycji domyślnej przeszkoda = millis(); while(millis() - przeszkoda < 800) {}; // Skręcaj przez 800 ms serwo.detach(); // Odłącz serwo } else { // Jeżeli wykryłeś przeszkodę serwo.write(2100); // Skręć czujnikiem w lewo przeszkoda = millis(); while(millis() - przeszkoda < 800) {}; //Poczekaj 800 ms if (sonarDystans() > 30) { // Jeżeli w odległości 30 cm nie ma przeszkody lewySilnik(-70); // Skręcaj w lewo prawySilnik(70); serwo.write(1400); // Ustaw serwo domyślnie przeszkoda = millis(); while(millis() - przeszkoda < 800) {}; // Skręcaj przez 800 ms serwo.detach(); // Odłącz serwo } else { // Jeżeli z każdej strony jest przeszkoda serwo.write(1400); // Ustaw serwo domyślnie digitalWrite(BUZZER, 1); // Daj sygnał buzzerem przeszkoda = millis(); while(millis() - przeszkoda < 500) {}; //Buzzer włączony przez 500 ms digitalWrite(BUZZER, 0); //Wyłącz buzzer serwo.detach(); //Odłącz serwo } } } przeszkoda = millis(); while (millis()-przeszkoda < 100) {} //Opóźnienie 100 ms dla wykrywania przeszkód }
-
Dzień dobry. Mam problem z silnikami DC w moim linefollowerze - a mianowicie taki, że się psują. Parametry mojego robota to: - masa: 207 g - wymiary: długość 200 mm, szerokość od koła do koła 187 mm - zasilanie: 2 x Li - Po (w pełni naładowane łącznie 8,4 V) https://botland.com.pl/akumulatory-li-pol-1s-37v/15618-akumulator-li-pol-akyga-1100mah-1s-37v-zlacze-jst-bec-gniazdo-55x32x62mm-5904422343613.html - sterownik silników: DRV8835 (ciągły prąd 1.2 A, chwilowy 1.5 A, zakres napięć 2 - 11 V) https://botland.com.pl/sterowniki-silnikow-dc/851-drv8835-dwukanalowy-sterownik-silnikow-11v12a-pololu-2135-5904422367220.html Zdjęcia robota: Jak widać, robot ma dwa tylnie koła, a z przodu "ślizga" się na tej małej kulce (ona się nie obraca jak ball caster, robot się po prostu ślizga) Dotychczas robot był napędzany tymi silnikami: https://botland.com.pl/silniki-micro-n20-seria-mp-medium-power/12555-silnik-n20-bt16-micro-101-2000rpm-9v-5904422306564.html Maksymalne napięcie zasilania to 8.4 V, a realne napięcie wystawiane przez sterownik silników przy największej prędkości to 6.8 V (mierzone multimetrem). Niestety mimo że te napięcia zawierają się w zakresie napięć tego modelu silnika (3 - 9 V) to silnik się psuje - wał silnika bardzo ciężko obrócić i nie chce startować. Dlatego proszę o pomoc w dobraniu odpowiednich parametrów silnika DC do mojego robota, lub (jeszcze lepiej) konkretnego modelu silnika. Najlepiej jakby miał takie same wymiary co dotychczas, żebym nie musiał zmieniać podwozia robota. Jeśli pominąłem coś ważnego to odpowiem na dalsze pytania, z góry dziękuję za wszelką pomoc.
- 3 odpowiedzi
-
- linefollower
- robot
-
(i 1 więcej)
Tagi:
-
Cześć, Zaprezentuje swojego robota albo raczej prototyp, który powstał głównie do stworzenia i testowania oprogramowania do zarządzania robotem. Natomiast drugim celem było zebranie danych dla sieci neuronowej. Zadaniem robota było jeżdżenie miedzy liniami i zebranie danych z kamery i sterownika silników. I ostatnim celem było wykorzystanie nauczonej sieci prowadzania robota między liniami. Elektronika i zasilanie: Raspberry Pi 4B WiFi 4GB RAM kamera HD OV5647 5Mpx sterownik silników TB6612FNG siniki i przekładnia (344,2:1) to jakaś stara Tamiya power bank 20000mAh,2A MAX chyba Części mechaniczne i konstrukcyjne: gąsienice i koła wydrukowane (pobrane ze strony: www.printables.com) mocowanie do kamery drukowane Oprogramowanie: https://github.com/noxgle/pt2 Problemy: Sterownik silników jest zasilany bezpośrednio z Raspberry co powdowiało że przy pełnym wypełnieniu pwm "brakowało prądu" i następował restart. Zmniejszenie wypełnienia pwm do 50% pomogło do momentu większego rozładowanie baterii. Robotem podczas zbierania danych sterowała aplikacja uruchomiona na laptopie po sieci WiFI. Dane z kamery były obrabiane były wykorzystaniem biblioteki OpenCV. Sterowanie robotem z nauczoną siecią też odbywało się z wykorzystaniem laptopa. Do nauki została wykorzystana biblioteka fast.ai
-
Animatronika Kolejny krasnolud do kolekcji
ethanak opublikował temat w Projekty - DIY w budowie (worklogi)
Mocne postanowienie: na podstawie doświadczeń z lalkami zrobić coś, co pozbawione jest błędów poprzednich konstrukcji Robot początkowo miał być czarownicą, ale okazało się, że dzieci w przedszkolu negatywnie reagują na postacie tego typu (młodsze się wręcz boją czarownicy czy czarodzieja), dlatego ma być to kolejny Krasnolud. Tym razem nie Tolkienowski mieszkaniec podziemi, a sympatyczny Krasnal mieszkający w lesie, z ładną czerwona czapeczką i miłym dla oka szlafroczkiem. Ponieważ sprawę podwozia mam na razie nie do końca rozwiązaną, postanowiłem, że będzie to stary Krasnolud, jeżdżący w fotelu na kółkach. Takie rozwiązanie zwalnia mnie z konieczności ukrywania kół napędowych, a jednocześnie pozwala na użycie większych i tańszych silników (NEMA 17, kupione po 7 PLN na Allegro). Ponownie chcę użyć akumulatora Parkside (bardzo dobrze sprawdził się w poprzednim Krasnoludzie), tym razem nie kombinuję z EasyDriverami tylko wstawiłem stare dobre A4988. Zostawiam sobie jednak możliwość zastosowania TMC 2209 (o ile eksperyment pokaże, że detekcja zatrzymania silnika będzie działała poprawnie). Na razie mam złożone podwozie: Silniki które kupiłem miały założone zębatki na wałach, dlatego taka a nie inna konstrukcja kół napędowych. Teoretycznie mają półtora ampera na cewkę, na sterownikach ustawiłem na razie 0.7A a i tak są za mocne. Ale dokładniej będę mógł ustawić dopiero na zakończenie. I tu ciekawostka: koła wyposażone w łożyska 6mm miały być osadzone na wspólnej osi. Niestety, okazało się że gwintowany (podobno M6) pręt który mam ma jakieś 5.4mm średnicy i nie bardzo chciał współpracować z łożyskami. Użyłem pojedynczych śrub wymontowanych ze starej kanapy (jak dobrze sobie zostawić takie drobiazgi). A co z resztą? Głowę mam w połowie gotową. Dzisiaj powinny przyjść serwa HD1440A (zależy mi zarówno na wymiarach, jak i najmniejszym możliwym poborze prądu). W sumie jest tu pięć serw: po jednym HD1370A umieszczonych wewnątrz gałki ocznej, jedno do pionowego wspólnego ruchu oczu, jedno do skłonu głowy (uczciwe cięgło a nie jakieś wydumane zębatki) i jedno do obrotu (tym razem przekładnia zębata 1:2, sprawdziła się bardzo dobrze w poprzednich konstrukcjach). Jak tylko uda mi się zamontować serwa wrzucę jakąś ładną fotkę. Ręce - a właściwie ręka, bo tylko prawa ma być w pełni animowana. Zrobiłem bardzo ambitne założenie sześciu stopni swobody, zobaczymy co z tego wyjdzie. Serwa do napędu ręki mam. Kombinuję jeszcze z jakimś wyhamowaniem oscylacji na głównym serwie barkowym, być może uda mi się to osiągnąć programowo tylko musiałbym dodać jakieś sprzężenie zwrotne... no cóż, zobaczymy co z tego wyjdzie. Jeśli nic, zawsze mogę skorzystać ze sprawdzonego rozwiązania (ograniczenie prędkości ruchu serwa). No i oczywiście "drobiazgi": żyroskop/akcelerometr, kamera (do patrzenia na twarz rozmówcy), czujnik odległości (tym razem nie tylko do wykrywania przeszkód ale również do ustalania zbieżności oczu), syntezator mowy i takie tam różności. Zdalne sterowanie na razie poprzez UDP (ESP32 pracujący w trybie AP_STA, czyli z możliwością zarówno podłączenia do domowej sieci WiFi jak i do pracującego w trybie STA sterownika). Pozwala mi to na odłożenie zaprojektowania sterownika na sam koniec i sterowanie na razie prostą aplikacją na pececie. No cóż - sam jestem ciekaw co mi z tego wyjdzie -
Freestyle Robot gąsienicowy PENETRATOR
Arturo opublikował temat w Projekty - DIY w budowie (worklogi)
Cześć. Chciałem wam pokazać projekt nad którym pracuję: PENETRATOR Trochę konkretów: aluminiowy kadłub napęd: dwa silniki elektryczne szczotkowe 9V zasilanie 2 x 18650 + 2 x 18650 ukryte pod kadłubem kontroler: Raspberry Pi 3 A+ wizja: moduł kamery 1080p emitery IR umożliwiające kamerze pracę w ciemnościach łączność: WiFi (access point i serwer HTTP) język programowania : Python 3 sterowanie i obraz: autorska aplikacja webowa (w przeglądarce) umożliwiająca wyświetlanie obrazu z kamery i sterowanie robotem W PLANACH: mechaniczne ramię 7DOF oparte na serwomechanizmach MG996R obracanie kamery w 2 płaszczyznach przy pomocy serwomechanizmów mam też ochotę pobawić się sztuczną inteligencją, stąd wybór raspberry a nie np. esp8266 Przy okazji, podziękowania dla Forbot.pl za podstawy które wprowadziły mnie do świata robotyki- 10 odpowiedzi
-
- 6
-
-
- gąsienicowy
- robot
-
(i 2 więcej)
Tagi:
-
Witam mam następujący problem- Posiadam robota alphabot https://botland.com.pl/waveshare-roboty-edukacyjne/8077-alphabot-2-kolowa-platforma-robota-z-czujnikami-i-napedem-dc-waveshare-12249-5903351240291.html takiego jak w linku gdy wgrywam kod do sterowania ir kod nie działa czytałem że trzeba po przełączać jakieś zworki ale które nie wiem wstawiam również kod bo może to jest jego wina dodam że kod jest dołączony w instrukcji od robota z góry dziękuję za odpowiedź #include "AlphaBot.h" #define KEY2 0x18 //Key:2 #define KEY8 0x52 //Key:8 #define KEY4 0x08 //Key:4 #define KEY6 0x5A //Key:6 #define KEY1 0x0C //Key:1 #define KEY3 0x5E //Key:3 #define KEY5 0x1C //Key:5 #define SpeedDown 0x07 //Key:VOL- #define SpeedUp 0x15 //Key:VOL+ #define ResetSpeed 0x09 //Key:EQ #define Repeat 0xFF //press and hold the key #define IR 4 //he infrare remote receiver pin unsigned long n = 0; AlphaBot ArduinoCar = AlphaBot(); unsigned char t[30]; unsigned char results; char IR_decode(unsigned char code); void translateIR(); void setup() { Serial.begin(115200); pinMode(IR, INPUT); ArduinoCar.SetSpeed(150); } void loop() { if (IR_decode(&results)) { translateIR(); } if (millis() - n > 200) { ArduinoCar.Brake(); } } /*-----( Declare User-written Functions )-----*/ void translateIR() // takes action based on IR code received // describing KEYES Remote IR codes { n = millis(); ; switch (results) { case KEY1: ArduinoCar.LeftCircle(); break; case KEY2: ArduinoCar.Forward(); break; case KEY3: ArduinoCar.RightCircle(); break; case KEY4: ArduinoCar.Left(); break; case KEY5: ArduinoCar.Brake(); break; case KEY6: ArduinoCar.Right(); break; case KEY8: ArduinoCar.Backward(); break; case Repeat: break; default: ArduinoCar.Brake(); }// End Case } //END translateIR char IR_decode(unsigned char * code) { char flag = 0; unsigned int count = 0; unsigned char i, index, cnt = 0, data[4] = {0, 0, 0, 0}; if (digitalRead(IR) == LOW) { count = 0; while (digitalRead(IR) == LOW && count++ < 200) //9ms delayMicroseconds(60); t[0] = count; count = 0; while (digitalRead(IR) == HIGH && count++ < 80) //4.5ms delayMicroseconds(60); t[1] = count; for (i = 0; i < 32; i++) { count = 0; while (digitalRead(IR) == LOW && count++ < 15) //0.56ms delayMicroseconds(60); count = 0; while (digitalRead(IR) == HIGH && count++ < 40) //0: 0.56ms; 1: 1.69ms delayMicroseconds(60); if (count > 20)data[index] |= (1 << cnt); if (cnt == 7) { cnt = 0; index++; } else cnt++; } if (data[0] + data[1] == 0xFF && data[2] + data[3] == 0xFF) //check { code[0] = data[2]; Serial.println(code[0], HEX); flag = 1; } if (data[0] == 0xFF && data[1] == 0xFF && data[2] == 0xFF && data[3] == 0xFF) { code[0] = 0xFF; Serial.println("rep"); flag = 1; } } return flag; }
-
Witam jaki obliczyć jakie parametry powinny mieć 4 silniki dc, które napędzały by 4 kołową platformę o wadze 10 kg i mogły ją rozpędzić do prędkości 6 km/h?
-
Dzień dobry, na wstępie opiszę z grubsza założenia projektu - w przyszłości pracy inżynierskiej. Priorytetowym zadaniem, jakie ma stanąć przed moim robotem jest okrążenie kampusu mojej uczelni. Teren nie jest prosty, robot będzie miał do pokonania wyboiste drogi(częściowo przejazd przez las), krawężniki, trawniki i parkingi. Sterowanie ma być ręczne, realizowane zdalnie, za pośrednictwem internetu. Okrążenie to około 3km, zakładany czas przejazdu to niecała godzina. Konstrukcja opiera się na ramie zbudowanej z profili alu, o wymiarach 400x600. Do ramy będzie przymocowane większość osprzętu robota. Zawieszenie niezależne, 4 wahacze wzdłużne zawieszone na amortyzatorach do samochodów rc. Jako napęd 4 silniki wraz z przekładniami od samochodów dla dzieci. Koła 12 cali od wózka dziecięcego Część elektroniczna składa się z: Raspberry Pi 3, ICSTATION UNO, 4xmostek H VNH2SP30, przetwornica napięcia 5v USB, czujniki odległości(jeszcze nie wybrane), kamera(prawdopodobnie internetowa usb) Tyle z założeń, robot jest już w zaawansowanej fazie budowy. Zaczęło się od projektu w semestrze zimowym 2019/2020, projekt został zaliczony, jego dokumentacja tutaj(dokumentacja), a filmik zaliczeniowy z pierwszej jazdy terenowej poniżej Na tej fazie robot całą elektronikę miał zamontowaną "na taśmę", ze względu na zamówienie niewłaściwych kołków do pcb, a termin gonił. Obecnie robot jest rozebrany z całej elektroniki, powstaje miejsce w którym pojawią się akumulatory i elektronika(puszka elektryczna), osobny wyłącznik awaryjny oraz doprowadzenie kabli do silników. Poniższe zdjęcie przedstawia obecny stan robota: Aktualnie czekam na osłony na silniki wydrukowane w 3d, po zamontowaniu wszystkiego z zewnątrz będę mógł przejść do środka. W środku planuję zrobić ramkę z kątownika alu 20x20, w której będą miejsca na akumulatory(dwa akumulatory umieszczone po bokach), a pomiędzy nimi ma zostać umieszczona elektronika w sposób warstwowy(poziom 1: mostki H, poziom 2: ICSTATION UNO, poziom 3: Raspberry Pi 3). Poza tymi warstwami muszę znaleźć jeszcze miejsce na przetwornicę napięcia i mobilny ruter wifi. Całą ramkę chcę umieścić na gąbce, która by amortyzowała wstrząsy, tak samo zabezpieczyłbym moduł od góry. Dziękuję za uwagę, postępy i pytania będę starał się wrzucać tu na bieżąco.
-
Witam Próbuję zaimplementować algorytm podążania robota mobilnego 2-kołowego po trajektorii zadanej z góry wzorem na podstawie znalezionych materiałów. materiały: https://www.researchgate.net/publication/225543929_Control_of_Wheeled_Mobile_Robots_An_Experimental_Overview (strona 16 - Nonlinear Control Design) https://kcir.pwr.edu.pl/~mucha/Pracki/Rafal_Cyminski_praca_magisterska.pdf (strona 38) Problem polega na tym, że robot albo jedzie tylko część trajektorii albo ruch wynikowy nie przypomina ani trochę trajektorii wynikowej. void lissajousInit(lissajousTypedef *liss,trajectoryTypedef *traj, sampsonTypedef *samp) { traj->ts = 0.01F; robotMove1.ts = traj->ts; liss->amplitudeX_f32 = 0.5F; liss->amplitudeY_f32 = 0.6F; liss->paramA_u8 = 1.0F; liss->paramB_u8 = 2.0F; liss->paramDelta_f32 = M_PI/2; samp->Kp_f32 = 0.526; samp->Kd_f32 = 0.00263; traj->translationDesigned_f32 = integrateTrapz(0, M_TWOPI, 1000.0F, lissajousTrajectoryVelocitySpecial); } void lissajousTrajectoryGenarate(lissajousTypedef *liss,trajectoryTypedef *traj, sampsonTypedef *samp, robotMoveTypedef *robMov) { if(robMov->translationMeters <= traj->translationDesigned_f32) { traj->time_f32 += traj->ts;//M_PI_DIV; traj->trajRunning_u8 = 1; lissajousTrajectoryPath(traj, liss); calcAngleRadians(traj); trajectoryVelocity(traj); trajectoryAcceleration(traj); samp->angleNow_f32 = robMov->robotAngleDiff; samp->angleErr_f32 = (traj->angleRadiansDiff_f32- robMov->robotAngleDiff); samp->xErr_f32 = (traj->px_f32 - robMov->x); samp->yErr_f32 = (traj->py_f32 - robMov->y); samp->progrVelDesigned_f32 = traj->vxy_f32; samp->angVelDesigned_f32 = ((traj->ay_f32*traj->vx_f32) - (traj->ax_f32*traj->vy_f32))/traj->vxy_f32; sampsonAlgorithm(samp); } else { traj->trajRunning_u8 = 0; //robMov->translationMeters = traj->translationDesigned_f32; } } void lissajousTrajectoryPath(trajectoryTypedef *traj, lissajousTypedef *liss) { traj->pxPrev_f32 = traj->px_f32; traj->pyPrev_f32 = traj->py_f32; traj->px_f32 = liss->amplitudeX_f32*arm_sin_f32(liss->paramA_u8*traj->time_f32 + liss->paramDelta_f32); traj->py_f32 = liss->amplitudeY_f32*arm_sin_f32(liss->paramB_u8*traj->time_f32); } void trajectoryVelocity(trajectoryTypedef *traj) { if(lisTraj.amplitudeX_f32 > 0) { traj->vx_f32 = lisTraj.amplitudeX_f32*lisTraj.paramA_u8*cosf(lisTraj.paramA_u8*traj->ts + lisTraj.paramDelta_f32); traj->vy_f32 = lisTraj.amplitudeY_f32*lisTraj.paramB_u8*cosf(lisTraj.paramB_u8*traj->ts); } else { //for anothor purpose traj->vxPrev_f32 = traj->vx_f32; traj->vyPrev_f32 = traj->vy_f32; traj->vx_f32 = (traj->pxPrev_f32 - traj->px_f32)/traj->ts; traj->vy_f32 = (traj->pyPrev_f32 - traj->py_f32)/traj->ts; if(traj->velocityDesigned_f32) { if(traj->vx_f32 != 0) traj->vx_f32 = (traj->velocityDesigned_f32/traj->vx_f32)*traj->vx_f32; if(traj->vy_f32 != 0) traj->vy_f32 = (traj->velocityDesigned_f32/traj->vy_f32)*traj->vy_f32; } } float32_t sumOfSqares = (traj->vx_f32*traj->vx_f32) + (traj->vy_f32*traj->vy_f32); traj->vxy_f32 = sqrtf(sumOfSqares); } void trajectoryAcceleration(trajectoryTypedef *traj) { if(lisTraj.amplitudeX_f32 > 0) { traj->ax_f32 = -lisTraj.amplitudeX_f32*lisTraj.paramA_u8*lisTraj.paramA_u8*sinf(lisTraj.paramA_u8*traj->ts + lisTraj.paramDelta_f32); traj->ay_f32 = -lisTraj.amplitudeY_f32*lisTraj.paramB_u8*lisTraj.paramB_u8*sinf(lisTraj.paramB_u8*traj->ts); } else { //for anothor purpose traj->ax_f32 = (traj->vxPrev_f32 - traj->vx_f32)/traj->ts; traj->ay_f32 = (traj->vyPrev_f32 - traj->vy_f32)/traj->ts; } float32_t sumOfSqares = (traj->ax_f32*traj->ax_f32) + (traj->ay_f32*traj->ay_f32); traj->axy_f32 = sqrtf(sumOfSqares); } void calcAngleRadians(trajectoryTypedef *traj) { traj->angleRadiansPrev_f32 = traj->angleRadians_f32; traj->angleRadians_f32 = atan2f(traj->py_f32, traj->px_f32); traj->angleRadiansDiff_f32 = traj->angleRadians_f32 - traj->angleRadiansPrev_f32; } float deg2rad(float num) { return num * (M_PI / M_PI_DEG); } float rad2deg(float num) { return num * (M_PI_DEG / M_PI); } static float32_t lissajousTrajectoryVelocitySpecial(float32_t mytime) { static float32_t vxySpecial; trajectory1.vx_f32 = lisTraj.amplitudeX_f32*lisTraj.paramA_u8*cosf((lisTraj.paramA_u8*mytime) + lisTraj.paramDelta_f32); trajectory1.vy_f32 = lisTraj.amplitudeY_f32*lisTraj.paramB_u8*cosf(lisTraj.paramB_u8*mytime); float32_t sumOfSqares = (trajectory1.vx_f32*trajectory1.vx_f32) + (trajectory1.vy_f32*trajectory1.vy_f32); vxySpecial = sqrtf(sumOfSqares); return vxySpecial; } float32_t integrateTrapz(float32_t xp, float32_t xk, uint16_t N, float32_t(*f)(float32_t)) { float32_t dx = 0, s = 0; s = 0; dx = (xk - xp) / N; for (int i = 1; i < N; i++) { s += (*f)(xp + i * dx); } s = (s + ((*f)(xp) + (*f)(xk)) / 2) * dx; return s; } Algorytm omawiany w wyżej wymienionych publikacjach: void sampsonAlgorithm(sampsonTypedef *alg) { alg->xTrackErr_f32 = cosf(alg->angleNow_f32)*alg->xErr_f32 + sinf(alg->angleNow_f32)*alg->yErr_f32; alg->yTrackErr_f32 = -sinf(alg->angleNow_f32)*alg->xErr_f32 + cosf(alg->angleNow_f32)*alg->yErr_f32; if(alg->angleErr_f32 == 0) alg->angleErr_f32 = FLT_MIN; //very small number - 0 casued NaN (Not a Number) alg->progrVelRef_f32 = alg->Kp_f32*alg->xTrackErr_f32 + alg->progrVelDesigned_f32*cosf(alg->angleErr_f32); alg->angVelRef_f32 = alg->angVelDesigned_f32 + (alg->Kd_f32*alg->angleErr_f32) + (alg->progrVelDesigned_f32*alg->yTrackErr_f32*(sinf(alg->angleErr_f32)/alg->angleErr_f32)); alg->velLeftWheel_f32 = alg->progrVelRef_f32 - (ROBOT_LENGHT/2)*alg->angVelRef_f32; alg->velRightWheel_f32 = alg->progrVelRef_f32 + (ROBOT_LENGHT/2)*alg->angVelRef_f32; alg->velLeftWheelTicks_f32 = (convertMetersToTicks(alg->velLeftWheel_f32)/100.0F); alg->velRightWheelTicks_f32 = (convertMetersToTicks(alg->velRightWheel_f32)/100.0F); } Obliczanie pozycji robota: void calculateRobotKinematics(encoderTypedef *encLeft, encoderTypedef *encRight, robotMoveTypedef *robMov) { robMov->translationMeters = (encLeft->distanceMeters_f32 + encRight->distanceMeters_f32)/2; robMov->translationMetersDiff = (encLeft->distanceMetersDiff_f32 + encRight->distanceMetersDiff_f32)/2; MPU6050_Read_Gyro(&hi2c3, &MPU6050); if(fabsf(MPU6050.Gz) < 0.1F) //high-pass filter [deg] { MPU6050.Gz = 0.0F; } robMov->rotationRadians += deg2rad(MPU6050.Gz)*robMov->ts; // (encRight->distanceMeters - encLeft->distanceMeters)/ROBOT_LENGHT; robMov->rotationRadiansDiff = robMov->rotationRadians - robMov->rotationRadiansPrev; //może *ts ??? robMov->robotAngleDiff = robMov->robotAngle - robMov->robotAnglePrev; //może *ts ??? robMov->x = robMov->translationMeters*cosf(robMov->rotationRadians); robMov->y = robMov->translationMeters*sinf(robMov->rotationRadians); robMov->robotAngle = atan2f(robMov->y, robMov->x); robMov->rotationRadiansPrev = robMov->rotationRadians; robMov->robotAnglePrev = robMov->robotAngle; } Wywołanie całości (co 10ms --> f = 100Hz): if(START_PILOT_VIENNA || START_PILOT_JSUMO) { lissajousTrajectoryGenarate(&lisTraj,&trajectory1, &sampsonData, &robotMove1); PIDwheelVelocity(&pidLeftWheel, &encoderLeft, sampsonData.velLeftWheelTicks_f32); PIDwheelVelocity(&pidRightWheel, &encoderRight, sampsonData.velRightWheelTicks_f32); if(trajectory1.trajRunning_u8) { MotorSpeed(pidLeftWheel.PWMout, pidRightWheel.PWMout); } else { MotorSpeed(0,0); } } else { MotorSpeed(0,0); }
-
- lissajous
- trajektoria
- (i 3 więcej)
-
Robot balansujący - Sterownik silników
MR1979 opublikował temat w Projekty - DIY w budowie (worklogi)
Witam! Rozpoczynam nowy projekt, którym będzie próba zbudowania robota balansującego. Będzie to mój pierwszy robot. Ponieważ temat jest obszerny, oraz sama elektronika robota będzie modułowa, więc postanowiłem podzielić projekt na kilka worklogów. Zaczynam od modułu sterowania silników i tego będzie dotyczyć ten worklog. Założenia: 1. Dwa kanały (2 silniki BLDC - do gimbali) 2. Sterowanie FOC z enkoderem magnetycznym 3. Zintegrowany mikrokontroler który będzie tylko do sterowania silnikami (utrzymywanie równowagi i zadanych parametrów ruchu) 4. Zintegrowany akcelerometr i żyroskop 5. Monitorowanie max prądu silników (zabezpieczenie przed przeciążeniem) Zdecydowałem się na następujące główne komponenty: 1. Silniki BLDC do gimbali - 5208 - 2 szt. 2. Driver silników L6234 - 2 szt. 3. Enkodery magnetyczne AS5600 - 2 szt. 4. Akcelerometr i żyroskop - MPU6050 - 1 szt. 5. Mikrokontroler STM32F103RG (wersja XL-density bo ma dwa zaawansowane timery TIM1 i TIM8) Pozdrawiam, Marek -
Witam, Moim celem jest stworzenie robota kontrolowanego przez pilot z łącznością przez moduł radiowy FS100A Od strony technicznej wszystko mam zaplanowane lecz nie potrafię zaprogramować arduino z modułem radiowym jedyne co narazie mam to Kod Nadajnika: #include <VirtualWire.h> #define led_pin 11 #define transmit_pin 10 #define pot_pin A0 void setup() { vw_set_tx_pin(transmit_pin); vw_setup(2000); pinMode(led_pin, OUTPUT); } void loop() { int pot = analogRead(pot_pin); String toSend = (String(pot, DEC)); char msg[23]; toSend.toCharArray(msg, toSend.length() + 1); digitalWrite(led_pin, HIGH); vw_send((uint8_t *)msg, strlen(msg)); vw_wait_tx(); digitalWrite(led_pin, LOW); delay(1000); } Kod odbiornika: #include <VirtualWire.h> #define led_pin 13 #define receive_pin 11 #define pwm_pin 3 void setup() { Serial.begin(9600); Serial.println("setup"); vw_set_rx_pin(receive_pin); vw_setup(2000); vw_rx_start(); pinMode(led_pin, OUTPUT); pinMode(pwm_pin, OUTPUT); } void loop() { uint8_t buf[VW_MAX_MESSAGE_LEN]; uint8_t buflen = VW_MAX_MESSAGE_LEN; if (vw_get_message(buf, &buflen)) { int i,pwm,wartosc; String liczba; digitalWrite(led_pin, HIGH); for (i = 0; i < buflen; i++) { liczba+=char(buf); } wartosc = liczba.toInt(); pwm = map(wartosc,0,1023,0,255); Serial.print(wartosc); Serial.print(" "); Serial.println (pwm); analogWrite(pwm_pin, pwm); digitalWrite(led_pin, LOW); } } Tyle że jest to program przesyłający dane jednego potencjometru a la potrzebuje trzecz potencjometrów i dwóch przełączników ,nie mam pojęcia jak to przerobić pomoże ktoś???
-
Cześć, jestem początkujący, jestem w trakcie budowy czteronożnego robota kroczącego, używam Arduino Uno oraz 16 kanałowego sterownika PWM do sterowania 12 serwomechanizmami Tower Pro 9g. Problem pojawił się z doborem odpowiedniego zasilania dla serw. Potrzebuję w miarę kompaktowego zasilania 5/6 V oraz 4/5 A. Bardzo proszę o pomoc. Zastanawiam się nad użyciem dwóch ogniw litowo-jonowych 18650 (3,7V maksymalny prąd rozładowania 4A), tylko w jaki sposób doprowadzić do odpowiedniego napięcia,?
-
Witam wszystkich mam takie pytanko i problem jestem zielony w akumulatorach a mam do podmianki baterie do odkurzacza automatycznego czy da się podmienić cztery akumulatory widoczne na zdięciu i co to za płytka z układem jest połączona z bateriami ?? Dzięki za odpowiedz.
- 4 odpowiedzi
-
- akumulator
- Początkujący
-
(i 1 więcej)
Tagi:
-
Witam wszystkich. Jako, że na temat mojej pracy inżynierskiej wybrałem budowę manipulatora - plotera rysującego po powierzchni do której jest zamocowany, chciałbym prosić o kilka porad. Dodam też, że jestem w tym kompletnie zielony ale mam jeszcze około rok więc myślę, że się uda. Chciałbym żeby z wyglądu był zbliżony do KUKI. 1. Jako, że robot musi mieć funkcję plotera, w czym najlepiej to zaprogramować? (Kilka osób mi poleciło raspberry pi z pythonem). Będzie to nauka od postaw więc proszę o polecenie książek do nauki tego języka. 2. Jakie książki, dzięki którym będę wiedział jak budować danego robota, jaką elektronikę, jakie silniki itd. 3. Jeśli coś ważnego pominąłem to również proszę to napisać.
- 8 odpowiedzi
-
Ahoj. Byłbym szaleńczo wdzięczny za sugestie od graczy bardziej doświadczonych w zasilaniu rzeczy rozmaitych. Chciałbym zmontować pojazd wymachujący ramieniem i zaopatrzyłem się w 10 serwomechanizmów, z których większości powinno wystarczyć 5V, ale kilku chętnie posłałbym 6V, jednemu nawet powyżej 7V, jeśli to ma zwiększyć ich udźwig. Powinny utrzymywać pozycję w razie obciążeń, więc zakładam, że to nie będą skromne miliampery. Przyglądam się takiej opcji jak Dualsky 11.1V 25C, bo rozumiem, że wersja 7.4V mogłaby nie wystarczyć, a o bateriach 9V nie czytam wiele dobrego w kwestii poboru prądu. Ale jakie byłyby opcje na rozprowadzenie takiej mocy do dalszej regulacji, nie walcząc z projektowaniem oryginalnego PCB? Czy sterowniki + Arduino + osobne baterie to najlepsze wyjście z mniej skomplikowanych? Bo tu ładowanie tego wszystkiego na bagażnik brzmi trochę brutalnie. Chciałbym się ograniczać i z przestrzenią, i kosztami, i czasochłonnością rozwiązań. Nawet jeśli mistrzować jakiś PCB, to też wypadałoby to potestować w fazie programowania, a mój substytut Arduino nie daje rady zasilić nawet jednego serwa. Czy nie byłoby szans, by taki układ z jednym akumulatorem, regulatorami, mikrokontrolerami, modułem Bluetooth itd., polutować na takim wynalazku jak płytka uniwersalna? (I czy w takim wypadku istnieje jakiś stabilizator dla serwa 6–8.4V, które może pociągnąć pewnie i z 4A?)
