Hallo,
ich habe einen Code in Python welcher einen Stepp-motor antsteuert.
Wie kann ich diesen nun in eine Klasse packen?
Ich habe nur ganz grundlegende Python Kenntnisse..wäre das sehr
aufwending?
Gruß
1 | import machine
| 2 | import time
| 3 |
| 4 | # Definition der Pinbelegung
| 5 |
| 6 | d1 = machine.Pin(19, machine.Pin.OUT)
| 7 | d2 = machine.Pin(18, machine.Pin.OUT)
| 8 | d3 = machine.Pin(17, machine.Pin.OUT)
| 9 | d4 = machine.Pin(16, machine.Pin.OUT)
| 10 |
| 11 |
| 12 | class Stepper():
| 13 |
| 14 |
| 15 | def move(direction='counterclockwise'):
| 16 | pins=[d1,d2,d3,d4]
| 17 | if direction=='clockwise':
| 18 | pins.reverse()
| 19 |
| 20 | for steps in range(250):
| 21 | for i in pins:
| 22 | i.value(1); time.sleep(0.005); i.value(0)
| 23 | steps+=1
| 24 |
| 25 |
| 26 | move()
| 27 | move('clockwise')
|
O. A. schrieb:
> ich habe einen Code in Python welcher einen Stepp-motor antsteuert.
>
> Wie kann ich diesen nun in eine Klasse packen?
>
> Ich habe nur ganz grundlegende Python Kenntnisse..wäre das sehr
> aufwending?
Nein, überhaupt nicht. Stellt der angehängte Code deinen Versuch dar?
Ein Ansatz könnte so aussehen: (ungetestet)
1 | import machine
| 2 | import time
| 3 |
| 4 | class Stepper:
| 5 | def __init__(self, d1, d2, d3, d4):
| 6 | self.d1 = d1
| 7 | self.d2 = d2
| 8 | self.d3 = d3
| 9 | self.d4 = d4
| 10 |
| 11 | def move(self, direction='counterclockwise'):
| 12 | pins=[self.d1,self.d2,self.d3,self.d4]
| 13 | if direction=='clockwise':
| 14 | pins.reverse()
| 15 |
| 16 | for steps in range(250):
| 17 | for i in pins:
| 18 | i.value(1); time.sleep(0.005); i.value(0)
| 19 | steps+=1
| 20 |
| 21 | stepper = Stepper(machine.Pin(19, machine.Pin.OUT),
| 22 | machine.Pin(18, machine.Pin.OUT),
| 23 | machine.Pin(17, machine.Pin.OUT),
| 24 | machine.Pin(16, machine.Pin.OUT))
| 25 |
| 26 | stepper.move()
| 27 | stepper.move('clockwise')
|
Gerade vor Kurzem hatte hier jemand fast das gleiche Anliegen, da ging
es auch um Schrittmotor-Steuerung in micropython:
Beitrag "Micropython Stepper-Motor"
Dort habe ich folgenden Code für eine entsprechende
Schrittmotor-Python-Klasse gepostet, die wie ich finde bereits recht
komfortabel und konfigurierbar ist.
1 | import machine
| 2 | import time
| 3 |
| 4 | def value_with_default(value, default_value):
| 5 | return (value or default_value)
| 6 |
| 7 | class Stepper_Motor():
| 8 | def __init__(self, initial_step=None, step_time=None, steps=None, enabled=None, pin_1_id=None, pin_2_id=None, pin_3_id=None, pin_4_id=None):
| 9 | self.pin_1 = machine.Pin(value_with_default(pin_1_id, 16), machine.Pin.OUT)
| 10 | self.pin_2 = machine.Pin(value_with_default(pin_2_id, 17), machine.Pin.OUT)
| 11 | self.pin_3 = machine.Pin(value_with_default(pin_3_id, 18), machine.Pin.OUT)
| 12 | self.pin_4 = machine.Pin(value_with_default(pin_4_id, 19), machine.Pin.OUT)
| 13 | self.set_steps(steps)
| 14 | self.set_step_time(step_time)
| 15 | self.set_enabled(enabled)
| 16 | self.set_step(initial_step)
| 17 |
| 18 | def set_steps(self, steps=None):
| 19 | self.steps = value_with_default(steps, [
| 20 | [1,0,0,0],
| 21 | [1,1,0,0],
| 22 | [0,1,0,0],
| 23 | [0,1,1,0],
| 24 | [0,0,1,0],
| 25 | [0,0,1,1],
| 26 | [0,0,0,1],
| 27 | [1,0,0,1],
| 28 | ])
| 29 | self.number_of_steps = len(self.steps)
| 30 |
| 31 | def set_step_time(self, step_time=None):
| 32 | self.step_time = value_with_default(step_time, 0.005)
| 33 |
| 34 | def set_pin_states(self, pin_1_state, pin_2_state, pin_3_state, pin_4_state):
| 35 | self.pin_1.value(pin_1_state)
| 36 | self.pin_2.value(pin_2_state)
| 37 | self.pin_3.value(pin_3_state)
| 38 | self.pin_4.value(pin_4_state)
| 39 |
| 40 | def set_pins(self)
| 41 | if self.enabled:
| 42 | step_pin_states = self.steps[self.step % self.number_of_steps]
| 43 | self.set_pin_states(step_pin_states[0], step_pin_states[1], step_pin_states[2], step_pin_states[3])
| 44 | else:
| 45 | self.set_pins(0, 0, 0, 0)
| 46 |
| 47 | def set_step(self, step=None):
| 48 | self.step = value_with_default(step, 0)
| 49 | self.set_pins()
| 50 |
| 51 | def set_enabled(self, enabled=None):
| 52 | self.enabled = value_with_default(enabled, True)
| 53 | self.set_step(self.step)
| 54 |
| 55 | def move(self, number_of_steps):
| 56 | step_delta = 1
| 57 | if (number_of_steps < 0):
| 58 | step_delta = -1
| 59 | number_of_steps = -number_of_steps
| 60 | for step in range(number_of_steps):
| 61 | self.set_step(self.step + step_delta)
| 62 | time.sleep(self.step_time)
| 63 |
| 64 | def forward(self, number_of_steps=None):
| 65 | self.move(value_with_default(number_of_steps, 1))
| 66 |
| 67 | def reverse(self, number_of_steps=None):
| 68 | self.move(-value_with_default(number_of_steps, 1))
|
Mit den von Dir verwendeten Parametern/Pinbelegungen würde man die
ungefähr so benutzen:
stepper = Stepper_Motor(pin_1_id=19, pin_2_id=18, pin_3_id=17,
pin_4_id=16, step_time=0.005)
stepper.forward() # (Alternativ: stepper.move(1))
stepper.reverse() # (Alternativ: stepper.move(-1))
"value_with_default" ist die überflüssigste Utility-Funktion, die ich je
gesehen habe. Unklarer Name, und die Verwendung ist länger als das
Syntax-Konstrukt, das darin verpackt wird, jedesmal hinzuschreiben.
Sven B. schrieb:
> "value_with_default" ist die überflüssigste Utility-Funktion, die ich je
> gesehen habe. Unklarer Name, und die Verwendung ist länger als das
> Syntax-Konstrukt, das darin verpackt wird, jedesmal hinzuschreiben.
Ja, die Funktion müsste natürlich sinnvollerweise so implementiert sein: 1 | def value_with_default(value, default_value):
| 2 | return (value if (value is not None) else default_value)
|
Über den Namen kann man sich natürlich streiten. Ich persönlich finde
ihn selbsterklärend, aber wer das anders sieht, kann der Funktion durch
Suchen-und-Ersetzen natürlich gerne fix einen besseren Namen geben.
Joachim S. schrieb:
> Mit den von Dir verwendeten Parametern/Pinbelegungen würde man die
> ungefähr so benutzen:
> stepper = Stepper_Motor(pin_1_id=19, pin_2_id=18, pin_3_id=17,
> pin_4_id=16, step_time=0.005)
> stepper.forward() # (Alternativ: stepper.move(1))
> stepper.reverse() # (Alternativ: stepper.move(-1))
Vielen Dank für die Hilfe.
Ich habe es mal ausprobiert und wenn ich z.b den forward Befehl in die
Konsole eingebe bekomme ich folgende Fehlermeldung:
>>> motor.forward()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: function takes 1 positional arguments but 0 were given
Was kann ich da machen?
O. A. schrieb:
> Ich habe es mal ausprobiert und wenn ich z.b den forward Befehl in die
> Konsole eingebe bekomme ich folgende Fehlermeldung:
>
>>>> motor.forward()
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> TypeError: function takes 1 positional arguments but 0 were given
>
> Was kann ich da machen?
Schwer zu sagen, da ja leider keine Zeilennummer angegeben wird, wo der
Fehler auftreten soll. Da ich kein Micropython verwende, habe ich die
angegebene Klasse nie getestet, sondern einfach aus dem Kopf
hingeschrieben. Da kann sich leicht noch ein Fehler eingeschlichen
haben, und an mindestens einer Stelle gab es tatsächlich noch einen
Fehler, wie mir eben aufgefallen ist.
Hier daher mal eine leicht verbesserte Version - schau mal, ob der
Fehler da evtl. schon behoben ist:
1 | import machine
| 2 | import time
| 3 |
| 4 | def value_with_default(value, default_value):
| 5 | return (value if (value is not None) else default_value)
| 6 |
| 7 | class Stepper_Motor():
| 8 | def __init__(self, initial_step=None, step_time=None, steps=None, enabled=None, pin_1_id=None, pin_2_id=None, pin_3_id=None, pin_4_id=None):
| 9 | self.pin_1 = machine.Pin(value_with_default(pin_1_id, 16), machine.Pin.OUT)
| 10 | self.pin_2 = machine.Pin(value_with_default(pin_2_id, 17), machine.Pin.OUT)
| 11 | self.pin_3 = machine.Pin(value_with_default(pin_3_id, 18), machine.Pin.OUT)
| 12 | self.pin_4 = machine.Pin(value_with_default(pin_4_id, 19), machine.Pin.OUT)
| 13 | self.step = 0
| 14 | self.set_steps(steps)
| 15 | self.set_step_time(step_time)
| 16 | self.set_enabled(enabled)
| 17 | self.set_step(initial_step)
| 18 |
| 19 | def set_steps(self, steps=None):
| 20 | self.steps = value_with_default(steps, [
| 21 | [1,0,0,0],
| 22 | [1,1,0,0],
| 23 | [0,1,0,0],
| 24 | [0,1,1,0],
| 25 | [0,0,1,0],
| 26 | [0,0,1,1],
| 27 | [0,0,0,1],
| 28 | [1,0,0,1],
| 29 | ])
| 30 | self.number_of_steps = len(self.steps)
| 31 |
| 32 | def set_step_time(self, step_time=None):
| 33 | self.step_time = value_with_default(step_time, 0.005)
| 34 |
| 35 | def set_pin_states(self, pin_1_state, pin_2_state, pin_3_state, pin_4_state):
| 36 | self.pin_1.value(pin_1_state)
| 37 | self.pin_2.value(pin_2_state)
| 38 | self.pin_3.value(pin_3_state)
| 39 | self.pin_4.value(pin_4_state)
| 40 |
| 41 | def set_pins(self):
| 42 | if self.enabled:
| 43 | step_pin_states = self.steps[self.step % self.number_of_steps]
| 44 | self.set_pin_states(step_pin_states[0], step_pin_states[1], step_pin_states[2], step_pin_states[3])
| 45 | else:
| 46 | self.set_pins(0, 0, 0, 0)
| 47 |
| 48 | def set_step(self, step=None):
| 49 | self.step = value_with_default(step, 0)
| 50 | self.set_pins()
| 51 |
| 52 | def set_enabled(self, enabled=None):
| 53 | self.enabled = value_with_default(enabled, True)
| 54 | self.set_step(self.step)
| 55 |
| 56 | def move(self, number_of_steps):
| 57 | step_delta = 1
| 58 | if (number_of_steps < 0):
| 59 | step_delta = -1
| 60 | number_of_steps = -number_of_steps
| 61 | for step in range(number_of_steps):
| 62 | self.set_step(self.step + step_delta)
| 63 | time.sleep(self.step_time)
| 64 |
| 65 | def forward(self, number_of_steps=None):
| 66 | self.move(value_with_default(number_of_steps, 1))
| 67 |
| 68 | def reverse(self, number_of_steps=None):
| 69 | self.move(-value_with_default(number_of_steps, 1))
|
Joachim S. schrieb:
> def forward(self, number_of_steps=None):
> self.move(value_with_default(number_of_steps, 1))
Warum überhaupt so umständlich, und nicht einfach so?
1 | def forward(self, number_of_steps=1):
| 2 | self.move(number_of_steps)
|
Rolf M. schrieb:
> Ein Ansatz könnte so aussehen: (ungetestet)
> 1 | > stepper = Stepper(machine.Pin(19, machine.Pin.OUT),
| 2 | > machine.Pin(18, machine.Pin.OUT),
| 3 | > machine.Pin(17, machine.Pin.OUT),
| 4 | > machine.Pin(16, machine.Pin.OUT))
| 5 | >
| 6 | > stepper.move()
| 7 | > stepper.move('clockwise')
| 8 | >
|
Wie würde ich dann die Klasse in der Konsole aufrufen, bzw. mit welchem
Befehl den Motor ansteuern?
Das Programm startest du wie gewohnt in der Konsole
1 | python *Dateipfad/Datei*.py
|
O. A. schrieb:
> Wie würde ich dann die Klasse in der Konsole aufrufen, bzw. mit welchem
> Befehl den Motor ansteuern?
??
Das zitierte sind doch schon die dafür nötigen Kommandos.
Rolf M. schrieb:
> Joachim S. schrieb:
>> def forward(self, number_of_steps=None):
>> self.move(value_with_default(number_of_steps, 1))
>
> Warum überhaupt so umständlich, und nicht einfach so?
>
> 1 | > def forward(self, number_of_steps=1):
| 2 | > self.move(number_of_steps)
| 3 | >
|
Im vorliegenden Fall wäre die von dir gepostete Variante natürlich
kürzer.
Der Grund, warum ich trotzdem obige Variante genommen habe ist, dass ich
es mir einfach zur Konvention gemacht habe, in der Funktionsdeklaration
die default-Werte nicht direkt festzulegen, sondern dort None zu
notieren. So wird es m.W.n. auch in der Standard-API überwiegend
gemacht, weil die andere Variante einen kleinen Nachteil hat (siehe z.B.
hier:
https://graysonkoonce.com/always-use-none-for-default-args-in-python/ )
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|