schaltlogik entwickeln für 8-gang-schaltung

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

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

]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: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

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

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: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

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

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: 14018
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

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. 🙂
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
geist4711
User
Beiträge: 47
Registriert: Montag 29. Juli 2019, 11:48

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

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

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)

...
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

. Klar kann man Variablen nennen wie man will. Und beliebige Werte in Listen eintragen. Und wenn das Muster “aus einer Zahl auf einen Wert kommen” wie eben aus Gang zu Winkel passt, kann man das benutzen.

Aber das ganze pwmled-Zeug ist komplett daneben. Eine PWM kennt doch keinen Winkel.

Nur ist das doch nicht dein eigentliches Problem. Sondern das du in einem von mehreren Zuständen sein kannst (Licht aus, Licht an) und darauf dann wiederum temporäre Modifikationen anwendest, die nur so lange gelten, wie ein Schalter gedrückt ist. ZB Bremse oder Lichthupe. Das musst du lösen, und da kommt dann ggf ein Wert von 0-2 oder so (aus, an, richtig hell) raus. Den kannst du über so eine lookup Tabelle dann auf tatsächliche PWM Werte abbilden.

Und das ganze geclampe und co braucht es auch nicht, denn der Fahrer drückt ja nicht 10 mal die Lichthupe & dann ist 10mal heller.

Eine weg sowas zu machen ist die Zustände der diversen Schalter bitweise zu kombinieren. 1 für Licht an, 2 für bremse gedrückt. Verodert nimmt das dann Werte von 0-3 an, und DAS schlägst du dann in einer Liste mit PWMS, zb [0, 0.5, 1, 1] nach. Da ist dann nicht bremsen und nicht Licht aus, Licht an halb hell, und alle anderen Kombinationen - nur bremsen, oder bremsen mit Licht - ganz hell.
geist4711
User
Beiträge: 47
Registriert: Montag 29. Juli 2019, 11:48

ja genau,
ich sag mal wie ich mir das vorstelle:

man schaltet den pi an:
die beleuchtung geht auf 0.2(pwm) an, da kann man sehen ob alle lampen laufen und sieht das die anlage an ist ;-)

nun kann man bremse, fahrlicht und fernlicht an bzw aus schalten.
dabei gillt:
fahrlicht schaltet hinten und vorn 0.5(pwm) auf dauer an.

fernlicht macht die led auf100% hell, solange fernlicht gedrückt ist.
zurück dann dahin wo die helligkeit vorher war, egal ob grad fahrlicht an war oder nicht.

bremslicht geht auch nur an wenn 'gedrückt', auch auf100%, aber nur hinten, und fällt dann wieder dahin zurück wo es grad war.

hupe geht auch nur wenn gedrückt, schaltet aber 6v von externer quelle via fet und optokoppler.

blinker läuft solange die jeweiligen blinkschalter gedrückt sind, nur blinken, ohne pwm.

gänge werden geschaltet, je nach welchen schalter man drückt und es fängt immer bei '0', also 1. gang an


da man die 'gänge' ja auch durchschaltet, war das was ich da so 'zusammengebacken' hab
der halbwissende versuch, das damit auch um zu setzen, also das licht ähnlich wie die gangschaltung 'durch zu schalten' wie die gänge der gangschaltung :-)
ich glauib aber selber nicht, das das so soeinfach dann auch schon funktioniert ;-)

mir ging es ehr darum jetzt zu erfahren ob der kenner sagt: nee so wird das nie was, da mischt du listen funktionen oder wonstwas was ich da nicht beachte zusammen :-)

wobei mir tief im hinterkopf noch schwebt:
eigentlich wäre es für led's ja besser die mit ksq's zu betreiben, nur die kann man schlecht dimmen, oder pwm-ansteuern.
wobei eben der gedanke 'schwellt' alle led's zu messen(strom oder strom über die spannung eines kleinen widerstands wo man ja rechnen könnte welcher strom das wär ;-) ) und nach deren strom die pwm-ausgänge je led zu regulieren, so wie sie grad leuchten soll, also aus, testglimmen(gleichzeitig notlicht wenn akku fast leer später) halbe helligkeit, volle helligkeit(nur fernlicht und bremse).
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Joa. Dann man frisch ans Werk. Eines nach dem anderen bauen. Gute Namen vergeben, damit du dich nicht selbst und ggf uns wenn wir helfen sollen verwirrst.
geist4711
User
Beiträge: 47
Registriert: Montag 29. Juli 2019, 11:48

