понедельник, 18 апреля 2016 г.

Немного о футболе роботов WRO gen.III. Часть 3

Во второй части статьи наш робот-нападающий научился выполнять маневр, дающий ему шанс забить мяч в ворота соперников: он двигался к мячу, выбирал кратчайшую траекторию для его объезда, достигал точки, лежащей на прямой, соединяющей мяч и ворота, после чего разворачивался и ударял по мячу, пытаясь сохранить направление на ворота.


Как мы выяснили ранее, угол, при котором будет достигнута точка схода с "орбиты" и направление на ворота соперников зависят от расположения мяча на поле. Если принять направление на ворота соперников за 0 градусов, то точка схода с орбиты при движении робота вокруг мяча против часовой стрелки будет достигнута при 90 градусах, а при движении по часовой стрелке - при -90 градусах относительно направления на ворота.


В разных точках поля меняться будет только направление на ворота соперников, а указанное соотношение углов будет сохраняться. Но это все хорошо в теории, в реальных условиях один из углов легко может быть например 78 градусов, а другой -104. Это обусловлено как мы уже обсуждали ранее несовершенством датчика-компаса и магнитными наводками.
Таким образом для каждой точки поля (или его выделенной зоны) нам необходимы заранее сохраненные в памяти робота направления на ворота соперников и пара точек схода. Сколько будет таких точек (зон) - зависит от требуемой точности наведения на ворота (и, следовательно, разрешения воображаемой системы координат, делящей поле на зоны).


Очевидно, что чем рассматриваемая зона поля ближе к воротам соперников и чем она дальше от "горизонтальной" оси поля (напомним, что мы рассматриваем поле как 2D плоскость), тем угол "атаки" будет больше, см. рис. (a > b)

Теперь давайте поговорим о том, каким образом нападающий должен установить в какой конкретно точке (зоне) поля он находится, чтобы начать работать в соответствии с углами, актуальными для данной точки. Снова обратимся к регламенту и вспомним, что нападающий может иметь на борту дальномер, обращенный вправо, а измерять расстояние им он может только в направлении правого борта (относительно своих ворот), см. рис


Полагаясь на полученную с дальномера информацию нападающий может определить свою "вертикальную" координату на поле. Если никакой другой информации нет, то "горизонтальная" координата должна использоваться либо некая средняя (соответствующая центру поля), либо смещенная к воротам соперников. Выбор между этими вариантами можно сделать исходя из мощности "пиналки" на роботе, если она сильная, выгоднее фиксировать "горизонтальную" координату по центру поля, если слабая - ближе к воротам.

Футбол - командная игра и поэтому регламентом разрешено использовать Bluetooth для взаимодействия роботов в команде. Это открывает широкие тактические возможности, например беспроводную связь можно использовать для получения "горизонтальной" координаты нападающим от вратаря.

Действительно, вратарь, стоя в защите, располагает информацией об удаленности мяча (приблизительной) и угле, образованном направлением на мяч и направлением на ворота соперников:


Зная данный угол вратарь может определить точку поля (зону) в которой находится в данный момент мяч и передать ее координаты нападающему.

Информация о координатах с дальномера нападающего и координаты, передаваемые между роботами должны снабжаться временной меткой. На основании временной метки робот будет понимать, какая из них более актуальна, "Устаревшая" информация не должна использоваться для навигации нападающего, он должен ее игнорировать, действуя так же, как будто этой информации нет вовсе (работать по средним зонам).


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

суббота, 2 апреля 2016 г.

EV3 Телеграф

Давненько мы не задавали жару в виде наших хитрых задачек  готовым "бонусным" роботам. Одной из интереснейших "домашних" EV3-моделей является BANNER PRINT3R, инструкцию по сборке и базовую программу для нее подготовил Ральф Хемпел. Этот робот умеет писать EV3 LEGO MINDSTORMS на чековой ленте, ловко доставая ее из рулона.


Мы долго думали, чем бы озадачить данного робота, какие интересные дополнения внести в конструкцию и вспомнили об одном из наших ранних проектов в цикле "Строим из микроконтроллеров" под названием "Азбука Морзе на базе Arduino":

Нам показалось, что будет очень интересно совместить распознавание кода Морзе с печатью распознанных букв на ленте - получится телеграф.



Конструкцию печатающего узла мы оставили практически без изменений, немного доработав ее под более широкую ленту (именно такая попалась нам в магазине). Блок EV3 разместили таким образом, чтобы хорошо был виден экран, добавили датчик-кнопку для ввода точек и тире. Исходную инструкцию по сборке BANNER PRINT3R можно посмотреть в разделе "Больше роботов" в домашней версии ПО или скачать здесь.



Мы нигде не нашли как заправляется бумага в данный аппарат, но методом проб и ошибок выяснили, что наиболее оптимальной схемой выглядит следующая:



Если вы помните, то мы потихоньку перебрались с EV3-G на текстовое программирование, это связано с тем что проекты становятся все сложнее и реализовать все задумки в EV3-G оказывается если и возможно, то крайне трудоемко. Поэтому программировать в данном проекте мы будем на языке EV3 Basic.

Скачать нашу программу можно по ссылке.

Общую схему работы нашего "EV3 Телеграфа" вы можете посмотреть на картинке ниже.


Распознаватель кода Морзе анализирует нажатия на датчик-кнопку, выделяет короткие и длинные нажатия, короткие паузы между элементами кода в буксе и длинные паузы между буквами. Далее приведен код распознавателя:

