PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [ERLEDIGT] 1 Jahr erfolglos progrmmiert - verzweifelt - python-Programmierer gesucht



Chris1803
26.11.2018, 22:07
Hallo zusammen
Ich programmiere jetzt seit rund einem Jahr an der Steuerung meines LKWs. Zwischendurch funktionierte es zwar, war aber insgesamt wenig befriedigend, weil die Lenkung zu ungenau war und die Antriebsmotoren nur Vollgas oder Stillstand kannten. Nach einem Jahr bin ich nun so verzweifelt, dass ich das Ganze gerne in bessere Hände geben würde. Wenn jemand Zeit und Lust hat, sich die Sache mit mir anzusehen, wäre ich sehr dankbar. Mittlerweile würde ich sogar 50 EUR in die Hand nehmen, damit das Teil endlich richtig fährt.

Keine Ahnung, ob das das richtige Unterforum ist, geht insgesamt ja aber um die Motorsteuerung.

Chris

ARetobor
26.11.2018, 22:46
Hallo,
deine Frage ist zu allgemein.
- warum Python, wenn es Python sein soll, ist vielleicht ein Python Forum angebracht
- was für ein BS (Software) möchtest du als Plattform nutzen
- welche Hardware nutzt du
- was hast du biss her versucht

Gruß

hbquax
27.11.2018, 01:06
Wenn du so gut bastelst und programmierst, wie du kommunizierst... :confused:

oberallgeier
27.11.2018, 08:06
Hallo Chris.

.. Ich programmiere jetzt seit rund einem Jahr an der Steuerung meines LKWs ..Na das klingt doch nach etlichen, nach vielen, nach hundert(en) Stunden Programmierarbeit.


.. Wenn jemand Zeit und Lust hat, sich die Sache mit mir anzusehen .. würde ich sogar 50 EUR in die Hand nehmen ..Mal rechnen. Nen ordentlicher Programmierer oder Ingenieur, mit guten Fähigkeiten, könnte für nen so offenen (offen = sehr ungenau definiert) Werkvertrag, bescheiden gerechnet, mit tausend Steinen täglich rechnen. Bleiben also von dem Acht-Stunden-Tag runde zwanzig Minuten für den fraglichen Zeitaufwand. Ob dieses Angebot jemand vom Stuhl reißt?

HaWe
27.11.2018, 08:44
vergiss mal die beiden Posts direkt über meinem hier und sag erst mal, was du überhaupt für eine Programmier-Plattform verwendest.
Python könnte ja auf Raspberry Pi hindeuten.
Auch deine ganze restliche Steuer- und Antriebshardware wäre wichtig zu kennen, wie auch Aretobor schon schrieb.

Moppi
27.11.2018, 08:59
Wer weiß, ob das nicht sogar jemand liest der Python beherrscht. Nicht jeder will unbedingt Geld bekommen. Manche würden auch helfen, obwohl sie vielleicht gerade mit andern Dingen den Kopf voll haben, aber kein so ein Projekt nebenbei anfangen wollen. Um das Problem zu lösen müsste es genau vorgestellt werden. Also den Source Code, die Hardwarebeschreibung - wie HaWe schon sagt.

Ich habe auch schon so manches Projekt hinter mich gebracht, was zig Monate in Anspruch nahm und letztlich kristallisierte sich der ursprüngliche Ansatz als wenig tauglich heraus. Bei meinem Letzten habe ich dann noch mal von vorn angefangen, habe die Erfahrung aus der ersten Lösung mitgenommen und versucht es besser zu machen. s ist dann auch besser geworden und so sind nochmal 6 Jahre hinzugekommen. Wichtig ist zu lernen, dass man nicht aufgeben darf. Klar ist es bitter, viel Zeit verloren zu haben, aber man sammelt viel wertvolle Erfahrung. Wenn man dann die Flinte ins Korn wirft (oder meinetwegen in den Korn) dann hakt man das gedanklich ab und es hilft einem nicht weiter, ab jetzt gehen dann viele wertvolle Erfahrungen aus der Zeit verloren, wenn man sich nicht weiter damit beschäftigt und die tatsächlichen Probleme sucht. Wenn es gar nicht funktionieren will, vielleicht mit einer andern Programmiersprache da nochmal rangehen.

MfG
Moppi

