![]() |
|
My other sites |
|
|
|
|||
| [Home] [Projects] [Hardware] [Software] [Books] [Links] [Downloads] | |||
|
|
|||
|
|
|||
I particularly like the [OOPic] version of the Mark III, that lets me use the C programming language with a suite of predefined "Objects" to interface to the robot. In accordance with my standard philosophy of building modular, reusable code, I decided that I would design a stand-alone OOPic object class to encapsulate all of the I/O devices and capabilities on the Mark III.
The OOPic compiler is pretty cool: in addition to all the predefined Objects, it lets you, the programmer, create your own Objects. This is done by putting all the code and data for a new object class in one file, and then referencing that file when you create an oUserClass object in the calling program. For example, I decided to create a PhilBot class for the Mark III MiniSumo using all Virtual Circuits. I called it PBot_MkIII_VC. This page describes the OOPic V5.0 version of this user class.
Note: If you are using the V6.0 compiler, you should check out my [updated 6.0 page].
What I wanted was a generic UserClass that I could use as the basis for all my future Mark III projects. So I sat down and figured out my requirements:
I've included the full PBot_MkIII_VC Class source code on my [downloads] page, so it would probably help if you downloaded and printed it out for reference.
I
started out with the diagnostics, because this would let me debug things as I
coded them. I figured I could add some
LED's to the Bot and use these to display the flags being set by the UserClass.
I purchased the Mark III Prototyping board, and mounted a bank of 8 LED to the
board. I wired these LEDs to the bank "D" digital I/O port, (I/O 24 to 31)
and tied them to the 0V rail via 200 ohm resistors (See pic at right. Click
pic for full view).
Here are the three areas of code that defined and set up these LED objects.
// Object constants, used for
predefined values
Const DEBUG_LED_1 = 24;
Const DEBUG_LED_2 = 25;
Const DEBUG_LED_3 = 26;
Const DEBUG_LED_4 = 27;
Const DEBUG_LED_5 = 28;
Const DEBUG_LED_6 = 29;
// Object
Devices
oDIO1 LeftEyeOn = New oDIO1;
oDIO1 LeftLineOn = New oDIO1;
oDIO1 CenterLineOn = New oDIO1;
oDIO1 RightLineOn = New oDIO1;
oDIO1 RightEyeOn = New oDIO1;
oDIO1 BothEyesOn = New oDIO1;
// Setup the Status LEDs
LeftLineOn.IOLine = DEBUG_LED_1 ;
LeftLineOn.Direction = cvOutput ;
LeftEyeOn.IOLine = DEBUG_LED_2 ;
LeftEyeOn.Direction = cvOutput ;
CenterLineOn.IOLine = DEBUG_LED_3 ;
CenterLineOn.Direction = cvOutput ;
RightEyeOn.IOLine = DEBUG_LED_4 ;
RightEyeOn.Direction = cvOutput ;
RightLineOn.IOLine = DEBUG_LED_5 ;
RightLineOn.Direction = cvOutput ;
BothEyesOn.IOLine = DEBUG_LED_6 ;
BothEyesOn.Direction = cvOutput ;
Some things to notice here:
All of the other Mark III I/O devices were defined and initialized in a similar way.
After defining all the Inputs and outputs, I needed to connect them together with Virtual Circuits so that the "On" flags were automatically updated. To illustrate this I'll start out with an easy example: The line sensors.
Accept for a moment that there is a oByte object called LineLevel that holds the light/dark threshold value for the line sensors. If a sensor's value is less than this threshold, then the Line sensor is considered "On", otherwise it's off. So what we need is a Virtual Circuit that reads a Line Sensor's oA2D value, compares it with the LineLevel and sets the appropriate LineOn flag.
Here's the code for just the Left Line sensor:
// I/O and storage Objects
oByte LineLevel
= New oByte;
oA2D LeftLine = New oA2D;
// Virtual Circuit objects
oCompare LeftLineComp = New oCompare;
oWire LeftEyeWire = New oWire;
// --------------------------------
// setup the line sensors
// --------------------------------
// Start with a default Line Level for threshold.
// This is changed by CalibrateLine() function
LineLevel
= LINE_LEVEL;
// Configure I/O channels and enable inputs
LeftLine.IOLine = LEFT_LINE_IO;
LeftLine.Operate = cvTrue;
// --------------------------------
// setup the Line Virtual Circuits
// --------------------------------
// Compare Line level to threshold
LeftLineComp.Input.Link(LeftLine);
LeftLineComp.ReferenceIn.Link(LineLevel);
LeftLineComp.Fuzziness = 0;
// Wire Low Level to Line On.
LeftLineWire.Input.Link(LeftLineComp.Below);
LeftLineWire.Output.Link(LeftLineOn);
LeftLineComp.Operate = cvTrue;
You can see that I use an oCompare object that is linked to the
LeftLine oA2D object and the LineLevel oByte object.
This object has three output flags, above, below and between. I use Below
to indicate that the sensor is below the threshold. I then use an oWire
object to link the Below output to the LeftLineOn oBit object.
This will light the LED whenever the Mark III's Left Line sensor is on the white
line. This code is repeated for the other two line sensors.
The Eye sensors are just a bit trickier.
The left and right eye could be handled in a similar way, just comparing them with a threshold, but they are really a bit more complicated than that. In order to turn towards an opponent, you really need to discern one idle state and three different active states: 1) No contact, 2) Robot towards Left, 3) Robot towards Right & 4) Robot straight ahead. To do this we compare the relative values of the left and right sensors. If one is significantly higher than the other, we can say that the opponent is in that direction. If the eyes are not greatly different, but they are high in value, then the opponent must be straight ahead. Otherwise, we can't see the opponent at all.
When I first started creating virtual circuits to compare the left and right eye, I just fed the normal A2D values into an oCompare object and set the fuzziness to the signal difference that represented an off-center opponent. This didn't work because the oCompare object couldn't handle the negative values that occurred when one of the eye sensors was close to zero. To get around this, I changed the eye sensors to oA2DX objects, which enabled me to offset the values up above the "fuzziness" level, so all the comparisons were done as positive numbers. The code below produces eye values that range from 28 to 156. With a fuzziness of 24, any two oA2DX values can be compared and the numbers always stay positive.
The oCompare function generates three flag conditions. Above and Below are used to indicate left or right side opponents, and Between means either: no-opponent, or opponent dead ahead. More code is added later to discern between these two conditions.
Here's the code that detects the left eye or right eye dominance.
// Object constants, used for
predefined values
Const EYE_OFFSET = -100 ; // Bias the Eye level up
by 28
Const EYE_DIFFERENCE = 24; // Set diff less than Eye Bias
Const EYE_LEVEL = 52; // Level for "See
Him", includes Bias
Const LEFT_EYE_IO = 4;
Const RIGHT_EYE_IO = 3;
// Object Devices
oA2DX LeftEye = New oA2DX;
oA2DX RightEye = New oA2DX;
// Virtual Circuit objects
oCompare EyesComp = New oCompare;
oCompare0 EyeComp = New oCompare0;
oGate BothEyes = New oGate(2);
// Two inputs
oDIO1 LeftEyeOn = New oDIO1;
oDIO1 RightEyeOn = New oDIO1;
oDIO1 BothEyesOn = New oDIO1;
oWire LeftEyeWire = New oWire;
oWire RightEyeWire = New oWire;
// --------------------------------
// setup the Eye sensors
// --------------------------------
// Configure I/O channels and enable inputs
// We need to use oA2DX so we can bias the values up to permit
// the oCompare object to apply the "fuzzyness" factor without going negative
LeftEye.IOLine = LEFT_EYE_IO;
LeftEye.Center = EYE_OFFSET; // Bias the
level up
LeftEye.Unsigned = cvTrue; // Use whole 0-255 span
LeftEye.Limit = cvFalse; // Do not
limit range to 127
LeftEye.Operate = cvTrue;
RightEye.IOLine = RIGHT_EYE_IO;
RightEye.Center = EYE_OFFSET; // Bias the level up
RightEye.Unsigned = cvTrue; // Use whole 0-255 span
RightEye.Limit = cvFalse; // Do not limit
range to 127
RightEye.Operate = cvTrue;
// --------------------------------
// setup the Eye Virtual Circuits
// --------------------------------
// Compare left and right eyes.
EyesComp.Input.Link(LeftEye);
EyesComp.ReferenceIn.Link(RightEye);
EyesComp.Fuzziness = EYE_DIFFERENCE;
EyesComp.Operate = cvTrue;
// Wire Left Eye High to
Left Eye On
LeftEyeWire.Input.Link(EyesComp.Above);
LeftEyeWire.Output.Link(LeftEyeOn);
LeftEyeWire.Operate = cvTrue;
// Wire Right Eye High to Right Eye On
RightEyeWire.Input.Link(EyesComp.Below);
RightEyeWire.Output.Link(RightEyeOn);
RightEyeWire.Operate = cvTrue;
So to turn this into a virtual circuit, I add another oCompare object to check the level of the Right Eye, and then add a oGate object to do a logical AND with the Between state to detect when both conditions are true. The only remaining trick is that despite the Icon used for the oGate object, it does a logical OR operation, not an AND. But as all digital logic nerds know, to use an OR gate to do AND operations, you just invert all the inputs and outputs.
Here's the added code to detect the BothEyesOn condition.
// Compare Righ Eye with
threshold
EyeComp.Input.Link(RightEye);
EyeComp.Fuzziness = EYE_LEVEL;
EyeComp.Operate = cvTrue;
// Look for both eyes
active:
// AND "no eye dominance" with "high levels"
BothEyes.Input1.Link(EyesComp.Between);
BothEyes.Input2.Link(EyeComp.Above);
BothEyes.Output.Link(BothEyesOn);
BothEyes.InvertIn1 = cvTrue;
BothEyes.InvertIn2 = cvTrue;
BothEyes.InvertOut = cvTrue;
BothEyes.Operate = cvTrue;
There's the CalibrateLine( ) function for reading the three line sensors and calculating a new light/dark threshold based on the current values. This assumes that the Sumo is down on the black section of the ring when it's called. There's also a set of functions for driving the wheels to perform several typical Sumo motions. The Forward( ) function applies the same drive to both wheels to go forward or back. The Spin( ) function drives the wheels in opposite directions, and the Turn( ) function just drives one wheel. Finally Drive( ) combines the Forward( ) and Turn( ) functions into a single function to perform arc motions.
All that's left to do is show how to use the PBot_MkIII_VC.osc oUserClass in
a real Sumo program.
Sample Sumo programs are available on my [download] page, and I explain how they
work on my [MkIII Sumo] page.
Web content is copyright © PhilBot.com
2005, Deep Creek Lake, MD.
Contact: Phil Malone 301.387.2331, webmaster
@
PhilBot.com