суббота, 27 февраля 2016 г.

Большой железный робот. Часть 3. Энкодеры и звук

Энкодеры


Мы давно строим роботов из LEGO Mindstorms и привыкли к тому, что повернуть вал мотора на определенный угол или заставить вращаться мотор с заданной скоростью - задача простая, ведь каждый NXT/EV3-мотор имеет встроенные энкодеры (датчики угла поворота), позволяющие работать с точностью до 1 градуса. Во всех роботах, которых мы строили из Arduino таких полезных штук не было, соответственно эти роботы не могли перемещаться на строго заданное расстояние или поддерживать заданную скорость.
В проекте "большого железного робота" мы решили попробовать сделать энкодеры своими руками. Энкодеры нам нужны для следующих задач:

  • Перемещение на заданное расстояние
  • Поворот на заданный угол относительно текущего направления
  • Поддержание заданной скорости
  • Одометрия - использование данных с энкодеров для оценки перемещения
  • Компенсация разницы в скоростях вращения колес для сохранения заданного направления движения. Эту задачу можно решать разными способами, например используя компас, но наличие энкодеров как нам кажется облегчит решение
Наш робот - не станок с ЧПУ, а учебная модель, с которой работают дети, поэтому энкодеры будем делать простые в изготовлении и наглядные в работе. В качестве датчиков будем использовать популярные Arduino Line Sensor  (KY-033), выглядят они вот так:

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




На обратную сторону колесных дисков прикрепим "полосатые диски", на которые будут смотреть датчики. Такие симпатичные и полезные роботу диски мы сделали из ненужных CD/DVD-болванок с приклеенными сверху распечатками:

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



Звук


Молчаливый робот - это не интересно. В нашем роботе будет аудиосистема и мы надеемся что робот сможет применять ее с умом - озвучивать системные сообщения, сигнализировать о событиях, да и просто - болтать. 
Для сборки аудиоподсистемы робота нам потребуются следующие компоненты:
  • Динамик
  • Усилитель мощности
  • Акустического оформление для динамика
В качестве динамика мы используем автомобильный коаксиальный динамик Supra SSB-5 диаметром 13 см


Динамики продаются парой, нам же понадобится в роботе только один.
Динамик SSB-5 не слишком тяжел для мобильного робота, недорог и обладает приемлемыми характеристиками для наших задач (4 Ом, до 140 Вт).
Чтобы усилить звук Raspberry Pi мы воспользуемся усилителем НЧ на базе микросхемы TDA7297

Динамик, подключенный к усилителю играть конечно будет, но очень тихо, поэтому аудиосистеме должна иметь соответствующее акустическое оформление. Мы выбрали вариант типа "закрытый ящик" и решили собрать корпус колонки из ДСП. Габариты указаны на рисунке ниже.


Лист ДСП (мы использовали готовую мебельную полку из строительного магазина размерами 300x800x16) можно раскроить так:

Собраем раскроенное ДСП в ящик с помощью саморезов, заделываем швы с помощью герметика, шпатлюем при необходимости и красим. Отверстие под динамик можно высверлить по кругу дрелью и обработать затем напильником.


Внутрь поместим немного синтепона, динамик крепим через уплотнительное резиновое кольцо, вырезанное из старой автомобильной камеры, отверстие, через которое выходит провод герметизируем кусочком спички и клеем ПВА.



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



Для сборки аудиоподсистемы нам понадобились:

- Автодинамик 13 см с комплектным проводом (Supra SSB-5) - 1 шт.
- Усилитель НЧ на базе микросхемы TDA7297
- Лист ДСП ("полка мебельная") 300x800x16 мм
- Саморезы 3,5 x 30
- Шпатлевка по дереву, герметик
- Краска

Для энкодеров пригодились:

- Пара CD/DVD болванок (мы использовали прозрачные, такие встречаются на дне упаковки)
- Arduino Line Sensor  (KY-033) 2 шт.
- профиль аллюм. U-обр. 20x10x20x2
- заглушка кабель-канала 15 мм
- винты М3 и М4 с гайками

