schaltlogik entwickeln für 8-gang-schaltung

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
geist4711
User
Beiträge: 47
Registriert: Montag 29. Juli 2019, 11:48

Dienstag 30. Juli 2019, 14:15

ich hab mich mit dem wühlen und lesen in dem dok und eineigen anderen seiten im internet selber 'in's schlingern gebracht', zusätzlich einiges wohl falsch verstanden.

heut mittag hab ich dann 'bounce_time=0.2' (und andere zeitwerte) eigegeben und das wurde es besser mit dem tastenprellem, dqafür nimmt er tastendrücke etwas schlechter an, oft erst beim zweiten drücken. es ist jedenfalls nich genau gleich wiederholbar reproduzierbar was passiert und eigenlich ist das ja kein allzu wilder aufbau hier.
eben der pi, ein netzteil mit step-down-wandlern, ein steckboard und eben die schalter- mitkabeln dran und mini-krokoklemmen(die auch korrekten kontakt haben)....
hmmm...
kann das sein das ich da besser ein abgeschirmtes kabel nehmen sollte?
ich schalte ja nur die masse und nach etwa überlegung denke ich mir, das da evtl irgendwas einstrahlt auch wenn ich eigentlich der ansicht war, das das so recht störungsfrei laufen sollte?!

im augenblick jedenfalls kann man das so gerade so nutzen, manchmal muss man halt doppelt drücken, vor allem beim runter-schalten, beim hochschalten tritt das fast garnicht auf.

also 'pullup-widerstand sitzen bei mir übrigens 10k-widerstände direkt auf dem steckboard das direkt neben dem PI steht.

den gesammt-stellweg des servos noch etwas erweitern, damit werde ich nachher mal sehen ob das über 'min_puls_width=0.005' und 'max_puls_width=0.003' etwas strecken lässt, mechaanisch liesse der servo das durchaus zu, der könnte auch 180 grad statt die derzeitigen nur 90 reral mechanisch.
wenn da jemand einen besseren weg weiss immer gene her damit.

kann ich eigentlich die (wenn ich das richtig verstehe) funktion 'GEAR2SERVO' auch für das licht 'missbrauchen, dann nur mit ( 0.2, 0.5, 1) als mögliche einstellungen?
ist jetzt nur so eine idee und noch nicht genauer betrachtet.

leider gab es heute für mich das windows-update auf 1903 und das hat mich estmal nacharbeit und ein paar std zeit gekostet, sonst hätt ich schon angefangen da mal was zu coden, was ich mir so denke, so mit 'als vorlage das mit dem servo'.
noch gibt es nur einen schmierzettel der noch sehr wirr aussieht:-)
Benutzeravatar
__blackjack__
User
Beiträge: 3870
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Dienstag 30. Juli 2019, 14:36

`GEAR2SERVO` ist keine Funktion sondern eine Liste. Und natürlich kann man auch eine Liste für Helligkeitsstufen anlegen und verwenden.

Ich würde demnächst objektorientierte Programmierung auf den Lernplan setzen, damit das ``global`` aus dem Programm verschwinden kann.
“There's also a certain pleasure in actually getting things to work in Java, somewhat like the pleasure, I imagine, of building ships in bottles.”
— David Cook in c.l.p
geist4711
User
Beiträge: 47
Registriert: Montag 29. Juli 2019, 11:48

Dienstag 30. Juli 2019, 15:19

das 'global' nicht so prickelnd sein soll hab ich schonmal gelesen, aber das ist noch zu hoch für mich, ist ja meine erste echte programier-geschichte.

bin sschon glücklich das ich überheupt so weit gekommen bin :-) dank der tollen hlfe hier!

ähnliches ('programmieren', ähm oder sowas...) hab ich zuletzt gemacht wo ich mir ein paar batch-dateien zusammengeschreibselt hab wo ich für 'doom' eine angepasste config.sys, autoecex.bat, usw. unter DOS nutzen wollte ;-)

so ganz verstehe ich auch noch nicht alle zeilen des nun schonmal recht gut funktionierend code, aber je mehr ich lese und frage dämmert es :-)

ich bin alt, früher ging sowas besser und schneller ;-)

