I have a robot with a mechanical encoder attatched to an arm with a motor to lift the arm.
the encoder is at 50 resolution
the arm motor is attatched to pwm_02
the encoder is attatched to rc_dig_in06
I calculated that the encoder will “click” or turn on and off 10.7 times for the distance I need.(the encoder is 50 resolution).
basically I need the source so the motor attatched to pwm_02 will stop once the encoder “ticks” 10.7 (or eleven) times. Please keep it simple. I don’t have time to go through a tutorial right now. thank you so much for the help.
oh yeah, it would be nice If I could have the arm lift at the touch of a trigger on a joystick attatched to p1_sw_trig. and have the arm go back down at the touch of the trigger again. does the operator interface controller provide a way to simply shut everything down immediately in the event of a disaster?
please help.
thanks,
Stephen
can you look at this and tell me if you see any errors.
//the encoder is at 50 resolution
//the arm motor is attatched to pwm_02
//the encoder is attatched to rc_dig_in06
unsigned int encoder;
if (p2_sw_trig == 1)
pwm_02 = 220;
if (rc_dig_in06 == 1)
encoder = encoder + 1;
if (encoder == 11)
pwm_02 = 128;
Couple of problems, such as,
“encoder” needs to be static or a global, so it retains it’s value from call to call.
The check on rc_dig_in06 will increment “encoder” more often than every “tick”
“encoder” might shoot right past 11 and keep going.
You only want to increment the encoder variable when rc_dig_in06 goes from 0-1 or from 1-0 (pick one). So you need to keep track of the previous value and the current value, then increment only when when it changes.
First of all, you have not initialized your counter (maybe this is done in your actual code… I don’t know).
Second, what happens the next time through the loop? I’m assuming that you will want to perform this maneuver again and again (once again, I may be mistaken). For now, I will assume that this is a one shot deal…
Here is what I think will happen: When the encoder hits 11, the arm is turned off but the encoder micro-switch is still “closed”. The count will increase to 12 and the arm will continue to travel. You might want the last test to be “encoder > 11”…
we tried to keep the motor speed down so the encoder will read each tick before the program refreshes. so the motor doesn’t “beat” the program before it reads the encoder.
//the encoder is at 50 resolution
//the arm motor is attatched to pwm_02
//the encoder is attatched to rc_dig_in06
static unsigned int encoder;
static unsigned int pressedornot;
if (p1_sw_trig == 1)
{
if (encoder <= 10)
{
pwm_02 = 150;
if (rc_dig_in06 == 1)
{
encoder = encoder + 1;
if (encoder > 10)
{
pwm_02 = 127;
}
}
}
}
You can see I attempted to reformat your code to make it more readable. Now you can see how your code nests…
I agree with Mark. I’m not worried about you missing an encoder ping but rather that you will get multiple hits at one ping.
You should consider implementing a state machine. Do you have a mentor on your team (what team are you with anyway?) who can teach you what a state machine is?
thanks for the help and tips. I’ll have to look into state machines. Today I was in a kind of hurry (which was probably obvious). but now I’ve got more time to think things through. Our team doesn’t really have any mentors for programming. We never have, last year we had a wiz kid, and this year its kinda up to me and another guy. neither of us have much experience. I programmed with c#, but that was with Windows, which tends to behave much differently than a robot :yikes: . our team number is, I’m not sure. we’re team “lugnut” though, from Ohio.
We’ll be your mentors. There are quite a few of us to help you out.
That declaration only takes effect when the program starts. The use of “static” fixes it permanently in memory and that line will not get executed each time the routine is called. Without the “static” the variable would get initialized each time the routine is called.
//the encoder is at 50 resolution
//the arm motor is attatched to pwm_02
//the encoder is attatched to rc_dig_in06
static unsigned int encoder = 0;
if (p1_sw_trig == 1)
{
if (encoder <= 10)
{
pwm_02 = 254;
if (rc_dig_in06 == 1)
{
encoder = encoder + 1;
if (encoder > 10)
{
pwm_02 = 127;
}
}
}
}
I assigned a value of zero to encoder, however, every time the code is reread (every 30 milliseconds or something?), the value for encoder will be set back to zero, making its function useless. wish there was a way to make it so the thing didn’t reread the code every amount of time, but rather go over it once and remember everything, and do everything from there. that’s the way it is in most programming languages isn’t it. anyway, do you see what I mean? or will it only assign the value of zero to it once and then when it reanalyzes the code, it will use the last assigned value. I don’t think it works that way though.
What you have is not a mechanical encoder. It is an optical encoder made by CUI.
Here is a spec sheet: EC202A050A2(S or T)D. As you can see, it comes in two flavors a horizontal or vertical mount.
More importantly, it has a quadrature output so that you can determine direction in your code.
Team 177 used a very similar device last year. I very, very strongly suggest that you download Kevin Watson’s example code for optical encoders at http://kevin.org/frc/ and download the file ***edu_encoder.zip ** * open it up and examine his code very carefully.
What Kevin did is for the edubot. You will have to do the same stuff to the RC code. However, over 50% of the work has been done for you.
Continue in the direction Mike is sending you. I just want to address some of the previous outstanding questions.
That is the way “static” works.
The statement “static unsigned int encoder = 0;” will only take effect at compile time, not while the code is running. It sort of nails the variable in place and sets it’s initial value only once.
The statement “unsigned int encoder = 0;” will take effect while the code is running. Every time the routine is entered the variable encoder will be “created” and assigned the value of 0.
Referring back to Sean’s comment earlier about only counting rc_dig_06 when it changes, not every pass through the code that it happens to equal 1…
The following is an example of only counting changes in rc_dig_06. This particular method actually doubles the resolution of your encoder as it counts both when it changes to 1 and when it changes to 0.
static char toggle=1; // Start as TRUE
if (toggle == rc_dig_in06) // Encoder has changed
{
toggle = !toggle;
encoder = encoder + 1;
}
This method that we’ve been discussing is called polling the input and works fine for slow changes like your arm movement. If the changes occur faster, such as an encoder on a wheel or motor shaft, then you should use interrupts. Interrupts basically are like a good poke in the controller whenever the encoder state changes, and will be discussed in Kevin’s paper.
As the company that hosts my web server decided to change the IP on me, you may or may not be able to get a copy of the code at this time. It should start working soon as I just updated the DNS record on my end. If you need the code in the mean time, feel free to drop me a note and I’ll send it to you.
Yeah, I’ve been a real knuckle-head for not modifying the EDU-RC code to run on the FRC-RC. It’s been on my to-do list for some time, but I just haven’t had the time. I will, however, get it done before the kick-off.
We used it on our FRC last year and it worked PERFECTLY. We also used it with a relatively low-resolution encoder, about 64 ticks per revolution.
Some advantages:
- Uses interrupts, so that you don’t have to worry about missing your encoder ticks.
- Reads two quadrature outputs, so that you can detect which direction your encoder is spinning (increment your encoder variable when spun in one direction, decrement it in the other)
Things to look out for:
- The version I used had one interrupt per encoder, and interrupted only on rising edges
- This meant my encoder variable would only increase or decrease after about 4 encoder state changes, dividing my effective encoder resolution by 4
- This wasn’t a BAD thing, in fact it was a very good exercise in learning, and implementing two interrupts per encoder, which interrupted on rising AND falling edges, and gave me back full encoder resolution
*hint: don’t use two interrupts per encoder… to me external interrupts are more expensive than getting a higher resolution encoder. Last year, we had an interrupt or two to spare after we removed our IR after Pittsburgh. Next year, I know we WON’T have any spare external interrupts. I know it sounds crazy, maybe this advice comes a bit late, but buy an encoder with twice the resolution you expect to require.
It gave me a great opportunity to teach students about interrupts vs. polling, and the concepts of rising edges, falling edges and such. Even the whole concept of quadrature was quite interesting to them. Most didn't think it was that easy to figure out which way an encoder was spinning. In addition, we purchased an inexpensive mechanical encoder where we opened up the back, and you could physically see how the quadrature signal was generated with just a sweeping arm, and a few contacts.
I definitely learned a lot, and so did the students on 188.
Thanks Kevin for your code! We used your IR code too =), and were very successful in our empty gymnasium, but weren't so successful on the actual playing field.