Fast Turns, Stall Detection

A week ago I posted the NXT Dog Sled Team project, which (appeared to...) have a traction problem due to a severe weight balance issue. Now having some fun with the other extreme, this NXT Spinner Bot project has six wheels, but nearly all of the weight is balanced over the two drive wheels in the center, with the four castor wheels barely touching the ground for balance. This gives it a very quick turning ability for break-dancing-like spin turns.
The program provided with this project demonstrates a way to detect collisions by using the rotation sensors in the drive motors to detect when the motors have stalled, which allows the robot to bounce around your room without using any other sensors.


Brian Davis said…
Interesting, thanks for posting! Using two sequences in the program works, but for this application it actually will slow down both sequences. Another approach is to put the stall detection "in-line", with a Loop that only exits after the change in angular position is less than some set change. I use this in Nadar (as a self-contained My Block):

to detect when the camera button has been pushed properly (but not stall the program waiting for the button to be pushed to a certain position), and I use it in LNE/Packbot so that the robot can literally "feel" the height of an object with the front flipper treads. This way you don't slow the program down, and can "tune" the response ("how slow am I going to call a 'stall'", so you can have it trigger on a slow down condition and not wait for a "hard stall"), and furthermore don't reset any rotation sensors... which in complex programs, can mess up other things you hadn't thought to worry about.

I've also got a simplified version up in my Brickshelf gallery:

I agree with you, this is a *very* useful technique, and one I'm really surprised hasn't been used a lot more. Those rotation sensors are an extra three sensors "built in" to most systems... using them "just" to control the motors is a waste of excess capacity :)
Dave Parker said…
Hi Brian,

Well, I guess I have to disagree with your "slow down" point...

(Note to non-programmers reading this: this is a hypothetical discussion regarding CPU processing speed, not robot speed, which is not affected here).

Adding a second sequence does take a little processing power, but putting the stall detection "in-line" in the main task, as in your Nadar, blocks the main task completely, making it unable to do anything else at all (talk about slowing it down!)

My simple program doesn't have anything else to do in the main task (and neither does your Nadar, making this argument hypothetical...), so my "wait for stall" loop in the main task is empty, but it could have something else in there (polling other sensors, etc), and it would actually iterate extremely rapidly in there.

Even if you removed the "wait until" condition from your MyBlock and spliced the stall logic directly into the main sequence, you would introduce a 0.1 second delay (or whatever your timing interval is) into each iteration of your main task loop. Using a separate task, the main loop can continue to repeat as fast as the processor can run it (even though another task is running, which saps it slightly as you point out).

By the way, to keep my program as simple as possible I didn't add any "parameters", but a more advanced way to detect a partial stall from a driving motor would be to measure the rotation speed when the robot is at full speed, then compare the stall speed against that (looking for a drop of say 50% or so from the original speed).
Ethan Steckmann said…
Great yet again.

I have a request. I would like to see how you solve the problem of building a FLL robot and seeing how would you design the arm(s) how you would attach the third motor for accessory ect....

No I dont mean go against the spirit of FLL and show people how to do it I mean design bot for inspiration for other FLLers and sample ideas on how to keep things KISS.

Ethan Steckmann
Anonymous said…
No matter how you word it, it still sounds like fishing for a solution to a problem

- BRL -
Brian Davis said…
Dave wrote:

> I guess I have to disagree with your "slow
> down" point...

Well, as you noted, blocking the main sequence makes no difference in either your application or my application. So in this case, yours would run significantly slower than an in-line (single sequence) version. If there was an US sensor being watched, or a more complex timed behavior being executed, then yes, there's a need for a second sequence beam... but as you say, in the case you present it's hypothetical.

I guess I'm coming at this from the standpoint of speed of execution, which NXT-G has some issues with. Essentially, two sequence beams just about doubles execution time (try it), it multiplying sequence beams unless absolutely needed is something I try to avoid. It doesn't "sap it slightly"... a more accurate description (unless something has changed since I tested this... perhaps I need to test it again?) is that doubleing the number of sequences cuts the speed in half. And there are plenty of applications (like line following) where wringing every drop of speed out of the system is a good thing... even for young users. Using one sequence beam (where appropriate) also makes a program smaller, and potentially less conflict oriented (try using My blocks in a multi-sequence program... conflict over both sequences wanting to "use" the same My Block can really ruin your day). Are these hypothetical as well? Absolutely... but they can come back and bite your later in some cases, so I like to keep them in mind.

