PlayingfieldObject is used as an intelligent container for a movable robot and other field objects. It is used when you want to verify the path the robot will take.
PlayingfieldObject.tcl is used in TheField.tcl.
|
An empty ::Playingfield:: isn't much. All it shows is the title. This example shows the ::Playingfield:: with a ::Playingfield::Robot sitting in its initial position as specified in the example below. |
There are several proc[edures] in PlayingfieldObject.tcl. We are interested in three of them.
proc new { {PlayingfieldName} {NameOnCanv} {Xfs} {Yfs} \
{Xss} {BackColor} {Comment} } \
{
 # PlayingfieldName = Unique name for the ::Playingfield::.
 # NameOnCanv =
 # Xfs and Yfs = X and Y physical dimensions of the field.
 # Xss = X dimension of the field on the screen.
 # BackColor = Background color the playingfield sits on.
 # Comment = Text to be displayed with the graphic object.
The parameters PlayingfieldName and NameOnCanv are constants. Physical dimensions are in meters. Screen dimensions are in pixels.
proc Robot_new { {PlayingfieldRobotName} \
{ParentPlayingfieldName} {X} {Y} {HeadingPD} {Width} {Traction} \
{Crumbs} {Color} } \
{
 # PlayingfieldRobotName = Unique name for the PlayingfieldRobot.
 # ParentPlayingfieldName = Name of the Playingfield we are using.
 # X and Y = Initial physical position on the field
 # Heading = Physical heading
 # Width = Physical dimension of the robot.
 # Traction = Force required to slide this object.
 # Crumbs = Cycles between dropping crumbs on field.
 # BackColor = Background color the playingfield sits on.
This call places a robot onto the field. Physical dimensions are in meters. Heading is in degrees. A reasonable guess for Crumbs is 1000, but you will want to adjust this since it is a matter of taste and of how fast your robot is. If you don't want the robot to leave a bread crumb trail, set it to 0.
At the time of this writing, Traction only indicates whether objects are physical or simply paint on the floor. Painted objects are pushed to the bottom so that they don't visually occlude the real objects. At some time in the future traction may be used to resolve collisions. Paint on the floor should be given traction 0 or less. Real objects can have their mass.
proc Robot_update { {PlayingfieldRobotName} {DistanceL} {DistanceR} }\
{
 # PlayingfieldRobotName = the name that was declared with
 # ::Playingfield::Robot_new.
 # DistanceL and DistanceR = Distance to move the left and right
 # sides of the robot.
When ::Playingfield::Robot_update is intended to be used as a callback where DistanceL and DistanceR are provided by the calling procedure. At this point Encoderwheel::Measure is the only object which supports this.
First we create a PlayingfieldObject using ::Playingfield::new.
source {PlayingfieldObject.tcl}
toplevel .field; wm group .field .
::Playingfield::new TheField .field.field 10 15 200 "#4444ff" Field
pack .field.field -side left
The x and y dimensions of the field are declared in meters. We declare the screen window dimension in the x dimension only.
But we also want to have a robot to play with.
::Playingfield::Robot_new OurBot TheField 3 0.1 0 1 1000 "#00ffff"
Now lets take a look at TheRobot.tcl. We need to have Encoderwheels since that is the only object that can callback ::Playingfield::Robot_update.
::Encoderwheel::new idleL .robot.idlers.idleL \
{(127-$::pwm09)*1.5+($::pwm11-127)*1.0} \
{::idledummy} {0} {::portbb} {2} {0.01} {$::fastratio} "#7f8f7f" "L" \
{{::Encoderwheel::Measure_update idlewheelMeasure "L"}}
::Encoderwheel::new idleR .robot.idlers.idleR \
{(127-$::pwm09)*1.0+($::pwm11-127)*1.5} \
{::idledummy} {0} {::portbb} {3} {0.01} {$::fastratio} "#7f8f7f" "R" \
{{::Encoderwheel::Measure_update idlewheelMeasure "R"}}
 # Callback from ::Encoderwheel::Measure will update the robot position
 # with the <left delta> <right delta> message
 # ::Encoderwheel::Measure_new { {EncoderwheelMeasureName} \
 # {CalibrationLeft} {CalibrationRight} {CallbackList} }
::Encoderwheel::Measure_new idlewheelMeasure {0.13} {0.13} \
{{::Playingfield::Robot_update OurBot}}
In particular see the last line. That is the callback specification. Do you know why the callback is specified with only one parameter, but the function definition declares 3?
|
Here the robot has moved in a sinuous path from its initial position. You can see the path in the crumbs. This path represents about 10 seconds of real time. Unfortunately it took about 10 minutes to simulate those 10 seconds. The simulations will always run slower than reality. This was done on a 133MHz PC running Linux. A newer and faster computer can simulate those 10 seconds of game in far less real time. |
Currently you can place, but not move a box. That is planned for a future upgrade.
proc Box_new { {PlayingfieldBoxName} \
{ParentPlayingfieldName} {X} {Y} {Width} {Height} {HeadingPD} {Traction} \
{Color} } \
{
 # PlayingfieldBoxName = Unique name for the ::Playingfield::Box.
 # ParentPlayingfieldName = Name of the ::Playingfield:: we are using.
 # X and Y = Initial physical position on the field
 # HeadingPD = Physical heading in degrees.
 # Width and Height = Physical dimensions of the box.
 # Traction = Force required to slide this object.
 # Color = Color of the box.
Lines are implemented so that you can switch between Point-Point (PP) and Point-Heading (PH) specification at any time. In other words, you can create a line with ::Playingfield::LinePP_new, and then update it with either ::Playingfield::LinePP_update or ::Playingfield::LinePH_update.
Specify a line by the two end points.
proc LinePP_new { {PlayingfieldLineName} \
{ParentPlayingfieldName} {X1} {Y1} {X2} {Y2} {Thickness} {Traction} \
{Color} } \
{
 # PlayingfieldLineName = Unique name for the ::Playingfield::Line.
 # ParentPlayingfieldName = Name of the ::Playingfield:: we are using.
 # X1, Y1, X2 and Y2 = Initial physical position on the field.
 # Thickness = Line thickness in pixels on the screen.
 # Traction = Force required to slide this object.
 # Color = Color of the line.
Update a line by specifying the two end points.
proc LinePP_update { {PlayingfieldLineName} \
{XL} {YL} {XR} {YR} }\
{
 # PlayingfieldLineName = the name that was declared with
 # ::Playingfield::LinePH_new or ::Playingfield::LinePP_new.
Specify a line by the starting point, length, and heading.
proc LinePH_new { {PlayingfieldLineName} \
{ParentPlayingfieldName} {X} {Y} {Length} {HeadingPD} {Thickness} \
{Traction} {Color} } \
{
 # PlayingfieldLineName = Unique name for the PlayingfieldLine.
 # ParentPlayingfieldName = Name of the ::Playingfield:: we are using.
 # X and Y = Initial physical position on the field.
 # HeadingPD = Physical heading in degrees. Clockwise.
 # Length = Physical dimension of the line.
 # Thickness = Line thickness in pixels on the screen.
 # Traction = Force required to slide this object.
 # Color = Color of the line.
Update a line by specifying the new starting point and heading. The length is kept the same as the new or the last update, whichever is later.
proc LinePH_update { {PlayingfieldLineName} {X} {Y} {HeadingPD} }\
{
 # PlayingfieldLineName = the name that was declared with
 # ::Playingfield::LinePH_new or ::Playingfield::LinePP_new.
Currently you can place an oval but not move it.
proc Oval_new { {PlayingfieldOvalName} \
{ParentPlayingfieldName} {X1} {Y1} {X2} {Y2} {Thickness} {Traction} \
{Color} } \
{
 # PlayingfieldOvalName = Unique name for the ::Playingfield::Oval.
 # ParentPlayingfieldName = Name of the ::Playingfield:: we are using.
 # X1, Y1, X2 and Y2 = Physical position on the field.
 # Thickness = Oval thickness in pixels on the screen.
 # Traction = Force required to slide this object.
 # Color = Color of the oval.
|
By using boxes and circles you can show important playing field features such as goals and starting boxes. The example shown here was used to test a navigation algorithm. The robot was programmed to visit the yellow circles in the order shown. You can see that it overshot the mark in several places. This is because the Tractortank simulated inertia, but the navigation algorithm was not programmed to deal with that. |