Notifications
Clear all

Thoughts on motor encoders

Page 2 / 3

THRandell
(@thrandell)
Eminent Member
Joined: 6 months ago
Posts: 48
 

@dale

Sorry to be beating a dead horse.

In your case because you know that the vehicle is moving backwards you take the number of clicks while moving backwards to determine the distance traveled and track your pose with that information?  

Tom


ReplyQuote
NewburyPi
(@dale)
Estimable Member
Joined: 2 years ago
Posts: 120
Topic starter  

@thrandell  That's it, exactly. Ticks are a distance, with no inherent direction.

 

My SOP is:

- set a distance to be traveled (n ticks)

- set a direction for movement (forward or reverse)

- Apply power to the motors

- When n ticks have been counted (counted down) remove power. 

The actual position of the robot, is maintained at a higher level.

 

PS: The codemodification for determining direction (inc and dec ticks) is a tad more complex than I originally thought. To do so also requires and extra input pin (per encoder set). Playing with it right now and will let you know if I come up with anything .

Dale

--
Dale


ReplyQuote
robotBuilder
(@robotbuilder)
Noble Member
Joined: 2 years ago
Posts: 1004
 

@dale

If detected by software then the problem of missing a tick I may make it less than ideal to increase the pulse frequency?

You could change your current code to only check direction when A is high. Just store the direction in a variable. When A is low, increment or decrement according to the stored direction variable. Any error should be limited to one tick.

At least I think that would work <insert a shoulder shrug>.

Ultimately you have to try things to see if they work.

I spent some time working on the code to get the robot base to travel in a straight line using the encoders. One glitch was after a turn the swivel wheel would catch on the carpet as the base moved off in another direction causing the light weight base to "jump" and point the base in a slightly different direction.  A move that was not picked up by the encoders.

I had thought that maybe monitoring the swivel wheel's orientation to the base might be used to keep the base on the straight and narrow.

Ultimately the robot needs to orientate to fixed physical objects or fixed features to navigate and know where it is.

 


ReplyQuote
NewburyPi
(@dale)
Estimable Member
Joined: 2 years ago
Posts: 120
Topic starter  

@robotbuilder 

If detected by software then the problem of missing a tick I may make it less than ideal to increase the pulse frequency?

Yes that is always going to be a problem with slower/underpowered processors (or processors that are too busy doing other work). This is where hardware (like the LS7366R) comes in. Additionally some microcontrollers have hardware registers that can do the counting for you. 

One glitch was after a turn the swivel wheel would catch on the carpet as the base moved off in another direction causing the light weight base to "jump" 

Yep. The real world is a bummer. There is only so much you can do with waypoint. So... back to hardware. This is where IMUs come in. They can tell you how much of a jump you just made and allow you to compensate. 

Dale

 

--
Dale


ReplyQuote
NewburyPi
(@dale)
Estimable Member
Joined: 2 years ago
Posts: 120
Topic starter  

@thrandell I have some code that may work, if you want to double up your encoder frequency. Again watch out for lost ticks if it runs too fast for your microcontroller. I've commented out the second half, as it will not greatly improve the accuracy (3 ticks at most), and only impacts when changing directions. 

 

Dale

Oops! Had to republish the code, due to a b ad bad error. 

#include <Arduino.h>
#define LH_ENCODER_A 7 
#define LH_ENCODER_B 5 
#define lH_ENCODER_F 1      // doubled interrupt for Lefthand side
#define RH_ENCODER_A 6  
#define RH_ENCODER_B 4
#define RH_ENCODER_F 0      // doubled interrupt for righthand side

volatile unsigned int leftClicks;
volatile unsigned int rightClicks;

void setup() {
    pinMode(LH_ENCODER_A, INPUT);
    pinMode(LH_ENCODER_B, INPUT);
    pinMode(RH_ENCODER_F, INPUT);
    pinMode(RH_ENCODER_A, INPUT);
    pinMode(RH_ENCODER_B, INPUT);
    pinMode(RH_ENCODER_F, INPUT);
  
   // initialize hardware interrupts    
    attachInterrupt(digitalPinToInterrupt(1), leftEncoderEvent, CHANGE);
//  attachInterrupt(digitalPinToInterrupt(0), rightEncoderEvent, CHANGE);

}

