Forum: Mikrocontroller und Digitale Elektronik STM32 Nucleo L152RE mit Servo und Schrittmotor hängt


von Florian (flo6)


Angehängte Dateien:

Lesenswert?

Ich arbeite gerade an einem Schulprojekt, bei dem ein Servo verwendet 
wird, um einen Arm in eine Position zu bringen und dann mit 
Schrittmotoren eine Pumpe zu aktivieren. Hierfür verwende ich einen 
STM32 Nucleo L152RE. Das Problem ist, dass sich das Servo in die erste 
Position bewegt, dann aber der Controller stoppt und die LED ld2 anfängt 
zu blinken und der Controller dann nicht mehr reagiert, bis ich ihn 
zurücksetze. Es muss alles richtig angeschlossen sein, da der Servo 
einmal funktioniert. Der code funktioniert problemlos wenn ich ihn 
einzeln teste, also für den Servo und den Schrittmotor.

von Daniel D. (danielduese)


Lesenswert?

Debuggen.

von Florian (flo6)


Lesenswert?

Hat leider bei mir nie funktioniert.

von J. S. (jojos)


Lesenswert?

du rufst in der ISR ein sleep_for auf, das mag das OS nicht. Das Blinken 
hat ein Muster? Mbed blink of death, über die serielle würde ein 
Fehlercode ausgegeben werden.
Dann noch Bedenken das die Taster prellen können und die ISR schnell 
mehrmals aufgerufen werden.
Schaue dir die EventQueue an, damit lassen sich die Sequenzen einfach 
realisieren. Im Event kann dann eine Pause und die nächste Aktion in die 
Q geworfen werden.

von J. S. (jojos)


Lesenswert?

Florian schrieb:
> Hat leider bei mir nie funktioniert.

in welcher Entwicklungsumgebung? Debuggen ist bei den Nucleos eigentlich 
sehr einfach, sowohl in Keil als auch in VSC.

von Florian (flo6)


Lesenswert?

J. S. schrieb:
> du rufst in der ISR ein sleep_for auf, das mag das OS nicht. Das Blinken
> hat ein Muster? Mbed blink of death, über die serielle würde ein
> Fehlercode ausgegeben werden.
> Dann noch Bedenken das die Taster prellen können und die ISR schnell
> mehrmals aufgerufen werden.
> Schaue dir die EventQueue an, damit lassen sich die Sequenzen einfach
> realisieren. Im Event kann dann eine Pause und die nächste Aktion in die
> Q geworfen werden.

wie sollte ich das sleep_for sonst machen ich brauche es ja für die 
ansteuerung des Schrittmotors.
Ja, die Led blinkt immer ca. 6 mal kurz und dann 3 mal lang.
Falls das Prellen das Problem sein sollte würde dieses Problem doch auch 
auftreten wenn ich den Code für die Servos einzeln teste.
Wo finde ich die EventQueue finjde dazu nichts.

von J. S. (jojos)


Lesenswert?

Dann verwende die Ticker Klasse für den SM. Das ist ein Timer der einen 
Callback zyklisch aufruft. Der kann immer laufen und zum Pumpe starten 
setzt du die Anzahl Schritte in einer globalen Variablen. Im callback 
wenn Schritte > 0 dann runterzählen und State setzen.

Die EventQueue ist in der API Doku, wie habt ihr die anderen Klassen 
gefunden?
Durch die Verlagerung der ISR in die Q kannst du auch printf Ausgeben 
zum Debuggen nutzen. Einfach irgendein Terminalprogramm nutzen und den 
Virtuellen COM Port vom Nucleo öffnen.

von Florian (flo6)


Lesenswert?

J. S. schrieb:
> Dann verwende die Ticker Klasse für den SM. Das ist ein Timer der
> einen
> Callback zyklisch aufruft. Der kann immer laufen und zum Pumpe starten
> setzt du die Anzahl Schritte in einer globalen Variablen. Im callback
> wenn Schritte > 0 dann runterzählen und State setzen.
>
> Die EventQueue ist in der API Doku, wie habt ihr die anderen Klassen
> gefunden?
> Durch die Verlagerung der ISR in die Q kannst du auch printf Ausgeben
> zum Debuggen nutzen. Einfach irgendein Terminalprogramm nutzen und den
> Virtuellen COM Port vom Nucleo öffnen.

Wäre es dann so richtig kann es aktuell noch nicht ausprobieren
[c] #include "mbed.h"

PwmOut servo(PC_7);
InterruptIn s1_pos1(PA_10);
InterruptIn s2_pos2(PA_6);
InterruptIn s3_pos3(PA_1);

PortOut motor(PortC, 0xf00);

int m_state[4] = {0x300, 0x700, 0xc00, 0x900};

Ticker stepperTicker;
Timer timer;

unsigned int const T_periode = 20;

volatile int steps = 0;

void moveServoToPosition(int position) {
    switch (position) {
        case 1:
            servo.pulsewidth_us(500);
            break;
        case 2:
            servo.pulsewidth_us(1500);
            break;
        case 3:
            servo.pulsewidth_us(2500);
            break;
        default:
            break;
    }
}

void stepperCallback() {
    if (steps > 0) {
        motor = m_state[3 - steps % 4];
        steps--;
    }
}

void isr_s1_pos1() {
    moveServoToPosition(1);
    steps = 100;
}

void isr_s2_pos2() {
    moveServoToPosition(2);
    steps = 100;
}

void isr_s3_pos3() {
    moveServoToPosition(3);
    steps = 100;
}

