Multi-tasking for a DC motor and Current Sensor

Hello everyone,

I am working on a small project and facing some problems getting the Arduino do what I want !

It is basically controlling a DC motor through a motor drive and a current sensor.

I have it all wired up and running and giving me the inputs I want, but not the way I want it to do so.

My goal is to make the motor run at different speeds in different directions at different time intervals, while at the same time the current sensor reads the current and reacts accordingly ...

Example: (clockwise at full speed for 2 seconds, stop for 1 second, counterclockwise for 3 seconds at half speed, stops for 5 seconds, and so on....), the sensor reads the current and using the Interrupt function, if it goes above or below a threshold, it will stop the motor or make it do something else of my choice.

I have tried different codes with no success !

In a normal code with the "delay" function, the motor runs nicely and does what it is suppose to do, but the sensor has to wait for the full motor loop cycle to finish, then it sends the reading, but I want it to send the reading all the time while the motor does its thing !

In multitasking code with "mills" the sensor sends the reading continuously, but the motor is rotating continuously as well and not in the way I asked it to do !!

After reading, I understand the reason for that in both cases, and was wondering if there is a way to make the motor run as commanded and the sensor send a continuous readings and reacts as commanded !!

And if it is not possible to achieve this with one code in one Arduino, would it be possible to use the "master slave" as an alternative?! ... one controls the motor while the other one reads from the sensor and sends commands to the first one to react.

I have tried different codes with no success !

But you didn't post any of them.

Hi,

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Can you please post a copy of your sketch, using code tags?
They are made with the </> icon in the reply Menu.
See section 7 http://forum.arduino.cc/index.php/topic,148850.0.html

Tom..... :slight_smile:

Hi again, thanks for the quick reply

Below are the codes, it is just a copy/paste from different resources with minor modifications as I am still learning.

The forum wont allow me to post 2 codes as it will exceed the max 9000 caraters, so the second code will be in the next reply below

Code with "delay"

/* 

  an exercise in combining code

  */

  void setup(){


   setupMotor();


  setupSensor();


  }


  void loop(){


    loopMotor();


loopSensor();

  }

  void setupSensor() {
 
  Serial.begin(9600);
}
 
void loopSensor() {
 
 float average = 0;
  for(int i = 0; i < 1000; i++) {
average = average + (.0264 * analogRead(A0) -13.51) / 1000;   }
  Serial.println(average);  
  
}

/*  L298N_Dual_H_Bridge

motorA(mode, speed)
% replace A with B to control motor B %

mode is a number 0 -> 3 that determines what the motor 
will do.
0 = coast/disable the H bridge
1 = turn motor clockwise
2 = turn motor counter clockwise
3 = brake motor

speed is a number 0 -> 100 that represents percentage of
motor speed.
0 = off
50 = 50% of full motor speed
100 = 100% of full motor speed

EXAMPLE
Say you need to have motor A turn clockwise at 33% of its
full speed.  The subroutine call would be the following...

motorA(1, 33);

Created by 
Iain Portalupi http://www.youtube.com/iainportalupi
1/2/2014

This code is in the public domain.
*/

#define ENA 5  //enable A on pin 5 (needs to be a pwm pin)
#define IN1 2  //IN1 on pin 2 conrtols one side of bridge A
#define IN2 4  //IN2 on pin 4 controls other side of A



void setupMotor()
{
  //set all of the outputs
  pinMode(ENA, OUTPUT);
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
 
}

void loopMotor()
{

  motorA(1, 50);  //have motor A turn clockwise at 15% speed
  delay(2000);
 
  
  motorA(3, 100);  //brake motor A with 100% braking power
   delay(2000); 
  //have motor A turn counter-clockwise at 15% speed
  motorA(2, 50);  
  delay(2000);
  motorA(0, 100);  //let motor A coast
  delay(2000);
 
}

