Motor Stutters

Hey y’all,

So I’ve been tinkering with a seeed Motor Shield, I can get a DC motor to run with the motordriver.goForward();. The issue I am running into is incorporating the Ultrasonic sensors, not entirely sure if it has anything to do with the motor stutters… This is the current code, a part of the code is commented out for testing purposes.

#include "MotorDriver.h"
#include "Arduino.h"
class Ultrasonic
{
public:
  Ultrasonic(int pin);
  void DistanceMeasure(void);
  long microsecondsToInches(void);

private:
  int _pin;

  long duration;// the Pulse time received;
};
Ultrasonic::Ultrasonic(int pin)
{
  _pin = pin;

}
/*Begin the detection and get the pulse back signal*/
void Ultrasonic::DistanceMeasure(void)
{
  pinMode(_pin, OUTPUT);
  digitalWrite(_pin, LOW);
  delayMicroseconds(2);
  digitalWrite(_pin, HIGH);
  delayMicroseconds(5);
  digitalWrite(_pin,LOW);
  pinMode(_pin,INPUT);
  duration = pulseIn(_pin,HIGH);


}

/*The measured distance from the range 0 to 157 Inches*/
long Ultrasonic::microsecondsToInches(void)
{
  return duration/74/2;
}

Ultrasonic ultrasonicleft(7); //Left
Ultrasonic ultrasonicright(8); //Right

void setup()
{
  Serial.begin(9600);
  motordriver.init();
  motordriver.setSpeed(200,MOTORB);
  motordriver.setSpeed(200,MOTORA);
}
void loop()
{
  long RangeInInchesLeft, RangeInInchesRight;

  ultrasonicleft.DistanceMeasure();
  ultrasonicright.DistanceMeasure();// get the current signal time on right sensor
  RangeInInchesLeft = ultrasonicleft.microsecondsToInches();//convert the time to inches;
  RangeInInchesRight = ultrasonicright.microsecondsToInches();//RangeInCentimeters = ultrasonic.microsecondsToCentimeters();//convert the time to centimeters


/*
  if(RangeInInchesRight <= 10){
    motordriver.stop();
    Serial.println("Going Left. Current Ranges");
    Serial.println("Right Sensor: " + RangeInInchesRight);
    Serial.println("Left Sensor: " + RangeInInchesLeft);
    motordriver.goForward();
    motordriver.goLeft(); 
    delay(1000);   
  } else if(RangeInInchesLeft <= 10){
    //motordriver.stop();
    Serial.println("Going Right. Current Ranges");
    Serial.println("Right Sensor: " + RangeInInchesRight);
    Serial.println("Left Sensor: " + RangeInInchesLeft);
    motordriver.goForward();
    motordriver.goRight();  
    delay(1000);  
  }
  else if(RangeInInchesLeft < 7 && RangeInInchesRight < 7){
  // while(RangeInInchesLeft < 15 && RangeInInchesRight < 15){
   motordriver.stop();
    //motordriver.goBackward();
    Serial.println("Going Back Left. Current Ranges");
    Serial.println("Right Sensor: " + RangeInInchesRight);
    Serial.println("Left Sensor: " + RangeInInchesLeft);
    motordriver.backLeft();
    delay(2000);
   //}
 }*/
 
    motordriver.goForward();
    delay(2000);
    //Serial.println("Going forward. Current Range");
   // Serial.println("Right Sensor: " + RangeInInchesRight);
    //Serial.println("Left Sensor: " + RangeInInchesLeft);
     
  //if(RangeInInches > 15){
   // motordriver.goForward();
 // }
 //delay(200);
}

I would greatly appreciate any advise/comments thanks!

Hello,
I have the same problem - what voltage is your motor rated for? what current is your motor rated for?
a “rule of thumb” is to use a voltage for the motor from 10 to 20 times the rated voltage for the motor.

Also you might try a different driver like the DVR8825 from Texas insturments, but it requires a somewhat
differect coding technique - may also try to use manual PWM or analogWrite
Check this link: arduino.cc/en/Tutorial/SecretsOfArduinoPWM preface this with http, etc

I have not yet found a solution for my problem - it is most likely a coding issue.

