Добавление ограничений в 2D-модель

Для подготовки упражнений для учеников существует возможность внесения ограничений с помощью редактирования XML-файла.

Ограничения бывают трех видов:

  1. Временны́е. Например, лимит времени на исполнение задачи или конкретное действие в конкретный временной отрезок.

  2. Пространственные. Например, добавление регионов («Старт», «Финиш») или запрет / принуждение робота, его датчика или какого-то подвижного предмета находиться в определенные промежутки времени в определенном месте.

  3. Ограничения на устройства. Например, ограничение на набор датчиков или на поведение устройств.

Структура написания ограничений

Для описания ограничений используется главный тег <constraints>…</constraints>, в который вписываются все ограничения. Используется как контейнер. Ограничения описываются внутри тега, каждый дочерний тег должен быть одним из четырех:

<constraints>...</constraints>

Основной тег, в который вписываются все ограничения. Используется как контейнер.

<constraints>
     <!-- Временное ограничение -->
     <timelimit value="30000"/>
     
     <!-- Ограничение с условием. При нарушении условия будет выдана ошибка -->
     <constraint checkOnce="true" failMessage="Робот должен находиться на старте перед запуском!">
          <inside objectId="robot1" regionId="start_zone"/>
     </constraint>
     
     <!-- Инициализация переменной x со значением 2 -->
     <init>
          <setter name="x">
               <int value="2"/>
          </setter>
      </init>

</constraints>

<timelimit/>

Временное ограничение. Является обязательным.

Атрибуты

Синтаксис

<timelimit value="35000"/>

<constraint>...</constraint>

Ограничение с произвольным условием, при нарушении которого будет выдана заданная ошибка. Может использоваться как контейнер. Имеет один дочерний тег: <conditions>...</conditions>.

Атрибуты

Синтаксис

<constraint checkOnce="true" failMessage="Робот должен находиться на старте перед запуском!">
<!-- Проверяет при запуске, что на порту А1 установлен инфракрасный датчик расстояния -->
<constraint checkOnce="true" failMessage="У робота должен быть установлен инфракрасный датчик расстояния на порту А1">
    <equals>
        <typeOf objectId="robot1.A1"/>
        <string value="twoDModel::robotModel::parts::RangeSensor"/>
    </equals>
</constraint>
<!-- Проверяет, что робот находится в допустимом регионе на протяжении всего времени выполнения программы -->
<constraint failMessage="Робот покинул допустимую зону!">
    <inside objectId="robot1" regionId="warzone"/>
</constraint>

<event>...</event>

Основной инструмент задания динамических ограничений. Используется как контейнер.

Событие - это просто пара (условие, триггер).

Атрибуты

Синтаксис

<event id="finish checker" settedUpInitially="false">
	<condition>
		<inside objectId="robot1" regionId="finish"/>
	</condition>
	<trigger>
		<success/>
	</trigger>
</event>

<init>...</init>

Безусловное событие, выполняющееся перед началом выполнения программы.

Пример

<!-- Перед началом выполнения программы заводим переменную "my_value" со значением два -->
<init>
    <setter name="my_value">
        <int value="2"/>
    </setter>
</init>

Условия

Теперь обсудим, какими могут быть условия в элементах <constraint> и <event>. Условия задаются с помощью тега <condition> в случае, если проверяется только одно из атомарных условий, или тега <conditions>, если проверяется составное условие.

<condition>...</condition>

Внутри этого тега описывается проверяемое условие.

Пример

<condition>
    <!-- Внутри тега описано условие равенства двух значений -->
    <equals>
        <objectState object="robot1.display.smiles"/>
        <bool value="true"/>
    </equals>
</condition>

<conditions>...</conditions>

Используется для создания составных условий. Обязательным атрибутом должна быть указана логическая связка. Связкой может быть and или or. Отрицание выражения задается тегом <not> без атрибутов. Среди подвыражений могут также встречаться другие элементы <conditions>.

Атрибуты

Синтаксис

<conditions glue="and">
   <!-- Условие1 -->
   <!-- Условие2 -->
   <!--    ...   -->
   <!-- УсловиеN -->
</conditions>

<conditions glue="and">
   <not>
      <!-- Условие1 -->
   </not>
</conditions>

