Вот и добрался, наконец, до следующего этапа. Тут диплом, заморочки всякие страшные, жизненные трудности и перемены. Времени все не хватало на любимое хобби.
Зато у робота теперь есть имя:) Тимми, как у персонажа Южного парка. Итак, вот, что у меня пока получилось:
Как можно понять из заголовка, сегодня буду рассказывать про контроллер периферии.
В точности, как и планировалось, всю рутинную работу по дерганью ШИМом, регистрами, по опросу датчиков, измерению заряда батарей я возложил на отдельный маленький контроллер. Взял для этого AtMega8. Всего у этого контроллера хватает: и памяти полно, и периферии достаточно. Только портов ввода-вывода совсем мало. Этот недостаток легко исправляется сдвиговыми регистрами. А наличие аппаратного модуля SPI позволяет работать с ними в несколько строк кода.
Для управления мощными нагрузками поставил на плату два полевых транзистора. С их помощью можно, к примеру, отключить какой-нибудь блок на время, чтобы он не мешался.
Подключение регистров.
Очень важный момент! Линии SPI, идущие к регистрам и программатору нужно разделять. Если их не разделить, сожжете однозначно либо регистры, либо программатор. Вполне логично. Программатор щелкает тактирующей линией SCK, дабы отправить/считать что-то из МК, а в это время регистры гадят мусором по этим линиям. Секунды не пройдет, как программатор захочет установить высокий уровень в тот момент, когда регистр будет в низком… и
Микросхемы работают на волшебном дыму. Если он выйдет, чуда не будет.
Подробнее об этом можно прочитать в апноте AVR042:Hardware Design.
Схемы, платы…
Тут все стандартно, как всегда и как везде. AtMega8 + обвяз. Кварц взял на 14,7456 МГц. Частота эта выбрана не просто так: на этой частоте погрешность битрейта USART равна нулю, при этом мы близки к максимальной тактовой частоте в 16 МГц. Как говорилось выше, линии SPI развязаны резисторами на 4.7 кОм. Все порты с функцией АЦП выведены отдельно, на 6м напряжение с аккумулятора через делитель 56К-150К. Опорное напряжение 5В берется с AVCC и сглаживается конденсатором. Вход AREF в этом случае не подключается.
PB0 и PB1 щелкают входным и выходным регистрами. PD2 и PD3 управляют транзисторами, PD4:7 — дергают ШИМом драйвер двигателей.
Сдвиговые регистры скаскадированы по 2 каждый, т.е. доступно 16 входных и 16 выходных линий.
Может я туговато соображаю, но я еще ни разу не смог развести плату со сдвиговыми регистрами без перемычек на одной стороне. А вот давно я на двух сторонах ничего не делал:)
С лицевой стороны решил не лудить покрытие там, где нет дорожек. Отпечатал надписи и чтобы медь была как спина Бендера покрыл плату акриловым лаком. Красота вышла!
Маленькая хитрость еще с годов работы на заводе. Все, что не нужно залачить, плотно в два слоя заклеиваится малярным скотчем. Потом лак как немного подсохнет, пинцетом скотч отрывается. Если оторвать позже, скотч сильно прилипнет к лаку и останутся маленькие кусочки, что не красиво. Лак брал тот же, что и использовал раньше на производстве. Там у нас светодиодные экраны и в дождь по всему городу стояли. Без лака их чинить ездить просто бы не успевали, с лаком всего навсего замучились:) Как и рекомендуется, лак сушил феном при 70 градусах пол часа. Можно и сутки на балконе, но раз есть такая возможность.
Неясные проблемы и почему горим?
В ходе сборки столкнулся с парой трудностей. Сперва как подал напряжение на АЦП… МК сгорел. Я удивился такому повороту, потому как с АЦП уже несколько раз работал. Десять раз все перепроверил, пожал плечами, выпаял МК, поставил новый… и все чудесным образом сразу заработало. Похоже, попался брак.
На последнем этапе, написании прошивки, столкнулся с непонятными зависаниями через каждые 2-15 минут. Источник зависаний нашел: while(!(SPSR & (1 << SPIF))); — ожидание флага завершения работы SPI. Пришлось заменить на _delay_us(500). Теперь не зависает, но и задержка оказывается больше, чем необходимо. Странно это очень. Но пляски с бубном с этим изделием прошли успешно. Еще очень удивился тому, что левый мотор заметно отстает от правого. Даже откопал заказы на почте и проверил. Оба 250:1. Отпаивал проверял отдельно. Отстает все равно. Это просто выправил ШИМом. Хотя на этом проблемы не закончились, про остальные дальше. Связь.
Для связи с ПК, как и планировалось, использую модуль HC-05. Про него уже писалось достаточно и тут и на других ресурсах, поэтому я повторяться не буду, а лучше расскажу с чем столкнулся сам. А поплясать пришлось. Во первых с некоторыми версиями BlueSoleil модуль сильно тормозит на прием. Данные не теряются, но могут где-то зависнуть на минуту. Но это еще пол беды. GUI на С программировать я не умею, а кнопочками поуправлять хочется. Взялся написать скетчик на скриптовой примоченьке Processing. И тут с досадой узнал, что в нем есть баг, не позволяющий использовать COM-порт через блютус в виндоус. Печалька. Но что-же… если гора не идет к Мухаммеду, гора идет нафиг. Не стал я заморачиваться с тем, как убрать тормоза на приеме и как реализовать GUI без Processing, а просто взял второй модуль и сопряг их друг с другом. Про стопряжение достаточно написано тут, хочется еще только обратить внимание на один важный момент, который нигде не был упомянут: чтобы модули могли подключаться друг к другу, у них должны стоять одинаковые пароли. Я пол часа из-за этого убил впустую, но потом догадался.
А дальше все просто: аппаратный порт ПК -> преобразователь уровней -> HC-05 ~~~~~~> HC-05 -> наш контроллер. Все просто, прозрачно и без заморочек.
Пара слов про питание.
Как и собирался, питаю все это от трех Li-Ion аккумуляторов. Взял KeepPower на 2600мАч типоразмера А защищенные. Всем они хороши, кроме цены. 500р за штуку. Аккумулятор внутри имеет промышленный элемент 18650 фирмы Sanyo и схемку защиты.
Для них смастерил отсек из текстолита. Элементы прижимаются пружинами, взятыми из какого-то другого старого раскуроченного отсека. Вообще пружины при больших токах применять не рекомендуется: из-за плохой проводимости металла из которого их обычно делают будут большие потери и пружины могут нагреваться. У меня вся конструкция пока потребляет меньше полампера, и никаких нагревов я не заметил.
Припаять стальные пружины к меди — дело не из легких. Пришлось воспользоваться ортофосфорной кислотой. Химически активна и оставляет за собой пленку, превращающую все, что ей смажешь в огромный резистор. Отмывал ее после пайки сперва водой с содой, потом, как перестало шипеть, просто водой.
Софт.
На этом железная эпопея заканчивается и пора переходить с программам. Общий принцип прост: контроллер принимает команду по UART, выполняет и, если нужно, отвечает. Поскольку UART устройств у нас по плану несколько, для избежания коллизий никто не заикается до тех пор, пока основной контроллер не попросит. Поскольку это внутренний протокол, особой человекопонятности ему и не нужно, зато нужны надежность и краткость. В общих чертах решил делать так: первый байт — команда, несколько следующих за ним — параметры. Например, нужно установить левый двигатель на половину скорости в прямом направлении. Шлем контроллеру L0x7F и DLF. L — команда установки скорости левого двигателя, 0x7F — половинная скорость, D — команда установки направления, LF = left forward. Аналогично и со всем остальным. Таким образом можно реализовать до 255 команд с разветвленной системой параметров. С этим проблем на удивление не возникло.
На стороне ПК написал временный тестовый скетчик в Processing. Тупо жмем кнопки «вперед-назад-лево-право» и вспоминаем начальную школу, когда все перлись с RC машинок. Запустив терминалку, можно еще пощелкать выходами, опросить входы, попереключать транзисторы, спросить заряд аккумулятора и узнать напряжение на аналоговых входах. Раз у нас будет основной контроллер, то пока и не стоит делать интерфейс для всех функций.
Работа с регистрами.
Очень красиво получается работа с регистрами по SPI. Когда МК в режиме ведущего, запись в SPDR инициирует передачу, при этом все принятые данные попадают в приемный буфер, и из того же SPDR их можно считать. Тактирующую линию SPI при этом подключаем к тактирующим входам обоих регистров, выход входного забрасываем на MISO, а вход выходного на MOSI. Достаточно дернуть защелку входного регистра, дважды записать-считать и щелкнуть выходным. И всеми этими приемами-отправками занимается аппаратный модуль SPI, не нагружая нас, память и процессор.
Заводим структуру портов:
struct IO_Port { unsigned char input_h; unsigned char input_l; unsigned char output_h; unsigned char output_l; } IO_Port;
И функцию обновления:
void Shift_SPI(void) { // Щелкаем входом PORTB &= 0b11111110; PORTB |= 1 << PB0; // Передаем-принимаем SPI_MasterTransmit(IO_Port.output_h); IO_Port.input_l = SPI_Receive(); SPI_MasterTransmit(IO_Port.output_l); IO_Port.input_h = SPI_Receive(); // Щелкаем выходными регистрами PORTB |= 1 << PB1; PORTB &= 0b11111101; }
ШИМ двигателей.
L293DNE не любит высоких частот по входу, что нам и на руку. Реже придется занимать МК переключениями. Поскольку управлять придется двумя двигателями с четырех портов, я решил остановиться на программном ШИМе. Заводим таймер и два вектора прерывания: по переполнению — инициализация и забивание регистра сравнения следующим интервалом, по совпадению — установка следующего интервала и отключение вывода.
ISR (TIMER2_OVF_vect) { if (motors_needs_update) { motors_needs_update = 0; motor.left_speed = motor_left_temp; motor.right_speed = motor_right_temp; } if ((motor.left_speed || motor.right_speed) == 0) return; // Моторы остановлены if (motor.left_speed != 0) { motor_control(LEFT, motor.left_direction, TRUE); // левый включить } else { motor_control(LEFT, 0, 0); } if (motor.right_speed != 0) { motor_control(RIGHT, motor.right_direction, TRUE); // правый включить } else { motor_control(RIGHT, 0, 0); } if (motor.left_speed == 0 && motor.right_speed != 0) { OCR2 = motor.right_speed; pwm_state = 1; return; } if (motor.right_speed == 0 && motor.left_speed != 0) { OCR2 = motor.left_speed; pwm_state = 1; return; } if (motor.left_speed == motor.right_speed) { OCR2 = motor.left_speed; pwm_state = 1; return; } if ((motor.left_speed && motor.right_speed) != 0 && (motor.left_speed < motor.right_speed)) { OCR2 = motor.left_speed; pwm_state = 0; } else { OCR2 = motor.right_speed; pwm_state = 0; } } ISR (TIMER2_COMP_vect) { switch (pwm_state) { case 0: // Если разные скорости - кладем следующий интервал в регистр стравнения if (motor.left_speed < motor.right_speed) { motor_control(LEFT, 0, 0); OCR2 = motor.right_speed; } else { motor_control(RIGHT, 0, 0); OCR2 = motor.left_speed; } pwm_state = 1; break; case 1: // Все импульсы закончились, пора отключать порт motor_control(LEFT, 0, 0); motor_control(RIGHT, 0, 0); break; } }
Для читабельности сделал функцию, щелкающую портами для моторов:
void motor_control(char motor, char direct, char action) { // Левый мотор if (motor == LEFT) { if (action == FALSE) { PORTD &= 0b00111111; return; } else { if (direct == FORWARD) { PORTD |= 0b01000000; return; } else { PORTD |= 0b10000000; return; } } } // Правый мотор if (motor == RIGHT) { if (action == FALSE) { PORTD &= 0b11001111; return; } else { if (direct == FORWARD) { PORTD |= 0b00100000; return; } else { PORTD |= 0b00010000; return; } } } }
Полный исходник ищите в конце статьи. Если честно, то как программист я самоучка, не считая двух семестров паскаля в техникуме и бейсика в школе. Поэтому если что-то можно сделать толковее, рад только буду услышать.
В заключении.
Ухабами, да болотами, но задача контроллера периферии решилась. Впереди основной контроллер, датчики и сенсоры, сервоконтроллер, ожидание камеры и передатчика видеосигнала. Основным контроллером теперь можно взять вообще что угодно, что может работать с двумя USARTами. Хоть AVR, хоть stm32, хоть Arduino. Даже можно попробовать сперва одно, потом другое. Склоняюсь больше к привычным ATMEGA, но летом постараюсь перекрутить на stm32.
А в следующий раз будем по одной шине UARTа связывать несколько устройств.
И напоследок видео:
http://www.youtube.com/watch?v=ezRIqPGQuWI
Тут думаю и так все ясно, сами смотрите. Радиоуправляемая машинка, детство прям:)
Файлы к статье:
Исходный код (временно без мультимодульного USARTа).
Схемы и платы
Тестовый скетч
PS
Что-то тут все со своими проектами затихли. Печально будет, если никто так и не очнется.
Содержание серии:
0 — Планирование
1 — Приводы и питание
2 — Контроллер периферии и связь
3а — Мультимодульный USART. Теория.
3б — Мультимодульный USART. Реализация.
0 комментариев на «“Колесная робоплатформа. Часть 2 — Контроллер периферии и связь.”»
ЗдОрово получилось!
Так, навскидку, пока 2 вопроса:
1.«с некоторыми версиями BlueSoleil модуль сильно тормозит на прием» — с какими именно?
а то я тут как раз задумался о покупке лицензии на программу.
2. Когда я мутил свой мотор-шилд, мне пришлось затворы мосфетов притягивать к земле, ставил резюки на 10к, иначе они совсем не хотели переключаться 🙂
У Вас так работает?
А мелкая осьминогая таракашка в уголке платы — это и есть мосфеты? Как называется?
1. Я пробовал в 6.4.249 и 5.0.5. В 6й версии кроме проблемы с этим модулем все работает отлично. 5я у меня иногда вылетает с ошибкой при подключении гарнитуры Nokia к Skype. По моему у этой программы только один чего-то стоящий конкурент — Toshiba Bluetooth Stack, проигрывающий по всем параметрам. Так что выбор не большой. Обе версии уже устаревшие, уже есть 8я.
2. У меня так работает. Затворы подключены к выводу МК, а когда тот стоит на выход, на нем железно или 1 или 0. Другое означает сожженный порт. Сложно рассуждать без марки транзисторов и схемы.
Ага:) Восьминогая ктулха — как раз два мосфета в одном корпусе. Зовутся IRF7311, распространены, стоят рублей 10 и купить их не проблема. Использую часто, когда мосфетов нужно четное число:) К тому же при 5 вольтах на затворе открываются полностью, что тут и нужно.
Отличная работа!
Спасибо!
Очнемся! Сейчас сам делаю проект, покажу летом, он правда онлайн. На мой взгляд нам в первую очередь нужно учиться быть вместе. Поскольку к таким делам побуждаться всегда сложнее то ощущение плеча порой ох как не хватает
А вообще у меня давно вертятся мысли собрать команду любителей робототехники, и что-то делать вместе. Найти хорошего программиста, электронщика, механика… Эх, а надо бы так:) Ну или присоединится к существующим.
Ну вот команда ROBOCRAFT… чем не вариант, очень толковые и с человеческими качествами все слава богу! Идеология у нас одна, цели те же.
Мое предположение, что нужно чуть подправить формат сайта добавить сюда возможности работы в команде, видеоконференции например 🙂
собственно,здесь и можно попробовать что-то организовать 😉