Go Down

Topic: High-speed motor control with ninja-like precision (Read 6802 times) previous topic - next topic

pastafarian

Newb here, so go easy on me...

The project I'm trying to implement involves driving a dc motor at rather high frequency (~230 rotations/second) for a specified number of complete rotations. It's important that the motor comes to rest at the same position where it began, because I'll subsequently trigger a DSLR camera to snap a photo of the object being rotated, and repeat this process multiple times.

I'm using this Pololu motor (gearbox removed): http://www.pololu.com/catalog/product/2271, which has an integrated 48 CPR quadrature encoder. I'm controlling the motor with an Arduino Uno, via the Pololu Simple Motor Controller.

As a starting point, I've written a sketch that runs the motor for a specified number of encoder changes (equal to 20 complete rotations) then stops:

Code: [Select]

#include <SoftwareSerial.h>
#define rxPin 10
#define txPin 13
SoftwareSerial smcSerial = SoftwareSerial(rxPin, txPin);

#define encoder0PinA 2
volatile unsigned int encPos = 0;

int pinIRLED = 9;
int pinIRLED_G = 8;
int pinENC = 11;
int pinENC_G = 10;

void exitSafeStart()
{
  smcSerial.write(0x83);
}

void setup()
{
  // Set pins for motor encoder power
  pinMode(pinENC, OUTPUT);
  pinMode(pinENC_G, OUTPUT);
  digitalWrite(pinENC, HIGH);
  digitalWrite(pinENC_G, LOW);
 
  pinMode(encoder0PinA, INPUT);   
  attachInterrupt(0, EncoderA, CHANGE); // encoder pin on interrupt 0 (pin 2)

  smcSerial.begin(19200);
  Serial.begin(57600);

  // the Simple Motor Controller must be running for at least 1 ms
  // before we try to send serial data, so we delay here for 5 ms
  delay(5);
  smcSerial.write(0xAA);  // send baud-indicator byte
  exitSafeStart();  // clear the safe-start violation and let the motor run
}

void setMotorSpeed(int speed) // speed should be a number from -3200 to 3200
{
  smcSerial.write(0x85);  // motor forward command
  smcSerial.write(speed & 0x1F);
  smcSerial.write(speed >> 5);
}

void EncoderA()
{
  encPos = encPos + 1; // Count encoder A changes
}

int speedo = 3100; // Motor speed
int rotations = 20; // Number of complete motor rotations
int multiplier = 24; // Number of encoder changes per rotation
int pulses = rotations*multiplier;
int N = 5; // cycle repeat

int count = 1;
void loop()
{
  if (count <= N)
  {
    encPos = 0;
    while (encPos < pulses)
    {
      setMotorSpeed(speedo);  // CHARGE!
    }
       
    setMotorSpeed(0); // stop motor
    delay(100); // Allow motor to come to rest
   
    Serial.print(pulses); // # of changes I specified
    Serial.print(":");
    Serial.print(encPos); // # of changes measured
    Serial.println();
   
    count++; // iterate to next cycle
  }
  else
  {
     setMotorSpeed(0); // stop motor after last cycle
  }
   
}


Of course, the motor can't stop on a dime, so it overshoots the number of encoder changes I've specified in my while loop. In a bit of wishful thinking, I thought that if the overshoot was at least consistent from trial to trial, I could just subtract that from my "pulses" variable, and have the motor come to rest at exactly 20 complete rotations.  Not so much. The motor rotates for another 89 to 94 encoder changes at this frequency - so not consistent.  Plus, I'm not even totally convinced that the interrupts are catching every encoder change at this frequency (any thoughts on this?) 

So I'm not sure where to go from here. Is this even the right approach for this type of project? Should I be working with a PID controller instead? I have no experience with a PID controller, so am unfamiliar with their limitations and tuning challenges.

Many thanks for any thoughts!

PeterH

Do you really have to use a DC motor rather than a stepper motor?

If you are stuck with the DC motor, I'd suggest using a feedback system to control the position of the motor. A standard PID control algorithm would seem ideal for that, with the 'error' signal being the distance between the motor's current position and the desired position. The PID would enable you to control the acceleration and speed to move the motor to the desired position. You would need to ensure that the maximum speed was slow enough that you could reliably read the encoder, and of course you need to have a reliable way to read the encoder - without that, you're stuffed.

pastafarian

#2
Aug 06, 2012, 02:45 am Last Edit: Aug 06, 2012, 03:18 am by pastafarian Reason: 1
Thanks for your suggestions, Peter. No, I'm not stuck with a DC motor, so a stepper motor is a possibility. I originally went with a DC motor because I knew it would give me the speed I needed.  My understanding is that stepper motors are quite a bit slower - do you think I can gear a stepper motor to spin something as fast as 230 rotations per second?  Also, if anyone has any suggestions of a particular stepper motor that might work for my application, that would be much appreciated!

Also, if I do stick with the DC motor and PID controller route, do you happen to know what the time resolution is with interrupts on the Arduino?  I'm wondering at what speed I should start worrying about missing encoder change events.

