motor + PING))) = erratic PING))) results

I have a problem very similar to this thread:
http://arduino.cc/forum/index.php/topic,21215.0.html

My project is a simple "elevator" that goes up a specified distance if a button is pressed, or down a specified distance if another button is pressed. It knows when it's reached the top or bottom, based on what the PING))) sensor tells Arduino.

The PING))) sensor is continually read. Depending on the distance to an object it returns, a motor runs forward or backwards (or stops it, or keeps it stopped).

The problem is the output from the PING))) sensor. As the motor runs and moves the
car away from the sensor, the distance to the car that the sensor reports varies wildly. The
centimeters as measured by PING))) might look like this:
3, 3, 3, 1, 3, 3, 4, 4, 4, 0, 1, 4, 4, 4, 1, 4, 4, 4, 5, 5,5,5, 5, 1, 5, 5, 5, 1, 1, 1, 5 etc.

I am guessing that the introduction of the motor to the circuit is causing some interference with the PING. Without the motor, if I just move the "elevator car" up and down with my hands, the PING sensor always gives the right values, without the variations shown above.

I took the advice from the thread above about using a capacitor (I used 0.1uF) across the terminals of the motor, and it didn't solve the problem. The motor has a separate 5V power supply as shown in the Fritzing diagram.

This is the first real project I've tried with Arduino - I have very little experience with electronics, so I am at a loss for how to troubleshoot the issue. I did the tutorial booklets and studied the Arduino Cookbook, and am at a point where I can't continue.

