EmbeddedRelated.com
Forums

Launchpad Help: Six Potentiometers + Six Servos + MSP430G2553

Started by tech_juggernaut April 10, 2012
Al,

As I tell all my friends before a very difficult test in college, good
luck and Gods speed. Best part is I am agnostic, so it always confused
people.

Jake G.

Beginning Microcontrollers with the MSP430

Great find, thanks Peter, that was a HUGE help! :)

I talked to RobG over at 43oh.com and this is what he said:

Since you are using 2553, you do not need shift register to control 6
servos.
Using one CCR per servo is not possible (20 pin chip) due to pin
function arrangement, but you can still control up to 8 servos using 8
potentiometers.
You can use P1 port for all analog inputs and P2 port for servo output.
HS-645MG and HS-485HB servos are analog, 20ms cycle, looks like they do
not need any special treatment.
You can use this 4ch code as an example, just move all servo outs to P2.
Let me know if you need help with that.

Here's (untested) code, you may have to adjust min and max position as
some servos do not take out of range values too well.
P1.0 - P1.5 is A0 to A5, P2.0 - P2.5 is S0 to S5
For all you that are interested, the code that he came up with is below,
or can be found at this address:

http://www.43oh.com/forum/viewtopic.php?f=9&t(4&sidB1919d1925c1b25e4\
4442df3ea18367&start



-Jake
Al,
I hope all goes super smooth. Sending positive thoughts for a speedy recovery.

Barry
Thanks for everybody's best wishes, (un)fortunately flu and a chest
infection meant that the major surgery couldn't go ahead, so I'm back to
sit and wait for the next time. I did have a minor procedure done, just
a day job to keep me ticking for a couple of weeks until they can
reschedule. So couple of days rest, yeah right!!. This is a reply to the
O/P, sorry oif it confuses

I missed the fact that the 20 pin 2553 is fitted to the launchpad,
should have looked at my own. You also didn't mention that this was for
an R/C servo, this requires slightly different handling than a
conventional PWM. So timer per servo is not possible since Ta0-2 isn't
implemented. However, I agree with Matthias about the process in an ISR.
In fact I would go MUCH further. Since you are sitting in an ISR to do
everything, from scheduling the conversion to processing the servo logic
you could have really serious problems.

The adc conversion can be triggered from the timer directly, so I would
set up conversion in that way. In fact since the servo process involves
so much 'dead time' where the pulse is in a constant state, I would
sample all 6 channels during this time, and auto trigger this from the
timer, ie use the ADC10 in its sequence of channels mode.

The ADC10 also has a single channel DMA, and you could use these to
automatically transfer the results to your variables. so the conversion
sequence becomes:-

Initialise TimerA and ADC10
Initialise the DMA channel for the ADC10
Set Timer A as the trigger source for the ADC10
on timeout the ADC10 is automatically triggered to convert, so far you
have not needed to service an ISR
On completion your 6 results will be waiting in memory, process these
and figure out your servo on times.

To save processing time, and since you only have 1024 possible results
why not do the ADC10 value to servo time in a table? The 2553 has bucket
loads of memory. that makes it really quick! all you need to do then is
sort the sequence of times from first to last, allowing for possible
overflow. i am assuming that you plan to use the full analog mode of the
servo, rather than just 1 or two fixed positions, then again tables
would still be faster than doing >, < tests for just a few values since
it's a case of:_



This is probably really inefficient, my heads pretty fuzzy! but the
ideas there.

I would use a separate channel for the servo timing. There will still be
a little jitter, but nowhere near as much as your posted method.

calculate the required times after ADC conversion, and in the foreground
routine before the end of the 20msec servo period. basically you will be
turning the pulse OFF at the required time, so you need to set 7 times
in all.

1. the start time of the servo period. At this time all 6 channels turn
ON, so that's easy.
2. the 6 OFF time periods.

When calculating you actually should have loads of time, so i would
arrange these in order of time schedule, NOT in simple numeric order. If
I had the spare resources I would also allocate say 2 channels per timer
to make things easier.

arrange 6 variables which are the differential times from the start
period time. in order of occurence use the dstart label [PERIOD] for these.
arrange an array of 6 byte variables which indicate the pin states to be
set at that time. allocate a second register if available and count
singly or use a single register as I've done. label the start of these
vars [DUTY]
keep a count by 2 variable for ease of actioning the port. I would use a
register for this if possible, call it R4

In the ISR:-



In practice the last servo value would be the start time of the next
servo period, you could reconfigure the ADC10 conversion here, since it
should occur in the 'dead' period between the end of the maximum servo
duty time (2400usecs for the HS-645MG) and the start of the next period
(20msecs). Equally your foreground routine could search for R4 being 0
then configure the conversion timer at this point.

Soryy there is no hard tested code, I've worked with synchro resolvers
but never had cause to work with R/C servos before.

