Przeszukaj forum
Pokazywanie wyników dla tagów 'python'.
Znaleziono 26 wyników
-
Jako że na Forum nie ma działu gdzie można umieścić jakieś krótkie kawałki kodu, które nie kwalifikują się do miana DIY - postanowiłem założyć taki wątek. Ciekawe czy się przyjmie... Na początek - płynne miganie LED. Podobnego (ale bardziej rozbudowanego) kodu użyłem swego czasu w mini-reflektorze do teatru cieni (płynna zmiana barwy i jasności). //#define USE_MICROS #define LED_PIN 6 const int PERIOD = 5000; #define MINV (1.0/256.0) #define BITWIDTH 8 #define DELAYMS 2 float factor[2]; float wartosc; uint8_t dir; void setup() { Serial.begin(115200); float pcnt = PERIOD / (2.0 * DELAYMS); factor[0] = 1.0 / (factor[1] = pow(1.0/MINV - 1.0, (1.0 / pcnt))); wartosc = MINV; dir = 1; } void analogWriteFloat(uint8_t pin, float wartosc) { static uint8_t phase = 0; wartosc *= (1 << BITWIDTH); uint16_t pwm = (int)wartosc; if (wartosc < 16) { uint8_t w = (int)(4 * wartosc) & 3; if (w > phase) pwm+=1; } analogWrite(pin, pwm?pwm-1:0); phase = (phase + 1) & 3; } void loop() { static uint32_t ms=millis(); #ifdef USE_MICROS static uint32_t usbeg=micros(); #endif wartosc *= factor[dir]; if (wartosc < MINV) { wartosc = MINV; dir = 1; } else if (wartosc > 1.0) { wartosc = 1.0; dir = 0; Serial.println(millis() - ms); ms = millis(); } analogWriteFloat(LED_PIN, wartosc); #ifdef USE_MICROS uint32_t delta = micros() - usbeg; if (delta < DELAYMS * 1000) delayMicroseconds(DELAYMS*1000 - delta); usbeg=micros(); #else delay(DELAYMS); #endif } Miał być z komentarzami, ale kolega @farmaceuta podjął się ich napisania 🙂
-
KiCad - własne pluginy w Pythonie (PCB Python Bindings)
rziomber opublikował temat w Oprogramowanie CAD
W Internecie znajdziemy wiele skryptów Pythona ułatwiających rozmieszczenie komponentów na płytkach PCB w KiCad. Niestety w większości wypadków w ogóle nie działają pod wersją 8. Bazowy szkic jest na stronie PCB Python Bindings - Simple Plugin Example Znalezienie w Internecie aktualnych rozwiązań zajęło mi trochę czasu, postanowiłem podzielić się więc z Wami postem. Plugin umieszczamy w stosownym folderze. Po każdej zmianie kodu trzeba pamiętać o Odświeżeniu Pluginów z poziomu menu, o ile w momencie edycji KiCad jest uruchomiony. Proste przemieszczenie komponentów: import pcbnew board = pcbnew.GetBoard() def move_component(move_name, x, y): move_component = board.FindFootprintByReference(move_name) if move_component: vector = pcbnew.VECTOR2I_MM(x, y) move_component.SetPosition(vector) pcbnew.Refresh() print(f"Component {move_name} moved to {vector}") else: print(f"Component {move_name} not found") def move_component_relative(reference_name, move_name, x, y): move_component = board.FindFootprintByReference(move_name) reference_component = board.FindFootprintByReference(reference_name) if reference_component and move_component: shift_vector = pcbnew.VECTOR2I_MM(x, y) reference_position = reference_component.GetPosition() new_position = reference_position+shift_vector move_component.SetPosition(new_position) pcbnew.Refresh() print(f"Component {move_name} moved to {new_position}") else: print(f"Component {move_name} not found") class PlaceComponent(pcbnew.ActionPlugin): def defaults(self): self.name = "Place Component" self.category = "Modify PCB" self.description = "Place a component by name at a specified location" def Run(self): move_component_relative("D1", "D2", 26, 0) move_component("U1", 80, 88) # Register the plugin PlaceComponent().register() NIEOPTYMALNE (niepotrzebnie przenosi ścieżki do kolejnej linijki po przekątnej, zamiast "wężykiem"), przykładowe rozmieszczenie komponentów: import pcbnew board = pcbnew.GetBoard() def move_component(move_name, x, y): print('vector ' + str(x) + " " + str(y)) move_component = board.FindFootprintByReference(move_name) if move_component: vector = pcbnew.VECTOR2I_MM(x, y) move_component.SetPosition(vector) pcbnew.Refresh() print(f"Component {move_name} moved to {vector}") else: print(f"Component {move_name} not found") def move_component_relative(reference_name, move_name, x, y): print('vector ' + str(x) + " " + str(y)) move_component = board.FindFootprintByReference(move_name) reference_component = board.FindFootprintByReference(reference_name) if reference_component and move_component: shift_vector = pcbnew.VECTOR2I_MM(x, y) reference_position = reference_component.GetPosition() new_position = reference_position+shift_vector move_component.SetPosition(new_position) pcbnew.Refresh() print(f"Component {move_name} moved to {new_position}") else: print(f"Component {move_name} not found") def rearrangeComponents(): width = 3.5 height = 3.5 x_margin = 7 y_margin = 3.5 line = 0 number_led = 1 for i in range(0, 9): if i == 0 or i == 8: count = 2 for j in range(count): move_component_relative("D1", "D"+str(number_led), (width+x_margin)*j*5, (height+y_margin)*i) number_led += 1 #pygame.draw.rect(screen, WHITE, (initial_x+(width+x_margin)*j*5, initial_y+(height+y_margin)*i, width, height)) #all_leds += 1 else: if i%2 == 1: count = 4 initial_spacing = width+x_margin else: count = 3 initial_spacing = 2*width+x_margin+(x_margin-width)/2 for j in range(count): move_component_relative("D1", "D"+str(number_led), (width+x_margin)*j+initial_spacing, (height+y_margin)*i) number_led += 1 #pygame.draw.rect(screen, WHITE, (initial_x+(width+x_margin)*j+initial_spacing, initial_y+(height+y_margin)*i, width, height)) class PlaceComponent(pcbnew.ActionPlugin): def defaults(self): self.name = "Place Component" self.category = "Modify PCB" self.description = "Place a component by name at a specified location" def Run(self): rearrangeComponents() #move_component_relative("D1", "D2", 26, 0) #move_component("U1", 80, 88) # Register the plugin PlaceComponent().register() Dzięki modułowi pygame przyspieszymy testowanie kolejnych iteracji algorytmu. import pygame import sys pygame.init() screen = pygame.display.set_mode((580, 620)) pygame.display.set_caption("Shooting lights") BLACK = (0, 0, 0) GREEN = (0, 255, 0) WHITE = (255, 255, 255) initial_x = 10 initial_y = 10 width = 35 height = 35 x_margin = 70 y_margin = 35 line = 0 running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False # Fill the screen with black screen.fill(BLACK) #all_leds = 0 for i in range(0, 9): if i == 0 or i == 8: count = 2 for j in range(count): pygame.draw.rect(screen, WHITE, (initial_x+(width+x_margin)*j*5, initial_y+(height+y_margin)*i, width, height)) #all_leds += 1 else: if i%2 == 1: count = 4 initial_spacing = width+x_margin else: count = 3 initial_spacing = 2*width+x_margin+(x_margin-width)/2 for j in range(count): pygame.draw.rect(screen, WHITE, (initial_x+(width+x_margin)*j+initial_spacing, initial_y+(height+y_margin)*i, width, height)) #all_leds += 1 #print(all_leds) #pygame.draw.rect(screen, GREEN, (initial_x, initial_y, width, height)) # Update the display pygame.display.flip() # Quit pygame pygame.quit() sys.exit() Możemy skorzystać z wxPython (Tkinter nie chciał się uruchomić z poziomu KiCada), by za pomocą GUI, na żywo edytować parametry pracy. import pcbnew import wx #https://techoverflow.net/2023/05/13/how-to-show-wx-dialog-message-in-kicad-pcbnew-plugin/ #sudo dnf install python3-wxpython4* board = pcbnew.GetBoard() width = 3.5 height = 3.5 x_margin = 7 y_margin = 3.5 def move_component(move_name, x, y): print('vector ' + str(x) + " " + str(y)) move_component = board.FindFootprintByReference(move_name) if move_component: vector = pcbnew.VECTOR2I_MM(x, y) move_component.SetPosition(vector) pcbnew.Refresh() print(f"Component {move_name} moved to {vector}") else: print(f"Component {move_name} not found") def move_component_relative(reference_name, move_name, x, y): print('vector ' + str(x) + " " + str(y)) move_component = board.FindFootprintByReference(move_name) reference_component = board.FindFootprintByReference(reference_name) if reference_component and move_component: shift_vector = pcbnew.VECTOR2I_MM(x, y) reference_position = reference_component.GetPosition() new_position = reference_position+shift_vector move_component.SetPosition(new_position) pcbnew.Refresh() print(f"Component {move_name} moved to {new_position}") else: print(f"Component {move_name} not found") def rearrangeComponents(): line = 0 number_led = 1 for i in range(0, 9): if i == 0 or i == 8: count = 2 for j in range(count): move_component_relative("D1", "D"+str(number_led), (width+x_margin)*j*5, (height+y_margin)*i) number_led += 1 #pygame.draw.rect(screen, WHITE, (initial_x+(width+x_margin)*j*5, initial_y+(height+y_margin)*i, width, height)) #all_leds += 1 else: if i%2 == 1: count = 4 initial_spacing = width+x_margin else: count = 3 initial_spacing = 2*width+x_margin+(x_margin-width)/2 for j in range(count): move_component_relative("D1", "D"+str(number_led), (width+x_margin)*j+initial_spacing, (height+y_margin)*i) number_led += 1 #pygame.draw.rect(screen, WHITE, (initial_x+(width+x_margin)*j+initial_spacing, initial_y+(height+y_margin)*i, width, height)) class PlaceComponentGUI(pcbnew.ActionPlugin): def defaults(self): self.name = "Place Component GUI" self.category = "Modify PCB" self.description = "Place a component by name at a specified location" def Run(self): app = wx.App(False) frame = MyForm() frame.Show() app.MainLoop() # Register the plugin PlaceComponentGUI().register() class MyForm(wx.Frame): def __init__(self): wx.Frame.__init__(self, None, wx.ID_ANY, "Move components", size=(400, 400)) panel = wx.Panel(self, wx.ID_ANY) sizer = wx.BoxSizer(wx.VERTICAL) # Reference component x_margin_label = wx.StaticText(panel, label="x_margin:") self.x_margin_input = wx.TextCtrl(panel) global x_margin self.x_margin_input.SetValue(str(x_margin)) sizer.Add(x_margin_label, 0, wx.ALL, 5) sizer.Add(self.x_margin_input, 0, wx.ALL | wx.EXPAND, 5) y_margin_label = wx.StaticText(panel, label="y_margin:") self.y_margin_input = wx.TextCtrl(panel) global y_margin self.y_margin_input.SetValue(str(y_margin)) sizer.Add(y_margin_label, 0, wx.ALL, 5) sizer.Add(self.y_margin_input, 0, wx.ALL | wx.EXPAND, 5) move_button = wx.Button(panel, label="Move") move_button.Bind(wx.EVT_BUTTON, self.on_move) sizer.Add(move_button, 0, wx.ALL | wx.CENTER, 5) panel.SetSizer(sizer) def on_move(self, event): global x_margin global y_margin x_margin = float(self.x_margin_input.GetValue()) y_margin = float(self.y_margin_input.GetValue()) rearrangeComponents() Reimplementacja funkcji, która już istnieje w menu kontekstowym komponentu: import pcbnew import wx #https://techoverflow.net/2023/05/13/how-to-show-wx-dialog-message-in-kicad-pcbnew-plugin/ #sudo dnf install python3-wxpython4* board = pcbnew.GetBoard() def move_component(move_name, x, y): print('vector ' + str(x) + " " + str(y)) move_component = board.FindFootprintByReference(move_name) if move_component: vector = pcbnew.VECTOR2I_MM(x, y) move_component.SetPosition(vector) pcbnew.Refresh() print(f"Component {move_name} moved to {vector}") else: print(f"Component {move_name} not found") def move_component_relative(reference_name, move_name, x, y): print('vector ' + str(x) + " " + str(y)) move_component = board.FindFootprintByReference(move_name) reference_component = board.FindFootprintByReference(reference_name) if reference_component and move_component: shift_vector = pcbnew.VECTOR2I_MM(x, y) reference_position = reference_component.GetPosition() new_position = reference_position+shift_vector move_component.SetPosition(new_position) pcbnew.Refresh() print(f"Component {move_name} moved to {new_position}") else: print(f"Component {move_name} not found") class MyForm(wx.Frame): def __init__(self): wx.Frame.__init__(self, None, wx.ID_ANY, "Move components", size=(400, 400)) panel = wx.Panel(self, wx.ID_ANY) sizer = wx.BoxSizer(wx.VERTICAL) # Reference component ref_label = wx.StaticText(panel, label="Reference component:") self.ref_input = wx.TextCtrl(panel) sizer.Add(ref_label, 0, wx.ALL, 5) sizer.Add(self.ref_input, 0, wx.ALL | wx.EXPAND, 5) move_label = wx.StaticText(panel, label="Move component:") self.move_input = wx.TextCtrl(panel) sizer.Add(move_label, 0, wx.ALL, 5) sizer.Add(self.move_input, 0, wx.ALL | wx.EXPAND, 5) shift_label = wx.StaticText(panel, label="Shift vector:") sizer.Add(shift_label, 0, wx.ALL, 5) x_label = wx.StaticText(panel, label="X:") self.x_input = wx.TextCtrl(panel) sizer.Add(x_label, 0, wx.ALL, 5) sizer.Add(self.x_input, 0, wx.ALL | wx.EXPAND, 5) y_label = wx.StaticText(panel, label="Y:") self.y_input = wx.TextCtrl(panel) sizer.Add(y_label, 0, wx.ALL, 5) sizer.Add(self.y_input, 0, wx.ALL | wx.EXPAND, 5) move_button = wx.Button(panel, label="Move") move_button.Bind(wx.EVT_BUTTON, self.on_move) sizer.Add(move_button, 0, wx.ALL | wx.CENTER, 5) panel.SetSizer(sizer) def on_move(self, event): ref = self.ref_input.GetValue() move = self.move_input.GetValue() x_shift = float(self.x_input.GetValue()) y_shift = float(self.y_input.GetValue()) print(f"Reference: {ref}, Move: {move}, X shift: {x_shift}, Y shift: {y_shift}") move_component_relative(ref, move, x_shift, y_shift) class DialogExamplePlugin(pcbnew.ActionPlugin): def defaults(self): self.name = "Move components GUI" #self.category = "A descriptive category name" self.description = "GUI interface to arrangement components" self.show_toolbar_button = False def Run(self): app = wx.App(False) frame = MyForm() frame.Show() app.MainLoop() DialogExamplePlugin().register() Warto uruchomić KiCada z poziomu linii poleceń. Dzięki temu będziemy mieli podgląd w terminalu do tego, co wypisywane jest funkcją print(). Jeśli zainstalowaliśmy aplikację pod Linuksem z poziomu Flatpaka: flatpak run org.kicad.KiCad Przykładowy efekt pracy: -
Dzisiaj nieco odpoczynku od elektroniki. Ale oczywiście o ile ta cała kabelkologia jest niezmiernie ważna i ważne jest urządzenie sobie warsztatu - to samo można powiedzieć o "warsztacie programisty", czyli zorganizowaniu tak stanowiska, aby można było skupić się na tym co najważniejsze: tworzeniu kodu. Wrzucam to jako worklog, bo kilka spraw jest jeszcze nie do końca rozwiązanych (m.in. użycie esptool-ftdi, na czym bardzo mi zależy), ale w tej postaci jaka jest program jest absolutnie używalny i spełnia swoją funkcję. Na potrzebę powstania tego programu złożyło się kilka czynników. Przede wszystkim w większości do programowania swoich ESP używam frameworku Arduino, a Arduino IDE z różnych przyczyn uważam za mało używalne. Poza tym także nie przepadam za pisaniem Makefile (chociaż po napisaniu bardzo lubię używać make). Postanowiłem więc zrobić sobie wrapper do arduino-cli. Wrapper działa na Linuksie, ale nie widzę przeszkód w uruchomieniu go na Macu czy nawet na Windows, potrzebne by były jedynie niewielkie zmiany. Przede wszystkim musiałem zrobić to, czego mi a Arduino IDE brakuje - czyli oddzielna konfiguracja dla każdego szkicu. Postanowiłem pójść jeszcze dalej: ponieważ zdarza mi się ten sam program uruchamiać na kilku różnych architekturach, założyłem możliwość istnienia kilku wariantów konfiguracji dla każdego szkicu i zabrałem się do roboty. Ponieważ znałem już strukturę plików boards.txt i platform.txt poszło dość szybko - i w relatywnie krótkim czasie miałem już gotowy konfigurator. Oczywiście zanim cokolwiek się zrobi trzeba dodać nowy wariant. Po wciśnięciu klawisza "Nowa" ukazuje się okno tworzenia wariantu: Jak widać jest to podobne do menu wyboru płytki w Arduino IDE, dochodzi jedynie pole "Nazwa", pozwalające na nadanie wariantowi jakiejś łatwej do zapamiętania nazwy. Po utworzeniu wariantu można zabrać się do konfiguracji. I tu znów wzorowałem się na menu Arduino IDE - wszystkie parametry są widoczne na liście, a aktywacja wiersza (czyli dwuklik albo wciśnięcie Enter) powoduje pojawienie się możliwości wyboru predefiniowanej opcji: Jak widać, na razie różnice w stosunku do IDE są niewielkie, ale następną rzeczą, która w IDE jest dla mnie szalenie niewygodna, jest wybór portu do uploadu. Przede wszystkim - nasze systemy operacyjne przyporządkowują numer portu do urządzenia w sposób raczej losowy. Odłączenie i ponowne podłączenie płytki skutkować może np. zmianą portu z ttyUSB0 ma ttyUSB1, co potrafi trochę krwi napsuć. Dość dawno jednak stworzyłem prosty system detekcji portu, i zastosowanie go tutaj było oczywiste. Po prostu podaję jaki to ma być typ portu (do wyboru ttyS, ttyUSB i ttyACM) i/lub nazwę pod jaką zgłasza się podłączone urządzenie. Program szukając portu przeszukuje tylko te o zadeklarowanym typie, ewentualnie sprawdzając, czy nazwa odczytana z urządzenia zawiera w sobie wyszukany string. W ten sposób np. uploader dostaje informację że ma się połączyć na tym a nie innym porcie. Ten sposób działa u mnie już od ok. dwóch lat i jeszcze mnie nie zawiódł. W programie wprowadziłem jeszcze jedną zmianę: jeśli nazwa rozpoczyna się od VID:PID (np. "2341:0043 Uno R3") będzie wyszukiwane urządzenie odpowiadające odczytanym z USB wartościom VendorID i ProductID. Również nazwa w przypadku urządzeń USB będzie (o ile to mozliwe) pochodzić z oficjalnego wykazu. Następną sprawą jest ustawienie adresu i hasła OTA. O ile w IDE konieczne jest, aby urządzenie było włączone w czasie ustawiania portu, o tyle tu takiej konieczności nie ma: mogę albo skorzystać z listy urządzeń wykrytych przez zeroconf (przy czym mogę sobie zapisać albo nazwę, albo adres IP) albo podać te dane ręcznie (jeśli je znam). Poza tym mój program zapamiętuje hasło, co bywa wygodne (szczególnie w porównaniu do IDE w wersji 2.x). I ostatnia rzecz: użycie zewnętrznego programu do uploadu. Może to być np. program obsługi jakiegoś programatora, albo (jak w moim przypadku, co postaram się pokazać przy najbliższym DIY) skrypt wysyłający skompilowany plik do maszyny, do której podłączona jest płytka. W sumie okno konfiguratora uploadu wygląda tak: Istnieje również możliwość dodania dodatkowych parametrów do kompilacji. Dla architektury AVR można włączyć pełną wersję sprintf (tzn. taką, która pozwala na wypisywanie floatów). Można również dodać dowolną ilość definicji, które w programie będą traktowane jako dodatkowe linie #define. Poziom szczegółowości ostrzeżeń działa nieco inaczej niż w IDE: dla platform, dla których automatycznie dodawane jest -Werror przy wyświetlaniu wszystkich ostrzeżeń parametr ów nie jest dodawany automatycznie, można go dodać zaznaczając odpowiednie pole. W ten sposób można bez zbytniej ekwilibrystyki kompilować programy np. na ESP32 z wyświetlaniem wszystkich ostrzeżeń (w IDE przy takim przełączeniu kompilator odmawia kompilacji bibliotek które generują jakieś ostrzeżenia, choćby nawet nie miały wpływu na ich działanie): I to już cały konfigurator. Teraz wystarczy zapisać całą konfigurację (przycisk "Zapisz" lub "Zapisz i zakończ"). Jako domyślny zostanie wpisany wariant aktualnie wskazany na liście. No, ale konfigurator to nie wszystko - warto by było mieć coś, co z tego konfiguratora korzysta. Postanowiłem stworzyć jedno polecenie, które zależnie od podanych opcji będzie robiło różne czynności. Jako że najważniejszym poleceniem jest "help", tak wygląda wynik jego działania (i kilku następnych): Pisząc program natknąłem się na kilka nieprzyjemnych niespodzianek związanych z arduino-cli. Początkowo najbardziej naturalne wydało mi się umieszczenie katalogów build i cache wewnątrz katalogu szkicu. Stosowałem to już wcześniej używając arduino-builder i make, tak więc wydało mi się to najlepszym i w dodatku sprawdzonym rozwiązaniem. A guzik... arduino-cli bardzo grzecznie kompilował program, ale tylko raz. Ki diabeł? No tak, zajrzenie na githuba do issues wszystko wyjaśniło. Jest to stary, szacowny błąd z długą brodą, polegający na tym, że arduino-cli uważa pliku w katalogu build za pliki żródłowe, i próbuje je jeszcze raz skompilować (co się oczywiście nie udaje). W związku z tym preniosłem owe katalogi do /tmp, jakoś w miarę sensownie je ponazywałem i zadziałało... No prawie, a jak wiadomo - prawie robi wielką różnicę. Otóż plik konfiguracji (w formacie json) zapisywany jest w katalogu szkicu (no bo gdzie miałby być zapisany) z rozszerzeniem .json - a to też zmyliło arduino-cli które koniecznie chciało go skompilować. Zmiana rozszerzenia na .cfg skutecznie oduczyła arduino-cli nadmiernej gorliwości i wszystko ładnie ruszyło... Z jednym wyjątkiem: uploadu przez OTA. Podobno arduinio-cli to potrafi (w końcu jakoś IDE w wersji 2.x daje sobie z tym radę, aczkolwiek nie tak do końca). Postanowiłem więc darować sobie sprawdzanie i upload OTA rozwiązać "ręcznie". Jako że jak dla mnie dotyczy to tylko ESP, zaprzągłęm do pracy parser konfiguracji arduino (który i tak jest częścią programu), i dopisałem kilka linijek. Co prawda w tej postaci upload OTA możliwy jest wyłącznie dla ESP32 i ESP8266, ale po pierwsze nie mam innych mikrokontrolerów dla których mógłbym to wykorzystać, po drugie dopisanie kolejnych architektur to kwestia kliku minut, a po trzecie wszystko można załatwić możliwością uploadu przez zewnętrzne polecenie. Aha, no i najważniejsze: może autorzy arduino-cli jakoś w końcu uporają się z implementacją obsługi OTA 🙂 No cóż - chciałbym powiedzieć że to wszystko, ale już słyszę narzekania: linia poleceń? Ajaj, przecież to takie trudne, lepiej sobie kliknąć w jakieś menu w aplikacji! A da się. Porządne edytory (np. Geany) mają możliwość skonfigurowania zewnętrznych poleceń. Dla przykładu rozwiązanie wyklikane dla plików *.ino wygląda w Geany tak: No i na koniec kwestia instalacji. Najpierw musimy upewnić się, czy mamy potrzebne biblioteki i programy współpracujące:Python, gobject-introspection i gtk3 najprawdopodobniej już mamy; można to łatwo sprawdzić uruchamiając konsolę python3 i wpisując polecenia importu Gtk3: $ python3 Python 3.8.10 (default, Jun 22 2022, 20:18:18) [GCC 9.4.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import gi >>> gi.require_version('Gtk', '3.0') >>> from gi.repository import Gtk >>> Jeśli nie było błędu wszystko jest w porządku; w przeciwnym razie należy sprawdzić w dokumentacji swojej dystrybucji. Dodatkowo potrzebny będzie pakiet zeroconf i usb.ids. Jeśli ich nie będzie, pakiet zeroconf można zainstalować z githuba, a plik usb.ids można ściągnąć z internetu i umieścić gdziekolwiek wskazując ścieżkę we właściwym miejscu w pliku arduports.py w linii zawierającej polecenie: f=open('/var/lib/usbutils/usb.ids','rb') No i ostatnie najważniejsze: arduino-cli. Możemy zainstalować z githuba, lub użyć wersji zawartej w Arduino-IDE 2.x. Ważne, aby znalazło się w ścieżce wskazanej przez $PATH! Właściwy program instalujemy oczywiście z poziomu użytkownika, a nie roota! W tym celu musimy znać katalog, w którym możemy umieścić polecenia. Dla Linuksów będą to najprawdopodobniej ~/bin lub ~/.local/bin - można to sprawdzić poleceniem: echo $PATH Załóżmy że jest to katalog ~/bin. Plik pyrduino.tgz umieszczamy tam, gdzie nie powinien się zgubić (np. w katalogu domowym) i wykonujemy kolejno polecenia: tar -xzf pyrduino.tgz cd pyrduino-src chmod 755 ardu.py ln -sf $(pwd)/ardu.py ~/bin/arducfg ln -sf $(pwd)/ardu.py ~/bin/ardu I to wszystko. Możemy teraz wejść do katalogu szkicu i pobawić się poleceniami arducfg i ardu. Na koniec jedna uwaga: o ile polecenie arducfg musi pozostać takie a nie inne (można to zmienić w pliku ardu.py), o tyle zamiast nazwy ardu możemy użyć dowolnej, która nam się podoba. I jeszcze jedno: jak wspominałem na początku, da się to pewnie zainstalować na Macu (z niewielkimi zmianami) i na Windows (z większymi zmianami). Gdyby komuś się to udało - proszę o danie znać w komentarzu; może komuś się przyda! Do ściągnięcia: pyrduino.tgz I tak już całkiem na zakończenie dla miłośników make - krótki przykład: BINARY=$(shell ardu -show | grep -P '^Build\s+=' | tr -d " " | cut -d= -f2) $(BINARY): *.ino ardu PHONY: flash flash: $(BINARY) ardu -V -flash PHONY:ota ota: $(BINARY) ardu -ota PHONY:clean clean: ardu -clean Prawda, że proste?
-
import cv2 import pytesseract import time from pytesseract import Output def extract_license_plate(image_path): image = cv2.imread(image_path) gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) blur = cv2.GaussianBlur(gray, (5, 5), 0) edges = cv2.Canny(blur, 100, 200) contours, hierarchy = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) contours = sorted(contours, key=cv2.contourArea, reverse=True)[:10] plate_text = None for contour in contours: peri = cv2.arcLength(contour, True) approx = cv2.approxPolyDP(contour, 0.018 * peri, True) if len(approx) == 4: x, y, w, h = cv2.boundingRect(approx) roi = image[y:y + h, x:x + w] plate_text = pytesseract.image_to_string(roi, config='--psm 8 --oem 3 -c tessedit_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') return ''.join(filter(str.isalnum, plate_text)) return "no text detected" cap=cv2.VideoCapture(0) try: while True: ret, frame = cap.read() if ret: cv2.imwrite('/home/marek/tablica.png',frame) print("Image saved") text = extract_license_plate('/home/marek/tablica.png') else: print("fail") if text is not None: print(f"Extracted Text: {text}") time.sleep(5) except Exception as e: print(f"An error occurred: {e}") finally: cap.release() print("Camera released.") Pracuję nad projektem systemu służącego do automatycznego otwierania bramy, w momencie rozpoznania przez kamerę z Raspberry Pi, numerów tablic rejestracyjnych zapisanych w pliku tekstowym. Jestem dość zielony w jakiekolwiek programy związane z systemami wizyjnymi i mocno posiłkowałem się ChatemGPT 4, wrzuciłem do chatu zdjęcia przypominające docelowy obraz z kamery i kazałem mu pod to napisać program. Program działa prawie idealnie kiedy zczytuje tablice z gotowych zdjęć, jednak gdy zdjęcia pochodzą z kamery i pokazuje przed nią dokładnie to samo zdjęcie tylko wydrukowane, program nie rozpoznaje żadnych znaków. Pytanie gdzie może leżeć problem, czy wpływ na to ma zbyt niska jakość obrazu z kamerki (używam kamery ZeroCam z przejściówka do Raspberry PI 3A+) , potencjalnie zły kąt zdjęcia przed kamerka czy może jakiś błąd w kodzie? Testuje działanie na załączonym obrazku Z góry dziękuje za pomoc, ewentualny namiar do kogoś kto mógłby pomóc :))
- 1 odpowiedź
-
- Początkujący
- Raspberry Pi
-
(i 3 więcej)
Tagi:
-
Hej. Niestety - na programowaniu wind się nie znam, a potrzebuję kawałka kodu (najchętniej python), który zareaguje na naciśnięcie konkretnego klawisza. W Linuksach to trywialne (podpinam się pod evdev) - poszukiwania w góglu zwracają co najwyżej linki do exploitów (co mnie nie interesuje). Jest coś takiego w ogóle możliwe? A jeśli tak to jak? W końcu JAWS jakoś daje radę...
-
Błąd przy otwarciu udostępnianego pliku libmmal.so (picamera)
Pawelitto opublikował temat w Raspberry Pi
Siema. Mam problem z kamerką w raspberry pi 3, ponieważ występuje błąd przy importowaniu biblioteki 'picamera'. Kod python: from picamera import PiCamera from time import sleep camera = PiCamera() camera.start_preview() sleep(5) camera.stop_preview() Kod błędu: Traceback (most recent call last): File "/home/pi/Desktop/camera.py", line 1, in <module> from picamera import PiCamera File "/usr/local/lib/python3.9/dist-packages/picamera/__init__.py", line 72, in <module> from picamera.exc import ( File "/usr/local/lib/python3.9/dist-packages/picamera/exc.py", line 41, in <module> import picamera.mmal as mmal File "/usr/local/lib/python3.9/dist-packages/picamera/mmal.py", line 49, in <module> _lib = ct.CDLL('libmmal.so') File "/usr/lib/python3.9/ctypes/__init__.py", line 374, in __init__ self._handle = _dlopen(self._name, mode) OSError: libmmal.so: cannot open shared object file: No such file or directory- 2 odpowiedzi
-
- Raspberry Pi
- picamera
-
(i 3 więcej)
Tagi:
-
Własny asystent głosowy - Prosty bot głosowy w pythonie
Ruby opublikował temat w Artykuły użytkowników
Bot głosowy Marian Każdy chyba słyszał o asystentach głosowych, czy to Alexa czy Asystent Google. Ale czy ktoś z was próbował stworzyć własnego asystenta głosowego? Ja natchniony nowo zakupioną Alexą, postanowiłem spróbować swoich sił w napisaniu prostego bota sterowanego głosem, który może przeprowadzić proste interakcje z użytkownikiem. Sięgnąłem moim zdaniem po najodpowiedniejsze narzędzie do tego projektu, czyli po pythona, co zaowocowało powstaniem Mariana. Ten artykuł bierze udział w naszym konkursie! 🔥 Na zwycięzców czekają karty podarunkowe Allegro, m.in.: 2000 zł, 1000 zł i 500 zł. Potrafisz napisać podobny poradnik? Opublikuj go na forum i zgłoś się do konkursu! Czekamy na ciekawe teksty związane z elektroniką i programowaniem. Sprawdź szczegóły » Do stworzenia własnego bota głosowego wykorzystałem pythona w wersji 3.8.5, środowisko Spyder oraz cztery biblioteki pythona. import speech_recognition as sr #biblioteka odpowiedzialna za rozpoznawanie naszego głosu import pyttsx3 as tts #biblioteka odpowiedzialna za tworzenie głosu bota from playsound import playsound #biblioteka odpowiedzialna za odtwarzanie muzyki przez bota import time Poniżej komendy których należy użyć do pobrania niezbędnych bibliotek. pip install SpeechRecognition pip install pyttsx3 pip install playsound Następne linie kodu prezentują się następująco: version = "1.0" author = "AvirFrog" sleep_time= 3 r = sr.Recognizer() engine = tts.init() engine.setProperty('rate', 150) Zmienne version oraz author są wykorzystywane w dalszej części programu i nie są niezbędne do jego działania (jeśli zdecydujemy się na pominięcie tych zmiennych w kodzie to powinniśmy też usunąć jedną część o której wspomnę później). Zmienna sleep_time = 3 odpowiada za czas oczekiwania na wywołanie uruchomionego bota. Po włączeniu bota jeśli nie usłyszy on swojego imienia przez najbliższe 3 sekundy wyłączy się. Zmienna r = sr.Recognizer() pozwala nam na wczytywanie naszego głosu. Zmienna engine = tts.init() inicjalizuje silnik zmiany tekstu na mowę i właśnie na tej zmiennej możemy operować i modyfikować możliwości głosowe naszego bota. engine.setProperty('rate', 150) - jest to ustawienie prędkości z jaką nasz asystent głosowy mówi. Jeśli chcielibyśmy zmienić głos naszego bota to możemy wykorzystać poniższy kod voices = engine.getProperty('voices') engine.setProperty('voice', voices[0].id) Zmiana voices[0] na voices[1] sprawi że nasz bot będzie mówił głosem męskim po angielsku. Ja wolałem zostać przy podstawowym głosie żeńskim mówiącym po Polsku, ze względu na to że na razie jest to prototyp bota głosowego. def speak(text): engine.say(text) engine.runAndWait() def get_Text(): with sr.Microphone() as source: try: print("Słucham...") audio = r.listen(source) text = r.recognize_google(audio, language='pl-PL') if text != "": return text return 0 except: return 0 Pierwsza funkcja speak jest bardzo prosta, przyjmuje ona parametr text (czyli to co nasz bot będzie miał powiedzieć) i za pomocą engine.say(text) nasz bot jest w stanie powiedzieć to co mu kazaliśmy. Druga funkcja get_Text polega na zarejestrowaniu naszego głosu. W pierwszej linii za pomocą with sr.Microphone() as source: ustawiamy nasz mikrofon jako rejestrator dźwięku. Następnie mamy wychwytywanie błędu w rozpoznawaniu, czasami zdarzyć się może tak że nasz mikrofon nie zostanie wykryty i z tego powodu by zabezpieczyć program przed błędami używamy try/except. By mieć pewność że wszystko dobrze działa program informuje nas komunikatem "Słucham...", kiedy jest gotowy na przyjęcie polecenia. Niżej do zmiennej audio przekazujemy nasz zarejestrowany głos i zmieniamy go na tekst (korzystając z rozpoznawania mowy google). Poniższa funkcja pozwala mi zaokrąglać liczby po dzieleniu, nie ma w niej nic szczególnego i jest jednym z wielu możliwych rozwiązań (wykorzystamy tę funkcję w dalszej części kodu). def rounding_of_numbers(n, decimals=0): multiplier = 10 ** decimals return int(n * multiplier) / multiplier Nareszcie czas na mózg naszego bota głosowego. W tym miejscu wywołujemy powyższe funkcje i decydujemy na co i w jaki sposób reaguje nasz bot. while True: try: txt = get_Text().lower() txt = txt.split() if txt != 0 and txt[0] == 'marian': print(txt) speak("Tak") if txt != 0 and txt[1] == 'witaj': print(txt) speak("Witaj, co mogę dla Ciebie zrobić?") continue elif txt != 0 and txt[1] == 'włącz' and txt[2] == 'muzykę': print(txt) speak("Włączam muzykę") playsound('WikingFoxMusic_music.mp3') speak("Mam nadzieję że muzyka Ci się podobała, bo mi bardzo") elif txt != 0 and txt[1] == 'wyloguj': print(txt) speak("Dozobaczenia") break elif txt != 0 and txt[1] == 'policz': print(txt) speak("Zaraz policzymy") if txt != 0 and txt[3] == 'dodać': print(txt) speak("dodawanie") n1, n2 = int(txt[2]), int(txt[4]) wynik = n1 + n2 mwynik = str(wynik) speak(f'{str(n1)} dodać {str(n2)} jest równe {mwynik}') continue elif txt != 0 and (txt[3] == '-' or txt[3] == 'minus'): print(txt) speak("odejmowanie") n1, n2 = int(txt[2]), int(txt[4]) wynik = n1 - n2 mwynik = str(wynik) speak(f'{str(n1)} minus {str(n2)} jest równe {mwynik}') continue elif txt != 0 and txt[3] == 'na': print(txt) speak("dzielenie") n1, n2 = int(txt[2]), int(txt[4]) wynik = rounding_of_numbers((n1 / n2), 2) mwynik = str(wynik) speak(f'{str(n1)} podzielić {str(n2)} jest równe {mwynik}') continue elif txt != 0 and (txt[3] == 'x' or txt[3] == 'razy'): print(txt) speak("mnożenie") n1, n2 = int(txt[2]), int(txt[4]) wynik = n1 * n2 mwynik = str(wynik) speak(f'{str(n1)} razy {str(n2)} jest równe {mwynik}') continue else: print(txt) speak(f"Potrafię tylko dodawać, odejmować, dzielić i mnożyć dlatego nie wiem co to {txt[3]}") continue elif txt != 0 and txt[1] == 'informacje': print(txt) speak(f"Informacje o bocie głosowym Marian. Wersja {version}, Autor {author}.") continue else: print(txt) continue else: print(txt) continue except: time.sleep(sleep_time) speak("Skoro nic nie mówisz to wyłączam się. Bywaj") break Teraz postaram się wytłumaczyć jak działają poszczególne rzeczy w naszym bocie: txt = get_Text().lower() txt = txt.split() if txt != 0 and txt[0] == 'marian': print(txt) speak("Tak") Powyższy fragment kodu zmienia nasza mowę, rozpoznaną przez bota tak by była stringiem składającym się z małych liter. Wolałem mieć pewność że program nie będzie miał problemu z rozpoznaniem danego słowa kluczowego (czasami niektóre słowa zapisywał sobie z wielkiej litery co powodowało błędy jeśli nie zostało to uwzględnione w dalszej części kodu, dlatego ten mały zabieg zmiany wszystkich liter w wykrytym tekście na małe litery oszczędza nam wielu problemów). Cały string splitujemy dzięki czemu otrzymujemy tablicę ze słowami. Jeśli pierwszym naszym słowem jest "marian" to nasz bot podejmie z nami interakcję, w przeciwnym razie nie będzie reagował. Zainspirowała mnie do tego Alexa i Asystent Google. Po usłyszeniu swojego imienia bot odpowiada "tak". elif txt != 0 and txt[1] == 'włącz' and txt[2] == 'muzykę': print(txt) speak("Włączam muzykę") playsound('WikingFoxMusic_music.mp3') speak("Mam nadzieję że muzyka Ci się podobała, bo mi bardzo") W powyższym fragmencie można zauważyć że staramy się rozpoznać dwa słowa "włącz muzykę", przez zaproponowany przeze mnie sposób wykrywania komend, musimy właśnie w taki sposób operować na komendach składających się z dwóch lub większej ilości słów. Tutaj widzimy wykorzystanie biblioteki playsound, która uruchamia muzykę będącą w tym samym folderze co nasz skrypt z botem. elif txt != 0 and txt[1] == 'wyloguj': print(txt) speak("Dozobaczenia") break Wyżej natomiast mamy komendę do wyłączenia bota, za co odpowiada break, który wychodzi nam z nieskończonej pętli while. elif txt != 0 and txt[1] == 'policz': print(txt) speak("Zaraz policzymy") if txt != 0 and txt[3] == 'dodać': print(txt) speak("dodawanie") n1, n2 = int(txt[2]), int(txt[4]) wynik = n1 + n2 mwynik = str(wynik) speak(f'{str(n1)} dodać {str(n2)} jest równe {mwynik}') continue Tutaj znajduje się nasz prosty kalkulator, w momencie gdy nasz bot jako drugie słowo usłyszy "policz", zacznie liczyć to co mu każemy. Do wyboru mamy dodawanie, odejmowanie, mnożenie i dzielenie. Istotne tutaj jest to że rodzaj działania rozpoznajemy za pomocą czwartego słowa, czyli gdy powiemy "Marian policz cztery dodać pięć" bot podany tekst zmieni na "marian policz 4 dodać 5" z czego otrzymamy taką tablice słów: ["marian", "policz", "4", "dodać", "pięć"] Pamiętając że elementy w tablicy numerowane są od zera, element 0 uruchamia nam bota, element 1 pozwala na obliczanie prostych rzeczy, element 2 i 5 to podane przez nas liczby, zapisane za pomocą cyfr (dlatego w dalszej części kodu konwertujemy "4", które jest typu string na 4, które jest typu int. Uwaga na pułapki. Mówiąc minus, czasem bot da nam znak "-" a czasem słowo "minus" dlatego musimy w skrypcie umieścić informację że jesli chcemy odejmowac to jeśli czwarte słowo jest myślnikiem lub słowem minus. elif txt != 0 and (txt[3] == '-' or txt[3] == 'minus'): jeśli kogoś zastanawia czym jest txt != 0 to chodzi tu o to że nasz rozpoznany tekst nie może być pusty. Na koniec, wyłączanie bota po naszej nieaktywności głosowej. except: time.sleep(sleep_time) speak("Skoro nic nie mówisz to wyłączam się. Bywaj") break Jeśli nasz asystent głosowy nie wykrył naszego głosu przez ustawioną przez nas wcześniej ilość czasu, to się automatycznie wyłączy. Na samym końcu chciałbym jeszcze wspomnieć o kilku bolączkach tego bota, nie jest on idealny, i ma kilka wad. Głównym problemem jest to że bot w takim stanie w jakim jest obecnie (wersja 1.0), potrafi płynnie wykonać 3 lub 4 polecenia, następnie jego reakcje na kolejne polecenia drastycznie spadają. Marian na samym początku miał posłużyć do automatyzacji pewnych zadań, głosem dlatego też zdecydowałem się na taką formę interakcji za pomocą if else jak widzicie wyżej. W trakcie pisania kodu, pomysł ewoluował i powstał amatorski asystent głosowy, który przerósł moje najśmielsze oczekiwania, dlatego pomimo tego że płynnie wykonuje 3 lub 4 polecenia to nadal jest wart uwagi. Kolejnym problemem jest rozpoznawanie mowy, nie wiem jak to wygląda w przypadku innych języków, ale po polsku czasem zaczyna wariować, np. w przypadku podawania komendy "Marian policz dwa dodać dwa", rozpoznawanie głosu zapisuje "dwa" słownie a nie cyfrą, co powoduje problem. Nie jest to oczywiście wina bota, tylko specyfika działania biblioteki z której korzysta. Myślę że samo zmienianie tekstu na mowę oraz rozpoznawanie głosu może mieć szereg zastosowań, np. interaktywna stacja pogodowa, lub mówiący czujnik ruchu, dlatego liczę na to że artykuł pobudzi waszą kreatywność i wpadniecie na pomysł stworzenia czegoś na podstawie powyższego asystenta głosowego, a może uda wam się rozwiązać jego problemy i umieścić na popularnej malinie, co pozwoli na stworzenie własnej wersji Alexy? Kto wie? Podsyłam również link do filmu na YT, prezentującego aktualne możliwości bota ####################### Coś o mnie: Nazywam się Kacper, jestem studentem Bioinformatyki, programuję w pythonie i interesuje się analizą danych. Na Forbocie nazywam się Ruby a na Githubie i YT nazywam się AvirFrog. Zapraszam na na Github: AvirFrog/Marian, jeśli spodobał Ci się mój pomysł na asystenta głosowego zostaw gwiazdkę. Zapraszam również na kanał YT: AvirFrog, aktualnie znajduje się tam film z prezentacją możliwości przedstawionego tu bota głosowego Marian, ale w przyszłości pojawią się kolejne filmy z nowymi projektami, oraz omówienia kolejnych wersji Mariana. Dziękuję za przeczytanie całego artykułu, w razie pytań odnośnie bota, piszcie pod artykułem, chętnie na nie odpowiem. Pozdrawiam Ruby #######################- 32 odpowiedzi
-
- 13
-
- konkurs2021
- python
-
(i 1 więcej)
Tagi:
-
Ledwie w innym wątku pochwaliłem się działającymi skryptami a już męczę to samo rozwiązanie na RPi4. Z jakiegoś powodu stronka WWW działa tylko po części, czyta stany portów GPIO ale już nie steruje portami. Fakt, że wyświetla mi stany portów wskazuje na poprawną komunikację PHP-Python w ścieżce cgi-bin. Skrypty *.py wywoływane w shellu realizują poprawnie sterowanie portami GPIO. Dotarłem do ściany, w necie nie znalazłem odpowiedzi na moje problemy. Dajcie jakieś natchnienie koledzy, proszę... 😟
-
Witam wszystkich, bez zbędnych szczegółów mam do zrobienia układ który będzie musiał: Obsługa Xbee za pomocą magistrali UART Obsługa przetwornika A/C C/A (wstępnie myślałem nad układem pod magistralę I2C) Obsługa wyświetlacza OLED (również myślałem nad magistralą I2C ze względu na to że posiadam już takowy) Obsługa wyświetlacza LCD (chyba po magistrali SPI ok 3 cali) podgląd z kamery poprzez WiFi Obsługa WiFi jak w punkcie powyżej. Posiadać USB do kontrolera Ze względu na studencki budżet udało mi się kupić w bardzo dobrych pieniądzach (jak na obecną sytuację z "malinami") a są to Raspberry Pi zero wersje 1.3 oraz 1.1. Obawiam się, że jedna malinka nie podoła. Myślałem nad połączeniem dwóch za pomocą magistrali I2C ale wyczytałem, że Rasberry Pi może pracować tylko jako urządzenie typu Master i teraz nie wiem czy jedna dałaby rade podołać wszystkiemu czy dałoby radę jednak jakoś mądrze połączyć je i przesyłać proste informacje (może nawet kilka bitów) czy po prostu szukać czegoś mocniejszego aby obsługiwało wszystko. Miałby ktoś jakiś pomysł jak można by było ogarnąć temat z wykorzystaniem tego co mam, bądź co dałoby radę obsłużyć wszystkie potrzebne mi funkcje bez płacenia milionów monet? Zależy mi aby układ był stosunkowo niewielki i energooszczędny. Z góry dziękuję za wszystkie sugestie i pomysły oraz proszę o wyrozumiałość nie jestem aż tak biegły w temacie jak niektórzy doświadczeni użytkownicy i pasjonaci. Pozdrawiam!
-
Cześć, od kilku dni testuję wykrywanie ludzi w obrazie wideo z kamery przy użyciu biblioteki "OpenCV" (z bibliotekami8 python'a). Zacząłem od "kaskadowego Klasyfikatora Haar'a", który dobrze sprawdza się przy detekcji twarzy - patrz link: https://www.bogotobogo.com/python/OpenCV_Python/python_opencv3_Image_Object_Detection_Face_Detection_Haar_Cascade_Classifiers.php Niestety przy wykrywaniu ludzi (lub części ludzkiego ciała) wyniki nie są zadawalające. Jako drugi algorytm spróbowałem użycia deskryptora HOG (Histogram of Oriented Gradients) razem z algorytmem SVM (Support Vector Machines) - patrz linki: https://learnopencv.com/histogram-of-oriented-gradients/ https://www.thepythoncode.com/article/hog-feature-extraction-in-python https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_ml/py_svm/py_svm_index.html Użyłem wcześniej wytrenowanego SVM z deskryptorem HOG'a zainstalowanego razem z opencv -jak w tutorialu poniżej: https://www.pyimagesearch.com/2015/11/09/pedestrian-detection-opencv/ Według mnie poprawność wykrywania ludzi (zarówno false-positive jak i nie wykrycia ludzi) w danych (zdjęciach) na których algorytm nie był szkolony wynosi pomiędzy sześćdziesiąt a siedemdziesiąt procent. To trochę za mało do moich potrzeb, dlatego chciałbym doszkolić algorytm SVM, aby pewność poprawnej detekcji ludzkiego ciała wynosiła co najmniej 90 procent. Czy ktoś z Was próbował "doszkolić" SVM (z OpenCV) na swoich przykładach - jeśli tak to może mogę liczyć na jakieś podpowiedzi (czy linki). Z danych które znalazłem w sieci ten tutorial wydaje mi się najbardziej obiecujący: https://stackoverflow.com/questions/57598104/training-of-svm-and-prediction-using-opencv-with-python Próbował może ktoś robić podobną detekcję z użyciem konwolucyjnych sieci neuronowych CNN z frameworka Keras (razem z tensorflow), jeśli tak jakie były wyniki? Tutaj link do danych treningowych który znalazłem: https://paperswithcode.com/datasets BTW: czy u Was gdy uruchamiacie programy z wykorzystaniem biblioteki OpenCV na Raspbbery PI 4 lub Raspbbery Pi Compute Module 4 bardzo mocno przegrzewa się CPU? Pozdrawiam
- 26 odpowiedzi
-
- opencv
- HOG Descriptor
-
(i 2 więcej)
Tagi:
-
Witam W wolnym czasie robię sorter, program działa na taśmie, używam biblioteki CV2. Chcę spróbować robić to w locie. Potrzebuję obsłużyć 2 kamery patrzące na siebie np. kamera(zastanawiam się nad tą) w ustawionej rozdzielczości np. 640 × 75 i 240 fps. Jestem na etapie dobierania sprzętu, zastanawiam się nad wydajnością ze względu na ilość klatek, czy Nvidia poradzi sobie z zadaniem, czy może dwa raspberry pi do kazdej kamery osobno. Macie jakieś pomysły?
-
Witam, pracuję nad stworzeniem autonomicznego pojazdu, bazującego na Raspberry Pi i Pythonie. Do sterowania silnikami wykorzystuję układ DRV8835 od Pololu (dedykowany układ do RPi), ma on nawet stworzoną własną bibliotekę do obsługi. Testowałem jego działanie na przykładowym programie dostarczonym wraz z biblioteką i działa, tylko nie mogę znaleźć nigdzie jakiegoś projektu, informacji jak przełożyć to na jakieś konkretne zastosowanie. Poniżej wstawiam kod który był dostarczony z biblioteką. from __future__ import print_function import time from pololu_drv8835_rpi import motors, MAX_SPEED # Set up sequences of motor speeds. test_forward_speeds = list(range(0, MAX_SPEED, 1)) + \ [MAX_SPEED] * 200 + list(range(MAX_SPEED, 0, -1)) + [0] test_reverse_speeds = list(range(0, -MAX_SPEED, -1)) + \ [-MAX_SPEED] * 200 + list(range(-MAX_SPEED, 0, 1)) + [0] try: motors.setSpeeds(0, 0) print("Motor 1 forward") for s in test_forward_speeds: motors.motor1.setSpeed(s) time.sleep(0.005) print("Motor 1 reverse") for s in test_reverse_speeds: motors.motor1.setSpeed(s) time.sleep(0.005) print("Motor 2 forward") for s in test_forward_speeds: motors.motor2.setSpeed(s) time.sleep(0.005) print("Motor 2 reverse") for s in test_reverse_speeds: motors.motor2.setSpeed(s) time.sleep(0.005) finally: # Stop the motors, even if there is an exception # or the user presses Ctrl+C to kill the process. motors.setSpeeds(0, 0) W moim przypadku mam do pobrania z drugiego pliku wartości "angle" i "distance", muszę wprowadzić dodatkowo dwie stałe "dis=.75" oraz "ang=1" . Z tego wszystkiego muszę wyprowadzić sterowanie silników aby działały według równania które jest zamieszczone poniżej. Mógłby mi ktoś pomóc, poradzić, powiedzieć, naprowadzić mnie jak to zdefiniować na mim konkretnym przykładzie? from plik1 import angle, distance dis=.75 ang=1 rownanie=((distance*dis)+(angle*ang))
- 2 odpowiedzi
-
- sterowanie
- silnik
- (i 3 więcej)
-
Witam. Nigdy nie pracowałem wcześniej w środowisku ROS, jednak teraz jest mi potrzeba biblioteka mapująca do mojego robota mobilnego spełniajacego wymagania SLAM dlatego potrzebuję porady odnośnie użycia biblioteki Hector Slam. Każdy temat jaki sprawdzałem sugerował użycie Lidarów czy też innych "laserowych" czujników. Czy ta biblioteka będzie w stanie przekonwertować dane liczbowe otrzymywane z czujników ultradźwiękowych HC-SR04? Czy moze powinienem użyć innej metody/biblioteki do mapowania? Jakby ktoś chciał wiedzieć więcej na temat mojej teorii rozwiązania przesyłu i obródki danych: Główny program(pisany w Pythonie 3) znajduje się na płytce BeagleBone Black, nastomiast pomiary z czujników są pobierane na płytkę Arduino Uno Rev3, przeliczane na centymetry i wysyłane przez USB do BBB skąd mają być użyte do wykrywania potencjalnej kolizji z otoczeniem i przerobiane na mapę(wystarczyłoby abym wyznaczał punkt w miejscu potencjalnej kolizji). Oczywiście zdaję sobie sprawę że mógłbym to robić tylko na jednej płytce ale w tak późnej fazie nie chcę już zmieniać konceptu. Poza tym, to jest mój pierwszy robot którego tworzę od zera więc nie mam doświadczenia.
-
- SLAM
- Arduino Uno
-
(i 3 więcej)
Tagi:
-
Witam. Kanał ogólnie o elektronice oraz systemach wbudowanych. Poniżej wstawiam link do wideoporadnika jak obsłużyć microswitch-a w pythonie na platformie Raspberry Pi 3B+. Zapraszam do oglądania 🙂
-
- Raspberry Pi
- GPIO
-
(i 1 więcej)
Tagi:
-
Wideoporadnik - jak dodać skrypt Python do autostartu RPi?
uC_Academy opublikował temat w Raspberry Pi
Witam. Chciałem wam przedstawić krótki wideoporadnik pokazujący jeden z kilku sposobów na uruchomienie własnego skryptu Python automatycznie po starcie systemu. Praca odbywa się na systemie Raspberry Pi OS, do uruchomienia skryptu wykorzystamy popularny deamon Crontab. Zapraszam do oglądania 🙂-
- 2
-
- Raspberry Pi
- python
-
(i 1 więcej)
Tagi:
-
Raspberry Pi i pomiar fotorezystora bez ADC - wideoporadnik
uC_Academy opublikował temat w Raspberry Pi
Witam. Chciałem pokazać wam patent, jak sobie poradzić z pomiarem wskazań fotorezystora na Raspberry Pi, gdy nie mamy pod ręką żadnego przetwornika ADC. Ten sposób jest wysoce zależny od obciążenia naszego RPi, ale do prostych aplikacji wykrywania, czy światło jest zgaszone czy zapalone powinno wystarczyć. Ten sposób działa jedynie z sensorami o charakterze rezystancyjnym i nie nadaje się do sensorów z czysto analogowymi wyjściami. Mimo wszystko uważam, że warto go znać. Zapraszam do oglądania 🙂-
- Elektronika
- Raspberry Pi
-
(i 1 więcej)
Tagi:
-
Witam, skończyłem podstawy elektroniki część pierwsza, teraz miałem zamiar nauczyć się podstaw Pythona i zacząć z kursem Raspberry Pi (dodam tylko, że wcześniej programowałem ok. 4 miesiące w C++ i skończyłem kursy pana Mirosława Zelenta) lecz natrafiłem na pewien problem, który ogranicza możliwość dalszego rozwijania się, problem ten związany jest z wybieraniem Interpretera mianowicie w momencie kiedy ręcznie dodaję interpreter wyskakuje mi błąd "Permission denied". Proszę o pomoc, ponieważ nie chciałbym, żeby jakieś środowisko pracy stanowiło dla mnie przeszkodę w rozwijaniu się. (Dodam również, że mam 16 lat i jestem bardzo zmobilizowany do nauki programowania). Z góry dziękuje za wszelką pomoc. Poniżej zamieszczam screeny:
- 3 odpowiedzi
-
- problem z kodem
- problem
- (i 2 więcej)
-
Jakie IDE do programowania w Python na Raspberry Pi?
MaciejZyskowski opublikował temat w Raspberry Pi
Cześć! Zastanawiam się jakich programów używacie do pisania skryptów w Python. Jak wiadomo, język ten jest ekstremalnie wrażliwy na wszelkie białe znaki, więc dobry edytor to podstawa. Obecnie używam domyślnego Thonny Python IDE, lecz chciałbym mieć auto-uzupełnienie/podgląd do obiektów i metod. Zainstalowałem PyCharm, lecz nie do końca rozumiem dlaczego nie mogę importować bibliotek potrzebnych do mojego programu - unable to import module. Fajnie jakbyście podzielili się czego Wy używacie. 🙂- 5 odpowiedzi
-
- Raspberry Pi
- python
-
(i 1 więcej)
Tagi:
-
Hej! W tym artykule postaram się pokazać krok po kroku jak przygotować lampkę sterowaną mową, wykorzystując aplikację Wroob na smartfonie oraz Arduino. Czym jest projekt Wroob pisałem tutaj: Wroob - Czyli jak zaprogramować swój telefon Projekt może wymagać podstawowej wiedzy z języka Python i minimalnej znajomości systemu Wroob. Zachęcam do wcześniejszego zapoznania się z poprzednim artykułem. Można też skorzystać z kursów na naszym kanale YouTube - tłumaczymy tam jak zrealizować inne ciekawe projekty. Własny moduł na Arduino Najpierw zacznijmy od sprzętu, ja podłączyłem swoją płytkę Arduino UNO z modułem przekaźników, a do tego oprawkę żarówki podłączoną do gniazda sieciowego. Sposób podłączenia widoczny jest na obrazku poniżej. Pamiętajcie, aby zachować szczególną ostrożność pracując z napięciem sieciowym. Podobny efekt można otrzymać podłączając diodę LED do Arduino, nie wymaga to przekaźnika i jest znacznie bezpieczniejsze. W dalszej części artykułu nie będzie miało znaczenia, z której opcji korzystacie. Następnie musimy zmienić nasze Arduino w moduł systemu Wroob. Wykorzystamy do tego celu bibliotekę dostępną pod adresem https://github.com/wroob-io/arduino-wroobimp. Można ją też pobrać za pomocą managera bibliotek w Arduino IDE Biblioteka arduino-wroobimp posiada przykładowy program z którego będziemy korzystać: WroobImpGpio.ino. Znajdziecie go w Arduino IDE -> File -> Examples -> WroobImp -> WroobImpGpio. W programie WroobImpGpio inicjalizujemy pin 13 jako wyjście, a 14 jako wyjście. Jak pamiętacie, naszą lampę mamy podłączoną do pinu 13. #define PIN_OUT 13 #define PIN_IN 14 // initialize used GPIOs pinMode(PIN_OUT, OUTPUT); pinMode(PIN_IN, INPUT); Następnie uruchamiany jest protokół systemu Wroob. We Wroob moduły rozmawiają za pomocą komend w formacie JSON. Reszta kodu związana jest przede wszystkim z obsługą protokołu komunikacyjnego. // initialize Wroob protocol wroob.begin(my_callback); Jeżeli ktoś jest zainteresowany jak przebiega komunikacja między modułami w systemie Wroob można użyć programu com_imp_sniffer.py aby “podsłuchać” komunikacje między modułami. Program można znaleźć w Panelu Użytkownika Wroob w katalogu examples\hardware_projects. Jak jesteście ciekawi, chętnie opiszę protokół w osobnym poście. Program WroobImpGpio realizuje dwie funkcje ustawia oraz odczytuje wartość pinów za pomocą komend “SetPin” oraz “GetPin”. Ustawia stan na pinie 13 gdy otrzyma komendę “SetPin” lub odczytuje stan z pinu 14 gdy otrzyma komendę “GetPin”. Na tym etapie możemy uruchomić aplikację w Wroob na telefonie i przejść do panelu użytkownika w którym będziemy wykonywać resztę pracy. Jeśli nie wiesz jak to zrobić obejrzyj film Szybki start z systemem Wroob. Po podłączeniu modułu do telefonu w zakładce “Moduły” Panelu Użytkownika Wroob pojawi się jego graficzny widget. Do dalszej pracy potrzebujemy nazwy modułu w systemie. Nazwa widoczna jest w górnej części widgetu, w moim przypadku to 'eam001'. Początkowa nazwa nadawana jest automatycznie, składa się z typu modułu oraz kolejnych liczb. Możecie również ustawić własną nazwę, nie powinna się ona jednak powtarzać w systemie. Obsługa modułu Arduino Na początku klasę utwórzmy naszego własnego modułu, pozwoli nam to z niego korzystać w wygodny sposób w naszych programach. Najprostszą klasę modułu możemy zdefiniować w sposób przedstawiony poniżej. Korzystamy tutaj z wcześniej przygotowanej uniwersalnej klasy Module i tworzymy jedną funkcję set_pin() do obsługi komendy “SetPin” from wroob.modules.module import Module class Eam(Module): def __init__(self, moduleName): super(Eam, self).__init__(moduleName) #set_pin wysyła komendę "set_pin" do naszego modułu def set_pin(self, value): params = {"value":value} self._send_cmd('SetPin', params) W przypadku programu WroobImpGpio wgranego na Arduino można też skorzystać z wcześniej przygotowanej klasy Eam. Znajdziecie ją w katalogu examples\hardware_projects\example_arduino_module. Program korzystający z naszej klasy wygląda następująco: from eam import Eam #import klasy Eam z pliku eam from time import sleep eam = Eam ("eam001") #stworzenie obiektu eam powiązanego z modułem o nazwie “eam001” while(True): sleep(1) eam.set_pin(1) #użycie metody set_pin() sleep(1) eam.set_pin(0) Do konstruktora klasy Eam przekazujemy nazwę naszego modułu 'eam001' tworząc jego obiekt. Dzięki temu w programie możemy korzystać w prosty sposób z funkcji naszego modułu przez odwołanie jego do obiektu. Program jest czytelny i łatwy do rozbudowania. Sterowanie mową Kolejny etap to już czysta przyjemność. Wykorzystamy moduł rozpoznawania mowy (SRM) aby sterować naszą lampą. Aby go uruchomić należy przejść do zakładki “Moduły” a następnie wybrać z listy “Moduły w Panelu Użytkownika”. Moduł SRM wymaga mikrofonu podłączonego do komputera. W kolejnym etapie możemy rozbudować program korzystający z naszego nowo utworzonego modułu na Arduino o funkcje modułu SRM from eam import Eam from wroob.modules.srm import Srm #import klasy modułu Srm from time import sleep eam = Eam("eam001") srm = Srm("srm001") def srm_callback(speech): #funkcja reagująca na rozpoznaną mowę print(speech) if "zapal światło" in speech: eam .set_pin(0) elif "zgaś światło" in speech: eam .set_pin(1) srm.start_speech_reporting(srm_callback) #rozpoczęcie rozpoznawania mowy while(True): sleep(60) Efekt prezentuje się następująco: Więcej na temat rozpoznawania mowy i możliwości modułu SRM można się dowiedzieć na naszym kursie video Chatbot. Jeżeli ktoś nie chce przechodzić całego procesu, gotowe programy można znaleźć w zaktualizowanej właśnie aplikacji w folderze examples\hardware_projects\example_arduino_module Bez wprowadzania zmian w kodzie Arduino wszystko od razu powinno działać 🙂
-
Cześć. Robię projekt rozpoznawania jednego z kilku ruchów za pomocą akcelerometru, żyroskopu, STM32F467ZG i pakietu X-CUBE-AI. Opieram się na artykule @Elvis Sztuczna inteligencja na STM32, czyli przykład użycia X-CUBE-AI, ale mam kłopot z jego rozszerzeniem. Próbowałem różnych sposobów, ale nie mogę zrobić sieci, która zamiast wartości binarnej (ruch - brak ruchu) zwróci mi prawdopodobieństwa każdego z 6 wyjść (na razie chciałbym tyle różnych ruchów rozpoznawać). Mam książkę, którą poleca Elvis ("Deep Learning" autorstwa Chollet'a), ale brak doświadczenia z SSN, czy nawet językiem Python mocno mnie ogranicza. Chciałbym też, żeby zamiast jednego wejścia będącego prostą funkcją odczytów z czujników (suma kwadratów odczytów z akcelerometru), f = open('data1.csv','r') values = [] results = [] for line in f: fields = line.strip().split(',') if len(fields) == 4: x = float(fields[0]) y = float(fields[1]) z = float(fields[2]) values.append([math.sqrt(x**2 + y**2 + z**2)]) results.append(float(fields[3])) f.close() układ bezpośrednio korzystał ze wszystkich 6 (3ACC i 3 GYRO). Tutaj fragment kodu Elvisa z STM'a: 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 */ } 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); Pomożecie mi zmienić kod Python'a i STM'a, bym mógł go użyć do swoich potrzeb? Naprawdę długo szukałem sposobu i próbowałem wielu rozwiązań, ale albo nie działa mi sieć neuronowa, albo nie kompiluje się projekt w SW4STM32.
-
Python to język wysokopoziomowy, który ma bardzo szerokie zastosowanie. Można w nim napisać grę (PyGame) albo zrobić komunikację mikrokontrolera z programem na komputerze/laptopie (PySerial), aby na przykład wysyłać komendy. W tym kursie zajmiemy się tą drugą biblioteką. W starszych komputerach istnieją porty szeregowe RS-232. W nowszych komputerach portu tego raczej się nie uraczy. Ten wpis brał udział konkursie na najlepszy artykuł o elektronice lub programowaniu. Sprawdź wyniki oraz listę wszystkich prac » Partnerem tej edycji konkursu (marzec 2020) był popularny producent obwodów drukowanych, firma PCBWay. Jest jednakże światełko w tym ciemnym tunelu, gdyż sterowniki niektórych urządzeń USB emulują port szeregowy COM umożliwiając tym samym proste komunikowanie się z takim urządzeniem na nowszych maszynach. Do takich urządzeń należą płytki rozwojowe Arduino RS-232(rys. 1) Prosta komunikacja pomiędzy uC (mikrokontrolerem) a PC (rys. 2) 1.Wysyłanie informacji z mikrokontrolera do komputera/laptopa. Konfiguracja połączenia z portem COM Zanim zacznie się przygodę z komunikacją za pośrednictwem portu COM konieczne jest zapoznanie się z podstawami jego działania. Port ten przesyła dane dwukierunkowo za pomocą jednego pinu przesyłającego i jednego odczytującego dane. Dane przesyłane są zawsze z określoną prędkością mierzoną w bitach na sekundę. Standardowe ustawienie prędkości transmisji z urządzeniem wynosi 9600 bitów na sekundę. Ważne aby, wysyłać i odbierać dane z taką samą częstotliwością w przeciwnym przypadku dane nie będą odbierane przez urządzenie w sposób poprawny jak również program nie będzie w stanie poprawnie odbierać danych. Przy podstawowej konfiguracji konieczne jest również posiadanie wiedzy o nazwie portu. Pod Windowsem nazwy portów zaczynają się od COM i kończą liczbą określającą numer portu. Można sprawdzić w systemie, jakie porty COM są dostępne w Menadżerze urządzeń co też i widać na poniższym rysunku (rys. 3) rys. 3 Przygotowanie środowiska na komputerze/laptopie Tak jak już mówiłem, będziemy potrzebować biblioteki PySerial omówię jej instalację w środowisku PyCharm: Wchodzimy w terminal, następnie wpisujemy: "pip install pyserial" Naciskamy enter Powinniśmy zobaczyć coś takiego (rys. 4) rys. 4 teraz przejdzmy do Arduino. Przygotowywanie Arduino (oczywiście zadziała komunikacja zadziała wszędzie gdzie użyjemy UART'a, nie tylko Arduino) Na razie jedyne co napiszemy to: void setup() { Serial.begin(9600); // Ustawienie Baud Rate(prędkość transmisji) na 9600Hz } void loop() { Serial.println("Proba Komunikacji"); delay(1000); } Wgrywamy nasz program, uruchamiamy Monitor Portu Szeregowego gdzie powinno sie pojawić się (rys. 5) rys. 5 i tak co około sekundę (przy okazji widzimy, że funkcja delay nie jest taka dokładna (dlatego nie stosuje sie jej gdy robimy na przykład zegar)) 😁 Teraz można przejść do PyCharma import serial arduino = serial.Serial('COM5', 9600, timeout=0.1) while True: data = arduino.readline() if data: data = data.decode() print(data) Można powiedzieć, że właśnie zrobiliśmy monitor portu szeregowego z ArduinoIDE 😀 Omówienie kodu: Importujemy bibliotekę, Ustawiamy port do któego mamy podłączone Arduino oraz Baud Rate, Przypisujemy do zmiennej to co aktualnie jest przesyłane, Jeżeli zmienna nie jest pusta to ją dekodujemy i wyświetlamy na ekranie. ZAWSZE MUSIMY PAMIĘTAĆ O ZDEKODOWANIU (tylko na komputerze)!!! Wyłączamy monitor portu szeregowego (ten z ArduinoIDE), kompilujemy program i naszym oczom powinno ukazać się (rys. 6) rys. 6 2. Wysyłanie komend z komputera/laptopa do mikrokontrolera. Przejdźmy do PyCharma import serial import time arduino = serial.Serial('COM5', 9600, timeout=0.01) while True: arduino.write('wlacz'.encode()) time.sleep(1) arduino.write('wylacz'.encode()) time.sleep(1) Importujemy bibliotekę time (nie trzeba jej instalować) oraz wysyłamy "wiadomości": "wlacz" oraz "wylacz" To by było na tyle w PyCharmie, przejdźmy więc do ArduinoIDE rys. 7 Jako że robimy komunikację używając UART'a, który może wysyłać maksymalnie jeden znak, ponieważ (rys. 7) jeden znak to jeden bajt (bajt ma 8bitów) a my wysyłamy komendy: "wlacz" oraz "wylacz" to musimy zrobić taki mały myczek elektryczek 😀 i użyć zmiennej oraz pętli. Będzie wyglądać to tak: wysyłamy: w Arduino: "odbiera" i zapisuje do zmiennej wysyłamy: l Arduino: "odbiera" i zapisuje do zmiennej wysyłamy: a Arduino: "odbiera" i zapisuje do zmiennej wysyłamy: c Arduino: "odbiera" i zapisuje do zmiennej wysyłamy: z Arduino: "odbiera" i zapisuje do zmiennej nie wysyłamy nic Arduino: wychodzi z pętli oraz porównuje zawartość zmiennej z komendami które ma zapisane Arduino: wykonuje komendę Arduino: czyści zawartość zmiennej z komendą Takie wybrnięcie z sytuacji 😎 int i = 12; //pin do którego podłączymy diodę String komenda=""; void setup() { Serial.begin(9600); pinMode(i, OUTPUT); digitalWrite(i, HIGH); } void loop() { if(Serial.available() > 0) { while(Serial.available() > 0) { komenda += char(Serial.read()); } Serial.println(komenda); if(komenda == "wlacz") { digitalWrite(i, HIGH); } if(komenda == "wylacz") { digitalWrite(i, LOW); } komenda = ""; } delay(100); } Oczywiście można wysłać do komputera/laptopa "informację zwrotną" na przykład: Dioda jest wlaczona Dioda jest wylaczona Tylko musimy pamiętać aby użyć .decode(), ale tak jak mówiłem, tylko w programie na komputrzez/laptopie Jeżeli nasze komendy będą miały tylko 1 znak na przykład: a, A, 1, B, c, C ,4 (ogólnie to dowolny znak z tabeli ASCII) nie trzeba używać pętli tylko: if(Serial.read() == 's') oczywiście też w tym ifie: if(Serial.available() > 0) Jeżeli wstawilibyśmy tam więcej znaków dostalibyśmy taki komuniukat: warning: multi-character character constant [-Wmultichar]. 3. Podsumowanie Wysyłanie oraz odbieranie informacji jest bardzo przydatne, nie musi być to tylko pomiędzy uC, a komputerem. Może to być komunikacja pomiędzy dwoma uC na przykład: karta microSD ma w sobie procesor który komunikuje sie z uC używając SPI, termometr DS18B20 który komunikuje z uC używając protokołu komunikacji OneWire (rys. 8), czujnik podczerwieni, procesor w naszych komputerach z mostkiem, pamięcią i GPU, ładowarka z telefonem, aby ustalić jaki prąd i napięcie. Komunikacja jest wszędzie (można powiedzieć, że urządzenia są bardziej komunikatywne od nas 🤣). rys. 8
-
Cześć, po ponad półrocznej przerwie kontynuuje zmagania z z kamerką OV7675 z użyciem płytki Nucleo z stm32f446RE. DCMI ani DMA jeszcze nie udało mi się uruchomić ale na swój AVR'owy sposób jestem w stanie UARTem (baud 2M) przesłać w grayscale wartości pixeli z stm32 do apki w Python na moim PC. Po wygenerowaniu obraz jest akceptowalny, ale daleko mu do tego co widziałem na youtube, gdzie obraz nie dość że był czysty to jeszcze przsyłany na żywo( u mnie wygenerowanie zdjęcia przy 5 sekundach to jest dość szybko ^^). Problem wygląda tak: przesyłane dane a dokładniej linijki ( pixele przesyłam rzędami: [dane][index linijki] ) są często zlepkiem dwóch linijek, przez to rozmiar linijki często jest dwukrotnie większy niż to jest dla prawidłowego pakietu. Wydaje mi się że problem jest po stronie Pythona/Windowsa, który nie radzi sobie z taką ilością danych i gdy się gubi to skleja mi pakiety, chociaż dokumentacja PySerial mówi o obsłudze jeszcze większych baudrate. Podczas przeszukiwania internetu natknąłem się też na informacje że czasem taktowanie kamerki zegarem z MCU może powodować problemy i potrzebne jest ustawianie rejestrów w kamerce w celu przeskalowania zegara co powoduje jej poprawne działanie. Może miał ktoś podobny problem? Co myślicie?
-
Witam. mam taki kod, do uzyskiwania video, jak nałożyć białą maskę żeby tylko widzieć to co jest w niebieskiej ramce import cv2 cap = cv2.VideoCapture(0) cap.set(3,640) cap.set(4,380) while(1): _, frame = cap.read() cut = cv2,rectangle(frame, (220, 200), (450, 400), (255,0,0), 2) cv2.imshow('cut', cut) k = cv2.waitKey(5) & 0xFF if k == 27: break cv2.destroyAllWindows() Wielkie dzięki, pewnie dla was banalne, ja nie mogę znaleźć odpowiedzi.
-
Dzień Dobry Forumowicze! Problem dotyczy zarówno mikrokontrolera, jak i RPi, więc mam nadzieje że nie będzie problemu związanego z nieodpowiednim działem. Od kilku dni borykam się bezskutecznie z pewnym problemem, a prezentuje się on następująco: Potrzebuję wymienić dane poprzez SPI między Raspberry Pi Zero W (Master), a Atmegą64(Slave). Atmega zasilana przez 5V na własnoręcznie zaprojektowanej płytce (z konwerterem poziomów logicznych 3,3V-5V na MOSFET'ach). Generalnie elektrycznie wszystko jest sprawne i sprawdzone kilkukrotnie, więc to odpada. Jestem w stanie zaprogramować AVR'a przez RPi za pośrednictwem SPI właśnie (na RPi Rasbian w wersji 9), z wykorzystaniem AVRDUDE. Problem jaki się pojawia, to przy próbie wymiany danych między nimi. AVR'a programuje w C, natomiast RPi w Pythonie (kody programów niżej). Polega on na tym, że biblioteka Python'a SpiDev, jako sygnał ChipSelect podaje stan wysoki, podczas gdy ATMEGA wymaga podczas tej komunikacji stanu niskiego. Atmega nie posiada możliwości zmiany trybu na taki, aby czytała stan wysoki, a biblioteka SpiDev z kolei, nie ma funkcjonalności podania stanu niskiego. Chciałem to obejść poprzez podpięcie nóżki Atmegi pod zupełnie inną nóżkę RPi i ręcznego wysterowywania tej nóżki przed nadaniem paczki danych, jednak to nie działa - nie wiem jednak dlaczego. Nie używałem nigdy wcześniej SPI, więc finalnie nie jestem nawet pewien gdzie leży problem - czy w kodzie Slav'a, Mastera czy zupełnie gdzie indziej. Slave (C, Amtega64): #define F_CPU 1000000UL #include<avr/io.h> #include<util/delay.h> #include<avr/interrupt.h> #define ustaw(bajt, nr_bitu) (bajt |=(1<<nr_bitu)) #define skasuj(bajt, nr_bitu) (bajt &=~(1<<nr_bitu)) #define sprawdz(bajt, nr_bitu) ((bajt &(1<<nr_bitu))&&1) #define sleep(czas) for (int i=0; i<(czas); i++) _delay_ms(1) int data=500; void init_spi(void) { DDRB=(1<<PB3); //MISO - output SPCR=(1<<SPE)|(1<<SPIE); //SPI_ON & Interrupt SPDR=0; } uint8_t rec_spi(void) { while (!(SPSR & (1<<SPIF))) ; return SPDR; //return data register } int main(void) { sei(); init_spi(); DDRC |=1<<PC3; //LED'y DDRC |=1<<PC4; DDRC |=1<<PC5; while (1) { ustaw(PORTC, PC4); sleep(data); skasuj(PORTC, PC4); sleep(data); } } ISR (SPI_STC_vect) { data = rec_spi(); ustaw(PORTC,PC5); } Master (Python, RPi): import RPi.GPIO as GPIO import spidev import time GPIO.setmode(GPIO.BCM) GPIO.setup(7, GPIO.OUT) GPIO.output(7, GPIO.HIGH) spi = spidev.SpiDev() spi.open(0, 0) print('Open SPI') #GPIO.output(7, GPIO.LOW) data = 0xAA try: while True: print('Sending..') GPIO.output(7, GPIO.LOW) spi.xfer([data], 50000, 100, 8) # spi.writebytes([250]) GPIO.output(7, GPIO.HIGH) print('complete') time.sleep(2) #end while except KeyboardInterrupt: # sleep(0.1) spi.close() GPIO.cleanup() Na masterze (RPi) próbowałem ustawiać różne tryby (spi.mode), różne prędkości, próbowałem z spi.writebytes oraz z spi.xfer. Wszystko bez skutku. Na Atmedze, mrugam diodą co pół sekundy. Próbowałem osiągnąć taki efekt, by wysłać liczbę 250 i ustawić ją jako czas mrugania, co zauważyłbym jako szybsze mruganie diody. Próbowałem też zapalić inną diodę w przerwaniu od SPI - wszystko bezskutecznie. SPI w FuseBitach jest aktywne. Połączenia elektryczne są poprawne, przy czym Atmegowski SS jest podłączony do 7 pinu RPi. Byłbym bardzo wdzięczny za wszelką pomoc i sugestie. Pozdrawiam.
-
Cześć wszystkim, Chciałbym przetestować pewien program który znalazłem na internecie, niestety pojawia się problem przy instalacji biblioteki na Raspberry Pi , czy ktoś jest w stanie pomóc?