Jump to content

Recommended Posts

Geschrieben

Hallo

Ich habe ein Dosiersystem mit drei Peristaltikpumpen, gesteuert mit je einem Stepper Brick. Die Software ist in C/C++ geschrieben. Das Ganze funktioniert grundsätzlich. Bei folgender Problemstellung komme ich aber nicht weiter:

Wenn die Dosiervolumina sehr klein sind, drehen sich die Motoren auch entsprechend langsam. Dann würde ich gerne auf Intervallbetrieb umstellen (d.h. 1 Minute dosieren, 9 Minuten Pause, 1 Minute dosieren, 9 Minuten ....).

Hat jemand eine Idee, wie man das umsetzen kann?

Zusatzinfo:

Der TF-Stapel besteht aus Step-Down Power Supply, RED-Brick, 3 Stepper-Bricks, 3 Rotary Encoder 2.0 und 1 LCD128x64-Display.

Ein Real Time Clock Bricklet wäre vorhanden ist aber bisher nicht integriert.

Herzlichen Dank für eure Tips

Uwe

 

Geschrieben

Hallo Uwe,

ich verstehe dein Problem nicht ganz. Geht es dir um ein eine Hardwarelösung oder eine Softwarelösung?
Du könntest ja prüfen ob die Menge die benötigt wird einen Grenzwert unterschreitet und dann das takten(Intervallbetrieb) in einen Thread auslagern.

Grüße
Markus

Geschrieben

Hallo Markus.

Vielen Dank für Deine Rückmeldung. Das Problem ist, dass ich eigentlich noch Programmier-Anfänger bin. Was ich suche:

Wenn das Dosiersystem gestartet ist, brauche ich für jede Pumpe einen Timer, der sagt "Dosiere jetzt x Min, danach pausiere bitte y min". Ich weiss, dass es eine sleep-Funktion gibt. Den Begriff "Thread" habe ich zwar schon gehört, hab mich aber bisher nicht damit beschäftigt.

Mir fehlt im Moment die Idee, wie man solche Timer in C/C++ erstellt und in ein Programm einbindet (Stichwort Interrupt?)

Grüsse Uwe

Geschrieben

Da ich eigentlich so gut wie alles in Python programmiere ist meine Antwort jetzt vielleicht etwas python spezifisch. Müsste aber in C genauso möglich sein.
Es gibt hier natürlich wie immer mehrere Möglichkeiten deine Anforderung zu lösen.
Möglich wäre z.B.:
Du erstellst dir eine Klasse Dosierung wobei nun jede Pumpe eine Instanz bzw. ein Objekt der Klasse wird.
Du baust dir eine Schleife welche immer wieder alle Pumpen überprüft und führst diese regelmäßig in deinem Programm aus, ob die gewünschte Menge gefördert und die Zeit schon abgelaufen ist für das nächste Intervall.
Zum Beispiel könnte ein Attribute die Pausenzeit definieren welche bei den Intervallen eingehalten wird.
Alternativ könntest du jetzt natürlich auch einen eigenen Thread erzeugen der nur alle Pumpen prüft und diese entsprechend einstellt.
Oder du erzeugst pro Pumpe einen Thread was dann beim erzeugen der Objekte möglich ist. Würde ich bei vielen Pumpen aber eher davon abraten.

Vielleicht erklärst du mal was genau du dir schon überlegt hast?

Ein Thread ist wie ein Task den du auslagern kannst welcher unabhängig von deinem main abgearbeitet wird(parallel). Kann hilfreich sein.

Bzgl. Thread hier ein Link: https://stackoverflow.com/questions/266168/simple-example-of-threading-in-c

Sowie hier noch ein Link der dich auch interessieren könnte:

 

Geschrieben

Hallo Uwe,

das Ganze ist ja erst einmal unabhängig von der Programmiersprache.

Ich hatte eine ähnliche Problemstellung in C und das grob so gelöst.

Pro Gerät einen Thread erstellen.

Innerhalb des Threads dann per sleep die Wartezeit eingebaut. Da sleep() threatsafe ist, funktioniert das für jedes Gerät seperat.

Grüße

Jürgen

Geschrieben

Guten Morgen Jürgen.

Vielen Dank für Deine Info.

Ich habe zum Thema "Thread" mal ein Video (c++ Tutorial von Pilzschaf Nr. 68) angeschaut. Jetzt weiss ich so ungefähr, was man unter einem Thread versteht. Machen Threads auch beim "SingleCore"-Prozessor des RED-Bricks (Cortex A8) Sinn?

Meinen aktuellen Source-Code habe ich mal als Datei angehängt. Das Programm compiliert fehlerfrei und läuft auch fehlerfrei. _P202007MS02_Dosiersystem.cpp.

Allerdings tritt folgendes Problem auf:

Wenn ich eine der Pumpen im Intervall-Betrieb (LCD-Button "Inter" auf dem angehängten Bild) starte, dann macht diese Pumpe genau das, was sie soll. Das LCD ist jedoch für weitere Eingaben blockiert. Erst nach einer unreprodzierbaren Zeitspanne, sind dann plötzlich Eingaben möglich.

Die zugehörige Funktion:

