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 PlayingfieldRobot 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 Playingfield_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 PlayingfieldRobot_new { {PlayingfieldRobotName} \
{ParentPlayingfieldName} {X} {Y} {HeadingPD} {Width} {Traction} \
{Crumbs} {Color} } \
{
 # PlayingfieldRobotName = Unique name for the PlayingfieldRobot.
 # ParentPlayingfieldName = Name of the Playingfield we are measuring.
 # 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 PlayingfieldRobot_update { {PlayingfieldRobotName} {DistanceL} {DistanceR} }\
{
 # PlayingfieldRobotName = the name that was declared with
 # PlayingfieldRobot_new.
 # DistanceL and DistanceR = Distance to move the left and right
 # sides of the robot.
When PlayingfieldRobot_update is intended to be used as a callback where DistanceL and DistanceR are provided by the calling procedure. At this point EncoderwheelMeasure 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.
PlayingfieldRobot_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 PlayingfieldRobot_update.
Encoderwheel_new idleL .robot.idlers.idleL \
{(127-$::pwm09)*1.5+($::pwm11-127)*1.0} \
{::idledummy} {0} {::portbb} {2} {0.01} {$::fastratio} "#7f8f7f" "L" \
{{EncoderwheelMeasure_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" \
{{EncoderwheelMeasure_update idlewheelMeasure "R"}}
 # Callback from EncoderwheelMeasure will update the robot position
 # with the <left delta> <right delta> message
 # EncoderwheelMeasure_new { {EncoderwheelMeasureName} \
 # {CalibrationLeft} {CalibrationRight} {CallbackList} }
EncoderwheelMeasure_new idlewheelMeasure {0.13} {0.13} \
{{PlayingfieldRobot_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 PlayingfieldBox_new { {PlayingfieldBoxName} \
{ParentPlayingfieldName} {X} {Y} {Width} {Height} {HeadingPD} {Traction} \
{Color} } \
{
 # PlayingfieldBoxName = Unique name for the PlayingfieldBox.
 # ParentPlayingfieldName = Name of the Playingfield we are measuring.
 # 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 PlayingfieldLinePP_new, and then update it with either PlayingfieldLinePP_update or PlayingfieldLinePH_update.
Specify a line by the two end points.
proc PlayingfieldLinePP_new { {PlayingfieldLineName} \
{ParentPlayingfieldName} {X1} {Y1} {X2} {Y2} {Thickness} {Traction} \
{Color} } \
{
 # PlayingfieldLineName = Unique name for the PlayingfieldLine.
 # ParentPlayingfieldName = Name of the Playingfield we are measuring.
 # 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 PlayingfieldLinePP_update { {PlayingfieldLineName} \
{XL} {YL} {XR} {YR} }\
{
 # PlayingfieldLineName = the name that was declared with
 # PlayingfieldLinePH_new or PlayingfieldLinePP_new.
Specify a line by the starting point, length, and heading.
proc PlayingfieldLinePH_new { {PlayingfieldLineName} \
{ParentPlayingfieldName} {X} {Y} {Length} {HeadingPD} {Thickness} \
{Traction} {Color} } \
{
 # PlayingfieldLineName = Unique name for the PlayingfieldLine.
 # ParentPlayingfieldName = Name of the Playingfield we are measuring.
 # 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 PlayingfieldLinePH_update { {PlayingfieldLineName} {X} {Y} {HeadingPD} }\
{
 # PlayingfieldLineName = the name that was declared with
 # PlayingfieldLinePH_new or PlayingfieldLinePP_new.
Currently you can place an oval but not move it.
proc PlayingfieldOval_new { {PlayingfieldOvalName} \
{ParentPlayingfieldName} {X1} {Y1} {X2} {Y2} {Thickness} {Traction} \
{Color} } \
{
 # PlayingfieldOvalName = Unique name for the PlayingfieldOval.
 # ParentPlayingfieldName = Name of the Playingfield we are measuring.
 # 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.