hab nun den code etwas optimiert:

Code: Alles auswählen


#!/usr/bin/python3e
from gpiozero import LED, Button, PWMLED, AngularServo
from time import sleep
from signal import pause
from functools import partial

fahrlicht = Button(26, bounce_time=0.001) #lichtschalter
fernlicht = Button(19, bounce_time=0.001) #fernlichtschalter
blinker_li = Button(13, bounce_time=0.001) #blinkschalter links
blinker_re = Button(6, bounce_time=0.001) #blinkschalter rechts
hupe = Button(5, bounce_time=0.001) #hupenschalter
gang_hoch = Button(11, bounce_time=0.001) #servo hoch-schalten
gang_runter = Button(9, bounce_time=0.001) #servo runter-schalten

GEAR2SERVO = [-90, -64.3, -38.6, -12.9, 12.8, 38.5, 64.2, 90] 

current_gear = 0
servo = AngularServo(25,
    initial_angle=GEAR2SERVO[current_gear],
    min_angle=min(GEAR2SERVO),
    max_angle=max(GEAR2SERVO), min_pulse_width=0.0008, max_pulse_width=0.0023)

def clamp(value, lower, upper):
    return max(min(upper, value), lower)

def shift(direction):
    global current_gear
    current_gear = clamp(current_gear + direction, 0, len(GEAR2SERVO))
    servo.angle = GEAR2SERVO[current_gear]

gang_hoch.when_pressed = partial(shift, +1)
sleep(0.01)
gang_runter.when_pressed = partial(shift, -1)
sleep(0.01)

pause()

der servo macht nun fast 180° gesamtstellwinkel. opimal für das was ich machen möchte.
einzig zittert er noch etwas, aber nicht immer und gleichmässig, und eben die tasten reagieren nicht immer.
ohne 'bounce' schaltet man öfter doppelt auf einmal, mit 'bounce' reagieren die tastennicht immer auf drücken....
da muss ich noch mit den zahlen wohl etwas spielen, das ist noch nicht optimal.
Benutzeravatar
__blackjack__
User
Beiträge: 3870
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Dienstag 30. Juli 2019, 16:29

@geist4711: Die She-Bang-Zeile glaube ich nicht so ganz. Oder wo kommt die `python3e`-Datei her‽

Das mit dem global betrifft auch noch andere Namen. Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.

Da gehört dann auch `servo` rein (oder eben zumindest nicht auf Modulebene). Funktionen sollten alle Werte die sie ausser Konstanten benötigen als Argumente übergeben bekommen. Das `Servo`-Objekt sollte man also auch per `partial()` binden/übergeben.

Die `sleep()`-Aufrufe beim zuweisen der Rückruffunktionen machen keinen Sinn.

Namen sollten möglichst ohne Kommentare auskommen können. Wenn man einen Fernlichtschalter hat, sollte man den `fernlichtschalter` nennen und nicht `fernlicht` und dann ``#fernlichtschalter`` als Kommentar dahinter setzen.

Keine Abkürzungen in Namen. `*_links` statt `*_li` und `*_rechts` statt `*_re` ist verständlicher.

Zwischenstand:

Code: Alles auswählen

#!/usr/bin/env python3
from functools import partial
from signal import pause

from gpiozero import Button, AngularServo

GEAR_TO_ANGLE = [-90, -64.3, -38.6, -12.9, 12.8, 38.5, 64.2, 90]

current_gear = 0  # FIXME Globale Variable beseitigen.


def clamp(value, lower, upper):
    return max(min(upper, value), lower)


def shift(servo, direction):
    global current_gear
    current_gear = clamp(current_gear + direction, 0, len(GEAR_TO_ANGLE))
    servo.angle = GEAR_TO_ANGLE[current_gear]