void leftEncoderEvent() {
    static int A_Cnt;
  
    if ( digitalRead(LH_ENCODER_A) == HIGH ){
        A_Cnt++;
        if (A_Cnt == 1) {       // Only check B on first occurance of A being HIGH
            if ( digitalRead(LH_ENCODER_B == HIGH) )      
                leftClicks--;   // Reverse if B is HIGH on first pulse of A being HIGH
            else
                leftClicks++;   // Forward if B is LOW on fist pulse of A being HIGH
        } else 
            A_Cnt = 0;          // Reset A counter if A is LOW
/*     } else {     // This second part can be uncommented for some additional accuracy. 
        A_Cnt++;
        if (A_Cnt == 1) {       // Only check B on first occurance of A being LOW
            if ( digitalRead(LH_ENCODER_B == HIGH) )       
                leftClicks++;   // Reverse if B is HIGH on first pulse of A being LOW
            else
                leftClicks--;   // Forward if B is LOW on fist pulse of A being LOW
        } else
            A_Cnt = 0;          // Reset A counter if A is LOW */
    }
}
This post was modified 2 months ago by NewburyPi

--
Dale


ReplyQuote
huckOhio
(@huckohio)
Estimable Member
Joined: 2 years ago
Posts: 183
 

@dale 

@brianG

As I mentioned before I am just starting down the path of PID.  My objective is to get the chassis to drive in a straight line.  I am sending each motor a PWM value and the motor encoder is responding with pulses/time (I think).  So my question is what should I be evaluating to determine the "error"?

In one YouTube example the robot was trying to stay 30cm from the wall.  The robot was using an ultrasonic sensor to measure and reporting the actual distance in cm.  That is an easy calculation to calculate the error and magnitude since both values are in cm.  But I don't understand what I use for the baseline and what I use for the actual values?

Thanks

Mike

 

 


ReplyQuote
robotBuilder
(@robotbuilder)
Noble Member
Joined: 2 years ago
Posts: 1004
 

@huckohio

So my question is what should I be evaluating to determine the "error"?

"... the error is the motor spinning at the wrong speed and the corrective action is changing the power to the motor. It is this continuous testing of the motor’s speed and adjusting it to the correct speed which will make your robot’s motors spin at the correct speed and go straight."

https://projects.raspberrypi.org/en/projects/robotPID/3

 


THRandell liked
ReplyQuote
THRandell
(@thrandell)
Eminent Member
Joined: 6 months ago
Posts: 48
 

@dale

Thanks for your help with my encoder question.  I'll have to desk check your code for awhile before I understand it.

Is your assumption that the ENCODER_A and ENCODER_B lines are being input to an exclusive OR gate like the (74LS86) and that the output is connected to either the 0 or 1 hardware interrupt pin on my MCU?  So the interrupt is being triggered by the XOR results and additionally the code is testing the digitalReads for HIGH values on the ENCODER_A and ENCODER_B lines and counting appropriately.  si/no?

Thanks Tom

 


ReplyQuote
byron
(@byron)
Honorable Member
Joined: 2 years ago
Posts: 690
 

@huckohio

My spiel below has probably been better answered by @robotbuilder, but as I prepared it in my notepad, I give it in case its of interest.  And you will also probably get a better answer then mine from the gents you addressed, but I chip in the following:

If you are just considering PID based on encoder pulses then the error baseline you seek is just the difference in the encoder pulses in a given timespan.

To start with you could simply check what the difference in the number of pulses you receive from each motor. Prop up the bot to get the wheels spinning off the ground and count the encoder pulses over a time period, say one minute, when the motors are both driven at the same constant PMW rate. Find the difference in the encoder pulse numbers of each wheel and calculate the difference out a %. Now apply that percentage to the PMW to one or other of the motors, and the re-check to see if the encoders now report approx the same number of pulses over the timespan.

Thats a starting point and may get your bot running in a straight line. But probably still some more work to do, and the error rate may vary with the motor speed. But the above logic still applies and you will need to do your PID error calculation based on the difference in encoder pulses and feed this error back to adjust the PWM given to each motor. Of course you do this whilst the bot is actually moving on the ground. Now I'm sure you have seen @brianG video on tuning a PID so no point my repeating that good stuff here, but one thing I have found handy, is to use a board with wifi in the bot and establish wifi comms with your computer (http or mqtt) and then you can send PID tuning parameters direct to your bot without constantly re-programming it.

But in my experience using PID to make a bot go straight will not be so simple with just the encoders, even supposing the PMW as adjusted is spot on and the encoders are reporting the exact same number of pulses, when the bot get moving, as @robotbuilder indicated, the wheels may actually both rotate at the same rate, but other deflections such as a carpet, or something that makes one wheel slip a bit, can throw the bot off the straight line a bit.

My main play with this was with my outdoor bot, where using encoders PID feedback just does not work with the bot being tossed about on the grass and stones and the like. Indoors you may have more luck.

Posted by: @robotbuilder

Ultimately the robot needs to orientate to fixed physical objects or fixed features to navigate and know where it is.