суббота, 13 февраля 2016 г.

EV3 Саймон сказал

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


Если вы помните, ранее мы уже собирали "Саймона" из Arduino


Позднее мы добавляли возможность игры "Simon Says" в нашу волшебную лампу


Теперь пришла пора поиграть в игру и на платформе LEGO Mindstorms EV3. Поначалу мы планировали использовать кнопки для взаимодействия с игроком, но честно говоря результат получался скучноватым. Кнопки мы убрали и ограничились всего лишь тремя моторами, которые служат как для вывода последовательностей компьютером, так и для их ввода игроком. Плюсом этого решения можно считать возможность собрать проект как из домашней, так и из образовательной версии EV3.



Инструкцию по сборке (в форматах LDD и PDF) и программу к проекту можно скачать по ссылке

Программа написана на языке EV3 Basic, бесплатной среде программирования для EV3. О том где ее скачать и как установить можно прочитать здесь: Используя EV3 Explorer, входящий в состав EV3 Basic, создайте папку SimonSays и поместите в нее скачанные файлы проекта.

Интересной "фишкой", которую Вы можете рассмотреть в коде, является использование функции MyMotor(), которая реализует поворот мотора в нужную позицию с использованием кубического регулятора и контролем застревания. Так как EV3 Бейсик не поддерживает передачи параметров в функцию мы передаем параметры (какой мотор использовать и в какую позицию его установить) через переменные.

u = 1
M = "A"
P = 0
k = 1
For s = 1 To 20
  a = Math.GetRandomNumber(3)
  b[s] = Math.Round(a) 
EndFor   

Sub MyMotor
  t = EV3.Time
  regulator = "True"
  While regulator
    e = P - Motor.GetCount(M)
    v = e * k
    If M = "C" Then
      v = v * 0.75
    EndIf
    Motor.Start(M,v)
    If Math.Abs(Motor.GetCount(M) - P) < 5 Then
      regulator = "False"
    EndIf
    If  EV3.Time - t > 1000 Then
      regulator = "False"
    EndIf  
  EndWhile
  Motor.Stop(M,"True")
  Program.Delay(200)
  Motor.Stop(M,"False")
EndSub

While "True" 
  
  nextu:  
  
  For z = 1 To u
    If  b[z] = 1 Then
      M = "A"
      P = 50
      Speaker.Note(100, "C5", 150)
      MyMotor()
      M = "A"
      P = 0
      MyMotor()
    EndIf  
    If  b[z] = 2 Then
      M = "B"
      P = 50
      Speaker.Note(100, "D5", 150)
      MyMotor()
      M = "B"
      P = 0
      MyMotor()
    EndIf
    If  b[z] = 3 Then
      M = "C"
      P = -40
      Speaker.Note(100, "E5", 150)
      MyMotor()
      M = "C"
      P = 0
      MyMotor()
    EndIf    
  EndFor
  
  For w = 1 To u
    While Motor.GetCount("A") < 40 And Motor.GetCount("B") < 40 And Motor.GetCount("C") > -40
    EndWhile
    
    Program.Delay(200)
    
    If Motor.GetCount("A") > 40 Then
      If b[w] = 1 Then
        Speaker.Note(100, "C5", 150)
        Speaker.Wait()
      EndIf
      M = "A"
      P = 0
      MyMotor()      
      If b[w] <> 1 Then
        Speaker.Note(100, "C4", 300)
        M = "A"
        P = -50
        MyMotor()
        Speaker.Note(100, "C4", 300)
        M = "A"
        P = 0
        MyMotor()        
        Goto nextu
      EndIf        
    EndIf
    
    If Motor.GetCount("B") > 40 Then
      If b[w] = 2 Then
        Speaker.Note(100, "D5", 150)
        Speaker.Wait()
      EndIf
      M = "B"
      P = 0
      MyMotor()
      If b[w] <> 2 Then
        Speaker.Note(100, "C4", 300)
        M = "B"
        P = -50
        MyMotor()
        Speaker.Note(100, "C4", 300)
        M = "B"
        P = 0
        MyMotor()
        Goto nextu      
      EndIf
    EndIf 
    
    If Motor.GetCount("C") < -40 Then
      If b[w] = 3 Then
        Speaker.Note(100, "E5", 150)
        Speaker.Wait()
      EndIf
      M = "C"
      P = 0
      MyMotor()
      If b[w] <> 3 Then
        Speaker.Note(100, "C4", 300)
        M = "C"
        P = 50
        MyMotor()
        Speaker.Note(100, "C4", 300)
        M = "C"
        P = 0
        MyMotor()
        Goto nextu         
      EndIf        
    EndIf 
    
  EndFor
  
  u = u + 1    
  