def main():
    lichtschalter = Button(26, bounce_time=0.001)
    fernlichtschalter = Button(19, bounce_time=0.001)
    blinkschalter_links = Button(13, bounce_time=0.001)
    blinkschalter_rechts = Button(6, bounce_time=0.001)
    hupe = Button(5, bounce_time=0.001)
    
    gang_hoch = Button(11, bounce_time=0.001)
    gang_runter = Button(9, bounce_time=0.001)
    servo = AngularServo(
        25,
        initial_angle=GEAR_TO_ANGLE[current_gear],
        min_angle=min(GEAR_TO_ANGLE),
        max_angle=max(GEAR_TO_ANGLE),
        min_pulse_width=0.0008,
        max_pulse_width=0.0023,
    )
    gang_hoch.when_pressed = partial(shift, servo, +1)
    gang_runter.when_pressed = partial(shift, servo, -1)
    pause()


if __name__ == '__main__':
    main()
Das objektorientierte Programmierung noch zu hoch für Dich ist, ist ja kein Grund es nicht auf den Lernplan zu setzen. Im Gegenteil – es macht ja keinen Sinn da Sachen drauf zu setzen die man schon kann. Damit wird man dann nicht nur das ``global`` los, sondern fasst alles was zur Gangschaltung gehört in ein Objekt zusammen, statt das über das Programm zu verteilen. `GEAR_TO_ANGLE`, `shift()`, `gang_hoch`, `gang_runter`, `servo`, und `current_gear` sind dann nicht mehr einzeln, sondern in einem Objekt zusammengefasst.
“There's also a certain pleasure in actually getting things to work in Java, somewhat like the pleasure, I imagine, of building ships in bottles.”
— David Cook in c.l.p
geist4711
User
Beiträge: 47
Registriert: Montag 29. Juli 2019, 11:48

Dienstag 30. Juli 2019, 17:00

hallo,
der code schaut vom ansehen aus her sehr ordentlich aus, schöner wie mein 'konstrukt'

wo das 'e' nach python3 in der 'she-ban-zeile' (aha, heisst diese zeile so?), hmm, keine ahnung, muss ein tippfehler sein :-) ist mir nicht aufgefallen.

objektorientierung wollte ich dabei nicht 'bei seite schieben' oderso, sondern auf später verschieben, noch bin ich dabei den code überhaupt vollständig zu beherrschen und dieses dumme prellen weg zu bekommen.

daher auch noch diese 'sleep-geschichten' bei den schaltern, habe gedacht wenn ich danach ein sleep setze wird es evtl besser -und hab's nicht wieder entfernt...

habe eben auch nochmal einen ganz anderen ansatz verfolgt:
habe diese billigen china-schalter auseinander genommen.
ergebniss:
lötstellen alle taub, sprich matt -übergelötet
schlterkontakte, so ein merkwürdige feder-2-kontakte-konstruktion alle kontaktflächen sehen schrecklich aus als hätten diese kleinteile jahre im regal gelegen.
habe und 'patina' angelegt hätten.
die zerlegt und kontakltflächen angeschliffen.

naja, wirklich gehokfen hat das nicht, es scheint etwas besser geworden zu sein, mehr aber auch nicht.
die noname billig-taster die ich sonst noch hier hab, schalten auch nicht zuverlässig......

ich muss zuverlässige omron- oder sowas taster, gekapselt, besorgen.
so wird das nix, das ist unzuverlässt und irritiert/verwirrt einen dauernd.
__deets__
User
Beiträge: 6054
Registriert: Mittwoch 14. Oktober 2015, 14:29

Dienstag 30. Juli 2019, 17:02

Du kannst ggf. auch noch mit nem RC-Filter entprellen. Aber prinzpiell sollte das schon gehen, auch mit preiswerten Schaltern.
geist4711
User
Beiträge: 47
Registriert: Montag 29. Juli 2019, 11:48

Dienstag 30. Juli 2019, 17:16

]so wie es ausschalt sind die taster SO MIESERABEL, das sie wirklich nicht zuverlässig schalten. wenn ich mit mini-krokodilklemmenkabel(alles isoliert!) ohne taster taste, funktioniert es tadelos,
sch... chinas-mist :-)

dabei vielmir auf:
wenn ich hochschalte, über 7 hinaus, kommt:

File "/home/pi/python/servo-test.py", line 29, in shift
servo.angle = GEAR2SERVO[current_gear]
IndexError: list index out of range

es funktioniert trotzdem und wird evtl nur in thonnys python ide angezeigt, aber es irritiert.
ignorieren? gehört das so? oder kann man da noch etwas feilen des des nimmer passiert? irgendwo max=7 setzen oderso?

muss gleich etwas pause machen, meine konzentration lässt nach.....

edit:
hab grad ma bilder gemacht vom den tastern, kann man die hier irgendwie hochladen?
Zuletzt geändert von geist4711 am Dienstag 30. Juli 2019, 17:24, insgesamt 1-mal geändert.
__deets__
User
Beiträge: 6054
Registriert: Mittwoch 14. Oktober 2015, 14:29

Dienstag 30. Juli 2019, 17:19

Nein, das soll so nicht, das war eigentlich durch das clamp geregelt. Das muss aber natuerlich den richtigen Werteberich uebergeben bekommen.
geist4711
User
Beiträge: 47
Registriert: Montag 29. Juli 2019, 11:48

Dienstag 30. Juli 2019, 17:27

lass mich raten:
vieleicht hab ich ja glück:
hinter die '0,' noch eine '7,' ?

in der zeile:
current_gear = clamp(current_gear + direction, 0, len(GEAR2SERVO))

wenn nicht hab ich den sinn der '0' dort nicht verstanden -so wie vieles, noch, hoffe ich und das soll sich noch ändern :-)

ich hab halt nur eine grobe vorstellung davon was der code alles macht, aber noch nicht im detail und für alle gemachten angaben ;-)
Zuletzt geändert von geist4711 am Dienstag 30. Juli 2019, 17:31, insgesamt 1-mal geändert.
__deets__
User
Beiträge: 6054
Registriert: Mittwoch 14. Oktober 2015, 14:29

Dienstag 30. Juli 2019, 17:31

Nee. Ist aber ein Fehler von mir. 0 ist die untere Grenze. Die obere Grenze muss der Index des letzten Elementes von GEAR2SERVO sein. Das ist aber nicht len(GEAR2SERVO). Sondern len(GEAR2SERVO) - 1.
geist4711
User
Beiträge: 47
Registriert: Montag 29. Juli 2019, 11:48

Dienstag 30. Juli 2019, 17:35

das macht nichts deets, nobody ist perfekt.
es hat auch was gutes,
das hat mich angeregt noch weiter über den code zu senieren :-)
und zu versuchen ne lösung zu finden.

die -1 ist vermerkt und wird morgen eingefügt.
ich hätte da ehr mit einer 7, also angabe einer obersten zahl gerechnet :-)

grübel, grübel, grübel dann steht die angabe dafür das er nicht mehr als -1 an positionen die da oben wo die 'angle-angaben' in dr klammer gemacht sind hoch-'takten' soll?

nebenbei, hier die taster:
Bild
Bild
Zuletzt geändert von geist4711 am Dienstag 30. Juli 2019, 17:46, insgesamt 2-mal geändert.
Benutzeravatar
__blackjack__
User
Beiträge: 3870
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Dienstag 30. Juli 2019, 17:41

Hach, hatte ich gar nicht im Text erwähnt – der Fehler war mir beim Lesen aufgefallen und ist in meiner Abwandlung des Codes behoben gewesen. 🙂
“There's also a certain pleasure in actually getting things to work in Java, somewhat like the pleasure, I imagine, of building ships in bottles.”
— David Cook in c.l.p
geist4711
User
Beiträge: 47
Registriert: Montag 29. Juli 2019, 11:48

Dienstag 30. Juli 2019, 17:49

cool!
ich hoffe keiner von euch beiden ist nachher angesäuert weil ich dann einen von beiden codes letztendlich nehme?!

zum lernen für mich und 'verstehen lernen' sind beide sehr interessant und ich werde da weiter mich mit beschäftigen, bis ich soweit durchsteige das ich das auch alein hinkriegen könnte :-)

zb um meine 'gekraute' mit der beleuchtung zu erneuern :-)

da muss ich aber erstmal zurecht-schreiben wie ich glaube das es funktionieren könnte.
aber immer eins nach dem anderen....
geist4711
User
Beiträge: 47
Registriert: Montag 29. Juli 2019, 11:48

Dienstag 30. Juli 2019, 19:41