here is some sample code I found posted :
Check Nick Gammon’s website on use of timers.
/*
Using Timer 2. 1024 prescale, F_CPU/1024 divisor, 50% duty cycle:

[calculated]
base freq OCR2A OCR2B pulse width(ms) pin3 freq(Hz) RPM (@200 steps/rev)


61 255 127 8 61 18
120 129 64 4 120 36
240 64 32 2 240 72
480 32 15 1 489 144
→ 960 15 7 0.5 977 288 ←
| 1920 7 3 0.26 1954 576 |
| |
→ 960 seems to be about the limit of the 28BYG301 <----------
*/

// As currently configured, LOW on the direction pin is CCW.
// HIGH reverses to CW. Default to LOW for start.

int main( void )
{
int direction = 0; // 0 is LOW, 1 is HIGH.

// Setup the outputs: pin 3 for STEP, pin 4 for DIR. Per DVR8825 pinout.
DDRD |= (1 << 3); // Enable pin 3 for OUTPUT to step the DRV8825
DDRD |= (1 << 4); // Enable pin 4 for OUTPUT for step direction.

// Setup Timer2: fast PWM, clear OC2B on compare, 1024 prescale.
TCCR2A |= (1 << WGM20) | (1 << WGM21) | (1 << COM2B1 );
TCCR2B |= (1 << WGM22) | (1 << CS22 ) | (1 << CS21) | (1<< CS20);

while(1)
{

// Speed up.

for( int freq = 61; freq < 961; freq += 10 )
{
OCR2A = ((F_CPU / 1024) / freq) - 1;
OCR2B = ((OCR2A + 1) / 2) - 1;
cheap_delay( 100000 );
}

// Slow down.

for( int freq = 960; freq > 60; freq -= 10 )
{
OCR2A = ((F_CPU / 1024) / freq) - 1;
OCR2B = ((OCR2A + 1) / 2) - 1;
cheap_delay( 100000 );
}

// Reverse direction.

if( direction ) // Direction is HIGH (CW)
{
PORTD &= ~(1 << 4); // Set DIR pin LOW.
direction = 0; // Record for the next pass thru the test loop.
}
else // Direction is LOW (CCW)
{
PORTD |= (1 << 4 ); // Set DIR pin HIGH.
direction = 1; // Record for the next pass thru the test loop.
}
}
}

void cheap_delay( volatile unsigned long count )
{
while( count > 0 ) count–;
}

ewholz: a "rule of thumb" is to use a voltage for the motor from 10 to 20 times the rated voltage for the motor.

CAREFUL

That may be true for stepper motors with a proper stepper motor driver board but the OP said he has a DC motor and a motorshield, Neither of them is designed for over-voltage operation.

...R

  ultrasonicleft.DistanceMeasure();
  ultrasonicright.DistanceMeasure();// get the current signal time on right sensor
  RangeInInchesLeft = ultrasonicleft.microsecondsToInches();//convert the time to inches;
  RangeInInchesRight = ultrasonicright.microsecondsToInches();//RangeInCentimeters = ultrasonic.microsecondsToCentimeters();//convert the time to centimeters

Your Ultrasonic class leaves a bit to be desired. Having the time of flight as a member variable is not a bad idea. But, there is no way to access that value except through the microsecondsToInches() method. Therefore, instead of two calls you should only have to make one, and that one method would use a local variable, not a member variable, to store, if needed, the time of flight value.

Camel case for variable names is the recommended convention for a reason. ultrasonicRight is much easier to read and parse than ultrasonicright.

   long rangeLeft = ultrasonicLeft.Measure();
   long rangeRight = ultrasonicRight.Measure();

just looks better to me than your 6 lines of code.

You know that you are calculating the distances in inches. The names of the variables do not need to reflect that.

Just my $0.02 worth.

a "rule of thumb" is to use a voltage for the motor from 10 to 20 times the rated voltage for the motor.

Ouch ! If that is the case then why is the motor not rated 10 to 20 times higher ?

Robin2:

ewholz: a "rule of thumb" is to use a voltage for the motor from 10 to 20 times the rated voltage for the motor.

CAREFUL

That may be true for stepper motors with a proper stepper motor driver board but the OP said he has a DC motor and a motorshield, Neither of them is designed for over-voltage operation.

...R

Totally seconded, that rule of thumb is firstly nonsense, and secondly only for chopper-driven low-impedance stepper motors. The actual rule of thumb is to base the supply voltage on the back-EMF the actual motor generates at the actual speed you want it to spin... (Which isn't a rule of thumb, its a requirement to measure something!)