commit 40caa8f5daa92a785f59724141c8a15ab19f7bfa Author: Clément SAILLANT Date: Mon Apr 17 17:12:03 2023 +0200 first commit diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..75c3e77 Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..89cc49c --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..080e70d --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ], + "unwantedRecommendations": [ + "ms-vscode.cpptools-extension-pack" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..36f6cb8 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "idf.flashType": "JTAG" +} \ No newline at end of file diff --git a/include/README b/include/README new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/include/README @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/lib/README b/lib/README new file mode 100644 index 0000000..6debab1 --- /dev/null +++ b/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into executable file. + +The source code of each library should be placed in a an own separate directory +("lib/your_library_name/[here are source files]"). + +For example, see a structure of the following two libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +and a contents of `src/main.c`: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +PlatformIO Library Dependency Finder will find automatically dependent +libraries scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..617b9db --- /dev/null +++ b/platformio.ini @@ -0,0 +1,38 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:esp32doit-devkit-v1] +platform = espressif32 +board = esp32doit-devkit-v1 +framework = arduino +upload_protocol = esp-prog +monitor_speed = 115200 +build_flags = -DCORE_DEBUG_LEVEL=5 +lib_deps = + https://github.com/someweisguy/esp_dmx + https://github.com/madhephaestus/ESP32Encoder + pkerspe/ESP-FlexyStepper @ ^1.4.3 + + +[env:esp32dev] +platform = espressif32 +board = esp32doit-devkit-v1 +framework = arduino +upload_protocol = esp-prog +debug_tool = esp-prog +monitor_speed = 115200 +monitor_filters = esp32_exception_decoder +debug_init_break = tbreak setup +build_type=debug +lib_deps = + https://github.com/someweisguy/esp_dmx + https://github.com/madhephaestus/ESP32Encoder + pkerspe/ESP-FlexyStepper @ ^1.4.3 + diff --git a/src/PIN_mapping.h b/src/PIN_mapping.h new file mode 100644 index 0000000..b766d91 --- /dev/null +++ b/src/PIN_mapping.h @@ -0,0 +1,32 @@ +/// ********************** PIN ASSIGNEMENTS ********************** +// DMX +const int tx_pin = 17; // define the IO pin the DMX TX pin is connected to +const int rx_pin = 16; // define the IO pin the DMX RX pin is connected to +const int rts_pin = 4; // define the IO pin the DMX RTS pin is connected to + +// capteur BCD pour adressage DMX +#define q1 21 // define the IO pin for the thumbwheel '1' is connected to +#define q2 19 // define the IO pin for the thumbwheel '2' is connected to +#define q4 18 // define the IO pin for the thumbwheel '4' is connected to +#define q8 5 // define the IO pin for the thumbwheel '8' is connected to + +// driver moteur +const int MOTOR_ENABLE_PIN = 27; // define the IO pin the motor enable pin is connected to +const int MOTOR_STEP_PIN = 26; // define the IO pin the motor step pin is connected to +const int MOTOR_DIRECTION_PIN = 25; // define the IO pin the motor direction pin is connected to +#ifndef dev_mode +const int EMERGENCY_STOP_PIN = 13; // define the IO pin the emergency stop switch is connected to +#endif +const int HOME_SWITCH_PIN = 35; // define the IO pin where the home switches are connected to (switches in series in normally closed setup against ground) +const int LIMIT_SWITCH_PIN = 34; // define the IO pin where the limit switches are connected to (switches in series in normally closed setup against ground) + +// encoder moteur pas à pas +#define EB_plus 22 // define the IO pin for the encoder B is connected to +#define EA_plus 23 // define the IO pin for the encoder A is connected to + +// potentiomètre pour le réglage des fins de course +#define home_set_pot 36 // define the IO pin for the home set potentiometer is connected to +#define limit_set_pot 39 // define the IO pin for the limit set potentiometer is connected to +#define divider_pot 100 // define the divider potentiometer value + + diff --git a/src/dmx_data.h b/src/dmx_data.h new file mode 100644 index 0000000..6399298 --- /dev/null +++ b/src/dmx_data.h @@ -0,0 +1,147 @@ +#define nb_dmx_channel 2 // nombre de canaux DMX utilisés +#define pos_array 1 // position de la position dans le tableau DMX_data +#define speed_array 2 // position de la vitesse dans le tableau DMX_data +int DMX_start_channel; // numéro de la première adresse DMX +int pos_channel; // numéro de l'adresse DMX de la position +int speed_channel; // numéro de l'adresse DMX de la vitesse +const dmx_port_t dmx_num = DMX_NUM_2; // numéro du port DMX +byte data[DMX_PACKET_SIZE]; // tableau de données DMX +bool dmxIsConnected = false; // état de la connexion DMX +unsigned long lastUpdate = millis(); // temps de la dernière mise à jour des données DMX +uint8_t DMX_data[nb_dmx_channel + 1]; // tableau de données DMX +uint8_t DMX_data_old[nb_dmx_channel + 1]; // tableau de données DMX précédentes +bool dataChanged[nb_dmx_channel + 1]; // tableau de drapeau pour donnée DMX ayant changées +unsigned long last_connected_Time = 0; // temps de la dernière connexion DMX +unsigned long last_disconnected_Time = 0; // temps de la dernière déconnexion DMX +#define DMX_Connected_Time 1000 // temps en ms entre chaque vérification de la connexion DMX +#define DMX_Read_Time 500 // temps en ms entre chaque mise à jour des données DMX +#define dmx_debounce_try 0 // nombre de boucle pour le debounce DMX afin d'éviter les valeurs de 0 ou 255 erronées +int dmx_count[nb_dmx_channel + 1]; // compteur de boucle pour le debounce DMX afin d'éviter les valeurs de 0 ou 255 erronées + +// fonction +int readSwitch(); // fonction pour lire le codeur d'adresse DMX +void reset_dmx_counter(); // fonction pour réinitialiser le compteur de boucle pour le debounce DMX afin d'éviter les valeurs de 0 ou 255 erronées +void receiveDMX(); // fonction pour recevoir les données DMX + +int readSwitch() +{ + int total = 0; + if (digitalRead(q1) == HIGH) + { + total += 1; + } + if (digitalRead(q2) == HIGH) + { + total += 2; + } + if (digitalRead(q4) == HIGH) + { + total += 4; + } + if (digitalRead(q8) == HIGH) + { + total += 8; + } + return total; +} + +void reset_dmx_counter() +{ + for (int i = 0; i < nb_dmx_channel + 1; i++) + { + dmx_count[i] = 0; + } +} + +void receiveDMX() +{ + // set channel + // #ifndef dev_mode + // DMX_start_channel = readSwitch(); + // #else + DMX_start_channel = 1; + pos_channel = DMX_start_channel; + speed_channel = DMX_start_channel + 1; + // #endif + + dmx_packet_t packet; + if (dmx_receive(dmx_num, &packet, DMX_TIMEOUT_TICK)) + { + + if (!packet.err) + { + if (!dmxIsConnected) + { + Serial.println("DMX is connected!"); + last_connected_Time = millis(); + dmxIsConnected = true; + } + dmx_read(dmx_num, data, packet.size); + // mise à jour des données DMX si elles ont changé et si le temps écoulé depuis la dernière mise à jour est supérieur à DMX_Read_Time + if (millis() - lastUpdate > DMX_Read_Time) + { + lastUpdate = millis(); // réinitialisation du temps de la dernière mise à jour des données DMX + last_connected_Time = millis(); // réinitialisation du temps de la dernière connexion DMX + // mise à jour de la position + if (DMX_data[pos_array] != data[pos_channel]) + { + if (DMX_data[pos_array] == 0 || DMX_data[pos_array] == 255) + { + dmx_count[pos_array]++; + if (dmx_count[pos_array] > dmx_debounce_try) + { + DMX_data[pos_array] = data[pos_channel]; + reset_dmx_counter(); + (dataChanged[pos_array]) = true; + } + } + else + { + DMX_data[pos_array] = data[pos_channel]; + reset_dmx_counter(); + (dataChanged[pos_array]) = true; + } + } + + // mise à jour de la vitesse + if (DMX_data[speed_array] != data[speed_channel]) + { + if (DMX_data[speed_array] == 0 || DMX_data[speed_array] == 255) + { + dmx_count[speed_array]++; + if (dmx_count[speed_array] > dmx_debounce_try) + { + DMX_data[speed_array] = data[speed_channel]; + reset_dmx_counter(); + (dataChanged[speed_array]) = true; + } + } + else + { + DMX_data[speed_array] = data[speed_channel]; + reset_dmx_counter(); + (dataChanged[speed_array]) = true; + } + } + } + } + else + { + reset_dmx_counter(); + Serial.println("A DMX error occurred."); + } + } + else if (dmxIsConnected) + { + reset_dmx_counter(); + // Serial.println("DMX was disconnected."); // affichage de la déconnexion DMX + if (millis() - last_connected_Time > DMX_Connected_Time) + { + dmxIsConnected = false; + last_disconnected_Time = millis(); // réinitialisation du temps de la dernière déconnexion DMX + Serial.println("DMX was halted."); // affichage de la déconnexion DMX + // emergencyStop = true; // arrêt du moteur en cas de déconnexion DMX + // emercency_stop_timer = millis(); // réinitialisation du timer d'arrêt d'urgence + } + } +} diff --git a/src/limit.h b/src/limit.h new file mode 100644 index 0000000..136a878 --- /dev/null +++ b/src/limit.h @@ -0,0 +1,59 @@ + +// ********************** variables for software debouncing of the limit switches ********************** +#define switch_active 1 // active low switch configuration (NO connection with internal pull up) or HIGH for active high switch configuration (NC connection with internal pull up) + +volatile unsigned long lastDebounceTime = 0; // the last time the limit switch input pin was toggled +volatile unsigned long debounceDelay = 250; // the minimum delay in milliseconds to check for bouncing of the switch. Increase this slighlty if you switches tend to bounce a lot +bool buttonStateChangeDetected = false; // flag to indicate that the button state has changed +volatile byte limitSwitchState = !switch_active; // the current reading from the limit switch input pin +byte ConfirmedLimitSwitchState = !switch_active; // the last confirmed reading from the limit switch input pin +volatile byte homeSwitchState = !switch_active; // the current reading from the home switch input pin +byte ConfirmedHomeSwitchState = !switch_active; // the last confirmed reading from the home switch input pin + +volatile int home_steps = 15; // nombre de pas pour bien positionner le moteur à la position de départ +volatile int limit_steps = 105; // nombre de pas pour bien positionner le moteur à la position de fin + +void homeReachedCallback() +{ + Serial.println("Home reached"); +} + +void limitReachedCallback() +{ + Serial.println("Limit reached"); +} + +void IRAM_ATTR limitSwitchHandler() // interrupt handler for the limit switch +{ + lastDebounceTime = millis(); + limitSwitchState = digitalRead(LIMIT_SWITCH_PIN); +} + +void IRAM_ATTR homeSwitchHandler() // interrupt handler for the home switch +{ + lastDebounceTime = millis(); + homeSwitchState = digitalRead(HOME_SWITCH_PIN); +} + +void limit_sw_check() // fonction pour la sécurité si une limite est détectée par le bouton poussoir +{ + + if (limitSwitchState != ConfirmedLimitSwitchState && (millis() - lastDebounceTime) > debounceDelay) + { + ConfirmedLimitSwitchState = limitSwitchState; + Serial.printf("Limit switch change detected. New state is %i\n", limitSwitchState); + Serial.printf("Limit setting is %i\n", limit_steps); + buttonStateChangeDetected = true; + } +} + +void home_sw_check() // fonction pour la sécurité si une limite est détectée par le bouton poussoir +{ + if (homeSwitchState != ConfirmedHomeSwitchState && (millis() - lastDebounceTime) > debounceDelay) + { + ConfirmedHomeSwitchState = homeSwitchState; + Serial.printf("Home switch change detected. New state is %i\n", homeSwitchState); + Serial.printf("Home setting is %i\n", home_steps); + buttonStateChangeDetected = true; + } +} diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..c8e17c9 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,165 @@ + +/* + +TESTER AVEC LIB : https://github.com/Valar-Systems/FastAccelStepper-ESP32 ??? + +controle de moteur pas à pas selon commande DMX + +code par Clément SAILLANT pour Hémisphère - 2023 +c.saillant@gmail.com +0625334420 + +Un canal DMX est utilisé pour la commande de la position du moteur +Un autre canal DMX est utilisé pour la commande de la vitesse du moteur +Une fonction affine est utilisée pour convertir la valeur DMX en position ou vitesse +La position et la vitesse sont stockées dans des variables globales +Une fonction est utilisée pour la sécurité si un obstacle est détecté par la perte de pas du moteur + +moteur : 34HS59-6004D-E1000 +Angle de pas: 1.8 deg +Résolution de l'encodeur: 1000PPR(4000CPR) +https://www.omc-stepperonline.com/download/34HS59-6004D-E1000_Torque_Curve.pdf +https://www.omc-stepperonline.com/download/34HS59-6004D-E1000.pdf + +Controleur CL86T V4.0 +https://www.omc-stepperonline.com/index.php?route=product/product/get_file&file=389/CL86T%20(V4.0).pdf + +SW1 0 +SW2 0 +SW3 1 +SW4 1 + +SW5 On CCW +SW6 Off Close loop +SW7 Off Pul/Dir +SW8 Off Brk +*/ + +// #define dev_mode // mode developpeur + +#include "PIN_mapping.h" // fichier contenant les variables globales et le mapping des pins +bool emergencyStop = false; // variable pour stocker l'état de l'arrêt d'urgence + +#include +// #include +// #include "esp_attr.h" + +#include +// #include "esp_task_wdt.h" // librairie pour le watchdog +#include // librairie pour le controle des moteurs pas à pas +#include // librairie pour le controle des encodeurs + +ESP_FlexyStepper stepper; // création de l'ojet motor +ESP32Encoder encoder; // création de l'objet encoder + +#include "limit.h" // fichier contenant les fonctions de limites +#include "dmx_data.h" // fichier contenant les fonctions dmx +#include "moving.h" // fichier contenant les fonctions de mouvement +#include "security.h" // fichier contenant les fonctions de sécurité type emergency stop + +void setup() +{ + delay(1000); + Serial.begin(115200); + Serial.println("started"); + + // configuration DMX + dmx_set_pin(dmx_num, tx_pin, rx_pin, rts_pin); + dmx_driver_install(dmx_num, DMX_DEFAULT_INTR_FLAGS); + + // configuration encoder pour suivre la position du moteur et la perte de pas + encoder.attachHalfQuad(EB_plus, EA_plus); + encoder.setCount(0); + + // configuration ENABLE motor + pinMode(MOTOR_ENABLE_PIN, OUTPUT); + // configuration BCD Coder + pinMode(q1, INPUT); // thumbwheel '1' + pinMode(q2, INPUT); // thumbwheel '2' + pinMode(q4, INPUT); // thumbwheel '4' + pinMode(q8, INPUT); // thumbwheel '8' + + /* + #ifndef dev_mode + // attach an interrupt to the IO pin of the ermegency stop switch and specify the handler function + pinMode(EMERGENCY_STOP_PIN, INPUT_PULLUP); + + attachInterrupt(digitalPinToInterrupt(EMERGENCY_STOP_PIN), emergencySwitchHandler, RISING); + #endif + */ + pinMode(MOTOR_ENABLE_PIN, OUTPUT); + pinMode(LIMIT_SWITCH_PIN, INPUT); + pinMode(HOME_SWITCH_PIN, INPUT); + + + // ???????????????? Error : attachInterrupt with ADC enabled :'( ???????????????? + + // attach an interrupt to the IO pin of the home switch and specify the handler function + attachInterrupt(digitalPinToInterrupt(HOME_SWITCH_PIN), homeSwitchHandler, CHANGE); + stepper.registerHomeReachedCallback(homeReachedCallback); + + // attach an interrupt to the IO pin of the limit switch and specify the handler function + attachInterrupt(digitalPinToInterrupt(LIMIT_SWITCH_PIN), limitSwitchHandler, CHANGE); + stepper.registerLimitReachedCallback(limitReachedCallback); + + // connect and configure the stepper motor to its IO pins + stepper.connectToPins(MOTOR_STEP_PIN, MOTOR_DIRECTION_PIN); + // set the speed and acceleration rates for the stepper motor + stepper.setSpeedInStepsPerSecond(SPEED_IN_STEPS_PER_SECOND); + stepper.setAccelerationInStepsPerSecondPerSecond(ACCELERATION_IN_STEPS_PER_SECOND); + stepper.setDecelerationInStepsPerSecondPerSecond(DECELERATION_IN_STEPS_PER_SECOND); + stepper.setStepsPerRevolution(STEP_PER_REV); + stepper.registerTargetPositionReachedCallback(targetPositionReachedCallback); + + // start the stepper instance as a service in the "background" as a separate task + stepper.startAsService(); // at core 1 + + init_range(); // set home and limit position of the motor + + Serial.print("number of tasks is "); + Serial.println(uxTaskGetNumberOfTasks()); + Serial.print("home position is "); + Serial.println(min_steps); + Serial.print("limit position is "); + Serial.println(max_steps); + Serial.println("----------------------------------------"); +} + +void loop() +{ + receiveDMX(); // reception des données DMX + + // mise à jour de la vitesse du moteur si la valeur DMX a changé + if (dataChanged[speed_array]) + { + dataChanged[speed_array] = false; + Serial.printf("dmx speed receive => %ld\n", DMX_data[speed_array]); + speed_map(); // fonction pour convertir la valeur DMX en vitesse/acceleration/deceleration + } + + // mise à jour de la position du moteur si la valeur DMX a changée + if (dataChanged[pos_channel] == true && emergencyStop == false) + { + // stepper.setTargetPositionToStop(); + dataChanged[pos_channel] = false; + int pos_in_step = map(DMX_data[pos_array], 0, 255, min_steps, max_steps); + + // adaptation de la vitesse d'acceleration en fonction de la distance à parcourir + if (abs(DMX_data_old[pos_array] - DMX_data[pos_array]) < 25) + { + speed_in_accel = 50; + } + else + { + speed_in_accel = 500; + } + stepper.setAccelerationInStepsPerSecondPerSecond(speed_in_accel); + stepper.setTargetPositionInSteps(pos_in_step); + Serial.printf("dmx pos to step => %ld\n", pos_in_step); + DMX_data_old[pos_array] = DMX_data[pos_array]; + } + + // motor_follower(emergency_stop_loss_step); // fonction pour suivre la position du moteur et la perte de pas + emergency_check(); // fonction pour la sécurité si un obstacle est détecté par la perte de pas du moteur + limit_check(); // fonction pour la sécurité si un obstacle est détecté par le bouton poussoir +} \ No newline at end of file diff --git a/src/main.cpp.test b/src/main.cpp.test new file mode 100644 index 0000000..9f608e7 --- /dev/null +++ b/src/main.cpp.test @@ -0,0 +1,15 @@ +#include +const int MOTOR_ENABLE_PIN = 27; + +void setup() +{ + pinMode(MOTOR_ENABLE_PIN, OUTPUT); +} + +void loop() +{ + digitalWrite(MOTOR_ENABLE_PIN, HIGH); // disable and free motor + delay(500); + digitalWrite(MOTOR_ENABLE_PIN, LOW); // enable motor + delay(500); +} \ No newline at end of file diff --git a/src/moving.h b/src/moving.h new file mode 100644 index 0000000..702942b --- /dev/null +++ b/src/moving.h @@ -0,0 +1,132 @@ +#define STEP_PER_REV 3200 // nombre de pas par tour du moteur + +const int MIN_SPEED[3] = {0, 0, 0}; // vitesse, acceleration et deceleration minimum du moteur +const int MAX_SPEED[3] = {1000, 5000, 5000}; // vitesse, acceleration et deceleration maximum du moteur +const int SPEED_IN_STEPS_PER_SECOND = 500; // vitesse de déplacement du moteur +const int ACCELERATION_IN_STEPS_PER_SECOND = 500; // accélération du moteur +const int DECELERATION_IN_STEPS_PER_SECOND = 100; // décélération du moteur +int min_steps = 0; // position de départ du moteur +int max_steps = 1600; // position de fin du moteur + +volatile int speed_in_accel = 100; +volatile int speed_in_decel = 100; + +// fonction +void targetPositionReachedCallback(long position); // callback function as the target position is reached +// void limitSwitchHandler(); // interrupt handler for the limit switch +// void homeSwitchHandler(); // interrupt handler for the home switch +void speed_map(); // fonction de mapping de la vitesse du moteur avec accélération et décélération +void pos_map(); // fonction de mapping de la position du moteur +void set_min(); // fonction pour position minimum de la plage de déplacement du moteur +void set_max(); // fonction pour position maximum de la plage de déplacement du moteurF +void init_range(); // fonction d'initialisation de la plage de déplacement du moteur + +void targetPositionReachedCallback(long position) // callback function as the target position is reached +{ + Serial.printf("Stepper reached target position %ld\n", position); + Serial.printf("Encoder count is %ld\n", encoder.getCount()); +} + +// fonction de mapping de la vitesse du moteur avec accélération et décélération +void speed_map() // fonction de mapping de la vitesse du moteur avec accélération et décélération +{ + int speed_in_step = map(DMX_data[speed_array], 0, 255, MIN_SPEED[0], MAX_SPEED[0]); + // int speed_in_accel = map(DMX_data[speed_array], 0, 255, MIN_SPEED[1], MAX_SPEED[1]); + // int speed_in_decel = map(DMX_data[speed_array], 0, 255, MIN_SPEED[2], MAX_SPEED[2]); + stepper.setSpeedInStepsPerSecond(speed_in_step); + // set the speed and acceleration rates for the stepper motor + stepper.setAccelerationInStepsPerSecondPerSecond(speed_in_accel); + stepper.setDecelerationInStepsPerSecondPerSecond(speed_in_decel); +} + +void pos_map() // fonction de mapping de la position du moteur +{ + int pos_in_step = map(DMX_data[pos_array], 0, 255, min_steps, max_steps); + stepper.setTargetPositionInSteps(pos_in_step); +} + +void set_min() // fonction pour position minimum de la plage de déplacement du moteur +{ + min_steps = stepper.getCurrentPositionInSteps() - home_steps; + encoder.setCount(0); // remise à zéro de l'encodeur +} + +void set_max() // fonction pour position maximum de la plage de déplacement du moteur +{ + max_steps = stepper.getCurrentPositionInSteps() + limit_steps; +} + +void init_range() // fonction d'initialisation de la plage de déplacement du moteur +{ +#ifndef dev_mode + int direction = -1; + bool limit_OK = false; + int position_limit = 500; + Serial.println("starting homing"); + // delay(2000); + digitalWrite(MOTOR_ENABLE_PIN, LOW); // enable motor + stepper.setDirectionToHome(direction); + if (digitalRead(HOME_SWITCH_PIN) == switch_active) // si position est déjà à home + { + Serial.println("already in home position"); + stepper.setCurrentPositionAsHomeAndStop(); // set the current position as the home position and stop the stepper + stepper.setTargetPositionInSteps(position_limit); + delay(2000); + } + stepper.goToLimitAndSetAsHome(); // go to the limit switch and set the current position as the home position + + while (!limit_OK) + { + home_sw_check(); + if (ConfirmedHomeSwitchState == switch_active) + { + stepper.setLimitSwitchActive(stepper.LIMIT_SWITCH_BEGIN); // this will cause to stop any motion that is currently going on and block further movement in the same direction as long as the switch is active + stepper.setTargetPositionToStop(); + limit_OK = true; + } + else + { + stepper.clearLimitSwitchActive(); // clear the limit switch flag to allow movement in both directions again + } + } + + stepper.setCurrentPositionAsHomeAndStop(); // set the current position as the home position and stop the stepper + set_min(); + encoder.setCount(0); // remise à zéro de l'encodeur + Serial.println("home OK"); + stepper.clearLimitSwitchActive(); // clear the limit switch flag to allow movement in both directions again + limit_OK = false; + position_limit = 0; + Serial.println("waiting for limit switch"); + stepper.setTargetPositionInSteps(160); + while (!limit_OK) + { + limit_sw_check(); + if (ConfirmedLimitSwitchState == switch_active) + { + stepper.setLimitSwitchActive(stepper.LIMIT_SWITCH_END); // this will cause to stop any motion that is currently going on and block further movement in the same direction as long as the switch is active + stepper.setTargetPositionToStop(); + limit_OK = true; + } + else + { + stepper.clearLimitSwitchActive(); // clear the limit switch flag to allow movement in both directions again + if (stepper.getCurrentPositionInSteps() < 1350) + { + position_limit = stepper.getCurrentPositionInSteps() + 200; + } + else + { + position_limit = stepper.getCurrentPositionInSteps() + 5; + } + stepper.setTargetPositionInSteps(position_limit); + } + } + Serial.println("limit init OK"); + stepper.setTargetPositionToStop(); + set_max(); + stepper.clearLimitSwitchActive(); // clear the limit switch flag to allow movement in both directions again + stepper.setTargetPositionInSteps(max_steps / 2); + delay(2000); +#endif +} \ No newline at end of file diff --git a/src/notepad.txt b/src/notepad.txt new file mode 100644 index 0000000..3914abe --- /dev/null +++ b/src/notepad.txt @@ -0,0 +1,8 @@ +https://github.com/arttupii/CLSMB Closed loop step motor controller + +https://www.switchdoc.com/2018/04/esp32-tutorial-debouncing-a-button-press-using-interrupts/ +avec vtask pour plus d'efficacité + +voir pour mieur gérer le homming avec les fonctions explicité dans la lib felxystepper + +rajouter plus de délai à la lecture dmx pour mieux éviter les problème de chanement de valeurs trop rapide \ No newline at end of file diff --git a/src/security.h b/src/security.h new file mode 100644 index 0000000..06f4fed --- /dev/null +++ b/src/security.h @@ -0,0 +1,148 @@ + +#define emergency_stop_bounce_time 1000 // time in ms to wait before disabling the motor in emergency when step as been lost +#define emergency_release_time 2000 // time in ms to wait before releasing the emergency stop +#define emergency_stop_loss_step 5 // number of step to wait before disabling the motor in emergency when step as been lost +unsigned long emercency_stop_timer; // temps en ms depuis lequel le moteur est en arrêt d'urgence +unsigned long lastStepTime; // variable pour stocker le temps de la dernière mise à jour des données encoder +long old_count; // variable des précedentes données de l'encoder +long newPosition; // variable des données de l'encoder + +// fonction : +void motor_follower(int loss_step); // fonction pour suivre la position du moteur et la perte de pas +void emergency_check(); // fonction pour la sécurité si un obstacle est détecté par la perte de pas du moteur +void limit_check(); // fonction pour la sécurité si une limite est détectée par le bouton poussoir + +#ifndef dev_mode +/* +void IRAM_ATTR emergencySwitchHandler() // interrupt handler for the emergency stop switch +{ + + // we do not realy need to debounce here, since we only want to trigger a stop, no matter what. + // So even triggering mutliple times does not realy matter at the end + if (digitalRead(EMERGENCY_STOP_PIN) == LOW) // Switch is configured in active low configuration + { + // the boolean true in the following command tells the stepper to hold the emergency stop until reaseEmergencyStop() is called explicitly. + // If ommitted or "false" is given, the function call would only stop the current motion and then instanlty would allow for new motion commands to be accepted + stepper.emergencyStop(true); + } + else + { + // release a previously enganed emergency stop when the emergency stop button is released + stepper.releaseEmergencyStop(); + } + +} + */ +#endif + +void motor_follower(int loss_step) // fonction pour suivre la position du moteur et la perte de pas +{ + // Quand le moteur est en mouvement, on vérifie si la position a changé de plus de 5 pas + // mise à jour de la position de l'encodeur + newPosition = encoder.getCount(); + if (stepper.getDirectionOfMotion() != 0) + { + // Serial.printf("new position is %ld\n", newPosition); + if (newPosition > old_count || newPosition < old_count) + { + lastStepTime = millis(); + emergencyStop = false; + } + if (newPosition >= old_count + loss_step || newPosition <= old_count - loss_step) + { + // Serial.printf("new position => %ld\n", newPosition); + // Serial.printf("old position => %ld\n", old_count); + old_count = newPosition; + } + // dans le else : newPosition == old_count && + else if (millis() - lastStepTime > emergency_stop_bounce_time / (DMX_data[speed_array] + 1) && emergencyStop == false) + { + Serial.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!! emergency stop"); + stepper.setTargetPositionToStop(); + emercency_stop_timer = millis(); + emergencyStop = true; + } + } +} + +void emergency_check() // fonction pour la sécurité si un obstacle est détecté par la perte de pas du moteur +{ + if (emergencyStop) + { + if (millis() - emercency_stop_timer > emergency_release_time && emergencyStop == true) + { + digitalWrite(MOTOR_ENABLE_PIN, LOW); // enable motor + Serial.println("======================> emergency stop released"); + emergencyStop = false; + } + else if (digitalRead(MOTOR_ENABLE_PIN) == LOW && emergencyStop == true) + { + Serial.println("======================> emergency stop engaged"); + digitalWrite(MOTOR_ENABLE_PIN, HIGH); // disable and free motor + } + } +} + +void limit_check() // fonction pour la sécurité si une limite est détectée par le bouton poussoir +{ + const int limit_step_lost = 5; + limit_sw_check(); + home_sw_check(); + // active high switch configuration (NC connection with internal pull up) + if (limitSwitchState == switch_active && buttonStateChangeDetected == true) + { + buttonStateChangeDetected = false; + // limit_step = analogRead(limit_set_pot) / divider_pot; + ConfirmedLimitSwitchState = limitSwitchState; + Serial.printf("Limit switch change detected. New state is %i\n", limitSwitchState); + Serial.printf("Limit setting is %i\n", limit_steps); + // set_max(); + motor_follower(limit_step_lost); + if (emergencyStop) + { + stepper.setLimitSwitchActive(stepper.LIMIT_SWITCH_END); // this will cause to stop any motion that is currently going on and block further movement in the same direction as long as the switch is agtive + } + else + { + stepper.setTargetPositionInSteps(max_steps + limit_steps); + Serial.printf("go to Limit set : %i\n", max_steps + limit_steps); + } + } + else if (buttonStateChangeDetected == true) + { + buttonStateChangeDetected = false; + } + else + { + stepper.clearLimitSwitchActive(); // clear the limit switch flag to allow movement in both directions again + } + + if (homeSwitchState == switch_active && buttonStateChangeDetected == true) + { + buttonStateChangeDetected = false; + // home_step = analogRead(home_set_pot) / divider_pot; + ConfirmedHomeSwitchState = homeSwitchState; + Serial.printf("Home switch change detected. New state is %i\n", homeSwitchState); + Serial.printf("Home setting is %i\n", home_steps); + stepper.setCurrentPositionAsHomeAndStop(); // set the current position as the home position and stop the stepper + // set_min(); + motor_follower(limit_step_lost); + if (emergencyStop) + { + stepper.setLimitSwitchActive(stepper.LIMIT_SWITCH_BEGIN); // this will cause to stop any motion that is currently going on and block further movement in the same direction as long as the switch is agtive + } + else + { + stepper.setTargetPositionInSteps(min_steps - home_steps); + Serial.printf("go to Home set : %i\n", min_steps - home_steps); + } + } + else if (buttonStateChangeDetected == true) + { + buttonStateChangeDetected = false; + } + else + { + stepper.clearLimitSwitchActive(); // clear the limit switch flag to allow movement in both directions again + } +} diff --git a/test/README b/test/README new file mode 100644 index 0000000..9b1e87b --- /dev/null +++ b/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Test Runner and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html