Purpose
Illustrates how to define a stopping criterion and a complex display displaying at the same time the environment/agents and a chart.
Formulation
- Add a new global variable, coverage: the percentage of area covered.
- Add a new stopping criterion: when the coverage is higher than 95%, stop the simulation.
- Build a complex display allowing to display, in same panel, the environment/agents and a chart of the coverage evolution.
Model
Global variable
We add a new parameter: the range of perception of the robot.
<global>
...
<var type="float" name="coverage" init="0" value="(the_robot.the_known.area / the_bg.area) * 100.0"/>
...
</global>Stopping criterion
We have a new reflex method in the global section in order to add a stopping criterion. To stop the simulation, we have to use the halt action.
<global>
...
<reflex when="coverage > 95">
<do action="halt"/>
</reflex>
</global>Complex display
We have to define a complex display. In order to integrate, in the same display, a chart and the environment/agents, we have to use the position and size facets of the display markup (species and chart). Concerning the chart, we have to define a chart of type series to display the coverage evolution.
<output>
<display name="display" refresh_every="1">
<species name="background" aspect="base" position="{0.2,0.05}" size="{0.6,0.6}" />
<species name="obstacle" aspect="base" position="{0.2,0.05}" size="{0.6,0.6}" />
<species name="known_area" transparency="0.5" aspect="base" position="{0.2,0.05}" size="{0.6,0.6}" />
<species name="candidate" aspect="base" position="{0.2,0.05}" size="{0.6,0.6}" />
<species name="robot" aspect="base" position="{0.2,0.05}" size="{0.6,0.6}" />
<chart type="series" name="Percentage of area covered" background="rgb 'lightGray'" axes="rgb 'white'" position="{0.05,0.67}" size="{0.9,0.3}">
<data name="coverage" color="rgb 'blue'" value="coverage" style="line" />
</chart>
</display>
</output>Complete model
<model name="tutorial_gis_robot_exploration">
<global>
<var type="string" name="shape_file_background" init="'../gis/Background.shp'" parameter="Shapefile for the buildings:" category="GIS" />
<var type="string" name="shape_file_obstacles" init="'../gis/Obstacles.shp'" parameter="Shapefile for the roads:" category="GIS" />
<var type="float" name="speed_robot" init="3" min="1" max="10" parameter="Speed of the robot" category="Robot" />
<var type="float" name="robot_perception_range" init="8" min="1" max="1000" parameter="Perception distance of the robot" category="Robot" />
<var type="float" name="dist_pt_front" init="2" min="1" max="10" parameter="Distance between two considered candidates of the frontiers" category="Robot"/>
<var type="list" name="the_obstacles"/>
<var type="background" name="the_bg" />
<var type="robot" name="the_robot" />
<var type="float" name="coverage" init="0" value="(the_robot.the_known.area / the_bg.area) * 100.0"/>
<init>
<create species="background" from="shape_file_background" return="a_bg" />
<set name="the_bg" value="first a_bg" />
<create species="obstacle" from="shape_file_obstacles" return="the_obs"/>
<set name="the_obstacles" value="self union [agents:: the_obs]"/>
<ask target="the_bg">
<set name="geometry" value="self difference [geometry2::the_obstacles]"/>
</ask>
<create species="robot" number="1" return="a_robot">
<set name="location" value="self place_in [agent::the_bg]" />
</create>
<set name="the_robot" value="a_robot"/>
<create species="triangle" from="the_bg" type="'Triangles'"/>
<do action="compute_graph">
<arg name="name" value="'background'" />
<arg name="triangles" value="list triangle" />
</do>
</init>
<reflex when="coverage > 95">
<do action="halt" />
</reflex>
</global>
<environment bounds="shape_file_background" />
<entities>
<species name="background" skills="situated">
<aspect name="base">
<draw shape="geometry" color="rgb 'pink'" />
</aspect>
</species>
<species name="obstacle" skills="situated">
<aspect name="base">
<draw shape="geometry" color="rgb 'black'" />
</aspect>
</species>
<species name="robot" skills="moving">
<var name="the_known" type="known_area"/>
<var name="target_loc" type="point" init="nil" />
<init>
<set name="speed" value="speed_robot" />
<set name="range" value="robot_perception_range" />
<create species="known_area" return="a_known_area">
<set name="geometry" value="myself percieved_area [agent::the_bg, precision::20]" />
</create>
<set name="the_known" value="a_known_area" />
</init>
<reflex name="move">
<if condition="target_loc = nil">
<do action="choose_target" />
</if>
<do action="goto">
<arg name="graph_name" value="'background'" />
<arg name="target" value="target_loc" />
</do>
<if condition="location = target_loc">
<set name="target_loc" value="nil" />
</if>
</reflex>
<reflex name="update_the_known">
<let type="list" name="percept" value="self percieved_area [agent::the_bg, precision::20]" />
<ask target="the_known">
<set name="geometry" value="self union [geometry::percept]" />
</ask>
</reflex>
<action name="choose_target">
<ask target="list triangle">
<if condition="(self.known != 1) and (self overlaps [agent::myself.the_known])">
<set name="known" value="1" />
</if>
</ask>
<do action="update_graph">
<arg name="graph_name" value="'background'" />
<arg name="agents" value="list triangle" />
<arg name="weights" value="'known'" />
</do>
<ask target="list candidate">
<do action="die" />
</ask>
<let type="list" of="candidate" name="good_candidates" value="[]"/>
<let type="list" name="all_candidates" value="self points_exterior_ring [distance::dist_pt_front, agent::the_known]" />
<if condition="(all_candidates != nil) and !(empty all_candidates)">
<loop over="all_candidates" var="cand">
<create species="candidate" return="cs">
<set name="location" value="cand" />
<do action="build_basic_geometry">
<arg name="geometry_type" value="'square'" />
<arg name="side_size" value="0.5" />
</do>
<if condition="(self partially_overlaps [agent::the_bg]) or (self overlaps [geometry::the_obstacles])">
<do action="die" />
<else>
<add item="self" to="good_candidates"/>
</else>
</if>
</create>
</loop>
</if>
<set name="target_loc" value="(candidate (good_candidates with_min_of (self distance_graph [graph_name::'background', target::each]))).location" />
</action>
<aspect name="base">
<draw shape="geometry" size="2" color="rgb 'red'" />
</aspect>
</species>
<species name="known_area" skills="situated">
<aspect name="base">
<draw shape="geometry" color="rgb 'green'" />
</aspect>
</species>
<species name="triangle" skills="situated">
<var name="known" type="float" init="100000" />
</species>
<species name="candidate" skills="situated">
<aspect name="base">
<draw shape="geometry" color="rgb 'yellow'" />
</aspect>
</species>
</entities>
<output>
<display name="display" refresh_every="1">
<species name="background" aspect="base" position="{0.2,0.05}" size="{0.6,0.6}" />
<species name="obstacle" aspect="base" position="{0.2,0.05}" size="{0.6,0.6}" />
<species name="known_area" transparency="0.5" aspect="base" position="{0.2,0.05}" size="{0.6,0.6}" />
<species name="candidate" aspect="base" position="{0.2,0.05}" size="{0.6,0.6}" />
<species name="robot" aspect="base" position="{0.2,0.05}" size="{0.6,0.6}" />
<chart type="series" name="Percentage of area covered" background="rgb 'lightGray'" axes="rgb 'white'" position="{0.05,0.67}" size="{0.9,0.3}">
<data name="coverage" color="rgb 'blue'" value="coverage" style="line" />
</chart>
</display>
</output>
</model>