Tag Archives: motor library

Arcstronominutes

A while ago, we purchased a pair of 12-bit magnetic angular encoders from Digikey. They’re not real expensive, and they have a resolution of 0.0879 degrees. If you’re up for it, check out Angular Measurements on Cool Cosmos.

Now, let’s do some math:

For 12 bits, the encoder output value can range from 0 to 2^12, so:
    2^12 = 4096
and, there are 360 degrees in a full revolution, so:
    4096 count / 360 degrees = 11.38 count / degree
and, 60 arcminutes make up one degree, so:
    (60 arcminutes / degree) * (1 degree / 11.38 count) = 5.27 arcminutes / count

That means our 12-bit magnetic encoders have a resolution of 5.27 arcminutes. This is great! It’s about a tenth the width of your pinky, if you held your pinky at arms length towards the sky.

All you need is a hand

Not bad. One of the tasks of the Motor Library will be to take some angular measurement (which will consist of degrees, arcminutes, and arcseconds) and translate it into a 12-bit number, and vice versa. This is because one of the motor library’s primary functions is a GOTO function, which may receive a pair of angles as input. The library function ought to translate those pairs of angles into a 12-bit equivalent, so we have something to compare with the output of the 12-bit magnetic encoder. (An alternative way to do it is to convert the 12-bit magnetic encoder’s output into an angle, every time we poll the sensor, then compare it to the target angle. It might be more efficient the first way, who knows?)

The only problem I foresee is that it’s non-trivial to physically re-orient the magnet within the magnetic encoder, so it will probably cross over the 0-degree position. Crossing over means we might go from 12 degrees to 0 degrees to end up at 350 degrees. This is one of the reasons we might use the motor’s quadrature rotary encoder to indicate position. The only solution I can think of is a function like this

if our motion is clockwise {
    if current > target {
        subtract 4096 from current for an adjusted current position
    }
    keep spinning while adjusted current position is less than target
}
else if our motion is counterclockwise {
    if current < target {
        add 4096 to current for an adjusted current position
    }
    keep spinning while adjusted current position is more than target
}
else {}

There may be a way to do it better. I will think of one later.

Anyhow, what the GOTO function would do is A) slowly accelerate the azimuth motor and altitude motor, B) continue rotating until it approaches the target angles, C) slowly and gradually decelerate the azimuth motor and altitude motor, until it actually lands on the target angles. Now, getting it to land exactly on the target angles will be tricky.

As a part of the library, there will be some set of functions which will test the speeds of the motors and the amount of overshoot that occurs when told to stop (or slow down). Basically, we’re going to teach the arduino to anticipate how much overshoot. This may or may not involve us learning how to code PID. (In fact, we might even use PID for parts A and C to ensure smooth acceleration, and in part B for constant speed. With all the other potential overhead, it might be hand coded. But for now, we could implement one just to see how it works??)

Where does this leave us? Well, we need to finish the motor instruction buffer – because I want to try out canned operations like part A), B), and C) in one smooth motion. The next step is we write the conversion functions for the 12-bit magnetic encoder. And, write up the funky code that handles crossing over the 0-degree line.

-david

PWM and Speed, Objects and Structs

aeN40wB_700b_v1

I’m still determining how everything’s going to work…

Before we go any further, PWM refers to a number from {0-255} which corresponds to a voltage that the Arduino sends to the motor. The motor will rotate at a certain speed depending on that voltage. The rotary encoder sensor is attached to the end of the motor drive shaft. Every time the motor drive shaft spins, the sensor sends a HIGH-LOW signal to the Arduino, and the Arduino counts the number of HIGHs in order to keep track of the number of times the motor drive shaft has spun. Programmed speed refers to a technique where the program constantly tweaks the PWM number so that the rate of count per seconds (i.e. the measured speed of the motor) is constant for the duration of the motor instruction.

My ideas so far:

1) The Arduino contains a large set of motor instructions. These instructions are composed of two things:

PWM – the PWM number at which the motor should operate, OR the programmed speed at which the motor should operate

Count – the encoder count as position that the motor should keep turning to, OR the encoder count distance the motor should keep operating at said PWM, or programmed speed

2) Same as 1), with a variation on the 2nd element