I  agree with the observation made above.

 

This post was modified 2 months ago 3 times by byron

ReplyQuote
huckOhio
(@huckohio)
Estimable Member
Joined: 2 years ago
Posts: 183
 

@robotbuilder 

Thank you for the reply.  So in this case speed <> PWM value, but the number of pulses.  When comparing the pulses from each motor you're not comparing against a target value (e.g., PWM), but against each other.  Is that correct?  So the correction is to change the PWM inputs to get the pulses to match?  Would you keep one motor steady and adjust the other?  Or adjust both at the same time?

Thanks...this makes more sense now.  


ReplyQuote
huckOhio
(@huckohio)
Estimable Member
Joined: 2 years ago
Posts: 183
 

@byron 

Always appreciate your input!  I am working my way up to a GPS guided robot and trying to learn at the same time (hopefully this will also help when Bill starts the videos for his outdoor robot mentioned in the newsletter today).  Understand about the "slippage" issue with wheels and I am hoping to eventually use some type of better navigation (GPS & compass headings).


ReplyQuote
robotBuilder
(@robotbuilder)
Noble Member
Joined: 2 years ago
Posts: 1004
 

@huckohio

Would you keep one motor steady and adjust the other? Or adjust both at the same time?

The best way to test an idea is to try it 🙂

In one example I kept the pwm to one motor steady and increased or decreased the pwm to the other motor to keep the encoder counts the same. The idea was one motor would maintain the average speed desired.

However in theory you should be able to compute the actual position in an x,y coordinate system using the encoder data as illustrated below. You can then check to see if it is on the straight line (or any desired position for that matter). This is where you might use PID as was illustrated in another thread for keeping the robot a fixed distance from a wall.

https://forum.dronebotworkshop.com/db1/henry-ix-a-fully-autonomous-robot-platform/paged/8/#post-19546

With reference to the image below consider this scenario. We set our start coordinates at x=0 and y=0 with the robot pointing east (theta = 0). We want the robot to travel in a straight line east (blue line).  Perhaps I should add that I am using screen coordinates with the +y going downwards.

We apply a pwm rate of 200 to both motors. After a period of time we work out the velocity (distance/time) from the number of encoder ticks. It turns out that although we applied the same pwm to both wheels one wheel has travelled further than the other wheel. Using the distance travelled by each wheel we can calculate its new actual position (x=160, y=65) and new direction 43 degrees.

This is how I calculated its new position and direction (theta) given DL = distance travelled by the left wheel and DR distance travelled by the right wheel in a simulation.

 

 

    if (DL==DR){

      // Moving in a straight line 
      x = x + DL * cos(theta);
      y = y + DL * sin(theta);
      
     }else{
        
      // Moving in an arc 
      expr1 = w * (DR + DL)/ 2.0 / (DR - DL)  // w = length of axel;

      // compute new position of x and y
      x = x + expr1 * (sin((DR - DL) / w + theta) - sin(theta*DtoR));
      y = y - expr1 * (cos((DR - DL) / w + theta) - cos(theta*DtoR));

      // Calculate new orientation 
      theta = (theta + (DR - DL) / w);
      
      // Keep in the range -PI to +PI 
      if (theta > PI) {
        theta = theta + (2.0*PI);
      }
    
      if (theta < -PI) (
        theta = theta + (2.0*PI);
      }
      
    }
    

 

 

In the case of the wall following robot it was suggested sonar would measure the distance from the wall whereas in this case my assumption is you must calculate the distance from the straight line from the encoder values.

The error is the distance perpendicular to the straight line (wall).

To enlarge image, right mouse click image and choose, "Open link in new window"

 

fig1

 

 

 

 

This post was modified 2 months ago 7 times by robotBuilder

huckOhio liked
ReplyQuote
robotBuilder
(@robotbuilder)
Noble Member
Joined: 2 years ago
Posts: 1004
 

errata:

Remove the DtoR in the code example. I tend to think in degrees rather than radians probably because math isn't my forte and the DtoR stands for Degrees to Radians I missed that one when translating the code from the archaic BASIC language I like to C.

 

 


ReplyQuote
huckOhio
(@huckohio)
Estimable Member
Joined: 2 years ago
Posts: 183
 

@robotbuilder 

Thank you.  Will start "trying" today!  👍 


ReplyQuote
robotBuilder
(@robotbuilder)
Noble Member
Joined: 2 years ago
Posts: 1004
 

@huckohio 

The code example above (with errors I just noticed) was from this link,  see listing 3.

http://www.seattlerobotics.org/encoder/200010/dead_reckoning_article.html

 


ReplyQuote
Page 2 / 3