<conditions glue="and">
   <timer timeout="1000" forceDropOnTimeout="true"/>
   <conditions glue="or">
      <greater>
         <objectState object="robot1.display.labels.size"/>
         <int value="20"/>
      </greater>
      <less>
         <objectState object="robot1.display.labels.size"/>
         <int value="19"/>
       </less>    
    </conditions>
</conditions>

Атомарные условия

Атомарное условие представляет собой один из следующих элементов:

<equals>...</equals>

Равно. Операция сравнения значений функциональных символов. Может использоваться как контейнер.

Синтаксис

<equals>
	<objectState object="robot1.display.labels.first.text"/>
	<string value="finish"/>
</equals>

<notEqual>...</notEqual>

Не равно. Операция сравнения значений функциональных символов. Может использоваться как контейнер.

Синтаксис

<notEqual>
	<objectState object="robot1.display.labels.first.text"/>
	<string value="finish"/>
</notEqual>

<greater>...</greater>

Больше. Операция сравнения значений функциональных символов. Может использоваться как контейнер.

Синтаксис

<greater>
	<objectState object="robot1.display.labels.size"/>
	<int value="0"/>
</greater>

<less>...</less>

Меньше. Операция сравнения значений функциональных символов. Может использоваться как контейнер.

Синтаксис

<less>
    <objectState object="robot1.display.labels.size"/>
    <int value="10"/>
</less>

<inside/>

Позволяет задавать пространственные ограничения.

Атрибуты

Синтаксис

<!-- Задаем ограничение на то, что объект робот находится в регионе с id=”start” -->
<inside objectId="robot1" regionId="start"/>

<settedUp/> и <dropped/>

Позволяет проверить, взведено событие или нет.

Атрибуты

Синтаксис

<!-- Условие, что событие с id=”event1” взведено -->
<condition>
    <settedUp id="event1"/>
</condition>

<!-- Условие, что событие с id=”event2” опущено -->
<condition>
    <dropped id="event2"/>
</condition>

Пример

В условиях события “check event” проверяется, что другое событие с id=”Try move” находится во взведенном состоянии, а событие с id=”Go back” опущено и не выполняется. Если оба эти условия после проверки возвращают значение true, то программа успешно завершается.

<event id="check event" settedUpInitially="true">
    <conditions glue="and">
        <settedUp id="Try move"/>
        <dropped id="Go back"/>
    </conditions>
    <trigger>
        <success/>
    </trigger>
</event>

<timer/>

Предикат, который начинает выдавать true, когда с момента взведения данного события прошло заданное время, а до этого момента выдает false.

Атрибуты

Синтаксис

<timer timeout="1000" forceDropOnTimeout="false"/>

Пример

Рассмотрим использование <timer/> c различными значениями атрибута forceDropOnTimeout .

В событии “check region” проверяются временное и пространственное ограничения. Первое условие (timer) становится истинным спустя 1000мс, а до этого момента ложно. После этого его значение больше не изменяется. Второе условие (inside) проверяет, что робот находится в регионе с id=”start_zone”. В тот момент, когда оба этих условия будут выполнены одновременно, программа будет выполнена успешно.

1. Т. к. атрибут forceDropOnTimeout равен "false", то после заданного количества времени событие будет продолжать оставаться взведенным и ждать выполнения второго условия.

<event id="check region" settedUpInitially="true">
    <conditions glue="and">
        <timer timeout="1000" forceDropOnTimeout="false"/>
        <inside objectId="robot1" regionId="start_zone"/>
    </conditions>
    <trigger>
        <success/>
    </trigger>
</event>

2. Т. к. атрибут forceDropOnTimeout равен "true", то после заданного количества миллисекунд событие будет опущено, несмотря на наличие .другого условия. Таким образом, если в момент времени 1000 мс робот не находится в нужном регионе, то сообщение об успешном выполнении не будет выведено даже в случае, если робот окажется там спустя некоторое время.

<event id="check region" settedUpInitially="true">
    <conditions glue="and">
        <timer timeout="1000" forceDropOnTimeout="true"/>
        <inside objectId="robot1" regionId="start_zone"/>
    </conditions>
    <trigger>
        <success/>
    </trigger>
</event>

Типы переменных и арифметические операции

<int/>, <double/>, <string>, <bool/>

Задание константы.

Атрибуты

Синтаксис

<int value="0"/>

<string value="finish"/>