Thanks again for your help.

Edit: The object I'm spinning is extremely small and lightweight.

PeterH



do you think I can gear a stepper motor to spin something as fast as 230 rotations per second?

Edit: The object I'm spinning is extremely small and lightweight.


I think that's rather high for a stepper motor, but if you aren't going to need much torque perhaps you could gear it up. What sort of angular resolution do you need?

pastafarian


What sort of angular resolution do you need?


I think within a range of 5 deg. or so would be fine.

ardnut

230 Hz is about 14000 rpm !  What objects are you planning on spinning that fast?

That's like turbo injector speeds. Have you built a safety cage around it for when it flies off or disintegrates?


pastafarian


230 Hz is about 14000 rpm !  What objects are you planning on spinning that fast?


A hamster wheel. My hamster is fast.

Actually, I need to spin insect wings at their natural rotational velocity. 

ardnut

OK, I guess the rotational energy won't be that big then !

just make the support can't come off and everything is perfectly balanced.

Any off-axis weight will cause some nasty vibrations. You may want to glue the sample directly to the motor spindle. ;)


PeterH


I think within a range of 5 deg. or so would be fine.


That means you could probably get away with gearing the stepper up by about 5:1, which brings your top speed into the sort of range that you might achieve with a stepper - although it's likely to be marginal.

When you bring your sample to a stop does it always need to be in exactly the same orientation (i.e. from run to run) or does it need to stop at an arbitrary position?

pastafarian

#9
Aug 06, 2012, 03:11 pm Last Edit: Aug 06, 2012, 03:13 pm by pastafarian Reason: 1

When you bring your sample to a stop does it always need to be in exactly the same orientation (i.e. from run to run) or does it need to stop at an arbitrary position?


It needs to stop at the same position every time, so that it's always oriented the same way relative to the camera view.

jraskell


It's important that the motor comes to rest at the same position where it began, because I'll subsequently trigger a DSLR camera to snap a photo of the object being rotated, and repeat this process multiple times.


The camera is going to snap a photo while the object is being rotated, or when it stops?  I'm not clear on the exact connection between the motor stopping, and a photo being taken.  If it's what I think it is, then you don't really need an encoder or stepper, but just a trigger of some sort.  Regardless...



What sort of angular resolution do you need?


I think within a range of 5 deg. or so would be fine.


That could be obtained with your dc motor setup.  In fact, if utilizing a deceleration ramp is acceptable, you could well under that.

pastafarian



It's important that the motor comes to rest at the same position where it began, because I'll subsequently trigger a DSLR camera to snap a photo of the object being rotated, and repeat this process multiple times.


The camera is going to snap a photo while the object is being rotated, or when it stops?  I'm not clear on the exact connection between the motor stopping, and a photo being taken.  If it's what I think it is, then you don't really need an encoder or stepper, but just a trigger of some sort.  Regardless...



Sorry for the unclear description: The motor will rotate a wing for a specified X number of turns, then stop rotating. Camera will snap photo of wing (while motor is stopped). After photo, motor will start spinning again...and this process will repeat multiple times. The motor needs to stop at the same position after every spin, so that the wing is oriented in the same position (orthogonally to the camera view) for every photo.


If it's what I think it is, then you don't really need an encoder or stepper, but just a trigger of some sort.


Could you please elaborate? I already have the motor with the encoder, so I'm inclined to use the encoder output unless it's insufficient for this application, or has a shortcoming that I'm unaware of. For example, is there a chance I'm missing encoder change events at this rotation speed? (That would be a big shortcoming!) One channel of the encoder should be putting out 12 pulses per revolution of the motor shaft, or 24 edges. If I'm spinning at 230 Hz, that equates to an interrupt trigger every 181 microseconds (if I'm triggering on a CHANGE). Does anyone know whether this rate is within the limits of the arduino? I could always reduce resolution by triggering only on a rising or falling edge.


That could be obtained with your dc motor setup.  In fact, if utilizing a deceleration ramp is acceptable, you could well under that.


Great!  Can you point me to a good reference for coding a deceleration ramp?

Thanks.

PeterH


It needs to stop at the same position every time, so that it's always oriented the same way relative to the camera view.


That makes the problem much easier - all you really need is a small bias tending to stop the motor at a given position.

Do you actually care how many times it turns, or only the approximate number of turns and the final position?

pastafarian



That makes the problem much easier - all you really need is a small bias tending to stop the motor at a given position.

Do you actually care how many times it turns, or only the approximate number of turns and the final position?


Ideally I'd like the motor to spin the exact number of turns I specify.  However, if there's an easy control solution that comes with a little slop in the number of turns, I'm willing to be within ±2 turns of what I specify.

I'd love to hear more about incorporating a bias - sounds cool!

holmes4

Hi,

There is a very cheap and simple way of ensuring that the sample stops in exactly the same place every time if that will help. But the last turn or two will need to be slowish.

Would this be of any help?.

Mark

Go Up