//******************   Motor A control   *******************
void motorA(int mode, int percent)
{
  
  //change the percentage range of 0 -> 100 into the PWM
  //range of 0 -> 255 using the map function
  int duty = map(percent, 0, 100, 0, 255);
  
  switch(mode)
  {
    case 0:  //disable/coast
      digitalWrite(ENA, LOW);  //set enable low to disable A
      break;
      
    case 1:  //turn clockwise
      //setting IN1 high connects motor lead 1 to +voltage
      digitalWrite(IN1, HIGH);   
      
      //setting IN2 low connects motor lead 2 to ground
      digitalWrite(IN2, LOW);  
      
      //use pwm to control motor speed through enable pin
      analogWrite(ENA, duty);  
      
      break;
      
    case 2:  //turn counter-clockwise
      //setting IN1 low connects motor lead 1 to ground
      digitalWrite(IN1, LOW);   
      
      //setting IN2 high connects motor lead 2 to +voltage
      digitalWrite(IN2, HIGH);  
      
      //use pwm to control motor speed through enable pin
      analogWrite(ENA, duty);  
      
      break;
      
    case 3:  //brake motor
      //setting IN1 low connects motor lead 1 to ground
      digitalWrite(IN1, LOW);   
      
      //setting IN2 high connects motor lead 2 to ground
      digitalWrite(IN2, LOW);  
      
      //use pwm to control motor braking power 
      //through enable pin
      analogWrite(ENA, duty);  
      
      break;
  }
}
//**********************************************************

Code with "mills"

/* Multiple independent delay - Two blinking LEDs

Working code example that blinks two LEDs, each with its own independent period.
This extends the BlinkWithoutDelay example of a single LED, showing how to
implement multiple independent timing paths in the main loop.

Written by several forum members. In public domain.  Oct 2011.

Note: works even when millis () wraps around to zero after approximately 50 days.
*/

// Which pins are connected to which LED
const byte Sensor = A0 ;
const byte Motor = 5 ;

// Time periods of blinks in milliseconds (1000 milliseconds to a second).
// Time variable and constants are always unsigned long
const unsigned long Sensorinterval = 1000UL ;
const unsigned long Motorinterval = 1234UL ;

// Variable holding the timer value so far. One for each "Timer"
unsigned long Sensortimer = 0 ;
unsigned long Motortimer = 0 ;

// Variable to know what the current LED state is
int SensorState = LOW ;
int MotorState = LOW ;

void setupMulti() {
  pinMode (Sensor,INPUT) ;
  pinMode (Motor,OUTPUT) ;
  Sensortimer = millis () ;
  Motortimer = millis () ;
}

void loopMulti() {

// Handling the blink of one LED.
// First, check if it is time to change state
  if ( (millis () - Sensortimer) >= Sensorinterval ) {
    // It is time to change state. Calculate next state.
    if (SensorState == LOW)
      SensorState = HIGH ;
    else
      SensorState = LOW ;
    // Write new state
    analogWrite (Sensor, SensorState ) ;
    // Reset timer
    Sensortimer = millis () ;
  }

// The other LED is controlled the same way. Repeat for more LEDs
  if ( (millis () - Motortimer) >= Motorinterval ) {
    if (MotorState == LOW)
      MotorState = HIGH ;
    else
      MotorState = LOW ;
    digitalWrite (Motor, MotorState ) ;
    Motortimer = millis ()  ;
  }

/* Other code that needs to execute goes here.
   It will be called many thousands of times per second because the above code
   does not wait for the LED blink interval to finish. */

}






/* Fade Blink


  an exercise in combining code


  */


  void setup(){


   setupMotor();


  setupSensor();

  setupMulti();

  }

  void loop(){


    loopMotor();


loopSensor();

loopMulti();

  }

  void setupSensor() {
 
  Serial.begin(9600);
}
 
void loopSensor() {
 
 int sensorValue = analogRead(A0);
  Serial.println(sensorValue); 
 delay(1);
  
}


/*  L298N_Dual_H_Bridge

motorA(mode, speed)
% replace A with B to control motor B %

mode is a number 0 -> 3 that determines what the motor 
will do.
0 = coast/disable the H bridge
1 = turn motor clockwise
2 = turn motor counter clockwise
3 = brake motor

speed is a number 0 -> 100 that represents percentage of
motor speed.
0 = off
50 = 50% of full motor speed
100 = 100% of full motor speed

EXAMPLE
Say you need to have motor A turn clockwise at 33% of its
full speed.  The subroutine call would be the following...

motorA(1, 33);

Created by 
Iain Portalupi http://www.youtube.com/iainportalupi
1/2/2014

This code is in the public domain.
*/

