void manualControl()
{
if (manual == true)
{
BUTTONstate1 = digitalRead(BUTTON1);//read the button1 state
if (BUTTONstate1 == LOW)// if the button is press
{
runallowed = true; // enable the motor outputs. It can enter the runthemotor() function
stepper.setMaxSpeed(400);
stepper.setAcceleration(800);
RotateCounter++;
directionMultiplier = 1; //We define the direction
stepper.moveTo(directionMultiplier * RotateCounter);
}else{
stepper.disableOutputs();
}
BUTTONstate2 = digitalRead(BUTTON2);//read the button2 state
if (BUTTONstate2 == LOW)//is the button is press
{
runallowed = true;// enable the motor outputs. It can enter the runthemotor() function
stepper.setMaxSpeed(400);
stepper.setAcceleration(800);
directionMultiplier = -1; //We define the direction
RotateCounter++;
stepper.moveTo(directionMultiplier * RotateCounter);
}else{
stepper.disableOutputs();
}
}
}
here is the program I use to manually control the stepper motor by using the press button. I have to take a trial today to control it. The stepper motor has a response and turns the screw lift but it has gone out of control. It can not stop when I release the press button. I think that it might be due to the rotateCounter variable. Can someone help me modify it in order to let the motor stop moving when the button is released?
I have using the Accelstepper library for the program code
You should post your complete sketch. If you want a deep analysis of your code and what might be the reason why it does not work your whole code is needed. For example it is important to check variable types.
It doesn't matter if your code is 2000 lines long.
There is a search-function in the Arduino-IDE to quickly jump to certain lines: Ctrl-f
There is an automatic function for doing this in the Arduino-IDE
just three steps
press Ctrl-T for autoformatting your code
do a rightclick with the mouse and choose "copy for forum"
you have an if statement to check if the button is pressed. And when the button is press, then this line:
RotateCounter++;
continuslly keeps happening, probably a lot faster than the motor can spin. So it reaches a very high value. So then after you leave the button alone, it would take a looot of time for this system to reach the position you have set. Maybe inside moveTo try dividing by 100 or 1000. And to better understand what is happening, you can use Serial communication, and print your values to the screen, so you can see what you have in there. Then you will be able to easly figure out where is the problem and fix it yourself.
always only increases. if you get to 10000 in one direction. And then if you will want to switch your direction, your system will want to go to -10000 immediately. So maybe add a check if no button is pressed and set that variable back to 0 if so.
Sorry for the long waiting of the respond.
Here is the program code of the arduino
#include <AccelStepper.h>
//User-defined values
long receivedSteps = 0; //Number of steps
long receivedSpeed = 0; //Steps / second
long receivedAcceleration = 0; //Steps / second^2
char receivedCommand;
//-------------------------------------------------------------------------------
int directionMultiplier = 1; // = 1: positive direction, = -1: negative direction
bool newData, runallowed = false;// booleans for new data from serial, and runallowed flag
bool newData1, manual = false;// booleans for the serial. Enable the motor to move in maunal
AccelStepper stepper(1, 8, 9);// direction Digital 9 (CCW), pulses Digital 8 (CLK)
int RotateCounter = 0; //initial position
int BUTTON1 = 2;
int BUTTON2 = 3;
int BUTTON3 = 4;
int BUTTON4 = 5;
int BUTTONstate1 = 0;
int BUTTONstate2 = 0;
int BUTTONstate3 = 0;
int BUTTONstate4 = 0;
void setup()
{
Serial.begin(9600); //define baud rate
Serial.println("3D scanner control unit panel"); //print a messages
Serial.println("Please follow the instruction of the manual");
//setting up some default values for maximum speed and maximum acceleration
Serial.println("Default speed: 400 steps/s, default acceleration: 800 steps/s^2.");
Serial.println("The default 0 position is the lowest of the height control unit");
stepper.setMaxSpeed(400); //SPEED = Steps / second
stepper.setAcceleration(800); //ACCELERATION = Steps /(second)^2
stepper.setCurrentPosition(0); //initalise the current position (The lowest to 0)
stepper.disableOutputs(); //disable outputs
pinMode(BUTTON1, INPUT_PULLUP);
pinMode(BUTTON2, INPUT_PULLUP);
pinMode(BUTTON3, INPUT_PULLUP);
pinMode(BUTTON4, INPUT_PULLUP);
}
void loop()
{
//Constantly looping through these 2 functions.
//We only use non-blocking commands, so something else (should also be non-blocking) can be done during the movement of the motor
checkSerial(); //check serial port for new commands
RunTheMotor(); //function to handle the motor
manualControl();
}
void RunTheMotor() //function for the motor
{
if (runallowed == true)
{
stepper.enableOutputs(); //enable pins
stepper.run(); //step the motor (this will step the motor by 1 step at each loop)
}
else //program enters this part if the runallowed is FALSE, we do not do anything
{
stepper.disableOutputs(); //disable outputs
return;
}
}
void checkSerial() //function for receiving the commands
{
if (Serial.available() > 0) //if something comes from the computer
{
receivedCommand = Serial.read(); // pass the value to the receivedCommad variable
newData = true; //indicate that there is a new data by setting this bool to true
if (newData == true) //we only enter this long switch-case statement if there is a new command from the computer
{
switch (receivedCommand) //we check what is the command
{
case 'P': //P uses the move() function of the AccelStepper library, which means that it moves relatively to the current position.
receivedSteps = Serial.parseFloat(); //value for the steps
receivedSpeed = Serial.parseFloat(); //value for the speed
directionMultiplier = 1; //We define the direction
Serial.println("Positive direction."); //print the action
RotateRelative(); //Run the function
//example: P2000 400 - 2000 steps (5 revolution with 400 step/rev microstepping) and 400 steps/s speed
//In theory, this movement should take 5 seconds
break;
case 'N': //N uses the move() function of the AccelStepper library, which means that it moves relatively to the current position.
receivedSteps = Serial.parseFloat(); //value for the steps
receivedSpeed = Serial.parseFloat(); //value for the speed
directionMultiplier = -1; //We define the direction
Serial.println("Negative direction."); //print action
RotateRelative(); //Run the function
//example: N2000 400 - 2000 steps (5 revolution with 400 step/rev microstepping) and 500 steps/s speed; will rotate in the other direction
//In theory, this movement should take 5 seconds
break;
case 'R': //R uses the moveTo() function of the AccelStepper library, which means that it moves absolutely to the current position.
receivedSteps = Serial.parseFloat(); //value for the steps
receivedSpeed = Serial.parseFloat(); //value for the speed
directionMultiplier = 1; //We define the direction
Serial.println("Absolute position (+)."); //print the action
RotateAbsolute(); //Run the function
//example: R800 400 - It moves to the position which is located at +800 steps away from 0.
break;
case 'r': //r uses the moveTo() function of the AccelStepper library, which means that it moves absolutely to the current position.
receivedSteps = Serial.parseFloat(); //value for the steps
receivedSpeed = Serial.parseFloat(); //value for the speed
directionMultiplier = -1; //We define the direction
Serial.println("Absolute position (-)."); //print the action
RotateAbsolute(); //Run the function
//example: r800 400 - It moves to the position which is located at -800 steps away from 0.
break;
case 'S': // Stops the motor
stepper.stop(); //stop motor
stepper.disableOutputs(); //disable power
Serial.println("Stopped."); //print action
runallowed = false; //disable running
break;
case 'A': // Updates acceleration
runallowed = false; //we still keep running disabled, since we just update a variable
stepper.disableOutputs(); //disable power
receivedAcceleration = Serial.parseFloat(); //receive the acceleration from serial
stepper.setAcceleration(receivedAcceleration); //update the value of the variable
Serial.print("New acceleration value: "); //confirm update by message
Serial.println(receivedAcceleration); //confirm update by message
break;
case 'L': //L: Location
runallowed = false; //we still keep running disabled
stepper.disableOutputs(); //disable power
Serial.print("Current location of the motor: ");//Print the message
Serial.println(stepper.currentPosition()); //Printing the current position in steps.
break;
case 'H': //H: Homing
runallowed = true;
Serial.println("Homing"); //Print the message
GoHome();// Run the function
break;
case 'U':
runallowed = false; //we still keep running disabled
stepper.disableOutputs(); //disable power
stepper.setCurrentPosition(0); //Reset current position. "new home"
Serial.print("The current position is updated to: "); //Print message
Serial.println(stepper.currentPosition()); //Check position after reset.
break;
case 'M':
newData1 = true;
manual = true;
Serial.println("Maunal start");
Serial.println(stepper.distanceToGo());
break;
case 'C':
newData1 = false;
manual = false;
Serial.println("Maunal end");
Serial.println(stepper.distanceToGo());
break;
default:
break;
}
}
//after we went through the above tasks, newData is set to false again, so we are ready to receive new commands again.
newData = false;
}
}
void GoHome()
{
if (stepper.currentPosition() == 0)
{
Serial.println("We are at the home position.");
stepper.disableOutputs(); //disable power
}
else
{
stepper.setMaxSpeed(400); //set speed manually to 400. In this project 400 is 400 step/sec = 1 rev/sec.
stepper.moveTo(0); //set abolute distance to move
}
}
void RotateRelative()
{
//We move X steps from the current position of the stepper motor in a given direction.
//The direction is determined by the multiplier (+1 or -1)
runallowed = true; //allow running - this allows entering the RunTheMotor() function.
stepper.setMaxSpeed(receivedSpeed); //set speed
stepper.move(directionMultiplier * receivedSteps); //set relative distance and direction
}
void RotateAbsolute()
{
//We move to an absolute position.
//The AccelStepper library keeps track of the position.
//The direction is determined by the multiplier (+1 or -1)
//Why do we need negative numbers? - If you drive a threaded rod and the zero position is in the middle of the rod...
runallowed = true; //allow running - this allows entering the RunTheMotor() function.
stepper.setMaxSpeed(receivedSpeed); //set speed
stepper.moveTo(directionMultiplier * receivedSteps); //set relative distance
}
void manualControl()
{
if (manual == true)
{
BUTTONstate1 = digitalRead(BUTTON1);//read the button1 state
if (BUTTONstate1 == LOW)// if the button is press
{
runallowed = true; // enable the motor outputs. It can enter the runthemotor() function
stepper.setMaxSpeed(400);// set motor speed while manual control
stepper.setAcceleration(800);// set motor accelratino while manual
RotateCounter++;
directionMultiplier = 1; //We define the direction
stepper.moveTo(directionMultiplier * RotateCounter);
}else{
stepper.disableOutputs();
}
BUTTONstate2 = digitalRead(BUTTON2);//read the button2 state
if (BUTTONstate2 == LOW)//is the button is press
{
runallowed = true;// enable the motor outputs. It can enter the runthemotor() function
stepper.setMaxSpeed(400);
stepper.setAcceleration(800);
directionMultiplier = -1; //We define the direction
RotateCounter++;
stepper.moveTo(directionMultiplier * RotateCounter);
}else{
stepper.disableOutputs();
}
}
}
Well, it seems that the rotateCounter site has a little bit of error so the motor loses control. Meanwhile, I try to modify the code and let the rotateCounter move in the correct direction by multiplying with the direction counter. Maybe I need to do some more calculation.
the conventional approach is to connect the button between the pin and ground, configure the pin as INPUT_PULLUP to use the internal pullup resistor which pulls the pin HIGH and for the button to pull the pin LOW.
you should really give an overview about your project.
What is your device doing as final purpose?
You named the function manualControl()
So I guess sometimes you want to drive the steppermotor manually. In other cases somehow automatically. Is it important that this steppermotor has an exact position?
If you don't know simply tell what the steppermotor is used for = the final purpose of rotating the steppermotor.
It might be that another stepper-library called MobaTools is better suited than accelstepper. But this depends on your application.
The overview of the project is to build the setup for the 3D scanner and the platform. It aims to reduce the calibration period of the 3D scanner as the original setup requires a long duration for the user to calibrate at the correct height of the scanner. So this program aims to control two sets of coordination systems empowered by the stepper motor. The vertical control units is the screw lift and connect with the scanner. Meanwhile, the horizontal control unit is the belt and rollers system and is connected to the platform.
The serial communication site is to ensure the lift screw unit can lift the 3D scanner module in the pre-set height position and let the scanner stand at the stable height. The manual control will be used for fine-tuning during the calibration process.
Currently, this program is used to control lift screws only. As the template on control the horizontal control unit will be similar. So now I just complete the vertical control unit first then change the variable and code and insert the program for controlling the horizontal control unit.
like, let the user separate control the horizontal control unit only.
So this means pressing the button should make the steppermotor move a few steps and as closer as the system comes to the final position the slower the steppermotor shall move.
Have you ever thought about using a rotary-encoder for this?
two systems moved by a single steppermotor?
If you want to use this for finetuning / calibration
Do you want to use microstepping? If yes at which resolution?
If you want to stay with two buttons you should use state-change detection. And debouncing. The change from button unpressed to pressed shall create a well defined number of steps down to a single step.
And only if the button is released (= state-change from pressed to unpressed) and then pressed new shall create the next movement.
It will be much easier to repeat pressing the button mutliple times than holding the button down for a certain amount of time.
For the first question. I would prefer to rewrite the coding first instead of using the rotary encoder. It is because due to out of budget For the second question. The horizontal control unit is empowered by the second stepper motor. So all I need to do is to complete the first program which controls the vertical motion. Then modify the Serial Print Case in order to let the serial communication platform can switch to a different mode and let the serial communication platform can control horizontal or vertical control units only.
By the way, state-change detection seems to be the possible solution for the current case to let the button control easier. maybe I gonna need to work hard for testing the state-change program and debug for the variable at the rotateCounter side. Thanks for your suggestion
The second step might look like beeing "hard" but it is easy too:
You make a first attempt how you think it might be coded and if it does not what you intented post the complete sketch and a description what behaviour you see and what behaviour you want instead.
Thanks for the reply. I have further modified the previous code. Now the motor can stop when I release the button however it can not move in the reverse direction. So what part I should modify or add in order to let the motor move in opposite direction?
void manualControl()
{
if (manual == true)
{
BUTTONstate1 = digitalRead(BUTTON1);//read the button1 state
if (BUTTONstate1 == LOW)// if the button is press
{
runallowed = true; // enable the motor outputs. It can enter the runthemotor() function
stepper.setMaxSpeed(400);// set motor speed while manual control
stepper.setAcceleration(1200);// set motor accelratino while manual
RotateCounter++;
stepper.move(RotateCounter/80);
}else{
stepper.disableOutputs();
RotateCounter==0;
}
BUTTONstate2 = digitalRead(BUTTON2);//read the button2 state
if (BUTTONstate2 == LOW)//is the button is press
{
runallowed = true;// enable the motor outputs. It can enter the runthemotor() function
stepper.setMaxSpeed(400);
stepper.setAcceleration(1200);
RotateCounter--;
stepper.move(RotateCounter/80);
}else{
stepper.disableOutputs();
RotateCounter==0;
}
}
}
here is the new modified coding to control the motor by the switch. The previous coding is the same but only modify this part.
what is so hard about posting always your complete sketch
using this method?
There is an automatic function for doing this in the Arduino-IDE
just three steps
press Ctrl-T for autoformatting your code
do a rightclick with the mouse and choose "copy for forum"
paste clipboard into write-window of a posting
posting your complete sketch eilmininates misunderstandings about anything to zero.
posting your complete sketch reduces the work to get your code into the arduino-IDE to a single mouseclick in the top-right corner of the code.section.
You wrote about fine-tuning the position.
What number of steps are "fine" in your application?
Thanks for your suggestion, I finally can control the entire setup in the controllable circumstance.
Here is the updated coding.
#include <AccelStepper.h>
//User-defined values
long receivedSteps = 0; //Number of steps
long receivedSpeed = 0; //Steps / second
long receivedAcceleration = 0; //Steps / second^2
char receivedCommand;
//-------------------------------------------------------------------------------
int directionMultiplier = 1; // = 1: positive direction, = -1: negative direction
bool newData, runallowed = false;// booleans for new data from serial, and runallowed flag
bool newData1, manual = false;// booleans for the serial. Enable the motor to move in maunal
AccelStepper stepper(1, 8, 9);// direction Digital 9 (CCW), pulses Digital 8 (CLK)
int RotateCounter = 0; //initial position
int BUTTON1 = 2;// initial button pin
int BUTTON2 = 3;
int BUTTON3 = 4;
int BUTTON4 = 5;
int BUTTONstate1 = 0;// initial each button pin output to 0
int BUTTONstate2 = 0;
int BUTTONstate3 = 0;
int BUTTONstate4 = 0;
void setup()
{
Serial.begin(9600); //define baud rate
Serial.println("3D scanner control unit panel"); //print a messages
Serial.println("Please follow the instruction of the manual");
//setting up some default values for maximum speed and maximum acceleration
Serial.println("Default speed: 400 steps/s, default acceleration: 800 steps/s^2.");
Serial.println("The default 0 position is the lowest of the height control unit");
stepper.setMaxSpeed(400); //SPEED = Steps / second
stepper.setAcceleration(800); //ACCELERATION = Steps /(second)^2
stepper.setCurrentPosition(0); //initalise the current position (The lowest to 0)
stepper.disableOutputs(); //disable outputs
pinMode(BUTTON1, INPUT_PULLUP);// define the input button pins
pinMode(BUTTON2, INPUT_PULLUP);
pinMode(BUTTON3, INPUT_PULLUP);
pinMode(BUTTON4, INPUT_PULLUP);
}
void loop()
{
//Constantly looping through these 3 functions.
//We only use non-blocking commands, so something else (should also be non-blocking) can be done during the movement of the motor
checkSerial(); //check serial port for new commands
RunTheMotor(); //function to handle the motor
manualControl(); //function for manual control
}
void RunTheMotor() //function for the motor
{
if (runallowed == true)
{
stepper.enableOutputs(); //enable pins
stepper.run(); //step the motor (this will step the motor by 1 step at each loop)
}
else //program enters this part if the runallowed is FALSE, we do not do anything
{
stepper.disableOutputs(); //disable outputs
return;
}
}
void checkSerial() //function for receiving the commands
{
if (Serial.available() > 0) //if something comes from the computer
{
receivedCommand = Serial.read(); // pass the value to the receivedCommad variable
newData = true; //indicate that there is a new data by setting this bool to true
if (newData == true) //we only enter this long switch-case statement if there is a new command from the computer
{
switch (receivedCommand) //we check what is the command
{
case 'P': //P uses the move() function of the AccelStepper library, which means that it moves relatively to the current position.
receivedSteps = Serial.parseFloat(); //value for the steps
receivedSpeed = Serial.parseFloat(); //value for the speed
directionMultiplier = 1; //We define the direction
Serial.println("Positive direction."); //print the action
RotateRelative(); //Run the function
//example: P2000 400 - 2000 steps (5 revolution with 400 step/rev microstepping) and 400 steps/s speed
//In theory, this movement should take 5 seconds
break;
case 'N': //N uses the move() function of the AccelStepper library, which means that it moves relatively to the current position.
receivedSteps = Serial.parseFloat(); //value for the steps
receivedSpeed = Serial.parseFloat(); //value for the speed
directionMultiplier = -1; //We define the direction
Serial.println("Negative direction."); //print action
RotateRelative(); //Run the function
//example: N2000 400 - 2000 steps (5 revolution with 400 step/rev microstepping) and 500 steps/s speed; will rotate in the other direction
//In theory, this movement should take 5 seconds
break;
case 'R': //R uses the moveTo() function of the AccelStepper library, which means that it moves absolutely to the current position.
receivedSteps = Serial.parseFloat(); //value for the steps
receivedSpeed = Serial.parseFloat(); //value for the speed
directionMultiplier = 1; //We define the direction
Serial.println("Absolute position (+)."); //print the action
RotateAbsolute(); //Run the function
//example: R800 400 - It moves to the position which is located at +800 steps away from 0.
break;
case 'r': //r uses the moveTo() function of the AccelStepper library, which means that it moves absolutely to the current position.
receivedSteps = Serial.parseFloat(); //value for the steps
receivedSpeed = Serial.parseFloat(); //value for the speed
directionMultiplier = -1; //We define the direction
Serial.println("Absolute position (-)."); //print the action
RotateAbsolute(); //Run the function
//example: r800 400 - It moves to the position which is located at -800 steps away from 0.
break;
case 'S': // Stops the motor
stepper.stop(); //stop motor
stepper.disableOutputs(); //disable power
Serial.println("Stopped."); //print action
runallowed = false; //disable running
break;
case 'A': // Updates acceleration
runallowed = false; //we still keep running disabled, since we just update a variable
stepper.disableOutputs(); //disable power
receivedAcceleration = Serial.parseFloat(); //receive the acceleration from serial
stepper.setAcceleration(receivedAcceleration); //update the value of the variable
Serial.print("New acceleration value: "); //confirm update by message
Serial.println(receivedAcceleration); //confirm update by message
break;
case 'L': //L: Location
runallowed = false; //we still keep running disabled
stepper.disableOutputs(); //disable power
Serial.print("Current location of the motor: ");//Print the message
Serial.println(stepper.currentPosition()); //Printing the current position in steps.
break;
case 'H': //H: Homing
runallowed = true;
Serial.println("Homing"); //Print the message
GoHome();// Run the function
break;
case 'U':
runallowed = false; //we still keep running disabled
stepper.disableOutputs(); //disable power
stepper.setCurrentPosition(0); //Reset current position. "new home"
Serial.print("The current position is updated to: "); //Print message
Serial.println(stepper.currentPosition()); //Check position after reset.
break;
case 'M':
newData1 = true; //allow the manual control function activate
manual = true; //allow manual control by button
Serial.println("Maunal start");
Serial.println(stepper.distanceToGo());// debug use
break;
case 'C':
newData1 = false;//stop the manual control and allow serial control only
manual = false;//stop the manual input distract the motor while using serial control mrthod
Serial.println("Maunal end");
Serial.println(stepper.distanceToGo());//debug use
break;
default:
break;
}
}
//after we went through the above tasks, newData is set to false again, so we are ready to receive new commands again.
newData = false;
}
}
void GoHome()
{
if (stepper.currentPosition() == 0)
{
Serial.println("We are at the home position.");
stepper.disableOutputs(); //disable power
}
else
{
stepper.setMaxSpeed(400); //set speed manually to 400. In this project 400 is 400 step/sec = 1 rev/sec.
stepper.moveTo(0); //set abolute distance to move
}
}
void RotateRelative()
{
//We move X steps from the current position of the stepper motor in a given direction.
//The direction is determined by the multiplier (+1 or -1)
runallowed = true; //allow running - this allows entering the RunTheMotor() function.
stepper.setMaxSpeed(receivedSpeed); //set speed
stepper.move(directionMultiplier * receivedSteps); //set relative distance and direction
}
void RotateAbsolute()
{
//We move to an absolute position.
//The AccelStepper library keeps track of the position.
//The direction is determined by the multiplier (+1 or -1)
//Why do we need negative numbers? - If you drive a threaded rod and the zero position is in the middle of the rod...
runallowed = true; //allow running - this allows entering the RunTheMotor() function.
stepper.setMaxSpeed(receivedSpeed); //set speed
stepper.moveTo(directionMultiplier * receivedSteps); //set relative distance
}
void manualControl()
{
if (manual == true)
{
BUTTONstate1 = digitalRead(BUTTON1);//read the button1 state
if (BUTTONstate1 == LOW)// if the button is press
{
runallowed = true; // enable the motor outputs. It can enter the runthemotor() function
stepper.setCurrentPosition(0);
stepper.moveTo(-10);
stepper.enableOutputs();
stepper.setSpeed(800);// set motor speed while manual control
stepper.setAcceleration(1200);// set motor accelration while manual
while (stepper.currentPosition() != stepper.targetPosition()){
stepper.runSpeedToPosition();}
}else{
stepper.disableOutputs();//stop the motor input
stepper.setCurrentPosition(0);
}
BUTTONstate2 = digitalRead(BUTTON2);//read the button2 state
if (BUTTONstate2 == LOW)//is the button is press
{
runallowed = true;// enable the motor outputs. It can enter the runthemotor() function
stepper.setCurrentPosition(0);
stepper.moveTo(10);
stepper.enableOutputs();
stepper.setSpeed(800);// set motor speed while manual control
stepper.setAcceleration(1200);// set motor accelration while manual
while (stepper.currentPosition() != stepper.targetPosition()){
stepper.runSpeedToPosition();}
}else{
stepper.disableOutputs();//stop the motor input
stepper.setCurrentPosition(0);
}
}
}
Although there is too much redundant code, I will try my best to reduce it and do a trial for it and reduce it. Thanks for the kindly help for everyone in these previous days