I written a code piece using millis to run dc motor using h-bridge on way. I want to stop it for fraction of time and then run backwards. I am not able to understand how to do it? If I write other functions for stop and opposit direction motor run, that probably is not option. As I think these all will be executed same time.
Here is my code:
//DC motor
const int pwm = 3; //initializing pin 3 as pwm
const int in_1 = 8 ;
const int in_2 = 7 ;
//Sound sensor
//int soundSensor=2;
//boolean LEDStatus=false;
unsigned long currentMillis = 0;
unsigned long previousMillis = 0;
const int motorUPinterval = 500;
const int motorUPduration = 3000;
byte motorState = LOW;
void setup() {
Serial.begin(9600);
Serial.println("starting......");
pinMode(pwm,OUTPUT) ; //we have to set PWM pin as output
pinMode(in_1,OUTPUT) ; //Logic pins are also set as output
pinMode(in_2,OUTPUT) ;
}
void loop() {
currentMillis = millis();
runDCmotor(); // the method runs motor in one direction, I want the motor to stop and then run
//backward same amount of time
}
void runDCmotor (){
if(motorState == LOW) {
if(currentMillis - previousMillis >= motorUPinterval) {
motorState = HIGH;
digitalWrite(in_1,HIGH) ;
digitalWrite(in_2,LOW) ;
analogWrite(pwm,255) ;
}
}
else if(currentMillis - previousMillis >= motorUPduration)
motorState = LOW;
previousMillis += motorUPduration;
}
Instead of making the motor states LOW and HIGH, think about adding a few more states. Like state 0 might be "waiting for start button", state 1 will be "moving forwards", state 2 will be "reversing back to start". After state 2, go back to state 0 again.
Since you don't seem to have a start button, you just need 1 and 2 for now.
Then split the runDCmotor() functions into two: let one manage the states. This looks at the times (and any other inputs) to decide when to change from 0 to 1 to 2 to 0. The second function should do the actual output: when in state 0, everything is off. State 1 and 2 will have different outputs. Note that the motor-output function doesn't have to know anything about buttons or millis(). It just drives in the direction that it's told to go.
I have to start the motor by sound sensor. Oo state 0 is 'waiting for input from sound sensor', state 1 'moving forward', state 2 'moving backward', and back to 0.
Do you mean I make three methods with 3 state machines of their own or one method with 3 using 3 state machines for all 3 states?
One question is I put 'motorUPduration' to set how much should it run in one direction and stop. But it keep running continuously. It will be problem I also when making 3 state machines as when one side motor motion stops and halts and start running other direction.
Here is an example of a state machine close to what you want
enum : byte {WAITING_SOUND, SPIN_FWD, SHORT_PAUSE, SPIN_BWD} systemState;
unsigned long topChrono;
unsigned long currentDuration;
const unsigned long fwdDuration = 3000; // 3 seconds
const unsigned long pauseDuration = 200; // 0.2 seconds
const unsigned long bwdDuration = 3000; // 3 seconds
boolean testSound()
{
boolean soundOn = false;
if (Serial.available()) {
soundOn = ((char) Serial.read() == 'B'); // B for BOOOOM :)
}
return soundOn;
}
void spinFwd()
{
Serial.println(F(" - MOTOR FWD"));
}
void stopMotor()
{
Serial.println(F(" - MOTOR STOP"));
}
void spinBwd()
{
Serial.println(F(" - MOTOR BWD"));
}
void waitForSound()
{
systemState = WAITING_SOUND;
Serial.println(F("\n\nENTER B to get started"));
}
void setup() {
Serial.begin(115200);
waitForSound();
}
void loop() {
if ((systemState == WAITING_SOUND) && testSound()) {
Serial.print(F("Millis = ")); Serial.print(millis());
systemState = SPIN_FWD;
topChrono = millis();
currentDuration = fwdDuration;
spinFwd();
}
if ((systemState != WAITING_SOUND) && (millis() - topChrono >= currentDuration)) {
Serial.print(F("Millis = ")); Serial.print(millis());
switch (systemState) {
case SPIN_FWD: // we were in fwd mode and time is up, we stop the motor and wait a bit
systemState = SHORT_PAUSE;
topChrono = millis();
currentDuration = pauseDuration;
stopMotor();
break;
case SHORT_PAUSE:// we were in pause mode and time is up, we go spin the other way
systemState = SPIN_BWD;
topChrono = millis();
currentDuration = bwdDuration;
spinBwd();
break;
case SPIN_BWD: // we were in bwd mode and time is up, we stop the motor and wait for the sound
stopMotor();
waitForSound();
break;
default:
Serial.println(F("ERROR THIS SHOULD NOT HAPPEN!"));
break;
}
}
// here you can do other stuff
}
if you run this, and you type B in the Serial monitor (setup at 115200 bauds) then you'll see the machine working and going through the stages at the pace we defined
[color=purple]
ENTER B to get started
Millis = 1286 - MOTOR FWD [color=green]start time of motor t[sub]0[/sub] = 1286[/color]
Millis = 4286 - MOTOR STOP [color=green]t[sub]1[/sub]=4286 - t[sub]0[/sub] = 3 seconds[/color]
Millis = 4486 - MOTOR BWD [color=green]t[sub]2[/sub]=4486 - t[sub]1[/sub] = 0.2 seconds[/color]
Millis = 7486 - MOTOR STOP [color=green]t[sub]3[/sub]=7486 - t[sub]2[/sub] = 3 seconds[/color]
[/color]
I tried to split runDCmotor() into 2, one scheduler and other runDCmotor (). It is not working still. I am still thinking on the logic of how to stop when time elapsed and then run backward for same amount of time and do on.
Here is my code so far. It starts with clap and keeps running without break.
//DC motor
const int pwm = 3; //initializing pin 2 as pwm
const int in_1 = 8 ;
const int in_2 = 7 ;
//Sound sensor
int soundSensor = 2;
boolean sensStatus = false;
//millis
unsigned long currentMillis = 0;
unsigned long previousUpMillis = 0;
const int motorUPinterval = 500;
const int motorUPduration = 3000;
/*
unsigned long previousDownMillis = 0;
const int motorDowninterval = 500;
const int motorDownDuration = 3000;
*/
byte motorState = LOW;
void setup() {
Serial.begin(9600);
pinMode(pwm, OUTPUT); //we have to set PWM pin as output
pinMode(in_1, OUTPUT); //Logic pins are also set as output
pinMode(in_2, OUTPUT);
pinMode(soundSensor, INPUT); //sound sensor
}
void loop() {
currentMillis = millis();
//sound sensor to start motor running by a clap
int sensorData = digitalRead(soundSensor);
if (sensorData == 1)
{
if (sensStatus == false)
{
sensStatus = true;
runScheduleDCmotor();
runDCmotor();
}
else {
sensStatus = false;
}
}
}
void runScheduleDCmotor () {
if (motorState == LOW) {
if (currentMillis - previousUpMillis >= motorUPinterval) {
motorState = HIGH;
}
} else if (currentMillis - previousUpMillis >= motorUPduration){
motorState = LOW;
previousUpMillis += motorUPduration; }
}
void runDCmotor () {
if (motorState == LOW) {
digitalWrite(in_1, HIGH) ;
digitalWrite(in_2, LOW) ;
analogWrite(pwm, 255) ;
}
else if (motorState == HIGH)
{
digitalWrite(in_1, LOW) ;
digitalWrite(in_2, HIGH) ;
analogWrite(pwm, 255) ;
}
}
void runNeoPixel() {
//NeoPixel ring needs to run parallel to motor running, still to implement & it all start with sound sensor
}
Yes, first one is checking if the time elapsed is more than the interval between two pulse then it assigns HIGH value. While 2nd one checks if HIGH state exceeds the duration of a pulse so sate may be lowered when it does. And then last motorUPduration time is added to previous millis of the motor up counter.
@J-M-L Yes, I tried to use state model in your provided example. @MorganS: I added states, though even with previous states it was only using one state i.e. of BKWRDRUN.
Here is my current code with more states but its running motor in one direction constantly:
//DC motor
const int pwm = 3; //initializing pin 2 as pwm
const int in_1 = 8 ;
const int in_2 = 7 ;
//Sound sensor
int soundSensor = 2;
boolean sensStatus = false;
//millis
unsigned long currentMillis = 0;
unsigned long previousUpMillis = 0;
const int motorUPinterval = 500;
const int motorUPduration = 3000;
unsigned long previousDOWNMillis = 0;
const int motorDOWNinterval = 50;
const int motorDOWNduration = 3000;
/*
unsigned long previousDownMillis = 0;
const int motorDowninterval = 500;
const int motorDownDuration = 3000;
*/
//byte motorState = LOW;
enum motorStateENUM {
WAITING,
FRWDRUN,
BKWRDRUN,
STOPPING,
FINISHED,
};
motorStateENUM motorState = WAITING;
void setup() {
Serial.begin(9600);
pinMode(pwm, OUTPUT); //we have to set PWM pin as output
pinMode(in_1, OUTPUT); //Logic pins are also set as output
pinMode(in_2, OUTPUT);
pinMode(soundSensor, INPUT); //sound sensor
}
void loop() {
currentMillis = millis();
//sound sensor to start motor running by a clap
int sensorData = digitalRead(soundSensor);
if (sensorData == 1)
{
if (sensStatus == false)
{
sensStatus = true;
runScheduleDCmotor();
runDCmotor();
}
else {
sensStatus = false;
}
}
}
void runScheduleDCmotor () {
if (motorState == WAITING) {
if (currentMillis - previousUpMillis >= motorUPinterval) {
motorState = FRWDRUN;
}
} else if (currentMillis - previousUpMillis == motorUPduration){
motorState = STOPPING;
previousUpMillis += motorUPduration;
}
else if (currentMillis - previousDOWNMillis >= motorDOWNinterval){
motorState = BKWRDRUN;
previousDOWNMillis += motorDOWNduration;
}
else if (currentMillis - previousDOWNMillis >= motorDOWNduration){
motorState = WAITING;
previousDOWNMillis += motorDOWNduration;
}
}
void runDCmotor () {
if (motorState == WAITING) {
digitalWrite(in_1, HIGH) ;
digitalWrite(in_2, HIGH) ;
}
else if (motorState == FRWDRUN)
{
digitalWrite(in_1, LOW) ;
digitalWrite(in_2, HIGH) ;
analogWrite(pwm, 255) ;
}
if (motorState == STOPPING) {
digitalWrite(in_1, HIGH) ;
digitalWrite(in_2, HIGH) ;
}
else if (motorState == BKWRDRUN)
{
digitalWrite(in_1, HIGH) ;
digitalWrite(in_2, LOW) ;
analogWrite(pwm, 255) ;
}
}
void runNeoPixel() {
//NeoPixel ring needs to run parallel to motor running, still to implement & it all start with sound sensor
}
Ok, thank you very much !
I think you wrote it for me. It's very nice example for me to understand & learn.
Here is my code now that I basically replaced things from my code to yours kind of stub. Its rotating the motor backward & forward.
//DC motor
const int pwm = 3; //initializing pin 2 as pwm
const int in_1 = 8 ;
const int in_2 = 7 ;
[code]//Sound sensor
const int soundSensor = 2;
boolean sensStatus = false;
enum : byte {WAITING_SOUND, SPIN_FWD, SHORT_PAUSE, SPIN_BWD} systemState;
unsigned long topChrono;
unsigned long currentDuration;
const unsigned long fwdDuration = 3000; // 3 seconds
const unsigned long pauseDuration = 200; // 0.2 seconds
const unsigned long bwdDuration = 3000; // 3 seconds
boolean testSound()
{
//sound sensor to start motor running by a clap
int sensorData = digitalRead(soundSensor);
if (sensorData == 1)
{
if (sensStatus == false)
{
sensStatus = true;
}
else {
sensStatus = false;
}
}
return sensStatus;
}
void spinFwd()
{
digitalWrite(in_1, LOW) ;
digitalWrite(in_2, HIGH) ;
analogWrite(pwm, 255) ;
}
void stopMotor()
{
digitalWrite(in_1, HIGH) ;
digitalWrite(in_2, HIGH) ;
}
void spinBwd()
{
digitalWrite(in_1, HIGH) ;
digitalWrite(in_2, LOW) ;
analogWrite(pwm, 255) ;
}
void waitForSound()
{
systemState = WAITING_SOUND;
Serial.println(F("\n\nENTER B to get started"));
}
void setup() {
Serial.begin(115200);
waitForSound();
}
void loop() {
if ((systemState == WAITING_SOUND) && testSound()) {
Serial.print(F("Millis = ")); Serial.print(millis());
systemState = SPIN_FWD;
topChrono = millis();
currentDuration = fwdDuration;
spinFwd();
}
if ((systemState != WAITING_SOUND) && (millis() - topChrono >= currentDuration)) {
Serial.print(F("Millis = ")); Serial.print(millis());
switch (systemState) {
case SPIN_FWD: // we were in fwd mode and time is up, we stop the motor and wait a bit
systemState = SHORT_PAUSE;
topChrono = millis();
currentDuration = pauseDuration;
stopMotor();
break;
case SHORT_PAUSE:// we were in pause mode and time is up, we go spin the other way
systemState = SPIN_BWD;
topChrono = millis();
currentDuration = bwdDuration;
spinBwd();
break;
case SPIN_BWD: // we were in bwd mode and time is up, we stop the motor and wait for the sound
stopMotor();
waitForSound();
break;
default:
Serial.println(F("ERROR THIS SHOULD NOT HAPPEN!"));
break;
}
}
// here you can do other stuff
}
I have to yet add Adafruit NeoPixel code to light the pixel ring as soon as & as long as motor starts & keep moving. I downloaded the source from adafruit site. But it uses delay fundtion, that I think would cause may be trouble when working with this code. But need to experiment.
One more thing is how to make sure the motor shaft stops stops after completing amount of time it's give for backward move? Basically because I have to use this motor to move the part of a lamp, up & down. So time will be calculated & adjusted to find how much time does motor take to move the moving part to down edge and how much to top edge. So it keeps moving within those limits.
But question is when motor is stopped, if it is stopped in middle and again started and it starts moving from there will break the moving part.
I updated the code by new testSound () method and it's working same way. I tried to see what if I comment the return statement, then motor never starts. Seems some how it gets HIGH from sensor pin i.e. #2.