Sunday 4 February 2018

DC motor with rotary encoder feedback control using only a Raspberry Pi

In messing about with DC motors I knew I wanted to track position accurately, and I hoped I could do this with just an RPi, but all the advice and even some youtube videos said it couldn't be done reliably without using an arduino or other external controller - usually because the feedback loop timing requirements can't be met by an RPi. But having done a few very simple sums, it seemed to me it should be quite practical:
  • motor running at 10,000 rpm, with (say) 3 pole rotary encoder gives 500 pulses / second
That's pretty slow really - a package like pigpio says it can reliably time things to 5 microseconds or around  40 times faster than the pulse rate - so where's the problem? This nice thread here looked encouraging......

2 problems at least in what others have tried:
  1. trying to do this on an RPi running the full gui. Well gui's are well knows for being *really* nasty if you're trying to do anything time critical, if you want  an RPi to do something that has previously been done on dedicated hardware or low level machines like arduinos, starting by running a gui is like swimming in concrete boots!
  2. The VAST majority of code examples on picking up edges / pulses are using code looping reading the GPIO until it changes. Good grief, nice and simple, but REALY shouldn't be used other than a quick breadboard test to see if something appears to be working. Programming 101 grade F code.
So lets try and do this sensibly:
  1. Use a raspbery Pi Zero - cos we want something small, low power and cheap and if it works on a zero it will work on any other recentish Pi.
  2. Use raspbian lite. We can put the gui somewhere else - or use a web browser with the Zero running a baby web server.
  3. Use pigpio's daemon to do the hard work.
  4. Write in python - 'cos if it works reasonably well in python we can always use C++ to hand crank the 1 or 2 little bits that are critical.
  5. Use a pipgio callback to pick up the edges - in fact better still just use the callback tally function, because we probably only need the feedback loop to run 20 times a second or so.
So after couple of days messing about I have an untidy but working dc motor controller:
  1. Raspberry Pi Zero
  2. 2.5Ah power bank - Promate Aidbar-2
  3. Pure python3
  4. micrometal DC motor
  5. pololu magnetic rotary encoder
  6. H bridge in a pHat to drive the motor. (in fact I use pigpio PWM to drive the H bridge - it's about 1/2 the cpu load of the pimoroni library)
  7. home rolled motor control class with simple PID feedback running at 20Hz
The motor runs smoothly; although the low level control is quite jittery this is smoothed out pretty well by the motor's rotational inertia. Maybe some smoothing on the derivative component would help - I'll try that later.
The motor flat out no load runs at just over 500 ticks per second, this test is at 300 ticks per second and once initial correction has completed, the error is only 1% - 2%. This is with no load. The next graph shows the response to load changes:

This is a very basic test - I just squeezed the output wheel and released it a few times - sometimes to the point of nearly stalling the motor.

3 comments:

  1. Hello,

    I like what you did on this project and I would like to know if can you provide more information about your wiring and programming. I have a motor with an encoder but I do not know how to get the feedback from the encoder to my Raspberry Pi, I am new in electronics and Raspberry Pi, so your help will be really important for me.

    Thank you

    ReplyDelete
  2. same, how to read an encode with a raspberry pi and control the motor using the encoder?

    ReplyDelete
  3. There is proof of concept level code below, and also there are links to further info in the readme. I'm not using this code any more, so can't help you much with any further info beyond what is in the repo.

    https://github.com/pootle/pimotors

    ReplyDelete