hbquax
27.11.2018, 10:01
Um mal konstruktiv zu werden:
Du solltest dein Projekt nochmal vernünftig vorstellen:
-Was willst du eigentlich bauen und was soll es machen?
-Bisherige Baugeschichte (auch mal in sinnvoller Reihenfolge deine bisherigen Themen verlinken)
-Welche Komponenten und Software hast du bisher verwendet, und was funktioniert und was nicht? (Du hast z.B. irgendwann mal dieses Thema angefangen Servos-zucken-in-Neutralstellung-und-werden-heiss (https://www.roboternetz.de/community/threads/71577-Servos-zucken-in-Neutralstellung-und-werden-heiss), aber leider nie geschrieben, ob das Problem gelöst wurde und wenn ja, wie?)
- Bilder, Schaltpläne, Videos! Wir wollen uns ein Bild von deinem Projekt machen!

Eine vernünftige Beschreibung hier reinzustellen ist natürlich Arbeit, ABER eine gute Problembeschreibung trägt in sich oft bereits den Kern der Lösung.
Aber vielleicht hast du ja Glück, und es wohnt jemand in der Nähe der sich dein Projekt mal vor Ort anschaut, wo immer das ist...
Viel Erfolg!
:-)

wkrug
27.11.2018, 15:27
Was soll denn das Modell können - Welche Funktionen wie realisiert?
Wird es ferngesteuert?
Welche Sensoren und Treiberstufen sind verbaut?
Soll das Ganze autonom fahren?

Ich hab nen Modell LKW gebaut und will den mit nem Raspberry Pi, der mit Phyton geproggt wird, steuern ist schon sehr wenig Info.

Wenn es nur um die Ansteuerung von Servos bzw. Stellern geht halt ich den Raspberry ohnehin für Overkill.
Das lässt sich mit nem ATMEGA ( Arduino ) auch relativ einfach lösen.

HaWe
27.11.2018, 16:10
Was soll denn das Modell können - Welche Funktionen wie realisiert?
Wird es ferngesteuert?
Welche Sensoren und Treiberstufen sind verbaut?
Soll das Ganze autonom fahren?

Ich hab nen Modell LKW gebaut und will den mit nem Raspberry Pi, der mit Phyton geproggt wird, steuern ist schon sehr wenig Info.

Wenn es nur um die Ansteuerung von Servos bzw. Stellern geht halt ich den Raspberry ohnehin für Overkill.
Das lässt sich mit nem ATMEGA ( Arduino ) auch relativ einfach lösen.

mobile Robots mit Raspi und Python sind durchaus Anfängerprojekte in der Raspi-Community, also warum nicht.
Aber wo schreibt er denn, dass es tatsächlich einen Raspi nutzt?

Chris1803
27.11.2018, 18:06
Na da war ich gestern wohl doch zu müde und ungenau.
Ich programmiere ja nicht unentwegt daran, sondern immer wieder und verwerfe dann viele Änderungen wieder, weil sie dann doch nicht zum erhofften Resultat führen.

Hier das Setup:
LKW Marke Eigenbau
1 Achse angetrieben von zwei 12V-Motoren, verbunden an L298N-Treiber, dieser wiederum mit LiPo und RPi.
3 Achsen gelenkt mit je einem Servo (Bluebird DM620MG), diese verbunden via Modelcraft 6V/5A Spannungswandler mit LiPo und RPi.
2 Foxeer Arrow V2-Kameras und ein 5.8GHz-Video-Transmitter, beide verbunden mit LiPo und Videosignal an 5V-Relais, dieses verbunden mit RPi.
2 x je zwei Front- und Heck-LED (weiss/rot), verbunden an RPi
2 x zwei Blinker-LED (gelb), verbunden an RPi

1 RasberryPi macht die gesamte Softwaresteuerung und wird via WLAN angesprochen.

Python habe ich genutzt, weil es von Haus aus die GPIO des RPi ansprechen kann.

Grundsätzlich habe ich die Logik, wie das ganze Programm aufgebaut sein soll im Kopf zusammen. Versuche gerade das auf Papier zu bringen, so dass auch jemand anderes das interpretieren kann und nicht meine Code-Schnippsel durchgehen muss. Was mir aber immer noch nicht in den Schädel will, ist der ganze Python-Syntax. Wann immer ich versuche einen Wert einer Variable von einer Funktion in eine andere und zurück zu übergeben, erhalte ich irgendwelche Fehler.
Wie gesagt, der LKW fährt, die Achsen werden gelenkt, die Kameras schalten mit den Front-/Heck-LED zwischen vorne und hinten hin und her und die Blinker blinken. Nur nicht immer alles dann, wann es sollte und vor allem lenkt der LKW mal ja und mal nein und manchmal in die falsche Richtung.

Daher die Bitte um externe Hilfe.

Gruss
Chris

HaWe
27.11.2018, 18:19
das ist ja schon mal ne ganze Menge. Zur Fehlersuche musste du aber Teile abschalten und nur Einzelkomponenten testen.
Probleme, die ich sehe:
Python ist absolut nicht echtzeitfähig,
WLAN ist absolut nicht echtzeitfähig,
und Threads stören sich gegenseitig, wenn wichtige Threads keine höhere Priorität haben als andere, die warten können.

Also teste doch mal nur nackt WLAN in Verbindung mit der Motorsteuerung, ohne alles andere.

(ich selber kann kein Python, ich verabscheue diese "Sprache", ich verwende C(++), weil es klar ist und streng strukturiert und pthread Multithreading auch mit thread priorities erlaubt, bis hin zur Echtzeitfähigkeit.)

Chris1803
27.11.2018, 18:33
Nun, bei der Sprachwahl bin ich ganz offen. Ob C++, Java oder Python ist mir insofern egal.
Die Wahl ist damals auf Python gefallen, weil wie gesagt die GPIO einfach angesprochen werde konnten, ich überall gelesen habe, dass es die beste Möglichkeit sei und ich am meisten Tutorials gefunden habe.
Aber da lasse ich mich gerne eines Besseren belehren, denn die meisten in diesem Forum habe sicher mehr Erfahrung im Modellbau und der Programmierung als ich. Meine Stärke liegt da eher bei Datenbanken, Excel und Finanzanalysen...

Die Latenzzeiten bei diesem Konstrukt sind mir auch aufgefallen. Daher wollte ich über Variablen nachschauen, ob sich der aktuelle Wert der Einstellung für die Motoren um einen gewissen Prozentsatz, z.B. 5%, verändert hat und ansonsten soll nichts am aktuellen PWM-Signal verändert werden. Das Umschalten der Lichter/Kameras und die Blinker funktionieren soweit einwandfrei, manchmal zwar erst auf den zweiten Klick, aber damit könnte ich leben.

HaWe
27.11.2018, 18:54
probier erst mal, ob du dein Problem, wie ich es vorgeschlagen habe, eingrenzen kannst. Dann kann man weiter entscheiden.

ARetobor
27.11.2018, 19:16
Hallo,
das schon gelesen ?
https://www.elektormagazine.de/files/attachment/196

Gruß

Chris1803
27.11.2018, 23:29
So, ich habe die Skizze des Programms nun zusammen.
Links ist der Teil des PC, von dem aus der LKW gesteuert werden soll.
Rechts ist der Teil, der die Motoren usw. ansteuern soll.
Einerseits werden die Steuerbefehle in einem String vom PC zum RPi geschickt, andererseits soll zwischen den beiden Programmen kontinuierlich eine Kette von vier "Pings" hin und her geschickt werden, damit die Signalstärke über die Antwortzeit gemessen werden kann. Aktuell kein kritischer Teil und noch nicht implementiert.
Morgen Abend habe ich Zeit die einzelnen Code-Fragmente zu testen.
Ich hoffe, die Skizze ist einigermassen verständlich. Heute funktioniert der Code nicht parallel sondern nur sequenziell, was vermutlich die Ursache meines Problems ist. Parallel mit Python habe ich nicht hinbekommen.
33808

Moppi
28.11.2018, 11:16
Zwei Dinge sind bei der Sache:

Einmal hast Du geschrieben, reagiert manchmal etwas nicht / nicht sofort. HaWe hatte schon geschrieben, dass das am Netz liegen kann. Klingt für mich aber auch ein wenig nach UDP, statt TCP.
Dann hast Du geschrieben, dass er manchmal in die falsche Richtung lenkt. Das hört sich nach einem Fehler in der Programmlogik an, die ist aber eng verknüpft mit der Sprache selbst, so dass es dann auch Fehler aufgrund nicht verstehen der Programmiersprache sind, bzw. falscher Umsetzung mit der Programmiersprache.


MfG
Moppi

PS: wegen besserer Lesbarkeit:

1. Datenflussdiagramm (https://de.wikipedia.org/wiki/Datenflussdiagramm)
2. Programmablaufplan (https://www.heise.de/download/product/papdesigner-51889)
Kann bei der Dokumentation helfen, bzw. Sachverhalte übersichtlich und durchsichtig darzustellen.

Chris1803
21.12.2018, 21:39
Nun hatte ich endlich wieder Zeit, an der Steuerung weiterzubauen.
Bin mit euren Vorschlägen systematisch an die Sache ran und habe die ganze Verkabelung getestet, vielleicht ist da ja eine Lötstelle schlecht. Alles geprüft, alles i.O.
Also habe ich ein kleines Programm geschrieben, mit dem ich nur die Servos und nur in bestimmten Werten ansteuere. Das Programm läuft direkt auf dem RPi. So kann ich zumindest mal Übertragungsprobleme aus dem WLAN ausschliessen.
Zum Testen habe ich ebenfalls die Last von den Servos genommen. Unter Last läuft einer nicht, ohne Last laufen alle drei. Akku evtl. zu schwach?
Anbei die gewünschten Bilder des Lenkungsaufbaus, der Verkabelung und des Akkus.
338733387433875

Auf dem Video wäre zu sehen, dass die Servos auch ohne Last zittern. Daher gehe ich eher davon aus, dass irgendwo was mit dem PWM-Signal nicht passt.
Wie kann ich das hier einfügen, ohne einen Google- oder Facebook-Account erstellen zu müssen?

Hier der Code, mit dem ich die Steuerung prüfe:


import sys
import time
import socket
import RPi.GPIO as gpio
from decimal import Decimal

print "Setting up board"
#General board settings
gpio.setmode(gpio.BCM)

print "Setting pins"
#Pin settings for X axis
gpio.setup(16, gpio.OUT)
gpio.setup(20, gpio.OUT)
gpio.setup(21, gpio.OUT)

#Check LED on pwmServo Pin
#gpio.output(16, True)
#gpio.output(20, True)
#gpio.output(21, True)
#time.sleep(3)

#gpio.output(16, False)
#gpio.output(20, False)
#gpio.output(21, False)
#time.sleep(1)

#Set pwmServo Pins as PWM
pwmServo1 = gpio.PWM(16, 50)
pwmServo2 = gpio.PWM(20, 50)
pwmServo3 = gpio.PWM(21, 50)

#Pin settings for blinker
#gpio.setup(19, gpio.OUT)
#gpio.setup(26, gpio.OUT)

#Blinkers off
#gpio.output(19, False)
#gpio.output(26, False)

time.sleep(1)

#************************************************* ***********************************************
#Change from left to right
fltCounter = float(7.5)
pwmServo1.start(fltCounter)
pwmServo2.start(fltCounter)
pwmServo3.start(fltCounter)

while fltCounter < 10.0: #12.5:
print "Angle % 0.2f" % fltCounter
pwmServo1.ChangeDutyCycle(fltCounter)
pwmServo2.ChangeDutyCycle(fltCounter)
pwmServo3.ChangeDutyCycle(fltCounter)
time.sleep(0.1)
fltCounter = float(fltCounter + 0.1)

#************************************************* ***********************************************
#Change from right to left
fltCounter = float(10) #float(12.5)
while fltCounter > 5:
print "Angle % 0.2f" % fltCounter
pwmServo1.ChangeDutyCycle(fltCounter)
pwmServo2.ChangeDutyCycle(fltCounter)
pwmServo3.ChangeDutyCycle(fltCounter)
time.sleep(0.1)
fltCounter = float(fltCounter - 0.1)

#************************************************* ***********************************************
#Reset pins, turn off
print "Stop"
fltCounter = float(7.5)
pwmServo1.ChangeDutyCycle(fltCounter)
pwmServo2.ChangeDutyCycle(fltCounter)
pwmServo3.ChangeDutyCycle(fltCounter)
time.sleep(1)

#X axis stop
pwmServo1.stop()
pwmServo2.stop()
pwmServo3.stop()
gpio.output(16, False)
gpio.output(20, False)
gpio.output(21, False)

#Right and left blinker off
#gpio.output(19, False)
#gpio.output(26, False)

gpio.cleanup()

print "Exiting"

Moppi
22.12.2018, 07:59
Wenn ein PWM-Signal erzeugt wird, könnten Interrupts/Timerereignisse dieses stören. So dass das Timing des PWM-Signals geringfügig durcheinandergerät und sich also die Frequenz ändert. Besser ist vielleicht, einen externen PWM-Generator zu verwenden, der sich von nichts durcheinanderbringen lässt.

Noch eine Idee wäre, nur mal ein Programm dafür zu schreiben, dass eine PWM-Signal ausgegeben wird, aber sonst nichts gemacht wird. - Glaube das hast Du ja schon. Vielleicht kann man für kurze Zeit dort auch mal die Interrupts alle abstellen und sehen, ob die Servos während dieser Zeit ruhig sind.

Oder es ist ein äußerer Einfluss, der die Frequenz des Signals beeinflusst.

RPi kenne ich mich leider nicht aus, daher kann ich dazu nichts Konkretes sagen.

Eine Idee zum externen Test mit einem PWM-Signal wäre vielleicht der TL494.


Nachtrag:

Habe gerade gelesen, dass andere auch das Problem bei RPi haben, dass die PWM-Frequenz instabil ist. Mit externem PWM-Generator ist das dann wohl verschwunden.

MfG
:Weihnacht

Siro
22.12.2018, 09:30
Moin Chris,

normalerweise sind die PWM Module (zumindest in denen von mir verwendeten Controllern) Hardwaregesteuert,
somit dürfte da nix eiern, da kann die Software selbst sogar stehen bleiben ohne Auswirkungen auf die PWM.

Wenn die PWM aber tatsächlich per Software erzeugt wird, dann hat man ein RIESEN Problem, was eigentlich unlösbar ist.
Das kann man dann wirklich nur, wie Moppi schrieb, mit externen PWM Controllern in den Griff bekommen.
Ich weis aber nicht wie das beim RasPi abläuft. Da ich gelesen habe, dass ein Servo sogar in die falsche Richtung läuft,
klingt das wirklich wie ein Pulsbreitenproblem.

Kann man das rausbekommen ob die PWMs per Software erzeugt werden ?, bzw. sollte das sicher hier im Forum jemand beantworten können.

Es könnte auch ein Reset ausgelöst werden durch Lastschwankungen oder Störungen
In den Servos sitzen ja auch Controller, die bei Störungen auf der Versorgungspannung gerne mal einen Neustart ausführen können.
Der dauert nur paar Millisekunden, aber hier zuckt der Servo dann kurzzeitig und läuft evtl. auch in die falsche Richtung.
Das Problem tritt dann vermehrt in Erscheinung, je mehr Servos gleichzeitig laufen bzw. bei größerer Last.
Ich hab so ein Problem schon in meinem Hubis gehabt. Dann gibts nen kurzen Aussetzer und dann geht es wieder.
Hier hilft dann die Versorgungsspannung evtl. noch mit einem/mehreren dicken Elko abzublocken oder aber die Verkabelung genauer zu untersuchen.
Oft ist diese nicht optimal gelöst, über ein Steckbrett (Experimentierboard) z.B. sind solche Fehler besonders häufig.
Vielleicht zieht der eines Servo bei Dir mehr Strom weil er einen größere Last bewegen muss, dehalb verhält er sich dann etwas merkwürdig.
Im Zweifel sollte tausche ich auch gerne mal die Servos untereineinader, um sicherzustellen, das es nicht am Servo selbst liegt.
Wenn das Problem dann an andere Stelle auftaucht, hat das Servo wohl ein Problem.


Siro

HaWe
22.12.2018, 10:20
moin!
Auf AVRs oder ARMs werden die ausgewiesenen pwm-Pins über eigene Interrupts gesteuert und daher eigentlich nie durch andere Interrupts gestört.
Hier ntl nicht die "normalen" pwm-Befehle verwenden ( wie bei Arduino: analogWrite), sondern die auf Servo-Steuerung hin ausgelegten (bei Arduino: z.B. Servo.h, Servo::write(), damit kann ich hier bei mir 6 angeschlossene Servos meines Robotarms steuern )

Beim Raspi gibt es zum Einen 2 ausgewiesene Hardware-Interrupt Pins, die ebenfalls völlig ungestört arbeiten (verwende ich persönlich überhaupt nicht; man braucht dazu auch root Rechte).
Zusätzlich lässt sich aber zum Anderen jeder beliebige GPIO per Software-pwm ansprechen: Man kann dazu z.B. die C Wrapper Funktionen von pigpio oder wiringPi verwenden. Gordon Henderson, der Autor von wiringPi, schrieb einmal im Raspi.org Forum dazu, dass diese genauso gut in der Lage sind, pwm zu erzeugen, wie aufgesetzte oder angesteckte pwm-Platinen (wie z.B. PCA9685), und zwar nicht nur für 1 Pin allein, sondern auch für alle simultan.

edit2: hier Python Code:
https://learn.adafruit.com/adafruits-raspberry-pi-lesson-8-using-a-servo-motor/software

Ich selber habe es für 3 Servos schon problemfrei selber gemacht. Da der Raspi aber insgesamt recht wenige GPIOs ohne spezielle Sonderfunktionen hat (i2c, SPI, UART, 1-Wire,...), würde ich bei mehr als 3 Servos dennoch eher einen PCA9685 über i2c verwenden.

Immer jedoch wichtig: für die Servos eine externe, leistungsfähige Stromquelle verwenden (ich verwende 7V 10A bei meinen 6 Servos).
Dass Servos aber manchmal zittern, kann ich bei mir auch nicht immer verhindern.


edit -
PS, ich vergaß, du nutzt ja Python - aber wiringPi ist auch für Python verfügbar
https://learn.adafruit.com/adafruits-raspberry-pi-lesson-8-using-a-servo-motor/software

hbquax
22.12.2018, 11:20
Hol dir doch mal einen billigen Servotester, um sicherzugehen, das die Servos ok sind.

Chris1803
22.12.2018, 16:39
Der Vorschlag mit dem externen Servo-Controller kam jetzt ja bereits mehrfach. Da die Dinger nicht die Welt kosten, werde ich so einen besorgen und testen, ob die Servos sich immer noch so merkwürdig verhalten.
Die Frage zur Energiequelle habe ich mir auch gestellt. Der NiMH-Akku hat 3000 mAh und bringt 7.2V, die über den Modelcraft-Wandler auf 6V reduziert werden, damit die Servos nicht überhitzen.
https://www.conrad.ch/de/conrad-energy-modellbau-akkupack-nimh-72-v-3000-mah-zellen-zahl-6-stick-tamiya-stecker-206028.html

Aber würdie die Software so wenigstens passen? Mit der getesteten LED sah es gut aus. Wurde heller und wieder dunkler, als ich die Werte statt von 7.5-12.5 von 5-100 gestellt hatte.

HaWe
22.12.2018, 17:33
wenn du auch das oben von mir verlinkte Python-Beispiel (direkt an GPIOs) erfolgreich getestet hast, dann stimmt ja sicher alles, oder?
https://learn.adafruit.com/adafruits-raspberry-pi-lesson-8-using-a-servo-motor/software

PS, deine Batterien schauen gut aus, die Leistung deines DC-Wandlers ist aber auch wichtig!

Chris1803
06.01.2019, 18:52
Feiertage durch, PCA9685 da und verbaut. Mit dem ersten lief das Ganze mehr oder weniger problemlos. Dank eines unachtsamen Kurzschlusses ist der jetzt aber mit Rauchverletzung entsorgt worden. Jetzt habe ich den zweiten zusammengebaut und an den RPi angeschlossen. Um allfällige Verkabelungsprobleme auszuschliessen, habe ich einen Servo direkt an den PCa9685 angeschlossen. Dieser ist mit dem RPi und dem DC-Wandler (übrigens max 5A bei 6V) verbunden. Mit dem gleichen Testskript (ausgeliefert mit der Treibersoftware) geht im Moment gar nichts. Kein hin und her bewegen, kein Zucken, nicht mal ein Brummen.
Mit dem Voltmeter habe ich mal gemessen. Am Servo kommen 6V an. Interessanterweise höre ich aber kein Pfeifen, wenn ich die Verbindung mit dem Voltmeter prüfe. Beim Software-PWM gab es auf der Steuerleitung und dem Nullleiter jeweils ein schnelles Piep Piep Piep in der Geschwindigkeit der Frequenz. Jetzt nicht. Nun bin ich wieder gleich weit, weiss aber zumindest (hoffentlich), dass es kein Softwareproblem ist. Ideen? Braucht ihr Bilder vom Aufbau?

Moppi
07.01.2019, 08:16
Es ist grundsätzlich nicht verkehrt, sich nochmals damit auseinanderzusetzen, indem z.B. alles aufgezeichnet wird, wie es vorher war, wie es jetzt war/ist. Oftmals hilft schon das bloße Reden über ein Problem, um auf neue Gedanken zu kommen, was noch falsch sein könnte. Ich denke es gibt sicher noch andere Mittel der Reflexion.

Die Informationen die ich entnehmen kann sind:

1. PCA9685 verbaut und funktionierte
2. Kurzschluss verursacht, keine Funktion mehr
3. einen zweiten PCA9685 zusammengebaut
4. Servo jetzt direkt an PCA9685 angeschlossen, was vorher nicht so war
5. jetzt keinerlei Reaktion mehr

Frage ist auch, wannd er Kurzschluss entstand, ob andere Teile mit betroffen sind.

MfG

HaWe
07.01.2019, 08:58
Feiertage durch, PCA9685 da und verbaut. Mit dem ersten lief das Ganze mehr oder weniger problemlos. Dank eines unachtsamen Kurzschlusses ist der jetzt aber mit Rauchverletzung entsorgt worden. Jetzt habe ich den zweiten zusammengebaut und an den RPi angeschlossen. Um allfällige Verkabelungsprobleme auszuschliessen, habe ich einen Servo direkt an den PCa9685 angeschlossen. Dieser ist mit dem RPi und dem DC-Wandler (übrigens max 5A bei 6V) verbunden. Mit dem gleichen Testskript (ausgeliefert mit der Treibersoftware) geht im Moment gar nichts. Kein hin und her bewegen, kein Zucken, nicht mal ein Brummen.
Mit dem Voltmeter habe ich mal gemessen. Am Servo kommen 6V an. Interessanterweise höre ich aber kein Pfeifen, wenn ich die Verbindung mit dem Voltmeter prüfe. Beim Software-PWM gab es auf der Steuerleitung und dem Nullleiter jeweils ein schnelles Piep Piep Piep in der Geschwindigkeit der Frequenz. Jetzt nicht. Nun bin ich wieder gleich weit, weiss aber zumindest (hoffentlich), dass es kein Softwareproblem ist. Ideen? Braucht ihr Bilder vom Aufbau?

was bedeutet "einen Servo direkt an den PCA9685 angeschlossen" ?
Servo-pwm wird doch immer am PCA9685 (pwm) angeschlossen, und Servo-Vc/GND stammen von einer externen Spannungsquelle,
und der PCA9685 bekommt immer seine Steuersignale vom µC/SoC
- wie sollte es anders möglich sein?

Klebwax
07.01.2019, 09:16
Wenn man mit zeitlich veränderlichen Signalen arbeitet, braucht man passende Messmittel. Das ist typisch ein Scope. Geht es dabei nur um digitale Logiksignale tut es auch ein einfacher Logicanalizer. Alles andere ist das Stochern mit einer Stange im Nebel, führt zu falschen Problemanalysen und am Ende zu Frust.

Simple LAs (https://www.ebay.de/sch/i.html?_from=R40&_trksid=p2380057.m570.l1311.R1.TR4.TRC2.A0.H1.Xsal eae.TRS0&_nkw=saleae&_sacat=0) gibt es für weniger als eine Pizza kostet. Es gibt dazu freie Software (https://sigrok.org/), wenn man die Software von saleae nicht nutzen will, ohne deren LA zu kaufen. Damit kann man sowohl den I2C Bus des PCA als auch die Servosignale leicht überprüfen.

Braucht man den LA öfter, findet sich für kleines Geld oder auch ganz umsonst ein ausgedienter Laptop. Selbst ein älteres Teil reicht für diesen Zweck. Damit wird aus dem billig-LA ein richtiges Gerät, das man noch um andere Funktionen erweitern kann.

MfG Klebwax

P.S. Vorsicht, mit einem LA kann man die Qualität der Signale nicht überprüfen. Sie sehen immer perfekt aus.

P.P.S. Warum die Servos mit 6 NiMH und einem Spannungswandler betrieben werden, wo sie doch für 5 (ursprünglich mal 4) Zellen gebaut sind, leuchtet mir nicht ein. Jedes zusätzliche Modul erzeugt eigene Probleme.

Chris1803
07.01.2019, 19:48
was bedeutet "einen Servo direkt an den PCA9685 angeschlossen" ?
Servo-pwm wird doch immer am PCA9685 (pwm) angeschlossen, und Servo-Vc/GND stammen von einer externen Spannungsquelle,
und der PCA9685 bekommt immer seine Steuersignale vom µC/SoC
- wie sollte es anders möglich sein?

Wie auf den Bildern oben, vermutlich schlecht, zu erkennen ist, gibt es innerhalb des LKW eine Menge Drähte, die zu den ursprünglichen Steuerservos gehen. Um mal die Verkabelungsprobleme auszuschliessen, habe ich nicht die fest verbauten Servos mit den ganzen internen Drähten am PCA9685 angeschlossen, sondern andere, baugleiche Servos genommen und diese an den Controller angeschlossen.
Der PCA9685 ist am RPi an den Pins 1, 3, 5 und 9, also 3.3V, SDA/GPIO2, SCL/GPIO3 und GND bzw. VCC, SDA, SCB und GND (PCA-Seite) angeschlossen.
Die externe Stromversorgung ist via Wandler an V+ und GND verbunden. Verständlich?

Am RPi habe ich übrigens noch überprüft, ob über den Befehl i2cdetect -y 1 das Modul überhaupt gefunden wird. Wird es, und zwar genau so wie es in der Anleitung angegeben wird.

Ich werde jetzt noch etwas versuchen und mal alle 16 Ports ansprechen, nur um sicher zu sein, dass ich da nicht was falsch gemacht habe. Dann hänge ich eine LED an PWM und GND und schaue, ob die wenigstens leuchtet. Theoretisch müsste das gehen, wenn ein Signal kommt und der Widerstand passt.

Kann es sein, dass ich irgendetwas beim Zusammenlöten des PCA9685 falsch gemacht haben könnte? Ich habe mal die Eingangsspannung RPi -> PCA9685 auf allen drei Leitungen (VCC, SDA und SCL) gemessen. Immer 3.3V. Mit dem Testprogramm mal nach einander alle 16 PWM-Signale eingeschaltet (ohne externe Stromquelle, kommt ja eh nur bei VCC raus) und gemessen. Hier tauchen lediglich zwischen 0.12V und 0.48V auf. Müssten hier nicht auch die 3.3V ankommen? Fehler im Chip oder ich was falsch verstanden? würde erklären, wieso die Servos sich nicht bewegen. Meine Meinung.

HaWe
07.01.2019, 21:07
hast du einen Arduino, um den PCA9685 zutesten? Das müsste man als erstes sicher stellen, dass er noch funzt.

Chris1803
07.01.2019, 21:14
Leider nein, nur einen RPi.

HaWe
07.01.2019, 21:22
dann investier doch mal 5 EUR - wie willst du es sonst schnell mal testen? Solange die Funktion nicht geklärt ist, können wir uns hier die Finger wund schreiben... :-/

Moppi
08.01.2019, 08:37
Ich habe mal die Eingangsspannung RPi -> PCA9685 auf allen drei Leitungen (VCC, SDA und SCL) gemessen. Immer 3.3V. Mit dem Testprogramm mal nach einander alle 16 PWM-Signale eingeschaltet (ohne externe Stromquelle, kommt ja eh nur bei VCC raus) und gemessen. Hier tauchen lediglich zwischen 0.12V und 0.48V auf. Müssten hier nicht auch die 3.3V ankommen?

PWM ist ja nicht gleich HIGH-Pegel sondern was dazwischen weil sich dort HIGH und LOW schnell abwechseln und unterschiedliche Zeiten haben können. Mit einem Multimeter könntest Du allenfalls einen Zwischenwert erhalten, der eben nicht dem vollen HIGH-Pegel entspricht. Sonst müsstest Du einen Oszi.. dran hängen, um das Signal am Ausgang zu sehen.

MfG

Chris1803
09.03.2019, 00:37
So, fertig.
Hat noch einmal richtig Nerven gekostet, aber mit insgesamt etwa 10 Tagen Aufwand konnte ich nun alles lösen. Einzig, die Servos "zittern" immer noch, aber das schein wohl bauartbedingt zu sein. Auch mit dem Servotester zittern die Servos, und auch solche, die einfach nur rumliegen und nicht verbaut sind, zittern. Also alles im grünen Bereich.

Das Python-Programm habe ich noch einmal von vorne begonnen. Habe alle Funktionen, die ich im alten Programm in eigene Funktionsbausteine verpackt habe in eine Hauptschleife genommen. Dadurch gibt es kein Timeout an einer ungünstigen Stelle und der Code ist erst noch leichter verständlich - zumindest, wenn man das Programm und die Funktionen kennt.

Da mehrfach darauf hingewiesen wurde, dass Software-PWM nicht stabil ist habe ich einen PCA9685-Controller verbaut. Erst dachte ich, ich müsste mindestens zwei nehmen, da ich Servos (6.0V) und DC-Motoren (12V mit L298N) habe. Aber man kann ja auch einfach nur das PWM-Signal und Masse an den L298N anschliessen und die externe Stromversorgung ebenfalls direkt dranhängen statt über den PCA9685 zu gehen. Nachdem ich auch das begriffen hatte, wurde es immer einfacher. Es brauchte etwas Zeit zu verstehen, wieso der PCA9685 nicht einfach mit einem Signal von 0 bis 100 für Min/Max angesprochen werden kann sondern 0 bis 4095 verwendet, aber auch das ist schlussendlich nur noch Mathematik.

Die Servos haben mir noch etwas Kopfzerbrechen gemacht, genauer die Einschlagswinkel der Steuerachsen, da Achse 2 und 4 weniger stark einlenken müssen als Achse 1, und Achse 4 ja gegenlenkt und einen invertierten Winkel benötigt. Aber diese Rechnung musste eh angestellt werden.

Aufgebockt drehen die Räder, schlagen die Lenkungen ein, blinken die Blinker und schalten die Kameras. Ich bin zufrieden und sobald die Akkus wieder voll sind kommt die richtige Jungfernfahrt. Vielen Dank an alle Tippgeber im Forum!

Falls sich jemand für den Code interessiert, er ist unten angefügt. Nicht, dass man ihn so direkt nutzen könnte, aber vielleicht für den einen oder anderen Anfänger hilfreich.



from __future__ import division
import Adafruit_PCA9685
import socket
import sys
import time
from decimal import Decimal

#define all variables
HOST = ''
TCP_PORT = 10001

intDivider = 4096
intDividerMax = 4095

#Define pins
pinCamera1 = 2
pinCamera2 = 3

pinBlinkerRight = 4
pinBlinkerLeft = 5
pinLightReverse = 6
pinLightForward = 7

pinServo1 = 8
pinServo2 = 9
pinServo3 = 10

pinMotorForward = 15
pinMotorReverse = 14



#Start of script
print "Initiating... waiting for connection"
sckSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sckSocket.bind((HOST, TCP_PORT))
sckSocket.listen(1)
intFrequenz = 50
intBlinkerLeft = 0
intBlinkerRight = 0
intBlinkerCounter = 0

#Connection loop
while True:

#Accept connection and create new socket 'sckConnection1'
try:

global intBlinkerLeft
global intBlinerRight
global intBlinkerCounter

sckConnection1, strClientAddress = sckSocket.accept()
print "Connection established"
print "Setting up PWM"
pwm = Adafruit_PCA9685.PCA9685(address=0x40)
pwm.set_pwm_freq(intFrequenz)
pwm.set_pwm(pinMotorForward, 0, 0)
pwm.set_pwm(pinMotorReverse, 0, 0)
pwm.set_pwm(pinBlinkerLeft, 0, 0)
pwm.set_pwm(pinBlinkerRight, 0, 0)
pwm.set_pwm(pinLightForward, 0, intDividerMax)
pwm.set_pwm(pinLightReverse, 0, 0)
pwm.set_pwm(pinCamera1, 0, 0)
pwm.set_pwm(pinCamera2, 0, 0)


#loop while connected
while True:
strData = ""
strData = sckConnection1.recv(1024)
intStringStart = 0
intStringEnd = 0
intStringLen = 0
intXaxis = 5000
intYaxis = 5000
intBA = 0
intBB = 0
intBC = 0
intBD = 0
intBE = 0
intBF = 0
intBG = 0
intBH = 0
intBI = 0
intBJ = 0
intBK = 0
intBL = 0

#Check if strData <> null, else break loop
if strData <> "":

#Extract X axis
try:
intStringEnd = 0
intStringEnd = strData.find("X:")
if intStringEnd == 0:
intXaxis = intXaxis
else:
intStringStart = intStringEnd + 2
intStringEnd = strData.find(";", intStringStart)
intXaxis = int(strData[intStringStart:intStringEnd])
except:
intXaxis = intXaxis

#Extract Y axis
try:
intStringEnd = 0
intStringEnd = strData.find("Y:")
if intStringEnd == 0:
intYaxis = intYaxis
else:
intStringStart = intStringEnd + 2
intStringEnd = strData.find(";", intStringStart)
intYaxis = int(strData[intStringStart:intStringEnd])
except:
intYaxis = intYaxis

#Extract Button A
try:
intStringEnd = strData.find("BA:")
intStringStart = intStringEnd + 3
intStringEnd = strData.find(";", intStringStart)
intBA = int(strData[intStringStart:intStringEnd])
except:
intBA = 0

#Extract Button B
try:
intStringEnd = strData.find("BB:")
intStringStart = intStringEnd + 3
intStringEnd = strData.find(";", intStringStart)
intBB = int(strData[intStringStart:intStringEnd])
except:
intBB = 0

#Extract Button C
try:
intStringEnd = strData.find("BC:")
intStringStart = intStringEnd + 3
intStringEnd = strData.find(";", intStringStart)
intBC = int(strData[intStringStart:intStringEnd])
except:
intBC = 0

#Extract Button D
try:
intStringEnd = strData.find("BD:")
intStringStart = intStringEnd + 3
intStringEnd = strData.find(";", intStringStart)
intBD = int(strData[intStringStart:intStringEnd])
except:
intBD = 0

#Extract Button E
try:
intStringEnd = strData.find("BE:")
intStringStart = intStringEnd + 3
intStringEnd = strData.find(";", intStringStart)
intBE = int(strData[intStringStart:intStringEnd])
except:
intBE = 0

#Extract Button F
try:
intStringEnd = strData.find("BF:")
intStringStart = intStringEnd + 3
intStringEnd = strData.find(";", intStringStart)
intBF = int(strData[intStringStart:intStringEnd])
except:
intBF = 0

#Extract Button G
try:
intStringEnd = strData.find("BG:")
intStringStart = intStringEnd + 3
intStringEnd = strData.find(";", intStringStart)
intBG = int(strData[intStringStart:intStringEnd])
except:
intBG = 0

#Extract Button H
try:
intStringEnd = strData.find("BH:")
intStringStart = intStringEnd + 3
intStringEnd = strData.find(";", intStringStart)
intBH = int(strData[intStringStart:intStringEnd])
except:
intBH = 0

#Extract Button I
try:
intStringEnd = strData.find("BI:")
intStringStart = intStringEnd + 3
intStringEnd = strData.find(";", intStringStart)
intBI = int(strData[intStringStart:intStringEnd])
except:
intBI = 0

#Extract Button J
try:
intStringEnd = strData.find("BJ:")
intStringStart = intStringEnd + 3
intStringEnd = strData.find(";", intStringStart)
intBJ = int(strData[intStringStart:intStringEnd])
except:
intBJ = 0

#Extract Button K
try:
intStringEnd = strData.find("BK:")
intStringStart = intStringEnd + 3
intStringEnd = strData.find(";", intStringStart)
intBK = int(strData[intStringStart:intStringEnd])
except:
intBK = 0

#Extract Button L
try:
intStringEnd = strData.find("BL:")
intStringStart = intStringEnd + 3
intStringEnd = strData.find(";", intStringStart)
intBL = int(strData[intStringStart:intStringEnd])
except:
intBL = 0



#Set Speed (Y-axis)
#Value <= 4750 -> reverse
if intYaxis <= 4750:
intSpeed = int(round(intDividerMax - (intDividerMax / 4750 * intYaxis), 0))
pwm.set_pwm(pinMotorForward, 0, intSpeed)
pwm.set_pwm(pinMotorReverse, 0, 0)

#Value >= 5250 -> forward
elif intYaxis >= 5250:
intSpeed = int(round(intDividerMax / 4750 * (intYaxis - 5250), 0))
pwm.set_pwm(pinMotorForward, 0, 0)
pwm.set_pwm(pinMotorReverse, 0, intSpeed)

#Value > 4750 and < 5250 -> stop
else:
pwm.set_pwm(pinMotorForward, 0, 0)
pwm.set_pwm(pinMotorReverse, 0, 0)



#Set servo positions (X-axis)
#Value <= 4750 -> left
if intXaxis <= 4750:
fltWinkel1 = float( 90 - float( ( 4750 - intXaxis ) / 118.75 ) )
fltWinkel2 = float( fltWinkel1 * 0.8599 + 12.193 )
fltWinkel3 = float( fltWinkel1 * -0.2161 + 109.78 )
intServo1 = int( round( float( float( float( fltWinkel1 / 18 ) + 2 ) / 100 ) * 4096, 0 ) )
intServo2 = int( round( float( float( float( fltWinkel2 / 18 ) + 2 ) / 100 ) * 4096, 0 ) )
intServo3 = int( round( float( float( float( fltWinkel3 / 18 ) + 2 ) / 100 ) * 4096, 0 ) )
pwm.set_pwm(pinServo1, 0, intServo1)
pwm.set_pwm(pinServo2, 0, intServo2)
pwm.set_pwm(pinServo3, 0, intServo3)

#Value >= 5250 -> right
elif intXaxis >= 5250:
fltWinkel1 = float( 90 + float( ( intXaxis - 5250 ) / 118.75 ) )
fltWinkel2 = float( fltWinkel1 * 0.8599 + 12.193 )
fltWinkel3 = float( fltWinkel1 * -0.2161 + 109.78 )

intServo1 = int( round( float( float( float( fltWinkel1 / 18 ) + 2 ) / 100 ) * 4096, 0 ) )
intServo2 = int( round( float( float( float( fltWinkel2 / 18 ) + 2 ) / 100 ) * 4096, 0 ) )
intServo3 = int( round( float( float( float( fltWinkel3 / 18 ) + 2 ) / 100 ) * 4096, 0 ) )
pwm.set_pwm(pinServo1, 0, intServo1)
pwm.set_pwm(pinServo2, 0, intServo2)
pwm.set_pwm(pinServo3, 0, intServo3)

#Value > 4750 and < 5250 -> center
else:
intServo1 = int(intDividerMax / 2)
intServo2 = int(intDividerMax / 2)
intServo3 = int(intDividerMax / 2)
pwm.set_pwm(pinServo1, 0, intServo1)
pwm.set_pwm(pinServo2, 0, intServo2)
pwm.set_pwm(pinServo3, 0, intServo3)



#Blinker left
#Blink if Button BC (Button no. 3) is pressed or blink loop is still active
if intBlinkerLeft == 1:
if intBlinkerCounter < 20:
intBlinkerCounter = intBlinkerCounter + 1
if bool(int(round(intBlinkerCounter * 0.25 * 2, 2)) & 1) == True:
pwm.set_pwm(pinBlinkerLeft, 0, intDividerMax)
else:
pwm.set_pwm(pinBlinkerLeft, 0, 0)

else:
intBlinkerLeft = 0
pwm.set_pwm(pinBlinkerLeft, 0, 0)

elif intBC == 1:
pwm.set_pwm(pinBlinkerLeft, 0, intDividerMax)
intBlinkerLeft = 1
intBlinkerCounter = 0



#Blinker right
#Blink if Button BD (Button no. 4) is pressed or blink loop is still active
if intBlinkerRight == 1:
if intBlinkerCounter < 20:
intBlinkerCounter = intBlinkerCounter + 1
if bool(int(round(intBlinkerCounter * 0.25 * 2, 2)) & 1) == True:
pwm.set_pwm(pinBlinkerRight, 0, intDividerMax)
else:
pwm.set_pwm(pinBlinkerRight, 0, 0)

else:
intBlinkerRight = 0
pwm.set_pwm(pinBlinkerRight, 0, 0)

elif intBD == 1:
pwm.set_pwm(pinBlinkerRight, 0, intDividerMax)
intBlinkerRight = 1
intBlinkerCounter = 0



#Both blinkers (left and right)
#Blink if Button BB (Button no. 2) is pressed or blink loop is still active
if (intBlinkerRight == 1 and intBlinkerLeft == 1):
if intBlinkerCounter < 20:
intBlinkerCounter = intBlinkerCounter + 1
if bool(int(round(intBlinkerCounter * 0.25 * 2, 2)) & 1) == True:
pwm.set_pwm(pinBlinkerRight, 0, intDividerMax)
pwm.set_pwm(pinBlinkerLeft, 0, intDividerMax)
else:
pwm.set_pwm(pinBlinkerRight, 0, 0)
pwm.set_pwm(pinBlinkerLeft, 0, 0)

else:
intBlinkerRight = 0
pwm.set_pwm(pinBlinkerRight, 0, 0)
pwm.set_pwm(pinBlinkerLeft, 0, 0)

elif intBB == 1:
pwm.set_pwm(pinBlinkerRight, 0, intDividerMax)
pwm.set_pwm(pinBlinkerLeft, 0, intDividerMax)
intBlinkerRight = 1
intBlinkerLeft = 1
intBlinkerCounter = 0



#Set Camera view
#Turn on back camera if Button BE (Button no. 5) is pressed
if intBE == 1:
pwm.set_pwm(pinCamera1, 0, intDividerMax)
pwm.set_pwm(pinCamera2, 0, intDividerMax)

#Turn on front camera if Button BF (Button no. 6) is pressed
if intBF == 1:
pwm.set_pwm(pinCamera1, 0, 0)
pwm.set_pwm(pinCamera2, 0, 0)



#Break connection if Button BA (Button no. 1) is pressed and exit program
if intBA == 1:
print "Connection terminated"
print "Exiting script"
sys.exit(0)
break

time.sleep(0.25)

else:
print "Connection lost"
break

#Clean up after error or at termination
finally:
sckConnection1.close()

#End of script
print "Ending"
sys.exit(0)

HaWe
09.03.2019, 11:41
Glückwunsch, dass du es hingekriegt hast, vor allem auch mit Python! 8)