/**
* Die folgende Funktion startet die Pumpe und macht die Anzahl Schritte, die übergeben wurde.
* Die Motorsteps per second werden ebenfalls zuvor berechnet und übergeben.
* Über die Callbackfunktion wird sie nach einer gewissen Zeit (Delay-Time) wieder aufgerufen.
*
*/
void PumpMotorStartIntervalMode(PeristalticPump *DummyPump)
{
/* Anfang  - Variablen lediglich zur Kontrolle und nicht für Betrieb */
    uint16_t currVel;
    int32_t currPos;
    int32_t remainSteps;
    uint16_t stackVolt;
    uint16_t externVolt;
    uint16_t currConsumpt;
    char retPos;
/* Ende Variablen zur Kontrolle */

    uint16_t DosingFactor = 1;
    uint16_t MotorSpeedmLPerHour;
    uint16_t MotorSpeedStepsPerSecond;
    uint32_t NumberOfStepsPerHour;
    uint32_t NumberOfStepsPerDosingPeriod;
    uint8_t mode = STEPPER_STEP_MODE_EIGHTH_STEP;

    DosingFactor = (DummyPump->DosingIntervalTimeMinute_Value + DummyPump->DelayIntervalTimeMinute_Value) / DummyPump->DosingIntervalTimeMinute_Value;
    NumberOfStepsPerHour =  PUMP_FULL_STEPS_PER_ROUND * mode * DummyPump->RoundsPer100mL / 100 * DummyPump->FlowMLPerHour_Value * DummyPump->CalibrationFactorPercent_Value / 100;

    NumberOfStepsPerDosingPeriod = NumberOfStepsPerHour * (DummyPump->DosingIntervalTimeMinute_Value + DummyPump->DelayIntervalTimeMinute_Value) / 60;
    MotorSpeedStepsPerSecond = NumberOfStepsPerHour / 3600 * DosingFactor;


    stepper_set_motor_current(DummyPump->pStepper, STEPPER_CURRENT);
	stepper_set_step_mode(DummyPump->pStepper, mode);
    stepper_set_max_velocity(DummyPump->pStepper, MotorSpeedStepsPerSecond);

	stepper_enable(DummyPump->pStepper);
    for (uint16_t i = 1; i < DosingFactor; ++i)
    {


    stepper_set_current_position(DummyPump->pStepper, 0);
//    stepper_drive_forward(DummyPump->pStepper);
    stepper_set_steps(DummyPump->pStepper, NumberOfStepsPerDosingPeriod);
    millisleep(DummyPump->DelayIntervalTimeMinute_Value * 6000);
    }
//    stepper_set_steps(DummyPump->pStepper, 5000);
/** Kontrollausgabe zur Überprüfung am Bildschirm */
    std::cout<< std::endl << "PumpMotorStartIntervalMode(PeristalticPump *DummyPump)\n";
    sprintf(text03, "Dos: %2d\tDel: %2d\t DF: %2d\t Steps/h: %d\t Steps/Period: %d\t, Step/sec: %d", DummyPump->DosingIntervalTimeMinute_Value,
            DummyPump->DelayIntervalTimeMinute_Value, DosingFactor, NumberOfStepsPerHour, NumberOfStepsPerDosingPeriod, MotorSpeedStepsPerSecond);
    std::cout << "text03: " << text03 << std::endl;
/* Ende Kontrollausgabe*/

}

Vielleicht liegt die Ursache des Problems aber gar nicht in der Funktion selbst, sondern in den CallBack-Einstellungen in der main():

  	lcd_128x64_register_callback(&pLCD128x64,
	                             LCD_128X64_CALLBACK_GUI_TAB_SELECTED,
	                             (void (*)(void))cb_gui_tab_selected, &ActivePump
                                );
    lcd_128x64_register_callback(&pLCD128x64,
                                 LCD_128X64_CALLBACK_GUI_BUTTON_PRESSED,
                                 (void (*)(void))cb_gui_button_pressed01, &LCDTabIndex
                                 );

    rotary_encoder_v2_register_callback(pump[0].pEncoder, ROTARY_ENCODER_V2_CALLBACK_COUNT,
                                        (void (*)(void))cb_InputEncoder, &pump[0]);
    rotary_encoder_v2_register_callback(pump[1].pEncoder, ROTARY_ENCODER_V2_CALLBACK_COUNT,
                                        (void (*)(void))cb_InputEncoder, &pump[1]);
    rotary_encoder_v2_register_callback(pump[2].pEncoder, ROTARY_ENCODER_V2_CALLBACK_COUNT,
                                        (void (*)(void))cb_InputEncoder, &pump[2]);

    rotary_encoder_v2_set_count_callback_configuration(pump[0].pEncoder, 200, true, 'x', 0, 0);
    rotary_encoder_v2_set_count_callback_configuration(pump[1].pEncoder, 200, true, 'x', 0, 0);
    rotary_encoder_v2_set_count_callback_configuration(pump[2].pEncoder, 200, true, 'x', 0, 0);

    lcd_128x64_set_gui_button_pressed_callback_configuration(&pLCD128x64, 300, true);
	lcd_128x64_set_gui_tab_selected_callback_configuration(&pLCD128x64, 300, true);

 

Noch eine Anmerkung:

Derzeit compiliere und starte ich das Programm noch auf einem Windows-PC mit Code::Blocks.

 

Herzlichen Dank für weitere Tips im Voraus.

Uwe

 

IMG_0006.jpg

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Gast
Reply to this topic...

×   Du hast formatierten Text eingefügt.   Formatierung jetzt entfernen

  Only 75 emoji are allowed.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Clear editor

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

×
×
  • Neu erstellen...