Forum: Mikrocontroller und Digitale Elektronik Code in Python Klasse packen


von O. A. (sokrates1989)


Angehängte Dateien:

Lesenswert?

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')

von Rolf M. (rmagnus)


Lesenswert?

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')

von Joachim S. (oyo)


Lesenswert?

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))

von Sven B. (scummos)


Lesenswert?

"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.

von Joachim S. (oyo)


Lesenswert?

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.

von O. A. (sokrates1989)


Lesenswert?

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?

von Joachim S. (oyo)


Lesenswert?

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))

von Rolf M. (rmagnus)


Lesenswert?

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)

von O. A. (sokrates1989)


Lesenswert?

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?

von Chris M. (chris_appment)


Lesenswert?

Das Programm startest du wie gewohnt in der Konsole
1
python *Dateipfad/Datei*.py

von Rolf M. (rmagnus)


Lesenswert?

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.

von Joachim S. (oyo)


Lesenswert?

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.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.