Random header image... Refresh for more!

PaddleBots

Last time, the paddle was a bunch of errors and trials, approached from the point of view of the Bluetooth interface of the Mindstorms NXT.  It didn’t work out so well.  Many of the problems I had were the result of telling the NXT to do conflicting things, often queueing up many actions faster than it could process them.  It ended up having about as much control as a fully loaded freight train.  I’d tell it to rotate left and it would rotate left.  While it was rotating, every frame processed would tell it to rotate left again.  And again.

And again.

Then, the paddle would reach the point where I wanted it to stop, so I’d send a stop request.  Of course, I’d already sent a ton of “RotateLeft”s that it hadn’t processed yet, so it would run through them until it had used them all up.  Then it would stop.

By then, though, since the paddle had gone too far, I’d tell it to rotate right to get back where I wanted it.  In the next frame, it was still too far, so I’d tell it to rotate right again.  And again.

And again.

Eventually it would catch up and start rotating right, back toward the target point.  Now the queue was full of “RotateRight”s, so it would spin wildly back across the target.  Then again in the other direction.  Then back.

The ball, of course, wouldn’t wait around for the paddle to make up it’s mind and would sail steadily right past the confused rectangle.

Obviously, that’s bad.

I hacked around the problem by adding limited protection against command queuing.  I also lowered the power of the rotation motor so that the paddle would be less likely to swing past the target point, so it would be less likely to need to swing back.  Unfortunately, the lowered power also meant that it was no longer fast enough to reach from one side of the play field to the other.  If the paddle was at the bottom and the ball went for the top, it couldn’t make it.

In the end, this lack of control limited how well it could play.  It ended up playing just slightly better than the computer paddle.  Despite all of the technology and computing power involved, it was still no match for a reasonably skilled human player.

What I really needed was to be able to tell the paddle to go to a specific point as fast as it could. ROTATE 10 DEGREES LEFT.  And off it would go, just like that, resulting in a point that’s 10 degrees left of where it was.

Actually, I could tell it to do that.  Sort of.  I could tell it to rotate a certain number of degrees, but there were two problems with that.  First, the motor seemed to think that rotating somewhere in the same magnitude as 10 degrees was the same as rotating exactly 10 degrees.  I’d tell it to move 10 degrees and it would go full speed for 10 degrees, then coast for another 15, stopping at 25.  Then after that, if you told it to rotate another 10 degrees in the same direction, it wouldn’t go anywhere.  Since it went a total of 25 degrees with the first movement, it wasn’t going to go anywhere until the cummulative total of future movement requests was greater than 15 degrees.  Great, so now it was moving totally randomly and sometimes refusing to respond to movement requests.  That’s really useful right there.

The second problem is that it didn’t really matter if I could tell it how to rotate exactly 10 degrees, because I had no concept of what in the hell 10 degrees meant in the game world.  All of the calculations and projections were in pixels.  Degrees would be meaningless without some sort of conversion, and a conversion would require crazy calibration code.

I think I eventually may have solved the first problem, outside of the Crazy Weekend Project timeframe.  I think there was a mode for the Mindstorm motor that would force it to rotate the desired amount exactly, but that it was a hidden mode or was not accessible the way I was trying to use it or something like that.  I haven’t tried it out on a game, but I have a reasonable expectation of success there.

I think I’ve also solved the second problem, as well.  All of my initial thoughts on paddle calibration involved some crazy scheme where I’d rotate the paddle to the clockwise extreme of the screen, then take a reading, rotate it to the counter-clockwise extreme, take another reading, and use the numbers to come up with a conversion between pixels and degrees.  A little something like this:

TO THE EXTREME!

It’s all fine on paper, but in practice, it all falls apart.  First, you have to find the extremes.  You can’t just rotate the paddle all the way to the left, then all the way to the right, because Atari paddles have a useful range somewhere in the middle.  They have a roughly 270 degree arc, but for most games, there’s only about 100 degrees of usefulness.  Also, even if that did work, how will you detect when you’ve hit the end point of the paddle?  The motor will just keep going and going until something breaks.  You might be able to turn left or right until the on screen paddle quits moving, but in some games, like Pong, the paddle will happily sail off the screen.  If the paddle behaved and stayed on the screen, you still have to correlate the rotation angle of the paddle to the movement on screen, and stop moving and make your calculation at the instant the extreme is reached.  There’s a good chance that you’d have to move so cautiously and deliberately that you will have lost the game before you’ve calibrated your paddle.

However, the idea is sound.  The math is a simple transformation that works. So what if you take away the walls and try again?  Why bother with two variables, when you can do it with only one?  Like this:

The extremes don’t matter at all.  What matters is that you have a distance and an angle.  So why not start with specifying the angle?  Rotate 10 degrees clockwise or 25 degrees counter-clockwise.  Then, when the motion is done, see how far the paddle on the screen has moved.  This will be much easier to do, not to mention, much faster.  One movement and you’re done.

This is what I’m going to try to do.  I already have the Pong recognition set up and running from last time, so I’m going to use that as a base to implement and tune the new movement engine.

The general Paddle class interface will be something like this, although it will likely be modified and tuned as I go.

public class PaddleController
{
    public void Connect() { }

    public void Rotate(int theta, sbyte power) { }
    public void StartRotation(bool direction, sbyte power) { }
    public void Stop() { }

    public void ButtonPress() { }
    public void ButtonDown() { }
    public void ButtonUp() { }

    public bool Busy { get; protected set; }
    public ManualResetEvent Completed { get; protected set; }
}

0 comments

There are no comments yet...

Kick things off by filling out the form below.

Leave a Comment