uwew Geschrieben December 20, 2020 at 10:05 Geschrieben December 20, 2020 at 10:05 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 Zitieren
DoIT Geschrieben December 21, 2020 at 11:38 Geschrieben December 21, 2020 at 11:38 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 Zitieren
uwew Geschrieben December 21, 2020 at 12:38 Autor Geschrieben December 21, 2020 at 12:38 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 Zitieren
DoIT Geschrieben December 21, 2020 at 13:33 Geschrieben December 21, 2020 at 13:33 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: Zitieren
uwew Geschrieben December 21, 2020 at 16:49 Autor Geschrieben December 21, 2020 at 16:49 Hallo Markus. Vielen Dank für Deine Infos. Ich schau mir die Thread-Geschichte und das Projekt mal an. Gruss Uwe Zitieren
jgmischke Geschrieben December 28, 2020 at 10:59 Geschrieben December 28, 2020 at 10:59 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 Zitieren
uwew Geschrieben December 30, 2020 at 10:20 Autor Geschrieben December 30, 2020 at 10:20 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 Zitieren
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.