The suggestion about comparing the baseline running speed to the desired "stall" speed is a good one, and one I've used some, but I've found it more reliable in most of my applications to put in a firm limit. Once you have that coded in a My Block, you can always feed that My block with a tidbit of code that gets the current rotations speed and divides it by some number. Putting it into the My block in the first place limits the flexibility somewhat I find, but ease of use sometimes trumps flexibility.

In either case, this is again a good technique... and one I'd encourage our readers to check out and try for themselves.
Parax said…
As long as it was not stalled in the first place! you cant detect it if it doesn't change.

I kind of see Dave's Point you are relying on a pause under increasing power (albeit for 0.1 of a second) where as a multi thread can trigger seperatly in say 0.001s and is not waiting.

I'm not so sure that execution time is an issue, surely response is what your after.

My question is whose grabber is fastest without breaking the egg?
IE how fast can you be while still being delicate?
Dave Parker said…
Actually, the NXT-G's implementation of parallel sequences is pretty efficient, with a penalty over serial execution of only about 3% in a test of parallel vs. serial sensor polling (I just tested it, email me if you want details).

Of course, a parallel sequence will slow you down by something like half if you are adding more work to do that wasn't done before, but that's not a fair comparison. If you do the equivalent work in serial in the same task, the result will depend on the relative speed of the two tests you are running, but in this stall-detection case, serial execution would be *way* slower because of the time delay.

FYI if you want the numbers, I experimented and found that I could add a line following to my main task that would run at over 130 light sensor tests per second while also doing the stall testing in a parallel task. But if stall testing were done in serial with a 0.1 delay, you would obviously get less than 10 light sensor tests per second. And FYI, even if you could somehow reduce the time delay to zero, doing them in serial is then just about the same as in parallel (I tried it).
Brian Davis said…
Dave wrote:

> Of course, a parallel sequence will slow you
> down by something like half if you are adding
> more work to do that wasn't done before

Actually, that's exactly my point.

The entire time your program runs, it needs to be doing two sets of things... even when it is not caring or checking the stall condition of the motors (with the way NXT-G compiles right now, even the Wait block in the secondary sequence is chewing up exactly as many processor cycles as something "useful" happening in the primary sequence). If you are trying to do light following concurrently with stall detection, then you have to take this hit, I agree. But with your implementation, you take those dual-sequence beam hit all the time.

The routine you demonstrated has slightly worse than 0.25 second time resolution... because no matter how fast you check the variable "Stall" in the primary sequence, it only updates in the secondary sequence beam once every quarter of a second. Yes, if you are doing something else in that Loop it can still happen fast... but here, you're not. Essentially instead of one behavior ("check to see if the motor stalled") you've substituted two ("check to see if the motor stalled & if so set a variable", along with "check the variable to see if a stall has been flagged"), both of which continuously need timeslices from the NXT... even if you don't care about the stall condition.

A really simple example of how costly this can get is to take a simple program - say, a Loop that executes for 10,000 cycles just displaying the value of the Loop counter, and then displays the value of the Timer to show how long the Loop took. Once you have that elapsed time (13.2 seconds for a test I just ran), add a second sequence that is nothing more than an empty Loop (nothing in it) set to run forever. Execution time jumps to 34.4 seconds.

That implies that in your program, the presence of your continuously executing secondary sequence slows the primary sequence (even when it's backing up or starting the motors again) to worse than half-speed. I suspect the reason you don't see a major difference with this example between parallel & single-sequence is because by far most of this program's time is taking place in wait states of one type or another.
Dave Parker said…
OK, I think we are actually agreeing here..., but just misundersting each other's hypothetical intentions. In an actual more complex situation I'm sure we would both arrive at the same solution given the needs. We can take any remaining discussion offline.
Brian Davis said…
To everyone else... yeah, Dave and I removed our long, detailed, and probably rather boring-to-the-rest-of-you discussions off the blog. But thank you Dave for bringing up the issue!

Popular Posts