12.07.2010, 19:54
29.07.2004 датчик вращения ведущих колес
04.08.2004 ИК-сенсор (бампер)
Собрать самостоятельно платформу - не такое простое дело. Поэтому пришлось взять радиоуправляемую
машинку стоимостью примерно 10 долларов, снять кузов,
отпаять плату радиоуправления и уже на базе готового
шасси строить робота. Конечно, я знаю, что по канонам
робототехники (читай статьи) это не совсем то, что
требуется. Но всё-таки на Западе купить мотор с редуктором,
сервопривод или готову платформу проще простого. У
нас в Украине это или очень сложно, или достаточно
дорого. Поэтому прошу прощения за небольшое отступление
от правил.
Вот как выглядел Мерседес (а это был именно он) после
того, как я убрал радиоуправление (видно на фото пульт
и плата) и поставил первую плату. Она была достаточно
простая- AT90S2313, кварц, L293D, разъемы и выключатель
питания, шлейф к программатору.

Вначале плата работала нормально. Точнее, при простых
операциях вроде включить двигатель, включить поворот,
и так далее, но потом начались сбои. Я засомневался,
может ли данная схема нормально работать? Потом был
другой проект- Монстр-1, у которого двигатели сильно
"шумели" и не давали микроконтроллеру нормально
работать.
Поэтому я занялся разработкой плат. Первой была плата
управления на основе AT90S2313. Я сделал печатную
плату. Не без проблем, конечно, но сделал. Не нашел
пока что хорошей программы для разводки. Они либо
слишком сложные, либо простые. Так что я пока в поиске.
Пока использовал Layout 3.0, но проблема была в том,
что "на глаз" трудно рассчитать установочные
размеры деталей, в результате чего разъем программатора
закрыл места для 2-х светодиодов.
Вторая плата была плата управления двигателями. Я
использовал ту же L293, только поставил 8 диодов N5819,
сделал отводы для применения раздельного питания логики
этой микросхемы и питания двигателей и добавил схему
опторазвязки. В результате на плате может быть до
3-х разъемов питания. Пока напряжение питания невысокое,
я сделал перемычку и логика питается вместе с двигателями.
После тестовых испытаний оказалось, что эта схема
может не самая дешевая, но зато очень надежная.

Третьей платой была тоже плата управления двигателями,
но на основе микросхемы L298, которая может управлять
более мощными двигателями и идет сразу с теплоотводом
( L293 ещё нужно придумать, как охлаждать). В плате
используются также диоды и опторазвязка. Небольшое
нововведение- плата двухсторонняя, на нижней стороне
я расположил диоды в SMD-исполнении. Получилось очень
даже неплохо.