#define ENA 5  //enable A on pin 5 (needs to be a pwm pin)
#define IN1 2  //IN1 on pin 2 conrtols one side of bridge A
#define IN2 4  //IN2 on pin 4 controls other side of A

void setupMotor()
{
  //set all of the outputs
  pinMode(ENA, OUTPUT);
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
 
}

void loopMotor()
{

  motorA(1, 100);  //have motor A turn clockwise at 15% speed
  motorA(3, 100);  //brake motor A with 100% braking power
      //have motor A turn counter-clockwise at 15% speed
  motorA(2, 100);  
  
  motorA(2, 30);  //let motor A coast 
 
}

void motorA(int mode, int percent)
{
  
  //change the percentage range of 0 -> 100 into the PWM
  //range of 0 -> 255 using the map function
  int duty = map(percent, 0, 100, 0, 255);
  
  switch(mode)
  {
    case 0:  //disable/coast
      digitalWrite(ENA, LOW);  //set enable low to disable A
      break;
      
    case 1:  //turn clockwise
      //setting IN1 high connects motor lead 1 to +voltage
      digitalWrite(IN1, HIGH);   
      
      //setting IN2 low connects motor lead 2 to ground
      digitalWrite(IN2, LOW);  
      
      //use pwm to control motor speed through enable pin
      analogWrite(ENA, duty);  
      
      break;
      
    case 2:  //turn counter-clockwise
      //setting IN1 low connects motor lead 1 to ground
      digitalWrite(IN1, LOW);   
      
      //setting IN2 high connects motor lead 2 to +voltage
      digitalWrite(IN2, HIGH);  
      
      //use pwm to control motor speed through enable pin
      analogWrite(ENA, duty);  
      
      break;
      
    case 3:  //brake motor
      //setting IN1 low connects motor lead 1 to ground
      digitalWrite(IN1, LOW);   
      
      //setting IN2 high connects motor lead 2 to ground
      digitalWrite(IN2, LOW);  
      
      //use pwm to control motor braking power 
      //through enable pin
      analogWrite(ENA, duty);  
      
      break;
  }
}

Unfortunately I don't know how to draw the circuit in CAD, and it is a spaghetti mess eben if I take a picture it will not be clear enough, sorry !

but I have set it up following an instruction from a website and it is working with no problems.
The codes will show the pins am connecting to.

Hi,

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Tom..... :slight_smile:

Looking at the code in Reply #4, there is no attempt to time the motor movements, but it should be easy to add that.

What have you tried ?
I presume you are familiar with the demo several things at a time which illustrates the use of millis()

I note that there is delay(1) in the function loopSensor() - don't use delay() anywhere.

I have not looked at the code that uses delay() in Reply #3 - timing is much better managed with millis()

...R

TomGeorge:
Hi,

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Tom..... :slight_smile:

Hi Tom,

I don't know how to use CAD, but I will try to draw it using paint in windows or hand draw it if I can, although I don't think it has anything to do with the circuit as it is purely a programming issue, but if the circuit layout will help, then sure I will try to do it and post it in my coming reply.

Cheers

Think of your problem as going from one state ("motors off") to another state ("left motor at 50%") to another ("both motors at 100%") (or whatever).

The transitions from one state to another take virtually no time at all (just a few digital and anlogue writes), and the rest of the time, all the processor needs to do is look at the clock to see if it's time to do something.
Have a look at Robin2's post on doing multiple things.

I agree - I don't think we really need a schematic.

Robin2:
Looking at the code in Reply #4, there is no attempt to time the motor movements, but it should be easy to add that.

What have you tried ?
I presume you are familiar with the demo several things at a time which illustrates the use of millis()

I note that there is delay(1) in the function loopSensor() - don't use delay() anywhere.

I have not looked at the code that uses delay() in Reply #3 - timing is much better managed with millis()

...R

Hi Robin,

I have looked at the demo before I post my issue but I couldn't quite understand it and make it work for me, that's what am stuck with.

The delay in sensor loop was removed and still same problem !!

I have read few posts here and else where regarding mills() but its a bit complicated for me as I am still new to this, and even after copying some codes and modifying it still didn't work !!

Any chance you can modify the code to make the motor work in different cycles as I explained in the original post?
or an example code that I can apply and try?

Thank you