<variableValue/>

Значение переменной.

Возможно взятие свойства какой-либо переменной, для этого используется точка. Например, значение rect.width вернет ширину прямоугольника, сохраненного в переменной rect.

Атрибуты

Синтаксис

<variableValue name="rotation"/>

<objectState/>

Взять состояние объекта.

Атрибуты

Синтаксис

<objectState object="robot1.display.labels.first.text"/>

Пример

<!-- Присвоим переменной rotation значение угла поворота робота -->
<setter name="rotation">
     <objectState object="robot1.rotation"/>
 </setter>
<!-- Проверяем равно ли значение переменной rotation значению угла поворота робота -->
<equals>
   <variableValue name="rotation"/>
   <objectState object="robot1.rotation"/>
</equals>

<typeOf/>

Взять метатип объекта с заданным идентификатором. Например: если взять typeOf объекта wall с id=777, то он вернет, что тип этого объекта wall.

Чаще всего этот элемент будет нужен для проверки типа подключенных датчиков и моторов.

Атрибуты

Синтаксис

<typeOf objectId="robot1.A3"/>

<minus>..</minus>, <abs>...</abs>

Унарные арифметические операции отвечающие за изменение знака и взятие модуля числа.

Синтаксис

<minus>
    <objectState object="robot1.rotation"/>
</minus>

<abs>
    <objectState object="robot1.rotation"/>
</abs>

Пример

<!-- Модуль разности переменной rotation и значения угла поворота робота -->
<abs>
    <difference>
        <variableValue name="rotation"/>
        <objectState object="robot1.rotation"/>
    </difference>
</abs>

<sum>, <difference>, <min>, <max>

Сумма и разность значений. Минимальное и максимальное значение.

Пример

<!-- Разность между переменной rotation и значением угла поворота робота -->
<difference>
       <variableValue name="rotation"/>
       <objectState object="robot1.rotation"/>
</difference>

<!-- Сумма переменной counter и единицы -->
<sum>
       <variableValue name="counter"/>
       <int value="1"/>
</sum>

Триггеры

<trigger>...</trigger>

Действие или группа действий, которые будут выполнены один или множество раз по факту выполнения условия события.

Синтаксис

<trigger>
	<success/>
</trigger>

<fail/>

Показать ошибку, завершить проверку задания.

Атрибуты

Синтаксис

<fail message="Неверный ответ!"/>

<success/>

Задание успешно пройдено.

Атрибуты

Синтаксис

<success/>

<setter>...</setter>

Установить значение переменной

Атрибуты

Пример

<!-- Создаем переменную total_score со значением 0.-->
<setter name="total_score">
       <int value="0"/>
 </setter>

<!-- Добавляем к переменной total_score + 2. -->
<setter name="total_score">
       <sum>
              <variableValue name="total_score"/>
              <int value="2"/>
       </sum>
</setter>

<setUp/>, <drop/>

Взводит или опускает событие

Атрибуты

Пример

<!-- Запустить событие "finish checker" -->
<triggers>
				<setUp id="finish checker"/>
</triggers>

<message/>

Выводит текст в консоль

Атрибуты

<trigger>
<message text="Hello, world!"/>
</trigger>

При срабатывании такого триггера в консоль робота будет выведен текст "Hello, world!"

Названия датчиков

Датчики для робота TRIK

Датчики для робота Lego EV3

Дополнительные свойства робота

Работа с экраном контроллера

Пример

Проверяем, что на экран контроллера было выведено слово “сообщение”. Регистр слова важен.

<equals>
        <objectState object="robot1.display.labels.first.text"/>
        <string value="сообщение"/>
</equals>

Пример добавления ограничений