Фото не очень получились, но это всё, что есть.
Так вот, я соединяю плату 1 (мозг) и плату 2 (двигатели)
, подключаю всё это к платформе бывшего Мерседеса
и я получаю как раз то, что и требовалось.
Теперь задача посложнее. Колёса Мерса крутятся очень
быстро. Если включить двигатель хотя бы на 2-3 секунды,
он разгоняется так, что пролетает всю комнату и ударяется
о стену (дверь, шкаф, стул). При этом может развить
как саму платформу, так и платы. Что я делаю? Классика,
я делаю ШИМ (широтно-импульсную модуляцию). Я попробую
привести пример программы, но не уверен, что даже
специалисты её поймут. Я писал программу по блок-схеме,
но пока не смог нарисовать её в редакторе. Да и не
уверен пока, что программа действует. Я её прогнал,
конечно на модели, но всё же...
В чем задумка. Написать программу, которая работала
бы так, как работали драйвера в ДОСе или как работают
многозадачные операционные системы. Второй вариант
мне кажется предпочтительней. Прерывания в МК есть,
но их моежт не хватить на все случаи жизни. И я рискнул
работать не с прерываниями, а читать порт, просто
делать это достаточно быстро. Дребезг контактов можно
отсекать и программным путем.
Программа разделена на блоки. Каждый блок имеет свои
переменные (ячейки памяти) и свои константы (описаны
в начале программы). Например, мы устанавливаем константу
работы двигателя в режиме ШИМ- робот будет управлять
работой двигателя. В следующей версии программы я
сделаю из константу переменную и программа сама сможет
изменять скорость вращения колёс. Например, "глаза"
робота видят препятствие, но он ещё не "доехал"
до него. Программа может снизить скорость вращения
двигателя, робот подъедет к препятствию, коснётся
его, сработает либо контактный датчик, либо датчик
вращения колёс и робот будет точно знать что это именно
препятствие, а не что-нибудь другое. Таким же образом
можно сделать торможение- резко включить двигатель
назад на короткое время. Робот резко остановится.
Робот может двигаться не по идеально гладкой поверхности,
а по ковру, по наклонной поверхности вверх или вниз.
Для движения по таким участкам робот может корректировать
мощность, подаваемую на двигатели, ориентируюсь на
датчик вращения колес (частота вращения). Да, осциллографа
у меня пока нет, поэтому если что-то не соответствует
действительности, извините и поправьте.
Вот программа (просто управление двигателями, без
датчиков).
Я решил поставить дату 09.07.2004г. Если сделаю новую
программу, добавлю внизу.
.include "2313def.inc"
.EQU c_go_forward=$04 ; оба вперед
.EQU c_go_left=$01 ; левый
.EQU c_go_right=$02 ; правый
.EQU c_go_back=$08 ; оба назад
.EQU c_motor_mode=$03
.EQU c_motor_freq=$10
.EQU c_sensor_shaft_pin=1
.EQU c_sensor_shaft_wait1=$00
.EQU c_sensor_shaft_wait2=$01
.EQU c_sensor_contact_pin=2
.EQU m_sensor_shaft_wait1=$0070
.EQU m_sensor_shaft_wait2=$0071
;.EQU m_sensor_shaft_bcount1=$0070
.EQU m_motor=$0080
.EQU m_motor_new=$0081
.EQU m_motor_count1=$0082
.EQU m_motor_count2=$0083
.EQU m_motor_stage=$0084
.EQU m_motor_bcount1=$0085
.EQU m_motor_bcount2=$0086
.EQU m_motor_bcount3=$0087
.EQU c_wait1=$22
.EQU c_wait2=$ff
.DEF temp=R30
.DEF temp2=R29
;====================================
; I N I T
;====================================
; готовим порт В для вывода
ldi temp,$0F
out DDRB,temp
; готовим порт D для входа
ldi temp,$00
out DDRD,temp
; включаем резисторы- на входе будет 1
ldi temp,$7F
out PORTD,temp
; инициализация стека
ldi temp,RAMEND
out SPL,temp
; инициализация новых переменных
ldi temp,1 ; 1
sts m_motor_stage, temp ; стадия работы мотора
; начало
ldi temp, c_go_forward ; движение вперед
sts m_motor, temp
sts m_motor_new, temp
start:
;------- проверка режима работы
ldi temp, c_motor_mode ; загрузить режим работы мотора в темп
cpi temp, 0 ; режим полный?
brne l_motor2
;------- режим полный
lds temp, m_motor_new ; загрузить переменную мотор новый в темп
lds temp2, m_motor ; загрузить текущее значение мотора
sub temp, temp2 ; сравнить старое значение с новым
breq l_motor_end
lds temp, m_motor_new ; загрузить переменную мотор новый в темп
sts m_motor, temp
out PORTB, temp ; вывести temp в порт
rjmp l_motor_end
;------- режим ШИМ
l_motor2:
lds temp, m_motor_stage ; какая стадия работы?
cpi temp, 0 ; если 0-
breq l_motor2_11
lds temp, m_motor ; загрузить значение мотора
l_motor2_11:
out PORTB, temp ; вывести temp в порт
; минус счетчики
lds temp, m_motor_count1 ; загрузить счетчик младший
dec temp ; минус 1
sts m_motor_count1, temp ; сохранить младший байт
cpi temp, 0 ; равно 0 ?
brne l_motor_end ; если нет- на конец цикла
; eq 0 - init
ldi temp, c_motor_freq ; загрузить константу младшей части
sts m_motor_count1, temp ; сохранить младший байт
lds temp, m_motor_count2 ; загрузить старший байт
dec temp ; минус 1
sts m_motor_count2,temp ; save
cpi temp, 0
brne l_motor_end
; меняем стадию работы
;l_motor3_0:
lds temp, m_motor_stage ; какая стадия работы?
cpi temp, 0 ; если=0
brne l_motor3_1 ; если 1=
ldi temp,1
sts m_motor_stage, temp ; стадия=1
ldi temp, c_motor_mode ; частота - старшая часть
rjmp l_motor3_2
l_motor3_1:
ldi temp,0
sts m_motor_stage, temp ; стадия=0
ldi temp2, c_motor_mode ; частота - старшая часть
ldi temp,10 ; если 0- пауза, время паузы равно 10 минус время работы
sub temp, temp2 ;
l_motor3_2:
; установка для ШИМ
lsl temp
lsl temp
lsl temp
lsl temp
sts m_motor_count2, temp ; частота - старшая часть
ldi temp, c_motor_freq ; частота - mладшая часть
sts m_motor_count1, temp ;
l_motor_end:
rjmp start
; подпрограмма задержки
f_wait:
loop71:
ldi r27,c_wait1
loop72:
ldi r26,c_wait2
loop73: dec r26
nop
nop
nop
cpi r26,0
brne loop73 ;---------------
dec r27
cpi r27,0
brne loop72 ;----------------
dec r28
cpi r28,0
brne loop71 ;----------------
ret
.exit
29.07.2004 Датчик вращения
ведущих колес
Я приклеил маленький магнит к колесу, а на корпус
установил геркон, контакты которого подключил к общему
проводу и одному из входов.
Робот подъезжает к препятствию, останавливается,
примерно полсекунды уходит на то, чтобы понять, что
дальше ехать он не может, включается программа разворота
или поворота.
Программно реализовано достаточно просто- используя
2 ячейки памяти (AТ90S2313), я веду обратный отсчет
от факта изменения датчика (1/0). Если пауза затягивается,
идет переход на ту часть программы, которая отвечает
за разворот (поворот). При каждом изменении датчика
я инициализирую переменные обратного отсчета.
В перспективе можно установить 2 магнита. Также можно
написать программу, которая будет контролировать
именно скорость движения, потому что робот может двигаться
и по наклонной плоскости. В этом случае будет ложное
срабатывание.
; инициализация
.EQU c_sensor_shaft_pin=3 ; на каком пине shaft сенсор
.EQU c_sensor_shaft_wait=$A0 ; задержка пока есть контакт
.EQU m_sensor_shaft_wait1=$0070 ;counter
.EQU m_sensor_shaft_wait2=$0071 ;counter
.EQU m_sensor_shaft_mem=$0072 ; memory stage (1/0)
.DEF temp=R30
.DEF temp2=R29
; часть программы, которая обрабатывает данные с сенсора
lds temp2, m_sensor_shaft_mem
in temp,PIND ; прочитать порт Д
sbrs temp, c_sensor_shaft_pin ; если установлен сенсор
rjmp l_ssensor2
cpi temp2,1
breq l_ssensor3
ldi temp,1
sts m_sensor_shaft_mem, temp ; save 1
rjmp l_ssensor4
l_ssensor2:
cpi temp2,0
breq l_ssensor3
clr temp
sts m_sensor_shaft_mem, temp ; save 0
rjmp l_ssensor4
l_ssensor3:
; count test jump
lds temp, m_sensor_shaft_wait1 ; младшая часть
cpi temp,0
brne l_ssensor31
ldi temp, $ff ; частота - mладшая часть
sts m_sensor_shaft_wait1, temp ; сохранить младший байт
lds temp, m_sensor_shaft_wait2 ; старшая часть
cpi temp,0
brne l_ssensor32
rjmp l_back ; счетчики - нули, перейти на обработку разворота
l_ssensor31:
dec temp
sts m_sensor_shaft_wait1, temp ; сохранить младший байт
rjmp l_ssensor5
l_ssensor32:
dec temp
sts m_sensor_shaft_wait2, temp ; сохранить st байт
rjmp l_ssensor5
l_ssensor4:
; инициализировать счетчики
ldi temp, $ff
sts m_sensor_shaft_wait1, temp
ldi temp,c_sensor_shaft_wait
sts m_sensor_shaft_wait2, temp
l_ssensor5:
04.08.2004 ИК-сенсор (бампер)
В Интернете я нашел множество схем ИК-сенсоров, но
большинство их них были на МК PIC. Я с ними близко
не знаком, разбираюсь пока с Atmel, поэтому использовал
схему от www.roboclub.ru, основанную на ATiny12. Сенсор
получается достаточно дорогостоящим, но, думаю, что
вскоре я разработаю свой вариант. Главное- это стабильный
генератор. Его можно собрать и на элементах ЛА3, и
на микросхеме 555, но я не уверен, что сенсор будет
работать стабильно. У меня уже есть осциллгограф,
поэтому буду надеяться, что рани или поздно все получится.
С этой схемой я разобрался в основном после того,
как просмотрел все сигналы на осциллографе. Поэтому
рекомендую приобрести или взять в аренду (я купил
за $50 аппарат С1-49 выпуска 1970 года).
Вот тут я попытался изобразить схему.