AWOL:
Think of your problem as going from one state ("motors off") to another state ("left motor at 50%") to another ("both motors at 100%") (or whatever).

The transitions from one state to another take virtually no time at all (just a few digital and anlogue writes), and the rest of the time, all the processor needs to do is look at the clock to see if it's time to do something.
Have a look at Robin2's post on doing multiple things.

I agree - I don't think we really need a schematic.

Hi AWOL,

Thanks for your reply.

As I mentioned to Robin in my reply that I have looked at the post but it is confusing to my level as I am a beginner, I tried copying the code and modify it and I don't seem to get it right.

I am using only one motor, but the original code it for 2, but I have modified it for one motor only and that's all I need for the time being.

Example of what I need:

Current sensor sending readings continuously while motor is:
-rotating clockwise at 100% for 3 seconds
-stop for 2 seconds
-rotate counterclockwise at 25% for 5 seconds
-stops for 3 seconds
-rotates clockwise at 50% for 5 seconds
-stops for 1 second ......

and repeat......

I will keep trying with it while getting more help from you an/or suggestions and examples of codes if possible.

Thank you again :slight_smile:

OneGoal:
I have looked at the demo before I post my issue but I couldn't quite understand it and make it work for me, that's what am stuck with.

Your code in loop() is very simple (which is good) so it should not take much to make it do what you want.

If all the intervals were the same the code would be very simple - just make X happen for A millisecs, than make Y happen for A msecs etc.

If you want different timings for different actions then you need to store a list of the actions and their times. A simple way to do that would be with an array like this
int motorMoves[4][4]
motorMoves[0] = [1, 1, 100, 2000] // motor 1, mode 1, power 100, 2000 millisecs
motorMoves[1] = [1,0, 0, 1000] // motor 1 stopped 1000 milllisecs
motorMoves[2] = [1, 3, 100, 3000]
motorMoves[3] = [1,0, 0, 5000]

Then you can iterate over the 4 rows and pick out the timing etc for each step

Before going any further it would be useful to know

  • how many steps you want to use,
  • how many different motors
  • whether (if there is more than 1 motor) two or more motors need to run at the same time.

...R

A simple way to do that would be with an array like this

. . . . but obviously, not exactly like that, because the compiler won't like it.

I'm not sure if it will help the discussion any, but the OP seems like they are not understanding how a state machine works. Let me try to explain it using a "real world" example.

Suppose you are in a room, and there is a window, a fan, and a thermometer - the fan is plugged in, and turned off, and the window is closed. You haven't looked at the thermometer, so you don't know what the temperature is. Let's call this the initial state - or "State A".

On the wall is a clock, by which you can see the seconds go by.

So - a simple and linear state machine for keeping the room cool might be described as:

1. If in State A, turn off the fan and close the window.

2. If in State A (fan off, window closed), wait for 10 seconds to go by. Have 10 seconds passed? If so, change to State B.

3. If in State B, check the temperature with the thermometer.

4. If in State B (checking temperature), if the temperature goes over 80 degrees F, change to State C.

5. If in State C, turn on the fan.

6. If in State C (fan is on), change to State D.

7. If in State D, check the temperature with the thermometer.

8. If in State D (checking temperature), if the temperature goes over 90 degrees F, change to State E.

9. If in State E, open the window.

10. If in State E (window open), change to State F.

11. If in State F, check the temperature with the thermometer.

12. If in State F (checking temperature), if the temperature goes below 90 degrees F, change to State G.

13. If in State G, close the window.

14. If in State G (window closed), change to State H.

15. If in State H, check the temperature with the thermometer.

16. If in State H (checking temperature), if the temperature goes below 70 degrees F, change to State A.

17. Go to step 1.

These steps are spun thru over and over - you don't pause at any step, you just check the state, and if the state is the one you are on, you then perform a check action (see how much time has passed, or what things are in what position, or what a senor or something reads), and if the value or whatnot has been met, you change your state - then continue on. Because you are spinning thru all the steps really fast, you don't have to worry about directly doing the task indicated by a state, because you will eventually get to that new check.

While these checks, as I have indicated above, can be timed things or sensor readings - the checks can really be anything - so don't think you have to be limited. While the above example is fairly contrived (and likely wouldn't work properly - room cooling doesn't really work like this).