PWM – the PWM number at which the motor should operate, OR the programmed speed at which the motor should operate

Time – the duration of time (in miliseconds) that the motor should keep turning to, OR the system time until the motor should keep operating at said PWM, or programmed speed

That’s 8 possible interpretations for a 2 parameter instruction. For the first iteration of this library, we’re going with PWM number, and encoder count as position. It is the easiest and most straightforward. It might be relatively faster to run, and might not require a extensive amount of ‘correction’ later on. After we get it working in this style, we’ll switch it up to something more advanced later.

So, with PWM number and encoder count position comprising a motor instruction, we’re going to store these instructions as an actual data type. I know of two ways we can do this. The first way : in C++ we define a struct, comprised of an ‘int’ for PWM number, and a ‘long’ for count position. The second way : we create a class of objects, whose member variables are an ‘int’ for PWM number, and a ‘long’ for count position. I am not sure, but using a class of objects might be more expensive processing-wise and memory-wise, even if it only holds 2 simple elements. (Though, we might try it that way later to compare and contrast.) We’re going to go with the first method, using a C++ struct.

struct MotorInstruction {
  int pwm;
  long count;
}

It is simple enough…

Now that we have a data type we can use, let’s define a container in which to store these instructions. There are at least two ways to go about this. First, there is the C++ way : we define an array of type MotorInstruction :

struct MotorInstruction myMi[256];

This is the simplest and most straightforward way to do this. We just need to keep track of the current instruction position in the array, and the last instruction position in the array. We may need to initialize all the values in the array first. It can be done with a simple for loop during setup:

for (int i = 0; i < 256, i++) {
  myMi[i].pwm = 0;
  myMi[i].count = 0;
}

The second way to do it is to use user-written object containers for Arduino. I’ve found some list type object containers, such as QueueArray, QueueList, and StackList, which suite our need for a more clever array. Simply implementing them will take up some of my limited space on the Arduino, but using them may be more efficient in the long run.

I feel like eventually we’ll have to switch to simple arrays, to make the most of our memory on the Arduino. For now, we’ll try out QueueList. QueueList is a container with functions such as push(…) and pop(…). Every time you use ‘push’ you add an element to the end of the list. Every time you use ‘pop’ you remove an element from the beginning of the array. The order in which you insert elements into the list is the same order in which they are removed from the list.

* * *

I’m going to have to leave it at that for now

Check back later!

-david

It’s been a rough night

*pix not mine, scrounged from interwebs
*I do not take responsibility for this pix

The short story: I leapt before I looked. I tried to build the “motor library” all gungho like, only to my disappointment I had some serious design flaws. Last night I managed to successfully build and implement a simple motor library. It could not have been simpler. And yet I somehow turned working code into an epic 3 hour battle with anomalous compiler errors… Curses!

* * *

So at 1AM this morning, I resigned to revert back to simplistic, functional, sparse motor library code. It works, and that’s how I like it. It will be assimilated into a larger system that will receive and interpret the encoder interrupt signals, to somehow produce a PID look-a-like which will detect and handle “error conditions”, basically an advanced speed controller. But here’s the catch: I’m going to try to make it from scratch.

* * *

Good news: the whole Interrupt vs Serial Communication thing has been settled. I’ve been overthinking the problem, thinking the arduino microcontroller did some kind of threading/parallel processing, and that my interrupt code would blindly disrupt serial communication, or vice versa. I’ve done some digging. It appears, if I had just read the manual, my life would be easier.

[ see: gammon.com.au/interrupts ]

So, there is a priority with regards to Interrupts. And higher priority interrupts will be executed first… And, Serial communication does rely on interrupts as well. But if should any Serial communication get delayed by some other Interrupt code, the message gets buffered internally (at the hardware level I think) and Serial.available() is all I need to check if there’s anything in the buffer. It’s like checking voice-mail. So, for all conditions where the motor encoder interrupt is firing, and serial communication is happening, there’s no possibility for communication failure or missed counts. Or so I believe…. So at some point I have to provide test code to determine if it’s actually possible to miss a count on the encoder interrupt, or if it’s possible to disrupt in some way serial communication with really taxing interrupt code.

-david