Печатная плата вам не нужна, да и не умею я делать
красиво. Кстати, платы я делаю по технологии "пленка-лазерный
принтер-утюг-хлорное железо".
От плата:

Вот как это выглядит совместно с роботом:

Робот отлично "видит" стены, другие препятствия.
Если он упирается в какой-нибудь предмет и не может
сам разобраться, я беру в руки пульт ДУ и помогаю
ему. Дальнобойность пульта меня поражает (а может
это наоборот, чувствительность датчика?) - если я
вижу робота, то и робот видит сигнал. А если робот
уехал в коридор или другую комнату, то и там я его
могу "достать" при помощи пульта ДУ.
Тут по поводу пульта ДУ у меня уже есть идеи. Нужно
как-то кодировать сигнал, потому что он будет пересекаться
с сигналами других роботов, а в случае боевого робота
он должен наоборот, "идти" на вражеский
сигнал, а если видит отражение своего, реагировать
как на препятствия. Интересно, ведь от вражеского
робото тоже будет отражаться сигнал!?! Тут нужно подумать.
Часть программы я привожу, но она достаточно простая.
Еще не дошли руки до серьезной переработки.
;----- бампер начало
in temp, c_sensor_bumper_inpin ; прочитать порт bumper
sbrc temp, c_sensor_bumper_pin1 ; если не установлен сенсор
; rjmp l_bsensor2
rjmp program_stop
rjmp l_bsensor5
sbrc temp, c_sensor_bumper_pin2 ; если не установлен сенсор
; rjmp l_bsensor3
rjmp program_stop
rjmp l_bsensor5
l_bsensor5:
;----- бампер конец
|