int main() {
    s1_pos1.mode(PullDown);
    s1_pos1.rise(&isr_s1_pos1);

    s2_pos2.mode(PullDown);
    s2_pos2.rise(&isr_s2_pos2);

    s3_pos3.mode(PullDown);
    s3_pos3.rise(&isr_s3_pos3);

    servo.period_ms(T_periode);

    stepperTicker.attach(&stepperCallback, 4ms);

    while (true) {
    }
}[c]

von J. S. (jojos)


Lesenswert?

ja, sieht auf den ersten Blick gut aus.

von Florian (flo6)


Lesenswert?

Der Code funktioniert gut. Nun will ich aber das nachdem die schritte 
gemacht wurden das die pumpe kurz rückwärts dreht wie kann ich dies 
umsetzen da der Controller ja anscheinend mit den sleep_fors in den ISRs 
ein Problem zu haben.

von J. S. (jojos)


Lesenswert?

Steps ist ja ein int, wenn steps==1 ist könnte man es auf -100 setzen 
und dann wieder auf 0 Zählen. Oder sauberer zwei Variablen zur Steuerung 
verwenden.
Ansonsten bleibt der Tipp mit der EventQueue, damit sind Sequenzen mit 
mehreren Schritten gut zu realisieren.

von Florian (flo6)


Lesenswert?

Hab es so versucht aber funktioniert leider nicht so.
void stepperCallback() {
    if (steps > 0) {
        motor = m_state[3 - steps % 4];
        steps--;
        if (steps == 1){
            steps = -100;
        }
    }else if (steps < 0){
        motor = m_state[3 + steps % 4];
        steps++;
    }
}

von J. S. (jojos)


Lesenswert?

[3+steps % 4] sieht nicht gut aus, rechne nochmal nach.

Und bitte die richtigen Code tags benutzen.

von J. S. (jojos)


Lesenswert?

war schon zu spät, ich habe übersehen das der Index negativ ist, die 
Rechnung sollte stimmen. Trotzdem würde das 3+/+ weglassen und die 
Elemente im m_state Array umsortieren damit die Richtung stimmt. Oder an 
der Hardware ein Spulenpaar umpolen, damit kann man auch einfach die 
Richtung umkehren. Der Index ist einfacher abs(steps) % 4.
Damit der Motor etwas ruhiger läuft kann man auch den Halbschrittbetrieb 
nutzen, dann sind es 8 Teilschritte und die Periodendauer muss halbiert 
werden.

von Florian (flo6)


Angehängte Dateien:

Lesenswert?

habe inzwischen versucht den Code zu erweitern, dabei stoße ich wieder 
auf das Problem mit der LED, dazu habe ich inzwischen auch einen Error:
1
++ MbedOS Error Info ++
2
Error Status: 0x80FF0100 Code: 256 Module: 255
3
Error Message: Fatal Run-time error
4
Location: 0x800430D
5
Error Value: 0x0
6
Current Thread: main Id: 0x20001C50 Entry: 0x8005701 StackSize: 0x1000 StackMem: 0x20000498 SP: 0x200013B4 
7
For more info, visit: https://mbed.com/s/error?error=0x80FF0100&tgt=NUCLEO_L152RE
8
-- MbedOS Error Info --
9
InterruptIn error: irq channel conflict
Der neue Code soll drei Ultraschallsensoren(HC-SR04) nutzen um zu 
erkennen ob an dieser position was sthet und in diesem fall den arm mit 
der moveServoToPosition()-Funktion dorthin bewegen.

von J. S. (jojos)


Lesenswert?

InterruptIn s4_stop(PB_0);
InterruptIn us_2_echo(PB_0);

verwenden den gleichen Pin, Kopierfehler?

von Florian (flo6)


Angehängte Dateien:

Lesenswert?

J. S. schrieb:
> InterruptIn s4_stop(PB_0);
> InterruptIn us_2_echo(PB_0);
>
> verwenden den gleichen Pin, Kopierfehler?

war tatsächlich ein kopierfehler hier nochmal die main.cpp korrgiert.
Fehler bleib der gleiche.

von J. S. (jojos)


Lesenswert?

Den crash beim InterruptIn mit gleichem Pin konnte ich reproduzieren, 
das hätte es also sein können.

Dann ist es evtl. noch ein Resourcenkonflikt das diese InterruptIn nicht 
alle zusammenspielen, mal einzelne rausnehmen. Wenn es daran liegt, dann 
einen anderen Pin verwenden.

PS:
an welcher Schule wird mit Mbed gearbeitet?

edit:
PB_10 mag nicht als InterruptIn, an meinem F407 den ich hier gerade habe 
genauso.

: Bearbeitet durch User
von Florian (flo6)


Lesenswert?

J. S. schrieb:
> Den crash beim InterruptIn mit gleichem Pin konnte ich reproduzieren,
> das hätte es also sein können.
>
> Dann ist es evtl. noch ein Resourcenkonflikt das diese InterruptIn nicht
> alle zusammenspielen, mal einzelne rausnehmen. Wenn es daran liegt, dann
> einen anderen Pin verwenden.
>
> PS:
> an welcher Schule wird mit Mbed gearbeitet?
>
> edit:
> PB_10 mag nicht als InterruptIn, an meinem F407 den ich hier gerade habe
> genauso.

Habe es jetzt mit PC_2 und PC_3 gelöst.
1
InterruptIn s1_pos1(PA_10);
2
InterruptIn s2_pos2(PA_6); 
3
InterruptIn s3_pos3(PA_1);
4
InterruptIn s4_stop(PB_0);
5
InterruptIn us_1_echo(PB_5);
6
InterruptIn us_2_echo(PC_3);
7
InterruptIn us_3_echo(PC_2);

Wir arbeiten in der Oberstufe mit Mbed.

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.