Стартовав в синем квадрате, необходимо проехать вдоль стены с помощью датчика расстояния ИК до красного квадрата.

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <world>
      <background />
      <walls>
         <!-- Стена -->
         <wall id="{wall1}" end="300:150" begin="0:100" />
         <wall id="{wall2}" end="550:100" begin="300:150" />
         <wall id="{wall3}" end="650:200" begin="550:100" />
         <wall id="{wall4}" end="850:300" begin="650:200" />
         <wall id="{wall5}" end="1200:300" begin="850:300" />
         <wall id="{wall6}" end="1600:50" begin="1200:300" />
      </walls>
      <skittles />
      <balls />
      <colorFields />
      <images />
      <regions>
         <!-- Регионы -->
         <region visible="true" id="finish" x="1300" color="#ff0000" text="Finish" type="rectangle" width="300" textX="0" textY="0" y="-200" filled="true" height="300" />
         <region visible="true" id="start_zone" x="-50" color="#0000ff" text="Start" type="rectangle" width="150" textX="0" textY="0" y="100" filled="true" height="-150" />
         <region visible="false" id="warzone_1" x="-50" color="#ffff00" text="warzone1" type="rectangle" width="650" textX="0" textY="0" y="-50" filled="true" height="200" />
         <region visible="false" id="warzone_2" x="600" color="#ffff00" text="warzone2" type="rectangle" width="250" textX="0" textY="0" y="0" filled="true" height="250" />
         <region visible="false" id="warzone_3" x="850" color="#ffff00" text="warzone3" type="rectangle" width="750" textX="0" textY="0" y="50" filled="true" height="250" />
      </regions>
   </world>
   <robots>
      <!-- Описание робота -->
      <robot id="trikKitRobot" position="0:0" direction="0">
         <sensors>
            <sensor port="A1###input###А1###sensorA1" position="75:25" type="trik::robotModel::parts::TrikInfraredSensor" direction="45" />
            <sensor port="M3###output###JM3$$$C$$$3###" position="75:25" type="kitBase::robotModel::robotParts::Motor" direction="0" />
            <sensor port="M4###output###JM4$$$D$$$4###" position="75:25" type="kitBase::robotModel::robotParts::Motor" direction="0" />
         </sensors>
         <startPosition id="{ee2c46c1-23fc-4cda-98f4-77d9de775305}" x="25" y="25" direction="0" />
         <wheels left="M3###output###М3###" right="M4###output###М4###" />
      </robot>
   </robots>
   <constraints>
      <!-- Лимит на выполнение программы (30 секунд) -->
      <timelimit value="30000" />
      <!-- Зональное ограничение на начало езды. Проверяется один раз в начале программы -->
      <constraint checkOnce="true" failMessage="Робот должен находиться в синем квадрате перед запуском!">
         <inside regionId="start_zone" objectId="robot1" />
      </constraint>
      <!-- Ограничение на наличие и тип датчиков -->
      <constraint checkOnce="true" failMessage="Должен быть подключен только Датчик расстояния ИК на A1">
         <conditions glue="and">
            <equals>
               <typeOf objectId="robot1.A1" />
               <string value="trik::twoDModel::robotModel::parts::RangeSensor" />
            </equals>
            <equals>
               <typeOf objectId="robot1.A2" />
               <string value="undefined" />
            </equals>
            <equals>
               <typeOf objectId="robot1.A3" />
               <string value="undefined" />
            </equals>
            <equals>
               <typeOf objectId="robot1.A4" />
               <string value="undefined" />
            </equals>
            <equals>
               <typeOf objectId="robot1.A5" />
               <string value="undefined" />
            </equals>
            <equals>
               <typeOf objectId="robot1.A6" />
               <string value="undefined" />
            </equals>
            <equals>
               <typeOf objectId="robot1.D1" />
               <string value="undefined" />
            </equals>
            <equals>
               <typeOf objectId="robot1.D2" />
               <string value="undefined" />
            </equals>
         </conditions>
      </constraint>
      <!-- Контроль езды робота -->
      <constraint failMessage="Робот попытался выехать из разрешенной зоны!">
         <conditions glue="or">
            <inside regionId="warzone_1" objectId="robot1" />
            <inside regionId="warzone_2" objectId="robot1" />
            <inside regionId="warzone_3" objectId="robot1" />
         </conditions>
      </constraint>
      <!-- Событие, проверяющее не заехал ли робот в зону финиша -->
      <event settedUpInitially="true">
         <condition>
            <timer timeout="100" forceDropOnTimeout="true" />
         </condition>
         <trigger>
            <setUp id="finish checker" />
         </trigger>
      </event>
      <!-- Событие, оповещающее об успешном выполнении программы -->
      <event id="finish checker" settedUpInitially="false">
         <condition>
            <inside regionId="finish" objectId="robot1" />
         </condition>
         <trigger>
            <success />
         </trigger>
      </event>
   </constraints>
</root>

Last updated