Pulseout Timing Problem

Discussion about the ZBasic language including the System Library. If you're not sure where to post your message, do it here. However, do not make test posts here; that's the purpose of the Sandbox.
Post Reply
everest
Posts: 96
Joined: 31 May 2010, 9:01 AM

Pulseout Timing Problem

Post by everest »

Hi Don,

I'm playing around with the PulseOut command in preparation for trying to convert a robot platform from a Stamp2 platform over to the Zbasic platform. . .and I'm just totally stumped here.

The Zbasic system library says this:

"The pulse width may be specified by a Single value with units of seconds and a resolution of approximately 1.085μs (however, due to processing overhead, the shortest pulse that can be generated is slightly less than 2us)."

I've tried a single value in there, and integer values, but I just can't understand the results. For example, I would think that code like this:

Code: Select all

Sub Main()

Call PutPin(5, zxoutputlow)
Dim PulseWidth as Single = 0.25

Do

Call Pulseout(5, PulseWidth, 0)
Call PulseOut(0, PulseWidth, 1)

Loop

End Sub
Would produce a two pulses every second (2Hz) with a transition every .25 seconds. But instead it produces almost exactly 13 pulses every second (13Hz). I'd expect a change to 0.50 to produce 1Hz and instead it produces around 218Hz.

What the heck am I missing here? I can't fathom how to control the pulse width here. Help!

-Jeff
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Re: Pulseout Timing Problem

Post by dkinzer »

everest wrote:I've tried a single value in there, and integer values, but I just can't understand the results.
What integral value did you try? Although the documentation doesn't specifically indicate so, the maximum pulse width is 65535 * 1.086uS, or about 71mS using the default Register.TimerSpeed2 value. You can increase the maximum pulse width by changing the Register.TimerSpeed2 value but then you must use an integral value for the pulse width because the compiler converts Single values to integral using the 1.086uS resolution value.

Also, the pulse polarity parameter of the first call to PulseOut() is not correct given the initial state of the pin. The pulse polarity parameter indicates the logic sense of the pulse, i.e. a 1 means to generate a high pulse thus requiring the initial state of the pin to be zero. You don't notice this error in your example because of the loop. No pulse will be generated on the first pass through the loop but you will get a pulse on all subsequent passes.

All that aside, PulseOut() is not a particularly good solution for generating long pulses because it keeps interrupts disabled for the duration of the pulse (plus some overhead time). I doubt that you really want interrupts disabled for quarter-second periods.

What is it, exactly, that you're trying to accomplish? There is very likely a better way to achieve it.
- Don Kinzer
everest
Posts: 96
Joined: 31 May 2010, 9:01 AM

Post by everest »

Hi Don,

I tried a wide range of integral values starting at 1 and incrementing up to 50000 with the expectation that my Hz would gradually decrease as the values increased. That's not what I'm seeing though, the values just jump all over the place, very inconsistently.

I need to drive a whole bunch of servos. My initial thought was to use the suite of PWM functions to handle them, but I found that I have a very limited choice of pins that I can dedicate for PWM output (unless I'm mistaken of course!).

I'd like to be able to drive upwards of 8-10 servos. My solution on the Stamp2 platform was to cycle through subroutines of pulses set by the program several times a second. . .so the servos didn't get PWM continuously, but for all intents and purposes they worked fine because they cycled so fast.

A function to basically "drive PWM to pin X" is what I really need, for up to 10 pins.

-Jeff
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Post by dkinzer »

everest wrote:That's not what I'm seeing though, the values just jump all over the place, very inconsistently.
I tried your code with integral values from 10 to 50,000 using a 1..2..5 sequence and got the pulse widths shown in the table below.[table][mrow]Value[mcol]Width
[row]10[col]10.7uS
[row]20[col]21.6uS
[row]50[col]54.2uS
[row]100[col]108.4uS
[row]200[col]217uS
[row]500[col]542uS
[row]1000[col]1.08mS
[row]2000[col]2.17mS
[row]5000[col]5.42mS
[row]10000[col]10.9mS
[row]20000[col]21.7mS
[row]50000[col]54.3mS[/table]
everest wrote:A function to basically "drive PWM to pin X" is what I really need, for up to 10 pins.
How precise does the resulting "PWM" need to be? Do the duty cycles for the 10 outputs need to be different? Would you entertain solutions that required external hardware? What other functionality is also needed in this application?
- Don Kinzer
everest
Posts: 96
Joined: 31 May 2010, 9:01 AM

Post by everest »

Hey Don,

I'll do another check with my scope when I get home from work. Each servo needs it's own pulse rate in order to hold the desired position. There are quite a few relatively inexpensive servo controllers that I could use here, I'm just trying to use my Zbasic chips as much as possible before I go to purchasing additional boards.

The pulse rate needs to be pretty consistent. I can calibrate for timing variations very easily though, the rate just can't jump around.

In terms of what else I might ask the Zbasic processor to do. . .well. . .lots :) But remember that for all intents and purposes the pulses don't have to be continuous. Very short breaks to deal with other tasks (check switches, range sensors, etc.) are fine and don't seem to impact my servos at all, they just just like normal.

