Pages: [1]   Go Down
Author Topic: Counting hall sensor pulses  (Read 980 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello everybody!

First things first, new to arudino, new to programming, new to electronics! This is going to be difficult.

To start with, this is a project to electronically control the bump and rebound settings of the shock absorbers in our formula student race car this year via Arduino and bi-direction DC motors.

As i mentioned, I am very new to this whole area of engineering, being an automotive engineer. The first step taken was to compile a wireless programme (via Xbees) that would allow me to input a charactor in one COM port which would transmit to another, consequently controlling the motor as required, shown below:

#include <NewSoftSerial.h>
#include <AFMotor.h>
AF_DCMotor motor(1);
NewSoftSerial mySerial =  NewSoftSerial(2, 13);

void setup()  {
  pinMode(13, OUTPUT);
  Serial.begin(9600);
  Serial.println("Hi P!");
  // set the data rate for the SoftwareSerial port
  mySerial.begin(9600);
  mySerial.println("Hi D!");
  motor.setSpeed(200);
  }

void loop()                     // run over and over again
{
 char newchar;
  if (mySerial.available() > 0) {
    newchar = mySerial.read();
    Serial.print(newchar);
    if (newchar == '1'){
 
      //drive the motor
        motor.run(FORWARD);
        delay(1000);
        motor.run(RELEASE);
      }
    if (newchar == '2'){
 
      //drive the motor
        motor.run(BACKWARD);
        delay(1000);
        motor.run(RELEASE);
    }
  }
}

So pressing 1 turned the motor forwards for 1 second, and 2 turned it backwards for a second.

The next step is to count the amount of pulses from the hall sensor during this process. The sensor has 4 pulses per rotation and is geared at a ratio of 298:1 (encoder shaft : output shaft).

This is where i have got to:

#include <NewSoftSerial.h>
#include <AFMotor.h>

AF_DCMotor motor(4);

const int EncoderSpeed = 19; // pin that encoder speed attached to

NewSoftSerial mySerial =  NewSoftSerial(2, 13);

int pulseCounter = 0;  // counter for number of pulses


void setup()  {
  pinMode(EncoderSpeed, INPUT);
  pinMode(13, OUTPUT);
  Serial.begin(9600);
  Serial.println("Hi P!");
  // set the data rate for the SoftwareSerial port
  mySerial.begin(9600);
  mySerial.println("Hi D!");
  motor.setSpeed(200);
 
}
void loop()                     // run over and over again
{
   char newchar;
  if (mySerial.available() > 0) {
    newchar = mySerial.read();
    Serial.print(newchar);
    if (newchar == '1'){
 
      //drive the motor
        motor.run(FORWARD);
        delay(1000);
        motor.run(RELEASE);
        digitalRead(EncoderSpeed); // read the encoder input pin
        mySerial.println("number of encoder pulses:  ");
        mySerial.println(pulseCounter, DEC);
      }
  }
}

I am receiving feedback wirelessly with the number of pulses, which is incorrect, simply 0 every time i input 1 to turn the motor for 1 second. I appreciate that interupts is the way to go, however, have little understanding of these currently.

The encoder is connected to the motor shield via the speed signal, not the direction as this is not needed for the project. I assume this is a very simple issue, but some guidance on how to actually get the arduino to count the pulses and transmit this back to me would be greatly appreciated.

Finally, the end requirement is to input a character which signifies a number of pulses for the motor to turn for, again any input here would be appreciated. Although I am trying to learn bit by bit!

Thanks
« Last Edit: April 03, 2011, 10:56:14 am by UHRacing_P » Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 549
Posts: 46090
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
NewSoftSerial mySerial =  NewSoftSerial(2, 13);

void setup()  {
  pinMode(13, OUTPUT);
But, you are using pin 13 with NewSoftSerial. You should not be setting pinMode for that pin.

Code:
        digitalRead(EncoderSpeed); // read the encoder input pin
You are only reading the encoder once a second. That is not near often enough.

You really need to get rid of the delay() calls. Look at the BlinkWithoutDelay example.

Quote
The encoder is connected to the motor shield via the speed signal, not the direction as this is not needed for the project. I assume this is a very simple issue, but some guidance on how to actually get the arduino to count the pulses and transmit this back to me would be greatly appreciated.
Both the speed and direction pins are output. You can't read anything from them.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
You are only reading the encoder once a second. That is not near often enough.

How is it that i can adapt this?

What purpose does it serve to rid the delay() calls, at the moment they are simply there to turn the motor for a second. Eventually, they will not be used, rather the motor will turn to a set number of pulses.

Quote
Both the speed and direction pins are output. You can't read anything from them.

Pardon me for sounding stupid, but i thought the whole point of encoder outputs was to read and harness them. My interpretation was that i could read the pulses directly. Do i need to input an equation equating pulses from speed and time?
Logged

0
Offline Offline
Newbie
*
Karma: 1
Posts: 28
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I am receiving feedback wirelessly with the number of pulses, which is incorrect, simply 0 every time i input 1 to turn the motor for 1 second.
Your code is doing exactly what you are telling it to do, so it is not incorrect.

Code:
int pulseCounter = 0;  // counter for number of pulses

digitalRead(EncoderSpeed); // read the encoder input pin

mySerial.println(pulseCounter, DEC);

You declare pulseCounter and initialise it to zero and then later you print it out. You do precisely nothing to it in the interim. Perhaps if you added the value returned by digitalRead to the variable pulseCounter, different numbers would be printed.
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 549
Posts: 46090
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
What purpose does it serve to rid the delay() calls, at the moment they are simply there to turn the motor for a second.
The problem is that absolutely nothing else (except interrupts) happens during a delay(). You can't read encoder switching during a delay().

Quote
Pardon me for sounding stupid
No problem. Happens to the best of us.

Quote
i thought the whole point of encoder outputs was to read and harness them.
It is. The speed pin on the motor shield is not the place to do it, though. The encoder needs to be connected to one or more pins on the Arduino. Typically, encoders have an A switch and a B switch, so they need to be connected to two digital INPUT pins, and read as often as possible. The encoder itself does not keep track of switch changes. You must poll often enough to catch all changes.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
The encoder needs to be connected to one or more pins on the Arduino

The encoder is connected to the motor shield which relates to analogue i/o 6 (digital 19 i believe) on the Arduino. The encoder being used has one output for direction, and one for speed. We are simply interested in the speed.

Is the code written seriously incorrect, or am i only missing certain procedures to receive the correct pulse reading outputs?
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 549
Posts: 46090
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
The encoder is connected to the motor shield
Repeat after me: The encoder is NOT a motor.

The direction pin on the shield is an OUTPUT pin. You can't read diddlysquat from an OUTPUT pin. The shield is simply NOT wired to let the Arduino read from any of its pins.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I am completely baffled. There is no connection to the direction pin on the shield, where did this come from?

The encoder is wired to the shield feet which are inserted into the arduino uno, hence it is wired to analogue input 5 on the uno.

« Last Edit: April 05, 2011, 05:25:08 am by UHRacing_P » Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 238
Posts: 24353
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
There is no connection to the direction pin on the shield, where did this come from?
Well, so far, you haven't shown or told us anything about your shield, so we can't really comment.
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 549
Posts: 46090
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I am completely baffled. There is no connection to the direction pin on the shield, where did this come from?
From your first post:
Quote
The encoder is connected to the motor shield via the speed signal
Now perhaps we are not talking about the same thing. There are pins on the motor shield that control the direction and speed of the motor. My assumption, apparently faulty, since you are using the same names for the encoder output was that you were connecting the encoder to the motor pins.

You now seem to be not connecting the encoder to those pins at all. My apologies.

You don't measure speed with an encoder, though. At least not directly, so, it would be better if you did not refer to the encoder speed pin. What you measure is the number of pulses. If you count pulses for some known length of time, you can compute speed.

Depending on the frequency with which the pulses arrive, you may be able to count them all by polling. On every pass through loop (which means that you can never use delay()), read the encoder switch which is attached to some non-motor related digital pin. If it is high, and was not before, increment a counter. When the number of pulses reaches the goal, shut the motor off and reset the counter.

If the pulses arrive faster than polling can read them, you'll need to define an interrupt handler and attach it to an external interrupt pin (2 or 3), and have the interrupt handler increment the counter.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Apologies, it is an adafruit shield, found here http://www.ladyada.net/make/mshield/index.html

Quote
You don't measure speed with an encoder, though. At least not directly, so, it would be better if you did not refer to the encoder speed pin. What you measure is the number of pulses. If you count pulses for some known length of time, you can compute speed.

Firstly, apologies for the confusion with the encoder input. The plan is to measure the amount of pulses, and actually get the motor to turn for a set number of these, ie, 1192 pulse would be a full output shaft revolution in our case.

Quote
read the encoder switch which is attached to some non-motor related digital pin

We are using an analogue pin (A5) at the moment, but i believe this can also be used as a digital (19) i/o.

Quote
If the pulses arrive faster than polling can read them, you'll need to define an interrupt handler and attach it to an external interrupt pin (2 or 3), and have the interrupt handler increment the counter.

We have been told that we will need to use an interrupt, if possible could you push in the right direction with the best way to implement the code for this?

Regarding attaching to an external interrupt pin, does this require extra wiring or extra code?
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 549
Posts: 46090
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Regarding attaching to an external interrupt pin, does this require extra wiring or extra code?
The wire from the encoder would go to pin 2 or pin 3 instead of pin 19. So, no extra wiring.

Extra code - yes. Look at the attachInterrupt() function. There are examples.
Logged

Pages: [1]   Go Up
Jump to: