skizziks_53

Reddit synched stepper motors v1.0

Aug 15th, 2019
130
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.91 KB | None | 0 0
  1. /*
  2.   15 August 2019
  3.   Reddit - Dual simultaneous stepper motor control without a library.
  4.  
  5.   Note 1: this sketch only drives the motors at a constant speed.
  6.   Note #2: this sketch does not use delay() to operate the stepper motors at all.
  7. */
  8.  
  9. int motor_1_enable_pin = 2;
  10. int motor_1_direction_pin = 3;
  11. int motor_1_step_pin = 4;
  12.  
  13. int motor_2_enable_pin = 5;
  14. int motor_2_direction_pin = 6;
  15. int motor_2_step_pin = 7;
  16.  
  17.  
  18.  
  19. int motor_1_target_steps = 0; // This is the number of steps that you want this motor to take.
  20. int motor_2_target_steps = 0; // This is the number of steps that you want this motor to take.
  21. // This sketch doesn't really have variables or functions to set the enable and direction pins, but that part is pretty easy.
  22. int total_motor_step_time = 0; // This is the milliseconds time that both motors should complete their steps in.
  23. // ---------------- the above values need to be set before setting the value below!
  24. bool run_motors = false; // This is the variable that you set to 'true' to make the motors run.
  25.  
  26.  
  27.  
  28. bool motors_started = false; // This is a flag to make sure that all the motors start at the same time.
  29.  
  30. int motor_1_microstep_mode = 1; // Direct mode = 1. Half-step would be 2, quarter-step would be 4, etc.
  31. long motor_1_step_time = 0; // This is a milliseconds time that is computed automatically.
  32. int motor_1_step_counter = 0; // This is used for counting the steps as they are taken.
  33. int motor_1_maximum_steps_per_second = 665; // This represents ~200 RPMs, for a 1.8-degree (200-step) motor in direct step mode.
  34. int motor_1_step_state = 0;
  35. /*
  36.   I used two sets of declared variables for the stepper motors to make the sketch more obvious.
  37.   Normally I will make each named variable an array and then use a loop counter to set the step time and check each motor for stepping.
  38. */
  39. int motor_2_microstep_mode = 1; // Direct mode = 1.
  40. long motor_2_step_time = 0; // This is a milliseconds time that is computed automatically.
  41. int motor_2_step_counter = 0; // This is used for counting the steps as they are taken.
  42. int motor_2_maximum_steps_per_second = 665; // This represents ~200 RPMs, for a 1.8-degree (200-step) motor in direct step mode.
  43. int motor_2_step_state = 0;
  44.  
  45. unsigned long motor_1_begin_time = 0;
  46. unsigned long motor_1_current_time = 0;
  47. unsigned long motor_2_begin_time = 0;
  48. unsigned long motor_2_current_time = 0;
  49.  
  50.  
  51.  
  52. void setup() {
  53.   Serial.begin(9600);
  54.  
  55.   pinMode(motor_1_enable_pin, OUTPUT);
  56.   pinMode(motor_1_direction_pin, OUTPUT);
  57.   pinMode(motor_1_step_pin, OUTPUT);
  58.  
  59.   pinMode(motor_2_enable_pin, OUTPUT);
  60.   pinMode(motor_2_direction_pin, OUTPUT);
  61.   pinMode(motor_2_step_pin, OUTPUT);
  62.  
  63.   digitalWrite(motor_1_enable_pin, 1);
  64.   digitalWrite(motor_1_direction_pin, 0);
  65.   digitalWrite(motor_1_step_pin, motor_1_step_state);
  66.   digitalWrite(motor_2_enable_pin, 1);
  67.   digitalWrite(motor_2_direction_pin, 0);
  68.   digitalWrite(motor_2_step_pin, motor_2_step_state);
  69.  
  70.   Serial.println("Exiting setup()");
  71. }
  72.  
  73. void loop() {
  74.  
  75.   motor_1_target_steps = 100;
  76.   motor_2_target_steps = 300;
  77.   total_motor_step_time = 5000;
  78.  
  79.   compute_motor_step_times(); // This sets the step times of the motors. This must be called *after* all the motor target steps and total step time are set.
  80.  
  81.   run_motors = true; // Setting this to 'true' is what allows the motors to turn.
  82.  
  83.   check_stepper_motors(); // If the stepper motors need to be moved at all, this is the function that does that.
  84.  
  85.   delay(5000); // This is the only delay command used in the entire sketch.
  86. }
  87.  
  88. void compute_motor_step_times() {
  89.  
  90.   if (total_motor_step_time > 0) {
  91.     if (motor_1_microstep_mode > 0) {
  92.       if (motor_1_target_steps > 0) {
  93.         motor_1_step_time = 0;
  94.         motor_1_step_counter = 0;
  95.         // Check that the motor is not over its maximum speed limit:
  96.         int motor_steps_per_second = (int) (total_motor_step_time / 1000) / ((motor_1_target_steps * motor_1_microstep_mode) * 2);
  97.         // The above line assumes that the maximum steps per second scales with the microstep setting.
  98.         // This is generally true as long as you are not near the driver's maximum steps per second rating, which varies among different drivers.
  99.         // Stepper motor drivers can usually pulse much faster than a typical stepper motor itself can move (just due to the motor's impedance and physical inertia).
  100.         if (motor_steps_per_second <= motor_1_maximum_steps_per_second) {
  101.           motor_1_step_time = (int) total_motor_step_time / ((motor_1_target_steps * motor_1_microstep_mode) * 2);
  102.         }
  103.         else {
  104.           show_motor_1_overspeed_message();
  105.         }
  106.       }
  107.     }
  108.     if (motor_2_microstep_mode > 0) {
  109.       if (motor_2_target_steps > 0) {
  110.         motor_2_step_time = 0;
  111.         motor_2_step_counter = 0;
  112.         int motor_steps_per_second = (int) (total_motor_step_time / 1000) / ((motor_2_target_steps * motor_2_microstep_mode) * 2);
  113.         if (motor_steps_per_second <= motor_2_maximum_steps_per_second) {
  114.           motor_2_step_time = (int) total_motor_step_time / ((motor_2_target_steps * motor_2_microstep_mode) * 2);
  115.         }
  116.         else {
  117.           show_motor_2_overspeed_message();
  118.         }
  119.       }
  120.     }
  121.   }
  122. }
  123.  
  124. void show_motor_1_overspeed_message() {
  125.   // If you set this motor to a speed that was above its indicated maximum,
  126.   // then it won't turn at all and this message gets shown instead, called by compute_motor_step_times()
  127.   Serial.println("Motor #1 requested speed is too high");
  128. }
  129.  
  130. void show_motor_2_overspeed_message() {
  131.   // If you set this motor to a speed that was above its indicated maximum,
  132.   // then it won't turn at all and this message gets shown instead, called by compute_motor_step_times()
  133.   Serial.println("Motor #2 requested speed is too high");
  134. }
  135.  
  136. void check_stepper_motors() {
  137.   if (run_motors == true) {
  138.     if (look_ahead() == true) {
  139.       if (motors_started == false) {
  140.         // This section makes sure that all the motors begin with the same starting time.
  141.         Serial.println("Motors starting.");
  142.         motor_1_begin_time = millis();
  143.         motor_2_begin_time = motor_1_begin_time;
  144.         motors_started = true;
  145.       }
  146.       else { // if (motors_started == true)
  147.         if (motor_1_target_steps > 0) {
  148.           if (motor_1_step_time > 0) {
  149.             if (motor_1_step_counter < motor_1_target_steps) {
  150.               motor_1_current_time = millis();
  151.               if (motor_1_current_time >= motor_1_begin_time) {
  152.                 if (motor_1_current_time >= (motor_1_begin_time + motor_1_step_time)) {
  153.                   if (motor_1_step_state == 0) {
  154.                     motor_1_step_state = 1;
  155.                     // motor_1_step_counter += 1; // Using this line will result in the stepper motor ending with the step pin set to HIGH.
  156.                   }
  157.                   else {
  158.                     motor_1_step_state = 0;
  159.                     motor_1_step_counter += 1; // Using this line will result in the stepper motor ending with the step pin set to LOW.
  160.                     /*
  161.                       Most stepper motor drives change state when the step pin transitions from low to high.
  162.                       It may not matter either way, but I tend to prefer making sure that the step pin ends with being set to LOW.
  163.                     */
  164.                   }
  165.                   digitalWrite(motor_1_step_pin, motor_1_step_state);
  166.                   motor_1_begin_time = millis();
  167.                 }
  168.               }
  169.               else {
  170.                 // Error condition...?
  171.               }
  172.             }
  173.           }
  174.         }
  175.         if (motor_2_target_steps > 0) {
  176.           if (motor_2_step_time > 0) {
  177.             if (motor_2_step_counter < motor_2_target_steps) {
  178.               motor_2_current_time = millis();
  179.               if (motor_2_current_time >= motor_2_begin_time) {
  180.                 if (motor_2_current_time >= (motor_2_begin_time + motor_2_step_time)) {
  181.                   if (motor_2_step_state == 0) {
  182.                     motor_2_step_state = 1;
  183.                     // motor_2_step_counter += 1; // Using this line will result in the stepper motor ending with the step pin set to HIGH.
  184.                   }
  185.                   else {
  186.                     motor_2_step_state = 0;
  187.                     motor_2_step_counter += 1; // Using this line will result in the stepper motor ending with the step pin set to LOW.
  188.                   }
  189.                   digitalWrite(motor_2_step_pin, motor_2_step_state);
  190.                   motor_2_begin_time = millis();
  191.                 }
  192.               }
  193.               else {
  194.                 // Error condition...?
  195.               }
  196.             }
  197.           }
  198.         }
  199.         if (motor_1_step_counter >= motor_1_target_steps) {
  200.           if (motor_2_step_counter >= motor_2_target_steps) {
  201.             signal_motor_end();
  202.           }
  203.         }
  204.       }
  205.     }
  206.     else { // if (look_ahead() == false)
  207.       // This delay is used to make the stepping function wait until after the clock rollover,
  208.       // if there is not enough time left to complete the motor movement.
  209.       delay(1);
  210.     }
  211.   }
  212. }
  213.  
  214.  
  215. bool look_ahead() {
  216.   /*
  217.     When the millis() clock value rolls over, it messes up the motor timing as much as <2 steps.
  218.     The easiest way to avoid this error is to check the time remaining before rollover, to see that it is larger than total_motor_step_time.
  219.   */
  220.   bool function_result = false;
  221.   unsigned long time_now = millis();
  222.   unsigned long time_remaining = 4294967294 - time_now;
  223.   if (time_remaining > (total_motor_step_time * 1.1)) {
  224.     function_result = true;
  225.   }
  226.   return function_result;
  227. }
  228.  
  229. void signal_motor_end() {
  230.   // This is just a function that gets called whenever all the motors have completed.
  231.   run_motors = false;
  232.   motors_started = false;
  233.   motor_1_target_steps = 0;
  234.   motor_1_step_time = 0;
  235.   motor_2_target_steps = 0;
  236.   motor_2_step_time = 0;
  237.   total_motor_step_time = 0;
  238.   Serial.println("All motors finished.");
  239. }
  240.  
  241.  
  242. // ---- end -------
Add Comment
Please, Sign In to add comment