Here is the Fritzing diagram (the .fzz is also attached if this doesn't show up well):
The H-bridge chip is L293 (SN754410NE).
The power supply in the top left is SparkFun's 5V breadboard power supply.

Code:

/*
This is a project that started with the H-Bridge sketch from Arduino Cookbook page 283 and
the PING sensor tutorial at http://www.arduino.cc/en/Tutorial/Ping.  Also has some elements of the basic "getting input from a button" Arduino tutorial. 

There is a PING sensor that constantly locates an "elevator car" on rails.  When an "Up" button
is pressed, the motor runs, acting as a winch, to lift the car.  When the "Down" button is pressed, the motor runs the other direction.

The program below defines three "floors", with the ground floor position at 3 cm, and each "floor" being 6 cm high.

Pressing an Up button will add 6cm to the destination distance amount, and the motor will run until it reaches that position, and stop.  Pressing a down button, when the car is not at the "ground" level, will run the motor the other way to allow the car to move down.

The loop() function will get the distance from the sensor to the elevator car
and control the motor to move the car in the right direction to get to the 
distance stored in the variable called destinationPosition.

*/

//up and down tact buttons
int btnDown = 2; 
int btnUp = 3;

//H-Bridge pins
const int hBridgeInputPin2 = 4; //h-bridge input pin 2
const int hBridgeInputPin1 = 5; //h-bridge input pin 1
const int hBridgeEnablePin = 6; //h-bridge enable pin

//The pin number of the PING)) sensor's output.
const int pingPin = 7;

const int groundFloorPositionCm = 3;  //bottom of first floor is 3 cm from sensor
const int topFloorPositionCm = 21; //bottom of the third floor is at 21 cm from sensor
const int floorHeightCm = 6;  //a "floor" is 6 cm high.  This allows 3 floors betw 3 and 21 cms.                

//is the car going up? if so, this is set to true. If going down, it's set to false.
boolean goingUp = false; 

//this is the current destination, in cms from the sensor
//the motor will run in the correct direction to reach this position, then it will stop.
int destinationPosition = -1;  

void setup()
{
  //set up serial communication to receive debugging information
  Serial.begin(9600);
  
  //set up pins for the h-bridge
  pinMode(hBridgeInputPin1, OUTPUT); 
  pinMode(hBridgeInputPin2, OUTPUT); 
  
  digitalWrite(hBridgeInputPin1, LOW); 
  digitalWrite(hBridgeInputPin2, HIGH);
  
  //up and down button pins are used for input
  pinMode(btnUp, INPUT);
  pinMode(btnDown, INPUT);

  //set the initial destination to be the first floor by default.  When the loop() function starts running,
  //it will move the car to the initial position if it's not already there.
  InitializeElevatorPosition(); 
}

void loop()
{
  ReadButtons(); 
 
  ControlMotor();  
}

void ReadButtons()
{
  int curDistance =  GetCurrentCarPositionCms();  
  
  //was the Up button pressed? If the car is stopped, adjust the destination distance, and run the motor to go up.
  if (digitalRead(btnUp) == LOW) 
   {
     if (curDistance == destinationPosition && curDistance < topFloorPositionCm)
       {
         destinationPosition += floorHeightCm; 
         goingUp = true; 
       }
       
     Serial.println("****  button up");  
     return; 
    }

    //was the Down button pressed? If the car is stopped, reduce the destination distance and run the motor
   if (digitalRead(btnDown) == LOW) 
   {
     if (curDistance == destinationPosition && curDistance > groundFloorPositionCm)
      {
        destinationPosition -= floorHeightCm; 
        goingUp = false; 
      }
      
      Serial.println("**** button down"); 
      return; 
    }
}

//when the program starts, move it to the "ground" floor
void InitializeElevatorPosition()
{
  destinationPosition = groundFloorPositionCm;
}

//using the PING))), get the number of centimeters from the sensor
//to the bottom of the elevator car.
int GetCurrentCarPositionCms()
{
  // establish variables for duration of the ping,
  // and the distance result in inches and centimeters:
  long duration, inches, cm;

  // The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
  // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
  pinMode(pingPin, OUTPUT);
  digitalWrite(pingPin, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin, LOW);

  // The same pin is used to read the signal from the PING))): a HIGH
  // pulse whose duration is the time (in microseconds) from the sending
  // of the ping to the reception of its echo off of an object.
  pinMode(pingPin, INPUT);
  duration = pulseIn(pingPin, HIGH);

  return MicrosecondsToCentimeters(duration);
}

// Runs motor, if necessary, in the right direction to reach the 
// current destination.  Stops motor (or keeps motor stopped) if at the destination position
void ControlMotor()
{
  int cmsDistanceFromPing = GetCurrentCarPositionCms(); 
  Serial.print(cmsDistanceFromPing);
  Serial.println();
  
  //we're in the position we want - stop the motor, or leave it stopped.
  if (cmsDistanceFromPing == destinationPosition)
  {
    analogWrite(hBridgeEnablePin, 0);
    return; 
  }

  if (cmsDistanceFromPing > destinationPosition) 
  {
    //destination is below the current position - run the motor clockwise to lower the car
    digitalWrite(hBridgeInputPin1, HIGH); 
    digitalWrite(hBridgeInputPin2, LOW); 
  }
  else 
  {
    //run motor clockwise - lower the car
    digitalWrite(hBridgeInputPin1, LOW); 
    digitalWrite(hBridgeInputPin2, HIGH); 
  }

  //make sure the motor is running
  //use the map() function to control the speed of the motor (between 0 and 255)
  analogWrite(hBridgeEnablePin, 255); 
}

long MicrosecondsToCentimeters(long microseconds)
{
  // The speed of sound is 340 m/s or 29 microseconds per centimeter.
  // The ping travels out and back, so to find the distance of the
  // object we take half of the distance travelled.
  
  //http://www.arduino.cc/en/Tutorial/Ping
  
  return microseconds / 29 / 2;
}

Any ideas are welcome!

Thanks.

Don

Elevator (post for help).fzz (15.6 KB)

I took the advice from the thread above about using a capacitor (I used 0.1uF) across the terminals of the motor, and it didn't solve the problem.

Was it a ceramic capacitor?
Was it placed close to the motor?

Try adding a bulk decoupling capacitor like 100uF or more in parallel with the ceramic capacitor.

Give up on solderless bread board, you are on real projects now so solder everything. Use strip board or some other prototyping board.

Hi Grumpy_Mike,

Thanks for your reply.

Yes, it's a ceramic capacitor, and it's attached right at the leads of the motor, as close as I could make it.

I'll try your 100uF cap suggestion when I have a chance to get out and get some more capacitors. I only have Radio Shack as a local source of components, so I don't know how lucky I'll get there.

I'm planning to solder as soon as I can get it to work. :slight_smile: And I'm looking forward to it.

Thanks.

Don

Hi Grumpy_Mike,

After looking into it a little more, I see that the SparkFun power supply does have a 100uF capacitor (http://www.sparkfun.com/datasheets/Prototyping/Breadboard%20Power%20Supply%20v10.pdf). Is that where you were thinking one should go in my circuit? Or is it different?

If it's not what you were thinking, where specifically would you put the 100uF capacitor? Some information I've seen says to put a capacitor as close to the power supply as possible - would you put it next to the power supply, or at the H-bridge, or somewhere else?

I noticed no one suggested I use a motor shield - is that not necessary for what I'm doing, or would it help to smooth out the issues I'm seeing?

Thanks again.

Don

Polite bump...

I have some new capacitors now I could use in the circuit. I put one 100uF as close to the power supply as I could (I was guessing where to put it) but it didn't help.

I also reduced the weight of the payload the motor is moving up and down, and that didn't help either.

Any advice on the placement of the capacitor?

Thanks!

Don

Put them close to the load not the power supply. You could also try an inductor in a Pye circuit like the last diagram on this page:-
http://www.thebox.myzen.co.uk/Tutorial/De-coupling.html

Also try a star ground. That is connecting all the grounds together at one point instead of chaining them. Try and keep the wiring neat and away from the source of interference, that is your motor. You need caps on the motor and the chips.

I'd try running the leads to the motor through a ferrite bead. Go through the bead, loop back around and go through again, then back to the motor (or power source, depending on the side of the bead). Those are supposed to help with interference issues.