Working Random Servo Bi-Directional and Speed DCMotor Sketch

I was able to make the project I want by cut-copy-and-pasting different sketches.
This sketch uses the Adafruit Motor Shield V2 and runs 2 servos at random and one DC Motor in both directions with adjustable speed control.

I just have a few questions about how it works.

I notice there is some latency on the direction control of the DC motor. Is this because of the delay on the servo? Or is that just normal?

Please look at my sketch and you can see my questions.

There is a ON-OFF-ON direction switch on pins 6 & 7 with pull up resistors.

There is a 1 k pot on pin A0 for speed control (both ends tied to +5 and gnd).

Do you see anything that is not quite right?

thanks, steve


#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_PWMServoDriver.h"
#include <Servo.h>

Servo servo1;
Servo servo2;


Adafruit_MotorShield AFMS = Adafruit_MotorShield(); 

Adafruit_DCMotor *myMotor = AFMS.getMotor(1);


int potPin = A0;
int buttonApin = 6;
int buttonBpin = 7;
int pos = 0;               // does this refer to a pin or is it just a memory bank?
int pos2 = 1;            // this one too….?

void setup() {
  
  AFMS.begin();
  pinMode(buttonApin, INPUT);
  pinMode(buttonBpin, INPUT);
}

void loop() {
  if (digitalRead(buttonApin) == HIGH)
 if (digitalRead(buttonBpin) == LOW)
    {
  myMotor->run(FORWARD);
    }
    if (digitalRead(buttonApin) == LOW)
    if (digitalRead(buttonBpin) == HIGH)
    {
  myMotor->run(BACKWARD);
    }
    if (digitalRead(buttonApin) == LOW)
    if (digitalRead(buttonBpin) == LOW)
    {
  myMotor->run(RELEASE);
    }
  myMotor->setSpeed(analogRead(potPin)/4);
  
  int time = 150;      // what is this 150? there is another delay below…
      delay(time);
     
      int position = random(0, 180);
     int pos2 = random(0, 180);
     
      servo1.attach(10);  // 
      servo2.attach(9);
     
      delay(250);        // what does this do? how does it compare to the 150 above?
      servo1.write(position);
      servo2.write(pos2);
  }

I don't know why you have pairs of IF statements like this

  if (digitalRead(buttonApin) == HIGH)
 if (digitalRead(buttonBpin) == LOW)

If you mean only to test buttonBpin if buttonApin is HIGH then you need a "{" after the first line.

If you intend the code only to act if one is HIGH and the other LOW you need to have an && between them, or an || (OR) if you want to act when either of the tests is met.

...R

The latency occurs because you have delays in to limit the speed of loop(). With the approach you're using the delays are necessary so that the servos have time to move to each random position before you move to the next one.

While this approach sort-of works, it's not a good one. A better approach would be to use a non-blocking design to control the timed servo movements. The blink without delay example sketch demonstrates how to carry out actions after an interval without making your sketch stop and wait for the interval to pass.

Also, as Robin2 says, please sort out the structure of those if statements. I recommend that you always follow an if expression with a pair of { and } braces, with the conditional code between them. Put each { and } on separate lines with matching pairs indented to the same level and the code between them indented one extra level. The tools/autoformat command can be used to sort out the indentation. There are several places where you have multiple if statements that could and should be collapsed into a single if statement.

if (digitalRead(buttonApin) == LOW)
if (digitalRead(buttonBpin) == LOW)
{
    myMotor->run(RELEASE);
}

Would be better as:

if ( (digitalRead(buttonApin) == LOW) and (digitalRead(buttonBpin) == LOW) )
{
    myMotor->run(RELEASE);
}

Thank you for your help.
I cleaned up my if statements… but I think I need help with implementing the no-delay with the random servos. They are not just going on and off like an led blinking without a delay.

#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_PWMServoDriver.h"
#include <Servo.h>

Servo servo1;
Servo servo2;


Adafruit_MotorShield AFMS = Adafruit_MotorShield(); 

Adafruit_DCMotor *myMotor = AFMS.getMotor(1);


int potPin = A0;
int buttonApin = 6;
int buttonBpin = 7;
int pos = 0;
int pos2 = 1;

void setup() {

  AFMS.begin();
  pinMode(buttonApin, INPUT);
  pinMode(buttonBpin, INPUT);
}

void loop() {
  if ( (digitalRead(buttonApin) == HIGH) && (digitalRead(buttonBpin) == LOW) )
  {
    myMotor->run(FORWARD);
  }
  if ( (digitalRead(buttonApin) == LOW) && (digitalRead(buttonBpin) == HIGH) )
  {
    myMotor->run(BACKWARD);
  }
  if ( (digitalRead(buttonApin) == LOW) && (digitalRead(buttonBpin) == LOW) )
  {
    myMotor->run(RELEASE);
  }
  myMotor->setSpeed(analogRead(potPin)/4);

  int time = 150;
  delay(time);

  int position = random(0, 180);
  int pos2 = random(0, 180);

  servo1.attach(10);  // 
  servo2.attach(9);

  delay(250);
  servo1.write(position);
  servo2.write(pos2);
}

stevex:
They are not just going on and off like an led blinking without a delay.

You haven’t said how you want them to behave so it’s a bit difficult to give advice!

Do you want them to go on and off (whatever that means for a servo) like a blinking led?

It occurs to me that a delay of 250 millisecs is very short for a servo to do anything.

I think you need to study the “blink without delay” example to understand a better way of managing timing.

…r

stevex:
They are not just going on and off like an led blinking without a delay.