EndWhile


суббота, 6 февраля 2016 г.

Большой железный робот. Часть 2. Рама

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


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



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



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


Основу рамы мы собрали из профильной алюминиевой трубы 25x25x2 мм, из которой мы соорудили прямоугольник со сторонами 55 и 30 см.



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



Для расположения компонентов предусмотрим перемещаемые "рельсы" из уголка 15x15. Удобство решения в том, что их можно перемещать в зависимости от размеров устанавливаемых компонентов.



Снизу раму при желании можно закрыть листовым пластиком.

В качестве свободно вращающихся колес используем 2 колеса от тележки SC-75, они крепятся в задней части робота болтами М8. Колеса имеют подшипники в осях и в поворотных платформах.





Собранная рама с колесными узлами:




В следующий раз мы планируем построить для робота аудиосистему из автомобильного динамика и ДСП, а так же установить на колеса энкодеры.

В отдаленном приближении наш робот должен выглядеть примерно так:



Для сборки рамы потребовались:
- профильная алюминиевая труба 25x25x2 мм 2 м
- заглушки пластиковые для профильной трубы 25x25 4 шт.
- пластина стальная крепежная 60x300x2 2 шт.
- пластина стальная крепежная 120x300x2 1 шт
- опора поворотная SC-75 - 2 шт.
- болты М6 x 35 для сборки рамы
- болты М6 x 75 для крепления колесных узлов
- гайки самостопорящиеся М6
- кузовные шайбы М6  x 20
- болты и гайки М8 для крепления свободно вращающихся колес
- уголок алюминиевый 15x15x1,5 1 м

Small Basic. Виртуальный робот в лабиринте

Если Вы уже успели попробовать EV3 Basic, то наверное обратили внимание на то, что это не самостоятельный продукт, а расширение для Microsoft Small Basic. Попрограммировав роботов на EV3 Basic мы решили попробовать и другие возможности среды Small Basic, в частности задействовать ее компоненты для исполнения программы на компьютере..

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


Карту лабиринта мы зададим в двумерном массиве. 0 - ячейка свободна, 1 - занята. Массив может иметь любую размерность, но должен быть со всех сторон быть ограничен занятыми ячейками (стенками).

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

В бесконечном цикле робот опрашивает три датчика:
1) Если справа ячейка свободна, робот разворачивается направо (меняет направление) и движется вперед на 1 клетку (меняет позицию)
2) Если справа ячейка занята, робот проверяет ячейку спереди - если оан свободна - он движется вперед ан 1 клетку (меняет позицию)
3) Если и справа и спереди ячейки заняты - робот проверяет ячейку слева и, если она свободна разворачивается налево (меняет направление), если занята - разворачивается на 180 градусов (дважды меняет направление)



Используя EV3 Basic можно создавать гибридные программы, которые будут исполняться частично ан роботе, частично на компьютере, свободно обмениваясь информацией по Bluetooth или Wi-Fi. Например, реальный EV3 робот двигаясь в лабиринте может строить карту своих перемещений на экране компьютера.

Исходный код нашего виртуального робота в лабиринте можно посмотреть ниже.

GraphicsWindow.Width = 500
GraphicsWindow.Height = 500