jo, kommt, alles stückl für stückl.
erstmal aus dem gangschaltungs-kram was funktionierendes machen, für's licht.
da erstmal nur 'an aus/heller dunkel' und dann langsam weiter.

später dann zusammenführen.
wobei mir grad wider was in den sinn kommt:
wenn es ja 'main' gibt, gehen auch bestimmt 'unterteile' also teil 'gangschaltung' und 'beleuchtung'?

wie unterteilt man das?

so?:

def main()

def gangschaltung
-hier den code-
if __name__ == '__gangschaltung__':
gangschaltung()

def beleuchtung
-hier den code-
if __name__ == '__beleuchtung__':
beleuchtung()

if __name__ == '__main__'()
main()


geht das so?
Benutzeravatar
__blackjack__
User
Beiträge: 14018
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@geist4711: Nein, wieso sollte denn `__name__` plötzlich den Wert '__gangschaltung__' haben? Das hat als Wert den Modulnamen wenn das Modul importiert wurde und den Wert '__main__' wenn das Modul als Programm ausgeführt wurde. Damit kann man dann mit dem ``if __name__ == '__main__':`` dafür sorgen, das die Funktion `main()` ausgeführt wird, wenn man das Modul als Programm ausführt, und das die Funktion *nicht* ausgeführt wird, wenn man das Modul in einer Python-Shell, oder aus einem anderen Modul heraus importiert.

`gangschaltung()` und `beleuchtung()` sind auch keine guten Namen für Funktionen, weil man für Funktionen (und Methoden) in der Regel die Tätigkeit als Namen verwendet, die von der Funktion (oder Methode) durchgeführt wird. Damit kann man sie von eher passiven Werten unterscheiden. `gangschaltung` wäre ein guter Name für ein Objekt vom Typ `Gangschaltung`, den man sich als Klasse schreiben könnte um die globale Variable für den aktuellen Gang los zu werden. Und bei `beleuchtung` könnte man etwas ähnliches mit einer Klasse `Beleuchtung` machen, die die Zustände der Beleuchtung verwaltet.
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
geist4711
User
Beiträge: 47
Registriert: Montag 29. Juli 2019, 11:48

gut, dann hab ich das mit 'main' nur falsch verstanden bzw interpretiert :-)

wollte neben dem 'main' also meinem verständniss nach dem 'hauptprogramm'
die unter-rubriken 'gangschaltung' und 'beleuchtung' bezeichen :-)

damit man schöner sehen kann welche bereich das ist :-) auch für falls später noch mehr unfug dazu kommt....

ich mach besser erstmal morgen weiter, heute genug mist verzapft :-)
und morgen versuch ich erstmal die beleuchtung ähnlich wie die gangschaltung zu gestallten :-)
so mit liste und da auswählen wie hell es wann warum werden soll...
Benutzeravatar
__blackjack__
User
Beiträge: 14018
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Die Gangschaltung mal in eine Klasse verpackt (ungetestet):

Code: Alles auswählen

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

from gpiozero import Button, AngularServo

GEAR_CHANGE_SERVO_PIN = 15
GEAR_UP_PIN = 11
GEAR_DOWN_PIN = 9

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


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


class GearChange:
    
    def __init__(self, gear_to_angle, servo_pin, gear_up_pin, gear_down_pin):
        self._current_gear = 0
        self._gear_to_angle = gear_to_angle
        self._servo = AngularServo(
            servo_pin,
            initial_angle=self._gear_to_angle[self.current_gear],
            min_angle=min(self._gear_to_angle),
            max_angle=max(self._gear_to_angle),
            min_pulse_width=0.0008,
            max_pulse_width=0.0023,
        )
        self._gear_up_button = Button(gear_up_pin)
        self._gear_up_button.when_pressed = partial(self.change, +1)
        self._gear_down_button = Button(gear_down_pin)
        self._gear_down_button.when_pressed = partial(self.change, -1)

    @property
    def gear_count(self):
        return len(self._gear_to_angle)

    @property
    def current_gear(self):
        return self._current_gear
    
    @current_gear.setter
    def current_gear(self, value):
        self._current_gear = clamp(value, 0, self.gear_count - 1)

    def change(self, direction):
        self.current_gear += direction
        self._servo.angle = self._gear_to_angle[self.current_gear]


def main():
    lichtschalter = Button(26)
    fernlichtschalter = Button(19)
    blinkschalter_links = Button(13)
    blinkschalter_rechts = Button(6)
    hupe = Button(5)
    
    _gear_change = GearChange(
        GEAR_TO_ANGLE, GEAR_CHANGE_SERVO_PIN, GEAR_UP_PIN, GEAR_DOWN_PIN
    )
    pause()


if __name__ == '__main__':
    main()
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
geist4711
User
Beiträge: 47
Registriert: Montag 29. Juli 2019, 11:48

cool, war mir garnicht klar das man 'class' auch dafür nutzen kann.
das werd ich mir merken und später nutzen :-) danke!
geist4711
User
Beiträge: 47
Registriert: Montag 29. Juli 2019, 11:48

heute hab ich wider bissel was getan:

Code: Alles auswählen

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

from gpiozero import Button, AngularServo, LED, PWMLED

GEAR_TO_ANGLE = [-90, -64.3, -38.6, -12.9, 12.8, 38.5, 64.2, 90]
STUFE_ZU_PWM = [0.0, 0.2,0.6,1]

current_gear = 0  # FIXME Globale Variable beseitigen.
led_startvalue = 0.2

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

def clamp2(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)-1)
    servo.angle = GEAR_TO_ANGLE[current_gear]

def shift2(fahrlicht, direction):
    global led_startvalue
    led_startvalue = clamp2(led_startvalue + direction, 0, len(STUFE_ZU_PWM)-1)
    led.angle = STUFE_ZU_PWM[led_startvalue]


def blinker_links():
    blinker_links_led3.blink (on_time = 0.8, off_time = 0.2)

def blinker_rechts():
    blinker_rechts_led4.blink (on_time = 0.8, off_time = 0.2)

def hupe_an():
    hupen_led
    
def hupe_aus():
    hupen_led



def main():
    fahricht_hoch = Button(26)
    fahrlicht_runter = Button(19)
    blinkschalter_links = Button(13)
    blinkschalter_rechts = Button(6)
    hupenschalter = Button(5)
    bremslichtschalter = Button(10)
    gang_hochschalter = Button(11)
    gang_runterschalter = Button(9)

    blinker_links_led3 = LED (16)
    blinker_rechts_led4 = LED (12)

    hupen_led = LED(7) 
    
    fahrlicht = PWMLED(21,initial_pwm=STUFE_ZU_PWM[led_startvalue],
        min_angle=min(STUFE_ZU_PWM),
        max_angle=max(STUFE_ZU_PWM),
    )
    
    fernlicht = PWMLED(20,initial_value = led_startvalue)

    
    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)

    fahrlicht_hoch.when_pressed = partial(shift2, fahrlicht, +1)
    fahrlicht_runter.when_pressed = partial(shift2, fahrlicht, -1)

    blinkschalter_links.when_pressed = blinker_links
    blinkschalter_rechts.wehn_pressed = blinker_rechts

    hupenschalter.when_pressed = hupe_an
    hupenschalter.when_preleased = hupe_aus
    
    pause()


if __name__ == '__main__':
    main()

anmerkung:hupe ist erstmal nur rudimentär drin, glaube die funktioniert so noch nicht, das ist aber erstmal unwichtig :-)

script gestartet und:
fehlermeldung:
>>> %Run fahrlicht+gangschaltung_1.py
Traceback (most recent call last):
File "/home/pi/python/fahrlicht+gangschaltung_1.py", line 93, in <module>
main()
File "/home/pi/python/fahrlicht+gangschaltung_1.py", line 60, in main
fahrlicht = PWMLED(21,initial_pwm=STUFE_ZU_PWM[led_startvalue],
TypeError: list indices must be integers or slices, not float
>>>

ich verstehe das so, das ich dort keine 'komma-werte'(float) eintragen darf.
wie ändere ich das bzw behebe ich den fehler -oder wie erlaube ich in der liste float-werte?

die sonst noch darin steckenden fehler (servo.angle durch led.angle ersetzt in 'def shift2' zb) hoffe ich dann später selbst weg zu bekommen, aber da steh ich grad auf den schlauch...
Sirius3
User
Beiträge: 18260
Registriert: Sonntag 21. Oktober 2012, 17:20

@geist4711: was ist der Sinn von `clamp2`? Wie unterscheidet sich diese Funktion von `clamp`?

Was soll ein Index von 0.2 denn bedeuten? Was willst Du mit der Zeile aussagen?
PWMLED hat auch kein min_angle oder max_angle-Argument.
Antworten