While "True"
    
  m[0] = 0
  m[1] = 0
  m[2] = 0
  m[3] = 0
  m[4] = 0
  m[5] = 0
  
  X = 0
  P = EV3.Time
  
  While  next_letter
    If Sensor.ReadPercent(1) > 50 Then
      If A = 0 Then
        A = EV3.Time
        Speaker.Note(100,"E5",10000)
        Program.Delay(50)
      EndIf
      P = EV3.Time  
    EndIf 
    
    If Sensor.ReadPercent(1) = 0 And A > 0 Then
      If B = 0 Then
        B = EV3.Time
        Speaker.Stop()
        Program.Delay(50)
      EndIf
      P = EV3.Time 
    EndIf
    
    If A > 0 And B > 0 Then
      T = B - A
      If T > 500 Then
        m[X] = 2
      Else
        m[X] = 1
      EndIf
      A = 0
      B = 0
      X = X+1
      P = EV3.Time
    EndIf
        
    If EV3.Time - P >= 2000 Or X > 5 Then 
      next_letter = "False"
    EndIf
        
  EndWhile 

В массив m мы записываем 1 для точек и 2 для тире. Остальные, невостребованные в букве элементы заполняются нулями.

Руководствуясь кодом Морзе для русского алфавита


мы закодировали коды Морзе для всех русских букв в массивы b1 .. b33

'a
b1[0] = 1
b1[1] = 2
b1[2] = 0
b1[3] = 0
b1[4] = 0
b1[5] = 0


b2[0] = 2
b2[1] = 1
b2[2] = 1
b2[3] = 1
b2[4] = 0
b2[5] = 0

После того, как получена длинная пауза или ведены все 6 символов кода буквы анализируем совпадение элементов массива m (буфера) с элементами массивов b1 .. b33 используя конструкцию вида

h = "True"
  For I = 0 To 5  
    If  m[i] <> b1[i] Then
      h = "False"
    EndIf    
  EndFor
  If h = "True" Then
    Speaker.Play(100,"EV3Telegraph/b1")
    LCD.BmpFile(1,0,0,"EV3Telegraph/b1")
    BO = 1

    BOprint()
  EndIf  

Данный код при совпадении массивов выводит на экран распознанную букву, произносит ее и запускает процедуру добавления в очередь печати:

Sub BOprint
  i = 0
  While O[i] <> 0 
    If O[i] <> 0 Then
      i = i + 1
    EndIf    
  EndWhile
  O[i] = BO
EndSub

Блок "драйвера" принтера работает с очередью печати, забирая первую букву, если очередь не пустая и выводит ее на печать

Sub Printer
  While  "True"
    If O[0] = 1 Then 
      b1()
      Clear()
    EndIf
    ...
    If O[0] = 32 Then 
      b32()
      Clear()
    EndIf 
  EndWhile
EndSub

После печати буквы она удаляется из очереди, а вся очередь сдвигается после этого влево, чтобы "драйвер печати".обработал следующую букву в очереди:

Sub Clear
  i = 0
  While O[i] <> 0 
    O[i] = O[i+1]
    i = i + 1    
  EndWhile  
EndSub 

Для печати буквы используем процедуры движения по осям MoveX() и MoveY()

Sub MoveX
  If  XM > 0 Then
    Motor.Move("C",-50,XM,"True")
  Else
    Motor.Move("C",50,-1 * XM,"True")
  EndIf  
EndSub

Sub MoveY
  If  YM > 0 Then
    Motor.Move("A",50,YM,"True")
  Else
    Motor.Move("A",-50,-1 * YM,"True")
  EndIf  
EndSub

Процедура MoveXY() позволяет рисовать наклонные линии

Sub MoveXY
  If YM > 0 Then
    For j = 1 To XM / 5
      Motor.Move("A",50,5,"True")
      Motor.Move("C",-50,-5,"True")
    EndFor  
  Else
    For j = 1 To XM / 5
      Motor.Move("A",-50,-5,"True")
      Motor.Move("C",-50,-5,"True")
    EndFor      
  EndIf  
EndSub

Для поднимания и опускания маркера (ручки) используем процедуру PenMotor()

Sub PenMotor
  tM = EV3.Time
  regulator = "True"
  If pen = "True" Then
    PM = 150
  Else
    PM = 0
  EndIf
  While regulator
    eM = PM - Motor.GetCount("B")
    vM = eM * kM
    Motor.Start("B",vM)
    If Math.Abs(Motor.GetCount("B") - PM) < 5 Then
      regulator = "False"
    EndIf
    If  EV3.Time - tM > 1000 Then
      regulator = "False"
    EndIf  
  EndWhile
  Motor.Stop("B","True")
EndSub

В качестве примера, чтобы нарисовать букву "И" требуется выполнить следующую последовательность вызова процедур:

Sub b9
  Y = 300
  MoveY()
  
  pen = "True"
  PenMotor()
  
  Y = -300
  MoveY()  
  
  Y = 300
  X = 300
  MoveXY()
  
  Y = -300
  MoveY()  
  
  pen = "False"
  PenMotor()  
  
  X = 100
  MoveX()
EndSub    

Многие задают нам вопрос - почему наши видео выходят все реже. Дело в том что проекты становятся все сложнее и требуют больше времени на их подготовку. Кстати, если у вас возникнут интересные идеи по новым проектам - пишите, мы открыты к реализации интересных идей.

Самое популярное