m[1][1]=0
m[1][2]=1
m[2][1]=0
m[1][3]=1
m[3][1]=1
m[2][2]=0
m[2][3]=0
m[3][2]=0
m[3][3]=1
m[1][4]=1
m[2][4]=1
m[3][4]=1
m[4][4]=0
m[4][1]=0
m[4][2]=0
m[4][3]=0
m[1][5]=0
m[2][5]=0
m[3][5]=0
m[4][5]=0
m[5][1]=1
m[5][2]=1
m[5][3]=1
m[5][4]=0
m[5][5]=1
m[1][6]=0
m[2][6]=1
m[3][6]=1
m[4][6]=1
m[5][6]=1
m[6][1]=1
m[6][2]=1
m[6][3]=0
m[6][4]=0
m[6][5]=0
m[6][6]=0
m[1][7]=0
m[2][7]=1
m[3][7]=0
m[4][7]=0
m[5][7]=0
m[6][7]=0
m[7][7]=1
m[7][1]=0
m[7][2]=0
m[7][3]=0
m[7][4]=1
m[7][5]=0
m[7][6]=1
m[1][8]=0
m[2][8]=0
m[3][8]=0
m[4][8]=1
m[5][8]=1
m[6][8]=0
m[7][8]=0
m[8][8]=0
m[8][1]=0
m[8][2]=0
m[8][3]=1
m[8][4]=1
m[8][5]=1
m[8][6]=1

For e = 0 To 9
  m[e][0] = 1
  m[0][e] = 1
  m[9][e] = 1
  m[e][9] = 1
EndFor

a = 1
b = 1
n = 3

Sub ris
  GraphicsWindow.Clear()  
  GraphicsWindow.PenColor = 0
  GraphicsWindow.BrushColor = 0
  GraphicsWindow.Show()
  GraphicsWindow.DrawRectangle(0,0,500,500)
  For y = 0 To 9
    For x = 0 To 9
      If m[x][y] = 1 Then
        GraphicsWindow.FillRectangle(x * 50,y * 50,50,50)
      EndIf
    EndFor
  EndFor
  
  GraphicsWindow.DrawEllipse(a*50,b*50,50,50)
  If n = 1 Then
    GraphicsWindow.DrawLine(25+(a*50),25+(b*50),25+(a*50),25+(b*50)-25)
  EndIf  
  If n = 2 Then
    GraphicsWindow.DrawLine(25+(a*50),25+(b*50),25+(a*50)+25,25+(b*50))
  EndIf 
  If n = 3 Then
    GraphicsWindow.DrawLine(25+(a*50),25+(b*50),25+(a*50),25+(b*50)+25)
  EndIf  
  If n = 4 Then
    GraphicsWindow.DrawLine(25+(a*50),25+(b*50),25+(a*50)-25,25+(b*50))
  EndIf
  Program.Delay(1000)
EndSub

While "True"
  
  If n = 1 Then
    If m[a + 1][b] = 0 Then
      n = 2
      ris()
      a = a + 1
      ris()
    ElseIf m[a][b - 1] = 0 Then
      b = b - 1
      ris()
    ElseIf 1 = 1 Then
      n = 4
      ris()     
    EndIf    
  EndIf
  
  If n = 2 Then
    If m[a][b + 1] = 0 Then
      n = 3
      ris()
      b = b + 1
      ris()
    ElseIf m[a + 1][b] = 0 Then
      a = a + 1
      ris()
    ElseIf 1 = 1 Then
      n = 1
      ris()    
    EndIf    
  EndIf
  
  If n = 3 Then
    If m[a - 1][b] = 0 Then
      n = 4
      ris()
      a = a - 1
      ris()
    ElseIf m[a][b + 1] = 0 Then
      b = b + 1
      ris()
    ElseIf 1 = 1 Then
      n = 2
      ris()       
    EndIf    
  EndIf
  
  If n = 4 Then
    If m[a][b - 1] = 0 Then
      n = 1
      ris()
      b = b - 1
      ris()
    ElseIf m[a - 1][b] = 0 Then
      a = a - 1
      ris()
    ElseIf 1 = 1 Then
      n = 3
      ris()    
    EndIf    
  EndIf

EndWhile

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