Sorry, just ran out of steam

Cheers

Al
Hay Al,
Things must have worked out ok! I hope that is why you are back so soon.

I didn't know this was about servos ether. As I recall, servos on an RC
platform go like this:

You only have to pulse width each servo intermediately. So they are
handled in a time slot way. There is plenty of room for six servos so
that you can just handle one at a time. The slot is just a couple of
milliseconds wide. Means every servo can be updated in less than some 15
to 20 milliseconds. Makes the code simple. I'm not sure what the
feedback from a pot is about as the servos are self contained, position
results directly from the pulse width. If there is some kind of fine
tuning going on, I'd just generate a table and flash it. This would free
up the micro to do so much more. I'd find it hard to believe you could
continuously beat the internal servo positioning with any meaning.

Then again, I'm missing something. But it would not be the first time!

Best, Dan.
Hi Dan, thanks to you and all for the good wishes. It wasn't good news
necessarily. I just have the flu, and a chest infection, so they
couldn't operate. Instead they did the secondary procedure which was
another neural block in my skull, so I have a bit of a headache. I was
due to have my butt drilled!!! Definitely not looking forward to it.
Seriously though, I have damage to 17 vertebrae after a work accident in
November 2000, as a result my spine deteriorates at a savage rate. My
cocyx is damaged and I need the nerves burning out, plus it needs some
filler to slow down and reverse the degeneration. So in one hit they
drill up either side of the spinal canal, run electrodes up to the nerve
bundles, connect test electrodes higher up and read the singal
transmission to my lower limbs while they fiddle the electrodes to make
sure they get the right ones. then they burn out selected nerves. this
should allow me to stand and walk better. On the way out they pump in a
slurry of bone cement and other gunk to help stop the bone from breaking
down. So yes my butt was going to be drilled and filled!

I've never had cause to deal with R/C servos, but as i understand it
they have a duty cycle type control with a period of 20msecs and a pulse
on period of 600 to 4200usecs, where 600usecs is 'null' and 2400msecs is
180 degrees, so I am assuming that a 360 degree servo motion would be
4200usecs. That is from the data sheet for the servo the OP mentioned,
which is an analog servo, from which I gather there are servos that
effectively have a few fixed positions. all else is 'dead time' as I
think of it. And plenty of time to run your calcs.

I guess timing depends on what your fastest positional update rate needs
to be. Do you really expect to have to change position every 20 msecs,
if so then synching the servo control signals makes a lot of sense.

I assume the pots are there to provide data entry for the position, but
why not use a single pot and a switch selector, or just pure digital
control. Who knows. I've given up second guessing why people do things
the way they do in this group. Then again variety is the spcie of life,
and who doesn't want their life to be spicy?

Cheers

Al
Hi Al,

Sorry to hear that you've been sick! It's been a few days since your last reply, I hope you're feeling better. :) I was only down for a few months after a much less serious back injury a couple of years ago. I couldn't imagine having to deal with something like that for over 12 years... I seriously hope they get you fixed up soon!

Sorry it took so long to respond, I've been working around the clock on tweaking the code. I should've mentioned that they were R/C servos and that I was using the 20 pin DIP, my apologies.

Thanks for the input, to answer your questions, I'm using multiple pots so that I can control the robotic arm more efficiently; I built a control panel to hold all six pots so I can just move from one to the other and operate it faster. I don't have much experience with R/C servos either, all I knew in the beginning was that I had to keep a constant signal to all of the servos so that the arm could keep its position. Plus I built the control panel pretty early on and it took a good chunk of time, so I figured if it works, it works. :)

As far as the code goes, at first I calculated the CCR max and min values in the while loop in the ADC ISR but just changing the added constant after the adcValue/8 would get me closer to or farther from the max value and had an inverse effect on the min.

I started looking into using a table, like you mentioned, and a guy over at 43oh.com gave me an equation that would map any ADC value to any servo value. I eventually set the CCR max and min values as well as the adc max and mins and just replaced the code in the while loop with the formula that he gave me. It was a lot easier to tweak the CCR max and mins once I did that, just had to change the assigned values in their declarations until I got the range of motion that I wanted. I'd still like to use a LUT but I have zero experience with them.

In the earlier calcs, I found the max and min servo values to be 2100us / 8us = ~263 and 900us / 8us = ~113, but their motion was limited inside of about 100 degrees or so. I was surprised to find that after changing their values a few times and testing the servo ranges that they actually had to be much higher/lower if I wanted 180+ degrees. Still confused about that... I ended up with a max of 320 and a min of 75 and the formula made the calculated CCR values in-between really precise. I have two servos at the shoulder of the arm for more torque but they're fighting each other so I'll have to get them in synch, but other than that it seems to work really well. :)

Here's a picture of I'm working with: http://flic.kr/p/bNH7Br

Thanks again for any help, I really appreciate it!

The code so far:

---------