With the Stamp2 implementation I would just have a "sub" in Pbasic that cycled through all my output pins driving servos and gave them a fraction of a second series of pulses, and that routine got called several times a second. Works great!

-Jeff

-Jeff
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Post by dkinzer »

everest wrote:The pulse rate needs to be pretty consistent.
The pulse rate isn't going to be consistent unless interrupts are disabled and you won't want to do that unless the ZX isn't going to be doing any thing else. The reason that it works relatively well on the Stamp is because the Stamp doesn't use interrupts at all so there is nothing to interfere with the timing of a code loop.

You mentioned PWM but observed that the pin selection is limited. You can address this limitation using an external decoder/demultiplexer. For example, a 1-of-16 decoder would support 16 servo outputs using a 4-bit selector code. If you configure 16-bit PWM for 400Hz operation then 1mS, 1.5mS and 2mS pulse widths are achieved with 40%, 60% and 80% duty cycle, respectively. Your code could loop through the desired servo channels, outputting a channel select code, calling PWM() with the desired duty cycle, pausing for some period of time, and then setting the duty cycle to zero. One issue that I see with this strategy is that the outputs of a decoder/demultiplexer are generally active low; they would probably need to be inverted.
- Don Kinzer
everest
Posts: 96
Joined: 31 May 2010, 9:01 AM

Post by everest »

Maybe I could just use a stamp2 module as a servo controller, and send it commands with my Zbasic chips? I'll do some more experiments, but I guess spending a little $$ on a servo controller board might be the most straightforward thing to do here. Thanks for all the info!

-JEff
kurakaira
Posts: 77
Joined: 21 March 2007, 1:21 AM
Location: Finland

Post by kurakaira »

I'm having no problems controlling servos with PulseOut , even when updating them every now and then .
It depends on the servo how long the pause between signals can be .

Code: Select all

TravelS = 0.00150  ' Center position 1.5ms
Call PulseOut(ServoPin, TravelS, 1)
everest
Posts: 96
Joined: 31 May 2010, 9:01 AM

Post by everest »

IF you are JUST controlling servos then things work just fine. I've only had problems when doing multi-tasking and when other tasks start doing a lot of time based operations. Otherwise it does indeed work perfectly. Then again the SSC-32 servo controller is also perfect and consumes only one pin from the Zbasic process :) I've built a Phoenix hexapod and have it walking all around the floor using semi-dynamic gaits with a Zbasic-brain.

Next step. . .inverse Kinematics. . . .

-Jeff
spamiam
Posts: 739
Joined: 13 November 2005, 6:39 AM

Post by spamiam »

everest wrote:Next step. . .inverse Kinematics. . . .
Just looked it up on Wikipedia. Extremely interesting issue. Probably extremely hard to solve deterministically.

The article gave an example of the human arm. I suspect that the brain does not solve for a unique solution. Probably just a general approximation, with a couple of rules and suggestions. Suggestions such as:

1) Keep joints as close to the middle of their range as possible. If strength is to be required, try very hard to keep those involved joints near mid-range.

2) Avoid blocking the sensors (visual or tactile).

3) There may be an advantage to allow certain joints to reach full excursion and therefore "lock" and reduce power consumption holding the joint in position

I think that the harder part is deciding how to snake an appendage around obstructions most effectively.

-Tony
Post Reply