Implementing a state machine in software is really, really simple. You execute (most unconsciously) various state machines every single day, as part of your daily routine. You don't call the steps and wait periods "states" - but they are. Think about that - think about the real world and states - then apply that knowledge and insights to a programmed state machine. Just remember that you never, ever should use delay statements inside your state machine - the loop should "spin" continuously. If you need to pause, set it up as another state.

I hope this helps you (or someone else). Good luck with your project. :smiley:

Robin2:
Your code in loop() is very simple (which is good) so it should not take much to make it do what you want.

If all the intervals were the same the code would be very simple - just make X happen for A millisecs, than make Y happen for A msecs etc.

If you want different timings for different actions then you need to store a list of the actions and their times. A simple way to do that would be with an array like this
int motorMoves[4][4]
motorMoves[0] = [1, 1, 100, 2000] // motor 1, mode 1, power 100, 2000 millisecs
motorMoves[0] = [1,0, 0, 1000] // motor 1 stopped 1000 milllisecs
motorMoves[0] = [1, 3, 100, 3000]
motorMoves[0] = [1,0, 0, 5000]

Then you can iterate over the 4 rows and pick out the timing etc for each step

Before going any further it would be useful to know

  • how many steps you want to use,
  • how many different motors
  • whether (if there is more than 1 motor) two or more motors need to run at the same time.

...R

AWOL:
. . . . but obviously, not exactly like that, because the compiler won't like it.

When the experts disagree, a confused beginner gets even more confused :frowning:

cr0sh:
I hope this helps you (or someone else). Good luck with your project. :smiley:

Thanks cr0sh,

Great example, and that's exactly what im trying to achieve, but my struggle is with translating this simple words to a code !!

I wish it was as simple as your words :frowning:

OneGoal:
When the experts disagree, a confused beginner gets even more confused :frowning:

The error is in the detail - I have probably not used the correct syntax for creating the Array. It would have been nice if @AWOL had pointed out my mistake. (I am more familiar with Python than C++)

The concept I proposed remains sound. And it was the concept I was hoping you would respond to. If the concept works for you we can easily sort out the syntax.

...R

PS there was one really silly error in Reply #11 - I had all the items going into moveMotor[0]. I have now corrected that because it may have confused the concept. There is still probably another syntax error - that does not affect the concept.

AWOL:
. . . . but obviously, not exactly like that, because the compiler won't like it.

So what would the compiler like?

A little help would be appreciated.

...R

Robin2:
The concept I proposed remains sound. And it was the concept I was hoping you would respond to. If the concept works for you we can easily sort out the syntax.

SURE !

that's exactly what am looking for, as I mentioned in my previous replies, it is something like that

-Current sensor sending readings continuously while motor is:
-rotating clockwise at 100% for 3 seconds
-stop for 2 seconds
-rotate counterclockwise at 25% for 5 seconds
-stops for 3 seconds
-rotates clockwise at 50% for 5 seconds
-stops for 1 second ......

I will be using ONE motor to start with, then take it from there :slight_smile:

Does it matter how many steps I want ?
I think I can use as many as I want, unless there is a limitation !

Meanwhile I am playing with the SeveralThingAtTheSameTime code and trying to make it work for me, but its a bit challenging as it is using a servo with angles position and im trying with a DC motor, but I guess it wont hurt if it didn't work, am getting more familiar with some codes :slight_smile:

PS sorry for not responding to the concept in my previous reply as I got confused when I saw AWOL's reply and thought there might be a correction !

OneGoal:
that's exactly what am looking for, as I mentioned in my previous replies, it is something like that

I think we are misunderstanding each other.
I want to get your views on whether my suggestion to use an array to store the data seems suitable for what you want to do. Or do you think there are details in your requirment that I have not taken into account ?

I will be using ONE motor to start with, then take it from there :slight_smile:

If you only need one motor the data and the code can be much simpler.
You did not say whether (if there are two or more motors) they will need to run in parallel. That requirement would make the solution a lttle more complex.

Does it matter how many steps I want ?
I think I can use as many as I want, unless there is a limitation !

Yes there is a limitation. The array system I proposed uses quite a lot of memory and if you have too many steps you will not have enough memory space. If you need a lot of steps a different approach will probably be required.

The best thing would be to tell us what you would like the final project to do - described in English, not in code.

...R