Skocz do zawartości

Tablica liderów


Popularna zawartość

Pokazuje zawartość z najwyższą reputacją 22.05.2020 we wszystkich miejscach

  1. 1 punkt
    Cześć Da się. Przetwornic podwyższających napięcie trochę jest i tych pracujących z napięciami wejściowymi poniżej 5V też się znajdzie. Przykładem są przetwornice oparte na kontrolerze LM2577 - to przykład. Ten układ może pracować z napięciem wejściowym od 3,5V. W Twoim przypadku dla napięcia Vin = 6V na wyjściu przy 13,5V możesz uzyskać jeżeli dobrze liczę < ~0,9A max. Tylko czy to najlepsze rozwiązanie? Akumulatory żelowe "lubią" być ładowane stałym prądem w pierwszej fazie ładowania i stałym napięciem w końcowej fazie. Można zastosować przetwornicę, ale ja osobiście wybrałbym dedykowaną ładowarkę. Albo zamiast kupować moduł przetwornicy kupić moduł "do złożenia" ładowarki automatycznej np. AVT2309? Koszty zbliżone chyba będą.
  2. 1 punkt
    A na przykład: int guzik = HIGH; void loop() { // tu jakieś instrukcje int teraz_guzik = digitalRead(jakiśpin); // albo coś podobnego if (guzik && !teraz_guzik) { // znaczy się ktoś pchał paluchy obsluga_palucha(); } guzik = teraz_guzik; // i tu coś jeszcze co sobie chcesz } Ale prostsze będzie użycie biblioteki Bounce2, gdzie fragment kodu będzie mniej więcej taki: guzik.update(); if (guzik.fell()) { // paluch! obsluga_palucha(); } Bliższe informacje w przykłądach do Bounce2.
  3. 1 punkt
    Jak celowo użyte to czemu nie, próbowałem sobie tylko wyobrazić sytuację gdzie miałoby to czemuś zapobiec. To by musiała być sytuacja, gdzie startuję odliczanie i zanim minie sekunda zacznę usiłować zakończyć odliczanie. No i zwyczajowo zachęcam do reakcji na zbocza przy obsłudze przycisków, ale to taki już mój kaprys a tak to kod bardzo ładny. Tak trzymaj i powodzenia dalej!
  4. 1 punkt
    Patrząc na ten filmik przypomniało mi się, ze znalazłem ostatnio na Youtube człowieka który budował podobnego 4 nożnego robota (wiadomo że nie jest to ten sam poziom co na filmiku powyżej :D) Oprócz budowy opisuje on również kinematykę i programowanie takiej konstrukcji.
  5. 1 punkt
    @jas123 Trzeba znaleźć dokumentacje do tych modułów kamer (niestety mi nie udało się nic ciekawego znaleźć po wpisaniu symboli widocznych na zdjęciu) aby dowiedzieć się jaki interfejs wykorzystują, obawiam się że może to być praktycznie niemożliwe, ponieważ te moduły mogły być produkowane na zamówienie producenta tego telefonu Nawet jeżeli udało by się znaleźć konwerter np. z pasującym złączem, może on nie współpracować z tymi modułami kamer.
  6. 1 punkt
  7. 1 punkt
    Dzięki za opinię Ciekawa sugestia do przemyślenia Przyznam, że na początku sceptycznie podchodziłem do Arduino ale już teraz czuję, że zaczyna mnie wciągać. I moim zdaniem prawdą jest, że trzeba wykonywać dużo ćwiczeń praktycznych - nauka przez rozwiązywanie problemów jest skuteczna i sprawia dużo frajdy
  8. 1 punkt
    Korzystam z serii BN1936 firmy BOSSARD. Wkłady te łatwo wstępnie osadzić w otworze bo na dole mają kilka mm kompletnie gładkie. Otwór montażowy drukuję o 0,1mm większy niż zaleca producent w nocie katalogowej. Niestety nie mam warunków ani narzędzi do szlifowania plastiku w mieszkaniu.
  9. 1 punkt
    @ewgron fajnie że robisz zadania domowe Przejrzałem kod i wygląda na to, że działa i jest całkiem ładnie napisany. Zastanawiam się tylko czy nie dałoby się pominąć jakoś powtórzenie Serial.available(). Tak też przyszłościowo, możesz spróbować napisać taką grę ale bez wykorzystania delay() może to być ciekawe wyzwanie.
  10. 1 punkt
    Miło mi, że znajduje się tu również moje DIY.
  11. 1 punkt
    @Treker, znakomity artykuł. Ten kurs to jedno z lepszych opracowań o podstawach elektroniki jaki widziałem. Teraz nareszcie zrozumiałem dlaczego równolegle do kondensatora 100u na zasilaniu montuje się 100n i to robi różnicę. Szkoda, że 25 lat temu, kiedy studiowałem, nie było takich treści i wszystko musiało być w książkach takie cholernie skomplikowane. Elektronika to moja pasja z najmłodszych lat, teraz nieco zapomniana i zakurzona, ale dzięki Tobie przypominam sobie te piękne lata. Bardzo dziękuję, robisz świetną robotę. Pozdrawiam z Gdyni
  12. 1 punkt
    Moja propozycja rozwiązania zadania 4.5 Układ: Kod: #define zielona 8 #define czerwona 9 #define zolta 10 #define potencjometr A5 #define przycisk 11 String wpisanaWartosc = ""; //Wartość wpisana przez gracza int liczba = 0; //Wartość wpisana przez gracza zamieniona na liczbę int wartoscUstawiona = 0; //Wartość odczytana z potencjometru int proba = 0; //Licznik prób void setup() { Serial.begin(9600); //Uruchomienie komunikacji pinMode(zielona, OUTPUT); //Ustawienie wyjść pinMode(czerwona, OUTPUT); pinMode(zolta, OUTPUT); pinMode(przycisk, INPUT_PULLUP); digitalWrite(zielona, LOW); //Wyłącznie diod digitalWrite(czerwona, LOW); digitalWrite(zolta, LOW); } void loop() { if (proba<3) { //Jeżeli licznik prób jest mniejszy od 3 Serial.println("Przekręć potencjometr, a następnie naciśnij przycisk."); while (digitalRead(przycisk) == HIGH) {delay(50);} //Poczekaj na wiśnięcie przycisku wartoscUstawiona = analogRead(potencjometr); //Odczytanie wartości z potenjometru Serial.println("Podaj liczbę z zakresu od 0 do 1023."); //Wyświetlenie komunikatu while (Serial.available()==0){delay(50);} //Oczekiwanie na wprowadzenie wartości if (Serial.available()>0) { //Jeżeli wartość została wprowadzona wpisanaWartosc = Serial.readStringUntil('\n'); //Przeczytanie wartości wprowadzonej liczba = wpisanaWartosc.toInt(); //Konwersja wartości wprowadzonej na liczbę if ((liczba<wartoscUstawiona+50) and (liczba>wartoscUstawiona-50)) { //Jeżeli wprowadzona liczba mieści się w zakresie digitalWrite(zielona, HIGH); //Włączenie diody zielonej Serial.println("Wygrana."); //Wyświetlenie komunikatu informującego o wygranej Serial.println(wartoscUstawiona); //Wyświetlenie prawidłowego wyniku delay(2000); digitalWrite(zielona, LOW); //Wyłączenie diody delay(1000); } else { //Jeżeli wprowadzona wartość jest spoza zakresu digitalWrite(zolta, HIGH); //Włączenie żółtej diody Serial.println("Błąd."); //Wyświetlenie komunikatu informującego o błędnej wartośći delay(2000); digitalWrite(zolta, LOW); //Wyłączenie żółtej diody delay(1000); proba=proba+1; //Zwiększenie licznika prób } } } else if (proba == 3) { //Jeżeli osiągnięto limit prób digitalWrite(czerwona, HIGH); //Włączenie czerwonej diody Serial.println("Przegrana."); //Wyświetlenie komunikatu informującego o przegranej Serial.println(wartoscUstawiona); //Wyświetlenie prawidłowego wyniku delay(2000); digitalWrite(czerwona, LOW); //Wyłączenie czerwonej diody delay(1000); proba = 0; //Zerowanie licznika prób } }
  13. 1 punkt
    @Krzysiek_Kr witam na forum A co dokładnie masz na myśli pisząc o zmianie napięcia? Czy serwo nie działa poprawnie? Jeśli "tylko" mierzysz napięcie miernikiem, to zmiany wypełnienia sygnału PWM będą właśnie traktowane jako zmiana napięcia (bo miernik uśrednia pomiar).
  14. 1 punkt
    Ten "pomarańczowy" to kondensator ceramiczny i również służy do filtrowania zasilania . Kondensatory ceramiczne dobrze radzą sobie z filtrowaniem wysokich częstotliwości a elektrolityczne dobrze filtrują niskie częstotliwości.Dlatego często stosuje się oba rodzaje. Źródło :Kurs elektroniki – #4 – kondensatory, filtrowanie zasilania
  15. 1 punkt
    Hej, tu Maciek, jestem współtwórcą Wroob. Jesteśmy w trakcie dodawania tej funkcjonalności, powinna pojawić się w najbliższym czasie. Obecnie, jeżeli posiadasz pada, którego możesz podłączyć pod komputer, możesz użyć modułu RCM, aby mapować przyciski kontrolera na konkretne akcje. EDIT: Oprócz modułu RCM możesz też użyć modułu rozpoznawania mowy (SRM) i decydować o przepływie programu głosowo
  16. 1 punkt
    Hej! Chciałem się z wami podzielić projektem, który od jakiegoś czasu rozwijam z grupą znajomych. Nazywa się on Wroob i jest to aplikacja pozwalająca zaprogramować swój telefon. Głównym celem projektu jest urozmaicenie procesu nauki programowania w Pythonie, głównie przez wprowadzenie elementów robotyki. Jest to też system, który umożliwia wykorzystanie możliwości współczesnego smartphona we własnych projektach. Jeżeli chcemy na przykład śledzić twarz manipulatorem, nie potrzebujemy do tego celu RPi z kamerą, możemy użyć własnego telefonu z aplikacją Wroob. Ponieważ projekt jest już dość złożony. W tym tekście postaram się wyjaśnić na dość ogólnym poziomie czym jest system Wroob i co można z nim zrobić. Jeżeli będziecie zainteresowani to w kolejnych częściach omówię szczegółowo jak zostały zrealizowane poszczególne elementy systemu lub przygotuje poradniki jak stworzyć coś własnego używając aplikacji Wroob. Czym jest system Wroob? System Wroob składa się z trzech głównych elementów: 1. Aplikacja Wroob Jest to serce całego systemu. To na niej uruchamiane są wszystkie programy napisane przez użytkownika. Aplikacja umożliwia dostęp do Panelu Użytkownika Wroob i modułów (funkcjonalności) systemu. Słowem – zamienia telefon lub tablet w mózg robota. 2. Moduły System Wroob jest modularny, tzn. każda z funkcjonalności systemu jest dostarczana przez odpowiedni moduł. Na przykład telefon będzie odtwarzał dźwięki korzystając z modułu Audio Player Module, a dostęp do kamery czy rozpoznawanie twarzy realizowane będzie przez Video Processing Module. 3. Panel Użytkownika Wroob Otwiera się go w przeglądarce internetowej na komputerze lub innym urządzeniu. Panel umożliwia włączanie i wyłączanie modułów, graficzne widżety ułatwią zapoznanie się z ich funkcjami, a edytor kodu pozwala pisać programy w Pythonie. Panel Użytkownika Wroob to aplikacja webowa, której hostem jest telefon z aplikacją. Telefon udostępnia Panel Użytkownika w sieci lokalnej, więc możemy wejść z dowolnego urządzenia znajdującego się w tej samej sieci - najwygodniej pracuje się przy użyciu komputera Co można zrobić z aplikacją Wroob? Każdą funkcjonalność dostarczaną przez moduły można wykorzystać w dowolny sposób we własnych programach. Aktualnie dostępne moduły pozwalają między innymi na odtwarzanie dźwięków, rozpoznawanie twarzy, robienie zdjęć, syntezę i rozpoznawanie mowy czy podłączenie kontrolera do gier. Przygotowaliśmy kilka przykładów w formie kursów na YouTube/Wroob (znajdziecie tam też film jak rozpocząć pracę z systemem Wroob). Krótki filmik jak to działa: Gotowy kod programu alarmu wykorzystanego w filmie wygląda następująco: from wroob.modules.apm import Apm from wroob.modules.vpm import Vpm from time import sleep apm = Apm('apm001') vpm = Vpm('vpm001') THRESHOLD = 60 SENSITIVITY = 200 def alarm_callback(msg): if apm.state["status"] == "stopped": apm.play_sound("breach_alarm.wav") vpm.start_motion_detection_reporting(THRESHOLD, SENSITIVITY, alarm_callback) while(True): sleep(1) A tutaj prosty Chatbot: from wroob.modules.srm import Srm from wroob.modules.ssm import Ssm import time srm = Srm("srm001") ssm = Ssm("ssm002") slownik_zwrotow = { 'cześć' : 'Witaj, jak masz na imię?', 'tomek' : 'Miło cię poznać. Czym się zajmujesz?', 'programuje' : 'Doskonale. Widzę, że dobrze Ci idzie', 'na razie' : 'Miłego dnia!' } def odbior_mowy(data): print(data) if data in slownik_zwrotow: ssm.start_speech_synthesis(slownik_zwrotow[data]) else: ssm.start_speech_synthesis("Nie rozumiem, czy możesz powtórzyć?") srm.start_speech_reporting(odbior_mowy) while True: time.sleep(1) Hardware Oczywiście najciekawsza zabawa rozpoczyna się w momencie, gdy połączymy aplikację Wroob ze sprzętem. Na przykład w relatywnie prosty sposób możemy zaprogramować zdalnie sterowanego robota z podglądem z kamery na żywo czy robota sterowanego mową. We Wroob mamy własne moduły sprzętowe które pozwoliły nam na zbudowanie robota mobilnego (Wrooby). Aplikacja wspiera też komercyjne roboty firmy Makeblock, mBot-S i mBot-Ranger. Pojawiają się one w systemie jako moduły. Otwarty system System Wroob z założenia jest systemem otwartym. Oznacza to, że można go łączyć z własnymi autorskimi projektami stworzonymi na przykład na Arduino czy napisanymi w dowolnym języku programowania na komputerze i traktować je jako moduły w systemie Wroob. Posiadamy gotową bibliotekę na Arduino która pozwala na obsługę naszego wewnętrznego protokołu komunikacji. Znajdziecie ją na GitHub’ie https://github.com/wroob-io lub możecie pobrać bezpośrednio w Arduinio IDE. Jak podłączyć płytkę Arduino do systemu Wroob i stworzyć własny moduł z przyjemnością opiszę w kolejnym artykule. Jeżeli projekt Wam się podoba, z chęcią odpowiem na wszelkie pytania w komentarzach. Oprócz łączenia Arduino z Wroob i pisania własnego modułu, mam też kilka propozycji na kolejne posty: 1. Własny moduł w Pythonie 2. Opis architektury systemu Wroob 3. Opis funkcjonalności i implementacji wybranego modułu 4. Robot mobilny Wrooby Dajcie znać co was najbardziej interesuje. Zachęcam do testowania możliwości aplikacji Wroob na własną rękę - do końca czerwca jest całkowicie darmowa Do pobrania w Google Play Wroob - Robotyka dla każdego! – Aplikacje w Google Play
  17. 1 punkt
    @Sabre ciąłem ręcznie z dobre 2h wiec nie nie balem sie. chwytak dziala bardzo dobrze ale pojazd nie zabardzo radzi sobie z jazdą, wiec nie jest funkcjonalny. Zębatki od przerzutek są zbyt płytkie w dodatku każda jest taka sama no ale cóż jakos jedzie dziekuje za komentarz
  18. 1 punkt
    Niezły kawałek metalu, wykorzystanie kanistra pierwsza klasa. Nie bałeś się go ciąć? Ten chwytak jest funkcjonalny czy bardziej tylko do prezentacji?
  19. 1 punkt
    @tomeklagiewka na jakiej platformie chcesz oprzeć swojego robota? Będzie on działał na bazie Arduino czy na Raspberry Pi? Sterowanie diodami to żaden problem, chętnie pomożemy, ale musisz napisać coś więcej na temat swojego przyszłego robota. Jeśli zupełnie nie wiesz od czego zacząć to zerknij na nasz kurs budowy robotów na Arduino - znajdziesz tam najważniejsze informacje, które pozwolą Ci łatwo wystartować: Kurs budowy robotów – #1 – wstęp, spis treści
  20. 1 punkt
  21. 1 punkt
    Z poprzedniej części dowiedzieliśmy się, jak w prosty i wygodny sposób skonfigurować serwer Apache. Uruchomiliśmy nawet prosty program w PHP, który działa z uprawnieniami zwykłego użytkownika. Jednak PHP nie jest jedynym językiem, w którym możemy tworzyć skrypty. Już przed jego powstaniem opracowano znormalizowany interfejs CGI (czyli Common Gateway Interface), który umożliwiał pisanie programów wykonywanych przez serwer w dowolnym języku. PHP zyskał dużą popularność — szczególnie po ukazaniu się wersji 4 — przede wszystkim dlatego, że był zintegrowany z serwerem i interpreter rezydował w pamięci, podczas gdy wykonanie skryptu np. w Perlu wymagało za każdym razem załadowania interpretera, co trochę trwało. Jednak o ile na przełomie tysiącleci, w epoce dość wolnych dysków o niezbyt wielkiej pojemności było to bardzo ważne, dzisiaj traci to znaczenie - musimy pamiętać, że nasza malinka to demon prędkości w porównaniu z serwerami z lat 90-tych. Nawet programy w PHP są czasem z różnych przyczyn wykonywane jako CGI, a duże pojemności pamięci, szybkie dyski oraz (w przypadku niektórych języków) automatyczna kompilacja do kodu pośredniego pozwalają zmniejszyć ten czas do niezauważalnego minimum. Oprócz CGI powstały inne jeszcze metody komunikacji programów z serwerem, od zarzuconego już dawno SSI, poprzez interfejsy FastCGI, WSGI aż do tworzenia kompletnych serwerów w innych językach programowania i używania głównego serwera jedynie jako reverse proxy. My jednak zajmiemy się najprostszą metodą - czyli właśnie CGI. Interfejs jest bardzo prosty. W sumie wystarczy wiedzieć kilka rzeczy: w czasie wysyłania nagłówków wszystkie pojedyncze znaki '\n' są zamieniane na wymagane przez protokół HTTP pary '\r\n'; dodatkowy nagłówek Status zamieniany jest na linię odpowiedzi serwera i może być stosowany np. do przekazania kodu błędu lub po prostu innej odpowiedzi serwera niż domyślne (w przypadku jego braku) "200 OK"; nagłówki zapytania dostępne są w postaci zmiennych środowiskowych. Program po prostu musi wypisać na wyjście wszystkie potrzebne nagłówki wraz z kończącą je pustą linią, a dopiero wtedy wypisać właściwą odpowiedź (np. kod HTML). Z podobnym zachowaniem spotkaliśmy się zresztą już wcześniej przy tworzeniu serwerów HTTP na Arduino czy ESP, więc nie powinno to sprawiać trudności. Niestety, serwery nie są domyślnie skonfigurowane do obsługi CGI. Na szczęście w przypadku Raspbiana konfiguracja jest bardzo prosta. Zaczniemy od tego, że moduł odpowiedzialny za obsługę CGI co prawda został dostarczony razem z serwerem, ale nie jest domyślnie włączony. Musimy więc go włączyć poleceniem: sudo a2enmod cgi Co prawda dostaniemy informację o konieczności restartu serwera, ale na razie nie musimy tego robić bo i tak będziemy dopisywać obsługę CGI do naszej donyślnej strony. W tym celu otwieramy w edytorze plik konfiguracyjny, np. przez: sudo nano /etc/apache2/sites-available/000-default.conf i dopisujemy dosłownie dwie linijki do części Directory. Linijka AddHandler informuje serwer, że pliki o rozszerzeniu .cgi mają być traktowane jak skrypty, a Options zezwala na wykonywanie skryptów w ogóle w danym katalogu: AddHandler cgi-script .cgi Options ExecCGI Tak więc konfiguracja będzie wyglądać następująco: Po restarcie serwera możemy już spróbować napisać pierwszy skrypt. Musi mieć on rozszerzenie .cgi i mieć prawo do wykonywania. A więc do dzieła! Napiszmy pierwszy program, robiący dokładnie to samo co poprzedni skrypt w PHP. Ponieważ najbardziej popularnym językiem stosowanym na RPi jest python, będziemy pisać skrypty właśnie w tym języku. Umieśćmy więc w katalogu html plik test.cgi z następującą zawartością: #!/usr/bin/env python3 print("Content-Type: text/plain; charset=UTF-8\n") try: open("pytest.txt","w").write("Cos tam\n") print("Zapisane") except: print("Nie da się zapisać") Ponieważ funkcja print dodaje nową linię na końcu, znaczek '\n' w nagłówku wymusza po prostu pustą linię za jedynym interesującym nagłówkiem Content-Type. Teraz musimy nadać plikowi prawa do wykonania: chmod 755 html/test.cgi i po skierowaniu przeglądarki na adres http://<ip_malinki>/test.cgi powinniśmy zobaczyć wynik "Zapisane" lub informację, że zapisać się nie dało z jakichś przyczyn (z jakich — o tym później). Jako że najprawdopodobniej bardziej nas będą interesować zastosowania serwera w IoT czy robotyce — spróbujmy zaprząc Apacza do jakichś bliższych sercu zadań. Ostatnio ktoś pytał o możliwość odczytu kart RFID i pokazywania tego w przeglądarce... spróbujmy! Użyjemy do tego popularnego czytnika RC522, do którego biblioteki są dostępne bez zbytniego szukania. Zacznijmy od tego, że musimy zainstalować podstawowe biblioteki do Pythona, które umożliwią nam operowanie GPIO oraz magistralą SPI. A więc: sudo apt install python3-rpi.gpio python3-smbus python3-pip Biblioteka RPi.GPIO zapewne jest większości znana, smbus pozwala na komunikację właśnie z magistralą SPI, a pip pozwala na instalację pakietów, których nie ma w repozytorium Raspbiana. Upewnijmy się jeszcze, czy mamy włączoną obsługę SPI (w raspi-config), oraz czy użytkownik pi (lub ten, na którego się logujemy) ma dostęp do wszystkiego co potrzebne bez używania sudo. A więc wydajemy polecenie: groups Powinno wyświetlić się kilkanaście grup, do których należy użytkownik pi, czyli coś w rodzaju: pi adm dialout cdrom sudo audio video plugdev games users input netdev bluetooth gpio i2c spi Nas interesują tylko trzy ostatnie. Jeśli któraś nie występuje, musimy ją dopisać: sudo usermod -a -G spi,i2c,gpio pi (oczywiście wpisujemy tylko brakujące) i po przelogowaniu powinniśmy już widzieć użytkownika pi dopisanego do właściwych grup, umożliwiających manipulację pinami GPIO oraz magistralami SPI i I2C. Niestety, biblioteki obsługi RC522 w repozytorium nie ma, ale możemy ją zainstalować używając polecenia pip3: sudo pip3 install mfrc522 Kolej na podłączenie czytnika do naszej malinki. Podłączamy tylko siedem z ośmiu pinów, bo nie używamy pinu IRQ, a więc: SDA do pinu 24 SCK do pinu 23 MOSI do pinu 19 MISO do pinu 21 GND do pinu 6 RST do pinu 22 3.3v do pinu 1 Po włączeniu malinki (pamiętajmy, że wszelkie połączenia musimy wykonywać z odłączonym zasilaniem) powinna zapalić się dioda na czytniku. Napiszmy więc prosty program, umożliwiający odczyt kart: #!/usr/bin/env python3 import RPi.GPIO as GPIO from mfrc522 import SimpleMFRC522 reader = SimpleMFRC522() try: id=reader.read_id_no_block() finally: GPIO.cleanup() print("ID=%s" % id) Użyjemy tu nieblokującej metody, gdyż w przypadku skrypty CGI nie możemy blokować połączenia — przeglądarka przerwie połączenie, jeśli nie doczeka się danych w określonym czasie. Po uruchomieniu programu (bez sudo oczywiście) powinniśmy móc odczytać numerek zbliżonej karty lub pusty napis, jeśli karty nie ma. Czyżby to było takie proste? Spróbujmy teraz przerobić nasz program na skrypt CGI. Wystarczy do tego dopisać linijki odpowiadające za wysłanie nagłówków, i powinno działać! Tworzymy więc w katalogu html plik o nazwie (przykładowo) czytnik.cgi i wpisujemy do niego: #!/usr/bin/env python3 import RPi.GPIO as GPIO from mfrc522 import SimpleMFRC522 print("Content-Type: text/plain; charset=UTF-8\n") reader = SimpleMFRC522() try: id=reader.read_id_no_block() or '' finally: GPIO.cleanup() print("ID=%s" % id) Nadajemy plikowi prawa do wykonywania: chmod 755 html/czytnik.cgi Na wszelki wypadek sprawdźmy, czy działa wydając po prostu polecenie: html/czytnik.cgi Powinno działać! A więc przeglądarka w ruch, wpisujemy adres http://<ip_malinki>/czytnik.cgi i... ...i nic. Zaglądając do logu błędów Apacza zobaczymy, że program nie został wykonany. Dlaczego? Ponieważ ciągłe zaglądanie do logów nie jest zbyt wygodne, zmuśmy nasz skrypt do reakcji na błędy i wyświetlania ich w przeglądarce. Użyjemy do tego modułu cgitb, który pozwala właśnie na takie manipulacje. A więc nowa wersja skryptu będzie wyglądać tak: #!/usr/bin/env python3 import RPi.GPIO as GPIO from mfrc522 import SimpleMFRC522 import cgitb print("Content-Type: text/plain; charset=UTF-8\n") cgitb.enable(format="text") # włączamy wyświetlanie błędów w formacie tekstowym reader = SimpleMFRC522() try: id=reader.read_id_no_block() or '' finally: GPIO.cleanup() print("ID=%s" % id) Po uruchomieniu możemy zobaczyć, że skrypt nie ma uprawnień do smbusa i gpio! Ale przecież użyliśmy wcześniej modułu ruid2, który powinien uruchomić nasz program jako użytkownik pi! Ki diabeł? Musimy to sprawdzić. Dodajmy do skryptu linijki, które pokażą nam z jakimi uprawnieniami wykonywany jest nasz program: #!/usr/bin/env python3 import RPi.GPIO as GPIO from mfrc522 import SimpleMFRC522 import cgitb, sys, os print("Content-Type: text/plain; charset=UTF-8\n") sys.stdout.flush() # aby upewnić się, że nagłówki nie zostaną zbuforowane os.system("groups") Po uruchomieniu widzimy, że program uruchomił się z uprawnieniami grupy pi, ewentualnie (zależnie od konfiguracji) dodatkowo www-data. A gdzie nasze gpio? Gdzie spi? Spójrzmy do konfiguracji modułu ruid2. O właśnie — kazaliśmy uruchomić program z uprawnieniami użytkownika pi i grupy pi, bez żadnych dodatkowych grup. Ale od czego jest linijka RGroups? Właśnie od tego, aby dopisać dodatkowe grupy! Poprzednio mieliśmy tam wpisane @none. Dopiszmy więc dodatkowe grupy, zmieniając tę linijkę na: RGroups gpio spi i2c i zrestartujmy Apacza. Powinno być dobrze... Ale nie jest. Przeglądarka uparcie pokazuje nam, że Apacz nic nie wie o żadnych dodatkowych grupach... dlaczego? Po prostu zadziałało zabezpieczenie. Moduł nie pozwala nam na uruchamianie programu z uprawnieniami grup systemowych, czyli w przypadku Raspbiana z numerkami grupy mniejszymi niż 1000. Na szczęście i na to jest sposób. W konfiguracji możemy podać nazwę grupy o najmniejszym ID, który jest dozwolony. Musimy w tym celu przejrzeć plik grup: cat /etc/groups lub lepiej, aby ograniczyć wyświetlanie do najbardziej istotnych rzeczy: egrep '(spi|i2c|gpio)' /etc/group i znaleźć, która z tych grup ma najniższy numerek. W moim przypadku jest to grupa gpio o numerze 997, a więc dopisujemy dodatkową linię do konfiguracji ruid2: RMinUidGid pi gpio W efekcie nasza konfiguracja wygląda tak: Teraz restartujemy Apacza — i w efekcie po przyłożeniu karty do czytnika i wczytaniu strony do przeglądarki zobaczymy wreszcie odczytany ID! Ponieważ chcielibyśmy, aby dane były pokazywane na bieżąco, możemy po prostu dopisać odpowiedni nagłówek wymuszający na przeglądarce odświeżenie strony. Tak więc po usunięciu niepotrzebnych już linii i delikatnym "upiększeniu" nasz kod będzie wyglądać tak: #!/usr/bin/env python3 import RPi.GPIO as GPIO from mfrc522 import SimpleMFRC522 import cgitb print("Content-Type: text/plain; charset=UTF-8\nRefresh: 5\n") cgitb.enable(format="text") reader = SimpleMFRC522() try: id=reader.read_id_no_block() or 'Brak karty' finally: GPIO.cleanup() print("ID=%s" % id) Prawda, jakie to proste? Tyle na dziś — w następnej części dowiemy się, jak w pythonowym skrypcie CGI możemy dobrać się do przesyłanych danych.
  22. 1 punkt
    W poprzednich częściach udało się zebrać dane treningowe oraz przygotować sieć neuronową. Zostało ostatnie i najprzyjemniejsze, czyli napisanie końcowego programu. Jako punkt wyjścia używam program w wersji użytej do zbierania danych. Jest w nim już praktycznie wszystko co potrzebne, czyli konfiguracja modułów peryferyjnych oraz odczyt danych z akcelerometru. Spis treści serii artykułów: Sztuczna inteligencja na STM32, czyli przykład użycia X-CUBE-AI cz.1 Sztuczna inteligencja na STM32, czyli przykład użycia X-CUBE-AI cz.2 Sztuczna inteligencja na STM32, czyli przykład użycia X-CUBE-AI cz.3 Przechodzimy do widoku CubeMX i odnajdujemy wyjątkowo kiepsko widoczny przycisk "Additional Software": Po jego naciśnięciu zobaczymy okno pozwalające na dodawanie modułów do naszego projektu. Nas interesuje moduł "STMicroelectronics.X-CUBE-AI". Jeśli wcześniej tego nie zrobiliśmy, musimy najpierw ten moduł pobrać i zainstalować. Niezbędne opcje zobaczymy w prawej części okna: Po instalacji modułu X-CUBE-AI wystarczy zaznaczyć checkbox i użyć podstawową funkcjonalność, czyli Core. Gdybyśmy planowali wykorzystanie sieci neuronowej w poważniejszym programie, takie ustawienie byłoby chyba najlepszą opcją. Jednak na potrzeby nauki możemy wykorzystać gotowiec i dodać jeszcze opcję "Application Template". Jakość kodu, który zostanie dodany jako "template" jest delikatnie mówiąc niezbyt imponująca. Dlatego napisałem, że lepiej chyba nie używać go w poważniejszych zastosowaniach - ale do nauki to bardzo wygodne rozwiązanie. Teraz możemy wrócić do głównego widoku CubeMX i odszukać moduł "STMicroelectronics.X-CUBE-AI" w kategorii "Additional Software": W środkowej części okna widzimy konfigurację modułu naciskamy przycisk-zakładkę z symbolem "+" i dodajemy naszą sieć. Domyślna nazwa to "network", ale warto ją zmienić na coś bardziej opisowego, ja wybrałem "forbot_ai". Następnie wybieramy typ modelu "Keras" oraz sam model, czyli nasz plik data2.h5 utworzony w poprzedniej części. Gdy wszystko jest już gotowe możemy nacisnąć przycisk "Analyze" i poczekać aż X-CUBE-AI sprawdzi, czy nasza sieć pasuje do wybranego mikrokontrolera. Wynik powinien wyglądać następująco: Jak widzimy cała skomplikowana sieć wykorzystuje 8.39KB pamięci flash oraz 72 bajty RAM. To bardzo mało jak dla STM32L475, ale nawet znacznie słabiej wyposażone mikrokontrolery mogą skorzystać z możliwości jakie dają sieci neuronowe. Natomiast w przypadku większych sieci możemy wykorzystać opcję kompresji. Po zapisaniu projektu i wygenerowaniu kodu zobaczymy dwie ważne zmiany w pliku main.c. Przed pętlą główną pojawi się wywołanie MX_X_CUBE_AI_Init(), a w samej pętli znajdziemy MX_X_CUBE_AI_Process(). Inicjalizacja nie będzie nas interesować i możemy zostawić wygenerowany kod bez zmian. Warto natomiast zapoznać się z treścią funkcji MX_X_CUBE_AI_Process(). Kod, który w niej znajdziemy może przyprawić o palpitacje serca, ale na szczęście to tylko przykład, chociaż chyba niezbyt udany. Możemy więc spróbować zrozumieć o co w tym kodzie chodzi - i szybko odkryjemy, że jedyne co istotne to wywołanie funkcji aiRun(), która przyjmuje dwa parametry: pierwszy to tablica z danymi wejściowymi dla sieci, a w drugiej pojawią się wyniki. Warto jeszcze odszukać jakie są wymiary tych tablic: AI_FORBOT_AI_IN_1_SIZE ma wartość 128, i jest to wielkość zdefiniowana podczas trenowania sieci, właśnie tyle danych musimy podać na wejście. Wielkość danych wynikowych znajdziemy w stałej AI_FORBOT_AI_OUT_1_SIZE, która ma wartość 2. Przykładowy kod wykonuje mnóstwo dziwnych operacji na typach danych, ale w rzeczywistości dane wejściowe i wyjściowe to zwykłe float-y. Możemy więc skasować wszystko co automat nam wygenerował i napisać pierwszy kod: void MX_X_CUBE_AI_Process(void) { /* USER CODE BEGIN 1 */ float nn_input[AI_FORBOT_AI_IN_1_SIZE]; float nn_output[AI_FORBOT_AI_OUT_1_SIZE]; aiRun(nn_input, nn_output); /* USER CODE END 1 */ } Taki program oczywiście nic nie robi, ani nie działa poprawnie, ale umieściłem go aby pokazać jak łatwe jest używanie sieci neuronowej. Musimy wypełnić tablicę nn_input danymi do przetworzenia, następnie wywołujemy aiRun() i w nn_output mamy wyniki. Poniżej wstawiam już pełny kod: static uint32_t next_ms = 1000; static float nn_input[AI_FORBOT_AI_IN_1_SIZE]; float nn_output[AI_FORBOT_AI_OUT_1_SIZE]; while (HAL_GetTick() < next_ms) {} next_ms += READ_DELAY_MS; lsm6_value_t acc; acc = lsm6_read_acc(); for (int i = 0; i < AI_FORBOT_AI_IN_1_SIZE - 1; i++) nn_input[i] = nn_input[i + 1]; nn_input[AI_FORBOT_AI_IN_1_SIZE - 1] = sqrt(acc.x * acc.x + acc.y * acc.y + acc.z * acc.z); aiRun(nn_input, nn_output); if (nn_output[0] >= 0.5f) HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET); else HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_SET); Tablica nn_input jest definiowana jako statyczna, aby zachować historię pomiarów. Pomiary są wykonywane co 20ms, stąd czekanie w pętli while. Następnie odczytywana jest wartość przyspieszeń z akcelerometru. Wyniki przechowywane w tablicy nn_input są przesuwane o jedną pozycję, a najnowszy pomiar dodawany jest na końcu. Następnie wywoływana jest funkcja aiRun() i przetwarzane są wyniki. nn_ouput zawiera dwie wartości - pierwsza pozycja to prawdopodobieństwo, że nie wykryto gestu, druga to że wykryto - ich suma wynosi 1, więc wystarczyłaby jedna wartość, ale tak była trenowana sieć. Na podstawie obliczonego prawdopodobieństwa gaszona lub zapalana jest dioda LED. Poniżej efekt działania program (z drobną poprawką o której za moment): Uczenie sieci wymaga dużej ilości danych treningowych, w sumie im więcej tym lepiej. Niestety przykładowa sieć była trenowana na bardzo małej próbce. Efekty były i tak bardzo dobre, ale po wykryciu gestu pojawiały się pewne "zakłócenia". Po pierwsze czas zapalenia diody był bardzo różny, po drugie czasem dioda zapalała się kilka razy. Oczywiście najlepiej byłoby spędzić więcej czasu ucząc sieć, ale ja zastosowałem pewne obejście. W programie, po wykryciu machania płytką dioda jest zapalana na 1s - sieć mogłaby to robić sama, ale o wiele łatwiej było zmienić program. Podsumowanie Projekt opisany w tych artykułach miał być jedynie pierwszym krokiem, taką próbą użycia X-CUBE-AI. Planowałem poprawić opisywane przykłady, dodać bardziej rozbudowany projekt z innym czujnikiem oraz wykorzystać bardziej zaawansowaną topologię sieci. Ale jak to z planami często bywa, zostały niezrealizowane. Mam jedna nadzieję, że opisane możliwości zachęcą czytelników do eksperymentowania ze sztuczną inteligencją w systemach wbudowanych oraz dzielenia się swoimi doświadczeniami. Spis treści serii artykułów: Sztuczna inteligencja na STM32, czyli przykład użycia X-CUBE-AI cz.1 Sztuczna inteligencja na STM32, czyli przykład użycia X-CUBE-AI cz.2 Sztuczna inteligencja na STM32, czyli przykład użycia X-CUBE-AI cz.3
  23. 1 punkt
    Niestety za cholere nie mogę zminić stanu pinów na UP. Tak by to jakkolwiek zadziałało. Rasppery 4B. Jedyne widoczne zmiany to IN i OUT. te są dokumentowane w >>gpio readall system przyjmuje polecenie zmiany na UP ale nie ma zmiany zarówno w readall jak i w odczycie stanu dla okreslonego pinu. Wieczorem sprawdze w domu na Raspberry 3B+ Trzeba było przeczytać formum zanim zamiesciłem wpis - Rpi4 nie wspiera UP - czekamy na aktualizację bibliotek - problemy wieku dziecięcego nowego Pi
  24. 1 punkt
    @Tomcat witam na forum Jest to znany błąd - aktualne wersje bibliotek nie obsługują jeszcze pull-upa w nowym Raspberry Pi 4. Trzeba poczekać na aktualizację biblioteki, skorzystać z czegoś innego lub dodać rezystor podciągający ręcznie. Więcej informacji oraz przykładowe rozwiązania znajdziesz tutaj: https://forbot.pl/forum/topic/10480-kurs-raspberry-pi-12-podstawy-gpio-skrypty/?do=findComment&comment=133201
  25. 1 punkt
    Cześć, Mam taki "mały" problem z pull up na danym pinie. Polecenie gpio -g mode 26 up - nie działa. Wartość cały czas wynosi 0. Dlaczego tak się dzieje? Podobnie nie działa polecenie z wfi - gdy wciskam przycisk, nie następuje przerwanie procesu. Mam od paru dni Raspberrypi 4B i gpio version 2.52 Tomasz
Tablica liderów jest ustawiona na Warszawa/GMT+02:00
×
×
  • Utwórz nowe...