They are, if you think about it. The blink without delay example demonstrates how to do something after an interval. In the example, what it does it toggle an LED on or off. In your case you want it to generate the next random position and send that to the servo. What is does is different, but the logic that decides when to do it is the same.

@PeterH, I assumed that sentence was the OPs attempt to describe what is happening.

...R

Yes, sorry, I do want the servos to move at random.

You will have to explain in much greater detail what you would like to happen AND what is actually happening using the sketch you already have.

You do the hard work -- we provide little bits of help.

...R

I have one DC motor with an ON-OFF-ON switch on pins 6 & 7 with pull down resistors. This controls direction & shuts motor off like I want. I also have a speed control pot on pin A0 that controls speed of DC motor. This is working like I want but has a latency due to delays.

I also have 2 servos which I want to move at random. This is working, but the delays mess with the DCmotor switching directions and stopping.

My sketch is working the way I want, I just want to get rid of the latency or reduce it. I am not a coder at all. I’ve gotten this far by cut-copy-paste and messing with the code. The blink without delay makes a little sense to me, but to implement it in my sketch is beyond me so far.

#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_PWMServoDriver.h"
#include <Servo.h>

Servo servo1;
Servo servo2;


Adafruit_MotorShield AFMS = Adafruit_MotorShield(); 

Adafruit_DCMotor *myMotor = AFMS.getMotor(1);


int potPin = A0;
int buttonApin = 6;
int buttonBpin = 7;
int pos = 0;
int pos2 = 1;

void setup() {

  AFMS.begin();
  pinMode(buttonApin, INPUT);
  pinMode(buttonBpin, INPUT);
}

void loop() {
  if ( (digitalRead(buttonApin) == HIGH) && (digitalRead(buttonBpin) == LOW) )
  {
    myMotor->run(FORWARD);
  }
  if ( (digitalRead(buttonApin) == LOW) && (digitalRead(buttonBpin) == HIGH) )
  {
    myMotor->run(BACKWARD);
  }
  if ( (digitalRead(buttonApin) == LOW) && (digitalRead(buttonBpin) == LOW) )
  {
    myMotor->run(RELEASE);
  }
  myMotor->setSpeed(analogRead(potPin)/4);

  int time = 150;
  delay(time);

  int position = random(0, 180);
  int pos2 = random(0, 180);

  servo1.attach(10);  // 
  servo2.attach(9);

  delay(250);
  servo1.write(position);
  servo2.write(pos2);
}

OK, now I understand why you are comparing the values of two separate pins. But I presume that has nothing to do with the servos.

You should do the servo.attach stuff in setup() - it only needs to be done once.

The blink without delay concept is a bit like cooking dinner. You don't sit and watch the cooker for an hour and a half. Instead, you switch on the oven and note the time from the clock (say 18:00). When the clock says 18:10 you know the oven is hot enough so you put your chicken in to roast. When the clock say 19:20 (I'm not a cook) you know it's time to start the vegetables etc etc

With the Arduino millis() is the clock. Record the value at the start and then do other things when

millis() - prevValueOfMillis == theDelayYouWant

If you just want the same delay each time you could do something like this

first of all record the value of millis() in setup to get a starting value

prevMillis = millis();

Then where you now have delay(250) you would have something like this

newMillis = millis();
if (newMillis - prevMillis > 250) {
   prevMillis = newMillis;
   // stuff to move the servos
}

Remember to create prevMillis and newMillis as a data type of unsigned long.

...R

I have no idea what I’m doing…do I have to go and learn C++ to get this?
I still don’t know syntax and…

I stripped it down to just the two servos. With the delay it works, but I am not implementing things correctly without the delay. This gives me 2 servos shuttering, which I imagine is they don’t have the time to respond to the random commands.

Sorry, I study the refernce page and the blink without delay, but having a bit of trouble wrapping my head around it all.

-steve

#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_PWMServoDriver.h"
#include <Servo.h>

Servo servo1;
Servo servo2;

unsigned long prevMillis;
unsigned long newMillis;

int pos;
int pos2;

void setup()
{
  
  servo1.attach(10);
  servo2.attach(9);
  
  
}

void loop()
{
 
  prevMillis = millis();
 
  int pos = random(0, 180);
  int pos2 = random(0, 180);

  newMillis = millis();
if (newMillis - prevMillis > 250)
   prevMillis = newMillis;
   
  servo1.write(pos);
  servo2.write(pos2);

}

OMG. I think I got it.

This sketch is working without delay…!

Now I must study what the hell I did…

and add the DCMotor back in. :slight_smile:

#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_PWMServoDriver.h"
#include <Servo.h>

Servo servo1;
Servo servo2;

unsigned long prevMillis = 0;
long interval = 500;

int pos;
int pos2;

void setup()
{
  
  servo1.attach(10);
  servo2.attach(9);
  
}

void loop()
{
 
 unsigned long newMillis = millis();
 
  
if (newMillis - prevMillis > interval){
   prevMillis = newMillis;
   
   int pos = random(0, 180);
  int pos2 = random(0, 180);
   
  servo1.write(pos);
  servo2.write(pos2);

}}

Glad to hear you are making progress.

Isn't it much more satisfying when you figure things out yourself?

I find (literally) that I understand things better after the 5th or 10th read.

If there are specific program instructions that you don't understand ask a question here. There is a lot of useful info in the Reference section with little code snippets that illustrate things.

...R

Yes, thank you.

Here is a draw bot I made with the random servos...just a prototype at this point....
thanks for your help....

That's really cool and so wonderfully simple ....

...R