so, hab jetzt richtige vergossene taster genommen die zuverlässig schalten von hartmann.
alte aus dem modellbaubereich als es noch kaum chinasachen gab -;-) bestimmt 15 jahre alt.

jetzt schaltet es korrekt. muss nur sehen wie ich die dann an den lenker fest mache -egal, späteres problem...

habe beide schaltungen damit probiert, beide das selbe verhalten:
mit bounce unsicheres schalten, egal welche ms eingestellt(1ms-1sek getestet) sind. habe bounce wieder ganz raus genommen, überall.

eine kleinigkeit:
im 'objektorientierten script' haate sich der fehler mit dem 'überzählen' doch wieder eingeschlichen ;-)
hab dann das -1 gesetzt und nu keine fehlermeldung mehr,.
ohne den fehler hätt ich nie gewusst und mich mit beschäftigt solch eine fehlerfindgung zu machen.
danke dafür! das war toll! so macht lernen spass! man 'sieht' sofort wss man macht und hat sein erfolgserlebniss. natürlich mit eurer unterstützung.

so, schluss für heut, es qualmt der kopf ;-)
morgen mal schauen was ich mit meinem lichtscript verunstallten kann :-)
und ob ich das hin kriege was von dem gelernten mit der gangschaltung zu übernehmen und an zu wenden.
geist4711
User
Beiträge: 47
Registriert: Montag 29. Juli 2019, 11:48

Mittwoch 31. Juli 2019, 18:11

GEAR_TO_ANGLE = [-90, -64.3, -38.6, -12.9, 12.8, 38.5, 64.2, 90]

frage für wenn ich das umschreibe auf eine PWMLED:
GEAR_TO_ANGLE setzt ja gänge zu winkel um, ist hier aber ja nur eine bezeichnung.
und die werte sind die zahlen die da stehen.
wenn ich nun diese zeile nutzen möchte um das für PWM zu nuetzen,
könnte ich dann doch schreiben:

GEAR_TO_ANGLE =(0.2,0.5,1)

für die geplanten pwm-werte mit 'falschem begriff' davor und dieses dan zb
stufe_zu_pwm, eingedeutscht woraus dann:

stufe_zu_pwm = (0.2, 0.5, 1)
wird.

richtig?


dann müsste ich auch aus:
servo.angle = GEAR_TO_ANGLE[current_gear]

servo.angle = stufe_zu_pwm[current_gear]

machen und statt servo.angle
dann

led.pwm = stufe_zu_pwm[current value]

'current_value' statt 'current_gear'
nehmen und current_value dann zb für meine belange auf

current_value=0.2
setzen

dann sähe das ganze so aus:

stufe_zu_pwm = [0.2, 0.5, 1]

current value = 0.2 # FIXME Globale Variable beseitigen.

def clamp(value, lower, upper):
return max(min(upper, value), lower)

def shift(servo, direction): #fahrlicht
global stufe_zu_pwm1
current_value = clamp1(stufe_zu_pwm + direction, 0, len(stufe_zu_pwm)-1)
led1 = stufe_zu_pwm[current_value]

dann das ganze noch für fernlicht-schalter und beim hinteren licht für's bremslicht-schalter nach selben schema zusammensetzen.

auch richtig oder denkfehler?

wenn ich nun, beim fahlicht, die hintere led (led2) mit-schalten will, kann ich die mit 'einschleifen' oder muss ich da eine neue shift-anweisung setzen?

abgesehen davon das evtuell das bremslicht dann wie da fernlicht geschaltet wird ;-)
also

led1, led2 = stufe_zu_pwm [current_value]

in der letzen zeile von 'def shift'

achja, und geschaltet wird dann so:
fahrlichtschalter = pwmled(25, initial_angle=stufe_zu_pwm[current_value],
min_angle=min(stufe_zu_pwm),
max_angle=max(stufe_zu_pwm), )

fernlicht dann entsprechend ähnlich über:

fahrlichtschalter.when_pressed = partia1l(shift, servo, +1)
fahrlichtschalter.when_released = partial (shift, servo, -1)

fernlichttster_pressed = partial(shift, servo, +1)
fernlichttaster.when_released =partial (shift, servo -1)

...
Antworten