Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- 15 August 2019
- Reddit - Dual simultaneous stepper motor control without a library.
- Note 1: this sketch only drives the motors at a constant speed.
- Note #2: this sketch does not use delay() to operate the stepper motors at all.
- */
- int motor_1_enable_pin = 2;
- int motor_1_direction_pin = 3;
- int motor_1_step_pin = 4;
- int motor_2_enable_pin = 5;
- int motor_2_direction_pin = 6;
- int motor_2_step_pin = 7;
- int motor_1_target_steps = 0; // This is the number of steps that you want this motor to take.
- int motor_2_target_steps = 0; // This is the number of steps that you want this motor to take.
- // This sketch doesn't really have variables or functions to set the enable and direction pins, but that part is pretty easy.
- int total_motor_step_time = 0; // This is the milliseconds time that both motors should complete their steps in.
- // ---------------- the above values need to be set before setting the value below!
- bool run_motors = false; // This is the variable that you set to 'true' to make the motors run.
- bool motors_started = false; // This is a flag to make sure that all the motors start at the same time.
- int motor_1_microstep_mode = 1; // Direct mode = 1. Half-step would be 2, quarter-step would be 4, etc.
- long motor_1_step_time = 0; // This is a milliseconds time that is computed automatically.
- int motor_1_step_counter = 0; // This is used for counting the steps as they are taken.
- int motor_1_maximum_steps_per_second = 665; // This represents ~200 RPMs, for a 1.8-degree (200-step) motor in direct step mode.
- int motor_1_step_state = 0;
- /*
- I used two sets of declared variables for the stepper motors to make the sketch more obvious.
- 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.
- */
- int motor_2_microstep_mode = 1; // Direct mode = 1.
- long motor_2_step_time = 0; // This is a milliseconds time that is computed automatically.
- int motor_2_step_counter = 0; // This is used for counting the steps as they are taken.
- int motor_2_maximum_steps_per_second = 665; // This represents ~200 RPMs, for a 1.8-degree (200-step) motor in direct step mode.
- int motor_2_step_state = 0;
- unsigned long motor_1_begin_time = 0;
- unsigned long motor_1_current_time = 0;
- unsigned long motor_2_begin_time = 0;
- unsigned long motor_2_current_time = 0;
- void setup() {
- Serial.begin(9600);
- pinMode(motor_1_enable_pin, OUTPUT);
- pinMode(motor_1_direction_pin, OUTPUT);
- pinMode(motor_1_step_pin, OUTPUT);
- pinMode(motor_2_enable_pin, OUTPUT);
- pinMode(motor_2_direction_pin, OUTPUT);
- pinMode(motor_2_step_pin, OUTPUT);
- digitalWrite(motor_1_enable_pin, 1);
- digitalWrite(motor_1_direction_pin, 0);
- digitalWrite(motor_1_step_pin, motor_1_step_state);
- digitalWrite(motor_2_enable_pin, 1);
- digitalWrite(motor_2_direction_pin, 0);
- digitalWrite(motor_2_step_pin, motor_2_step_state);
- Serial.println("Exiting setup()");
- }
- void loop() {
- motor_1_target_steps = 100;
- motor_2_target_steps = 300;
- total_motor_step_time = 5000;
- 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.
- run_motors = true; // Setting this to 'true' is what allows the motors to turn.
- check_stepper_motors(); // If the stepper motors need to be moved at all, this is the function that does that.
- delay(5000); // This is the only delay command used in the entire sketch.
- }
- void compute_motor_step_times() {
- if (total_motor_step_time > 0) {
- if (motor_1_microstep_mode > 0) {
- if (motor_1_target_steps > 0) {
- motor_1_step_time = 0;
- motor_1_step_counter = 0;
- // Check that the motor is not over its maximum speed limit:
- int motor_steps_per_second = (int) (total_motor_step_time / 1000) / ((motor_1_target_steps * motor_1_microstep_mode) * 2);
- // The above line assumes that the maximum steps per second scales with the microstep setting.
- // This is generally true as long as you are not near the driver's maximum steps per second rating, which varies among different drivers.
- // 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).
- if (motor_steps_per_second <= motor_1_maximum_steps_per_second) {
- motor_1_step_time = (int) total_motor_step_time / ((motor_1_target_steps * motor_1_microstep_mode) * 2);
- }
- else {
- show_motor_1_overspeed_message();
- }
- }
- }
- if (motor_2_microstep_mode > 0) {
- if (motor_2_target_steps > 0) {
- motor_2_step_time = 0;
- motor_2_step_counter = 0;
- int motor_steps_per_second = (int) (total_motor_step_time / 1000) / ((motor_2_target_steps * motor_2_microstep_mode) * 2);
- if (motor_steps_per_second <= motor_2_maximum_steps_per_second) {
- motor_2_step_time = (int) total_motor_step_time / ((motor_2_target_steps * motor_2_microstep_mode) * 2);
- }
- else {
- show_motor_2_overspeed_message();
- }
- }
- }
- }
- }
- void show_motor_1_overspeed_message() {
- // If you set this motor to a speed that was above its indicated maximum,
- // then it won't turn at all and this message gets shown instead, called by compute_motor_step_times()
- Serial.println("Motor #1 requested speed is too high");
- }
- void show_motor_2_overspeed_message() {
- // If you set this motor to a speed that was above its indicated maximum,
- // then it won't turn at all and this message gets shown instead, called by compute_motor_step_times()
- Serial.println("Motor #2 requested speed is too high");
- }
- void check_stepper_motors() {
- if (run_motors == true) {
- if (look_ahead() == true) {
- if (motors_started == false) {
- // This section makes sure that all the motors begin with the same starting time.
- Serial.println("Motors starting.");
- motor_1_begin_time = millis();
- motor_2_begin_time = motor_1_begin_time;
- motors_started = true;
- }
- else { // if (motors_started == true)
- if (motor_1_target_steps > 0) {
- if (motor_1_step_time > 0) {
- if (motor_1_step_counter < motor_1_target_steps) {
- motor_1_current_time = millis();
- if (motor_1_current_time >= motor_1_begin_time) {
- if (motor_1_current_time >= (motor_1_begin_time + motor_1_step_time)) {
- if (motor_1_step_state == 0) {
- motor_1_step_state = 1;
- // motor_1_step_counter += 1; // Using this line will result in the stepper motor ending with the step pin set to HIGH.
- }
- else {
- motor_1_step_state = 0;
- motor_1_step_counter += 1; // Using this line will result in the stepper motor ending with the step pin set to LOW.
- /*
- Most stepper motor drives change state when the step pin transitions from low to high.
- It may not matter either way, but I tend to prefer making sure that the step pin ends with being set to LOW.
- */
- }
- digitalWrite(motor_1_step_pin, motor_1_step_state);
- motor_1_begin_time = millis();
- }
- }
- else {
- // Error condition...?
- }
- }
- }
- }
- if (motor_2_target_steps > 0) {
- if (motor_2_step_time > 0) {
- if (motor_2_step_counter < motor_2_target_steps) {
- motor_2_current_time = millis();
- if (motor_2_current_time >= motor_2_begin_time) {
- if (motor_2_current_time >= (motor_2_begin_time + motor_2_step_time)) {
- if (motor_2_step_state == 0) {
- motor_2_step_state = 1;
- // motor_2_step_counter += 1; // Using this line will result in the stepper motor ending with the step pin set to HIGH.
- }
- else {
- motor_2_step_state = 0;
- motor_2_step_counter += 1; // Using this line will result in the stepper motor ending with the step pin set to LOW.
- }
- digitalWrite(motor_2_step_pin, motor_2_step_state);
- motor_2_begin_time = millis();
- }
- }
- else {
- // Error condition...?
- }
- }
- }
- }
- if (motor_1_step_counter >= motor_1_target_steps) {
- if (motor_2_step_counter >= motor_2_target_steps) {
- signal_motor_end();
- }
- }
- }
- }
- else { // if (look_ahead() == false)
- // This delay is used to make the stepping function wait until after the clock rollover,
- // if there is not enough time left to complete the motor movement.
- delay(1);
- }
- }
- }
- bool look_ahead() {
- /*
- When the millis() clock value rolls over, it messes up the motor timing as much as <2 steps.
- 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.
- */
- bool function_result = false;
- unsigned long time_now = millis();
- unsigned long time_remaining = 4294967294 - time_now;
- if (time_remaining > (total_motor_step_time * 1.1)) {
- function_result = true;
- }
- return function_result;
- }
- void signal_motor_end() {
- // This is just a function that gets called whenever all the motors have completed.
- run_motors = false;
- motors_started = false;
- motor_1_target_steps = 0;
- motor_1_step_time = 0;
- motor_2_target_steps = 0;
- motor_2_step_time = 0;
- total_motor_step_time = 0;
- Serial.println("All motors finished.");
- }
- // ---- end -------
Add Comment
Please, Sign In to add comment