Tank-bot
- Войдите на сайт для отправки комментариев
Представляю вам своего робота .
Робот умеет обходить препятствия (ИК датчик радарного типа).
Не падать со стола /лестницы и т.д. (датчик поверхности).
Включать/выключать фары автоматически (фоторезистор).
Так же на борту есть индикатор заряда аккумов - три светодиода.
Когда уровень заряда выше 60% - горит зеленый , когда ниже - горит желтый , когда ниже 15% - горит
красный , когда ниже 5% - красный мигает , отключаются маршевые двигатели , головня серва устанавливается по центру.
В таком состоянии логика и светодиоды будут работать около 3часов.
Так же реализовано управление по ИК (пульт от телека) , правда программа ИК на отдельном МК ,
но скоро я совмещу две программы .





Остальные фото здесь foto.mail.ru/mail/heruvim219/Tank-bot
Видео здесь video.mail.ru/mail/heruvim219/Tank-Bot
Если кому интересно , схему и программу выложу позже.
участник конкурса "Arduino 2012"
>Если кому интересно
Да как вы могли предположить, что на таком сайте не найдется хотя-бы одного человека которому будет интерестно?
Конечно интерестно.
А аккумы заряжаются где-то снаружи или могут "прямо на месте"?
А по поводу проекта: однозначно "браво"!
Аккумы заряжаются внешним зарядником (потому сверху и стоят).
Просто на плате уже особо места не было , что бы ставить , какой нибудь , lm317 для заряда.
А прогу выложу позже (откоментирую и выложу).
Кстати , подскажите какую нибудь простенькую прогу для рисования схем.
"Arduino 2012"
Это очень очень круто! Даже немного завидно (по хорошему) прямоте рук.
Если выложишь код для ознакомления, будет просто здорово.
Я правильно понял, что ИК датчик закреплен на поворачивающейся платформе?
Класс! Вы не против если я помещу краткое резюме, одну из фоток и ссылку на эту ветку в раздел проекты?
>Я правильно понял, что ИК датчик закреплен на поворачивающейся платформе?<
Датчик вращается на серве.
И по положению сервы определяет с какой стороны препятствие , если препятствие прямо перед ним - сдает назад и разворачивается.
>Вы не против если я помещу краткое резюме, одну из фоток и ссылку на эту ветку в раздел проекты? <
Нет , не против .
Только я , немного , не понял где именно вы хотите ее поместить ?
Спасибо. Сюда http://arduino.ru/projects
Почему то в сети мало проектов роботов на дуино.
Изначально мой ездил с дуиной на борту , потом я развел плату (только с шестого раза сделал рабочюю плату) и дуину убрал.
Выложу схему и прогу и на одного дуино бота станет больше.
Вот программа робота.
Довольно сыровата , но , по мере апгрейда робота , буду выкладывать новые версии.
В прграмме довольно много рандомных значений это дает небольшую непредсказуемость в движениях.
Дело в том что машина с "жесткой" программой движения часто , надолго , зависала
в неудобных местах - узких проходах и т.д.
#include <Servo.h> //библиотека для серво Servo myservo;//объект серво volatile int state = LOW;//пременная обрабатываемая прерыванием int pos=0;//угол поворота сервы int val=0;//время маневра в зависимости от заряда аккума int napravlenie=0;//направление для разворота назад int povorot=0;//задержка поворота int servospeed=0;//скорость движения сервы void setup () { pinMode(3,INPUT);//датчик поверхности pinMode(1,OUTPUT);//сигнальный светодиод pinMode(13,OUTPUT);//мотор1 pinMode(12,OUTPUT);//мотор1 pinMode(11,OUTPUT);//мотор2 pinMode(10,OUTPUT);//мотор2 pinMode(9,OUTPUT);//частота на ИК светодиоды pinMode(6,OUTPUT);//индикатор заряда аккума желтый pinMode(7,OUTPUT);//индикатор заряда аккума красный pinMode(8,OUTPUT);//индикатор заряда аккума зеленый pinMode(2,INPUT);//головной TSOP pinMode(19,INPUT);//вход аккума - измерение уровня заряда pinMode(17,INPUT);//вход фоторезистора - включение фар pinMode(18,OUTPUT);//фары attachInterrupt(0, blink, CHANGE);//инициализация нулевого прерывания randomSeed(analogRead(0));//выбор случайного значения myservo.attach(5);//инициализация сервы } void loop () { if(analogRead(17)<11)//если на фоторезисторе меньше 9 то... { digitalWrite(18,HIGH);//включаем фары } else//если на фоторезисторе больше 9 то... { digitalWrite(18,LOW);//выключаем фары } //************АККУМУЛЯТОР*************************// if(analogRead(19)>615)//Если напруга выше 50%(3в на АЦП и выше) то... { digitalWrite(6,LOW); digitalWrite(7,LOW); digitalWrite(8,HIGH); //включаем зеленый светодиод val=0; //время маневра + 0 мс } if(analogRead(19)<615)//Если напруга ниже 50%(от3 до 2.5в на АЦП) то... { digitalWrite(6,HIGH); //включаем желтай светодиод digitalWrite(7,LOW); digitalWrite(8,LOW); val=150; //время маневра + 150 мс if(analogRead(19)<512)//Если напруга ниже 15%(от2.5 до 2.37в на АЦП) то... { digitalWrite(6,LOW); digitalWrite(7,HIGH); //включаем красный светодиод digitalWrite(8,LOW); val=500; //время маневра + 500 мс } } //*****************МИНИМАЛЬНЫЙ ЗАРЯД**********************// if(analogRead(19)<=490)//если напруга ниже 5% (2.35в и ниже) { digitalWrite(6,LOW); digitalWrite(7,HIGH);//мигаем красным светодиодом digitalWrite(8,LOW); digitalWrite(13,LOW); digitalWrite(12,LOW);//отключаем маршевые digitalWrite(11,LOW);//двигатели digitalWrite(10,LOW); delay(500); digitalWrite(6,LOW); digitalWrite(7,LOW); //мигаем красным светодиодом digitalWrite(8,LOW); delay(500); myservo.write(90);//устанавливаем головной сервопривод //в среднее положение } else { tone(9,38000);//генерируем частоту для TSOPов 36Кгц digitalWrite(1,LOW);//сигнальный светодиод выключен if(analogRead(17)<11)//если на фоторезисторе меньше 9 то... { digitalWrite(18,HIGH);//включаем фары } else//если на фоторезисторе больше 9 то... { digitalWrite(18,LOW);//выключаем фары } //***********************ДВИЖЕНИЕ************************// digitalWrite(13,HIGH);//едем вперед digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,HIGH); //********************************************************************************// //*******************ДВИЖЕНИЕ СЕРВЫ С ПРАВА НА ЛЕВО*******************************// //*******************************************************************************// servospeed=random(10,17);//случайно выбираем скорость движения головной сервы for(pos = 30; pos < 150; pos +=3) // с права на лево { myservo.write(pos);//установка сервы на заданный угол delay(servospeed);//движение головной сервы if(digitalRead(3)==HIGH)//если датчик поверхности не видит поверхности то ... { digitalWrite(1,HIGH);//включаем сигнальный светодиод digitalWrite(13,LOW);//едем назад 500мс digitalWrite(12,HIGH); digitalWrite(11,HIGH); digitalWrite(10,LOW); delay(500+val);//если уровень заряда аккума ниже 50% едем назад 650мс , если ниже 15% - 1000мс napravlenie=random(0,6);//случайно выбираем направление поворота if( napravlenie>3)//если больше 3 то... { digitalWrite(13,HIGH);//поворачиваем влево digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); delay(500+val);//если уровень заряда аккума ниже 50% едем назад 650мс , если ниже 15% - 1000мс } else//если меньше 3 то... { digitalWrite(13,LOW);//поворачиваем вправо digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,HIGH); delay(500+val);//если уровень заряда аккума ниже 50% едем назад 650мс , если ниже 15% - 1000мс } } if(state==HIGH&&(pos>=30&&pos<=85))//если сработал TSOP и угол сервы от 30 до 85град. то... { povorot=random(0,100);//случайно выбираем время завершения поворота digitalWrite(13,LOW);//поворачиваем вправо digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,HIGH); delay(povorot);//время поворота } if(state==HIGH&&(pos>=85&&pos<=95))//если сработал TSOP и угол сервы от 85 до 95град. то... { digitalWrite(13,LOW);//сдаем назад digitalWrite(12,HIGH); digitalWrite(11,HIGH); digitalWrite(10,LOW); delay(1000+val);//если уровень заряда аккума ниже 50% едем назад 650мс , если ниже 15% - 1000мс digitalWrite(13,HIGH);//поворачиваем влево digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); delay(500+val);//если уровень заряда аккума ниже 50% едем назад 650мс , если ниже 15% - 1000мс } if(state==HIGH&&(pos>=95&&pos<=150))//если сработал TSOP и угол сервы от 95 до 150град. то... { povorot=random(0,100);//случайно выбираем время завершения поворота digitalWrite(13,HIGH);//поворачиваем влево digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); delay(povorot);//время поворота влево } } //********************************************************************************// //*******************ДВИЖЕНИЕ СЕРВЫ С ЛЕВА НА ПРАВО*******************************// //*******************************************************************************// servospeed=random(10,17);//случайно выбираем скорость движения сервы for(pos = 150; pos >30; pos -=3) // с лева на право { myservo.write(pos); //угол поворота сервы delay(servospeed); //время поворота сервы if(digitalRead(3)==HIGH)//если датчик поверхности не видит поверхности то ... { digitalWrite(1,HIGH);//включаем сигнальный светодиод digitalWrite(13,LOW);//едем назад 500мс digitalWrite(12,HIGH); digitalWrite(11,HIGH); digitalWrite(10,LOW); delay(500+val);//если уровень заряда аккума ниже 50% едем назад 650мс , если ниже 15% - 1000мс napravlenie=random(0,6);//случайно выбираем направление поворота if( napravlenie>3)//если больше 3 то... { digitalWrite(13,HIGH);//поворачиваем влево digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); delay(500+val);//если уровень заряда аккума ниже 50% едем назад 650мс , если ниже 15% - 1000мс } else//если меньше 3 то... { digitalWrite(13,LOW);//поворачиваем вправо digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,HIGH); delay(500+val);//если уровень заряда аккума ниже 50% едем назад 650мс , если ниже 15% - 1000мс } } if(state==HIGH&&(pos>=95&&pos<=150))//если сработал TSOP и угол сервы от 150 до 95град. то... { povorot=random(0,100);//случайно выбираем время завершения поворота digitalWrite(13,HIGH);//поворачиваем влево digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); delay(povorot);//время поворота } if(state==HIGH&&(pos>=85&&pos<=95))//если сработал TSOP и угол сервы от 95 до 85град. то... { digitalWrite(13,LOW);//сдаем назад digitalWrite(12,HIGH); digitalWrite(11,HIGH); digitalWrite(10,LOW); delay(1000+val);//если уровень заряда аккума ниже 50% едем назад 650мс , если ниже 15% - 1000мс digitalWrite(13,LOW);//поворачиваем вправо digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,HIGH); delay(500+val);//если уровень заряда аккума ниже 50% едем назад 650мс , если ниже 15% - 1000мс } if(state==HIGH&&(pos>=30&&pos<=85))//если сработал TSOP и угол сервы от 85 до 30град. то... { povorot=random(0,100);//случайно выбираем время завершения поворота digitalWrite(13,LOW);//поворачиваем вправо digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,HIGH); delay(povorot);//время завершения поворота } } } } void blink()//функция внешнего прерывания //обработка сигнала с головного TSOРа { state = !state;//меняем значение переменной на противоположное digitalWrite(1,HIGH);//включаем сигнальный светодиод }Клево! а для чего нужны прерывания?
>а для чего нужны прерывания?
Уточните вопрос: вас интересует зачем вообще нужны прерывания, или зачем они используются в данном скетче?
>Вот программа робота.
Спасибо за прекрасно откоментированный код.
Для себя "подсмотрел" идею увеличивать время включения движков когда "просаживается" аккамулятор.
зачем они используются в данном скетче?
именно в этом
>а для чего нужны прерывания?<
Действительно , можно и без прерывания , просто опрашивать цифровой пин.
Но , спрерыванием он как то интереснее себя ведет.
Серва несколько задерживается в том положении , в которм обнаружила препятствие .
>Для себя "подсмотрел" идею увеличивать время включения движков когда "просаживается" аккамулятор.<
Это довольно таки условно.
Аккум просаживается нелинейно.
Сейчас работаю над модуляцией частоты ИК т.к. датчик , иногда , срабатывает на энергосберегающие лампы и яркое солнце.
видео бы еще для полного счастья =)
Ссылка на видео стоит в первом сообщении.
> зачем они используются в данном скетче?
Так в комментариях же написанно:"//обработка сигнала с головного TSOРа". TSOP, как я понимаю это датчик препятствия. Вот для того что-бы ловить его "срабатывание" и использовано прерывание.
Почему прерывание, а не просто опрос пина? Читаем документацию arduino.ru/Reference/AttachInterrupt, раздел ""Использование перерываний", там расписано в чем преимущества "через прерывание", по сравнению в простым чтением пина.
> Это довольно таки условно. Аккум просаживается нелинейно.
Ну это уже детали. Подобрать "приемлемые параметры", увеличить частоту дискретизации и т.п. всегда можно. Главное "идея", "подход". А идея увеличивать время реакции при просаживании, лично для меня, была нова. Честно говоря вообще не приходило в голову "что-то с этим делать", просто принимал как неизбежность.
>>Так в комментариях же написанно:"//обработка сигнала с головного TSOРа". TSOP, как я понимаю это датчик препятствия. Вот для того что-бы ловить его "срабатывание" и использовано прерывание.<<<
На самом деле можно и без прерывания.
Прерывание лишь изменяет состояние переменной , а она опрашивается в строго определенные моменты программы.
На первый взгляд , действительно , не видно разницы (в данном роботе) в поведении машины , но потестив ее пару дней
становится ясно что с прерыванием она ведет себя ... умнее , что ли.
Если кому интересно , схему и программу выложу позже.
Схемку можно глянуть, пажалуйста
>> Схемку можно глянуть, пажалуйста<<
Позже.
Скорее всего я полностью изменю прграмму.
Приблизительную схему можно составить по коментам в программе.
Народ , я в тупике.
Дело вот в чем.
Вот это програма управления , тем же , роботом с ИК пульта (одна она прекрасно работает).
unsigned long val=0; unsigned long val2=0; unsigned long val3=0; unsigned long val4=0; unsigned long val5=0; unsigned long val6=0; unsigned long val7=0; unsigned long val8=0; #include <Servo.h> Servo myservo; void setup() { pinMode(19,INPUT); pinMode(9,OUTPUT); pinMode(10,OUTPUT); pinMode(11,OUTPUT); pinMode(12,OUTPUT); pinMode(13,OUTPUT); pinMode(6,OUTPUT); pinMode(7,OUTPUT); pinMode(8,OUTPUT); myservo.attach(5); } void loop() { //**************************АККУМУЛЯТОР********************// if(analogRead(19)<615) { digitalWrite(6,HIGH); digitalWrite(7,LOW); digitalWrite(8,LOW); if(analogRead(19)<512) { digitalWrite(6,LOW); digitalWrite(7,HIGH); digitalWrite(8,LOW); } } if(analogRead(19)>615) { digitalWrite(6,LOW); digitalWrite(7,LOW); digitalWrite(8,HIGH); } //**********************МИНИМАЛЬНЫЙ ЗАРЯД*****************// if(analogRead(19)<=485) { digitalWrite(6,LOW); digitalWrite(7,HIGH); digitalWrite(8,LOW); digitalWrite(13,LOW);//вперд digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,LOW); delay(500); digitalWrite(6,LOW); digitalWrite(7,LOW); digitalWrite(8,LOW); delay(500); myservo.write(90); } //******************************************************// else { myservo.write(90); if(pulseIn(2,LOW)<1) { digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,LOW); digitalWrite(13,LOW); } val=pulseIn(2,LOW); val=(val/1000); if(val==2) { val2=pulseIn(2,LOW); val3=pulseIn(2,LOW); val4=pulseIn(2,LOW); val5=pulseIn(2,LOW); val6=pulseIn(2,LOW); val7=pulseIn(2,LOW); val8=pulseIn(2,LOW); if((val2/1000)==0&&(val3/1000)==0&&(val4/1000)==1&&(val5/1000)==0&& (val6/1000)==1&&(val7/1000)==1&&(val8/1000)==1) { digitalWrite(13,HIGH);//вперд digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,HIGH); } if((val2/1000)==0&&(val3/1000)==0&&(val4/1000)==1&& (val5/1000)==0&&(val6/1000)==1&&(val7/1000)==1&&(val8/1000)==0) { digitalWrite(13,LOW);//вправо digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,HIGH); } if((val2/1000)==1&&(val3/1000)==1&&(val4/1000)==0&& (val5/1000)==0&&(val6/1000)==1&&(val7/1000)==1&&(val8/1000)==0) { digitalWrite(13,HIGH);//лево digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); } if((val2/1000)==1&&(val3/1000)==0&&(val4/1000)==1&& (val5/1000)==0&&(val6/1000)==1&&(val7/1000)==1&&(val8/1000)==1) { digitalWrite(13,LOW);//назад digitalWrite(12,HIGH); digitalWrite(11,HIGH); digitalWrite(10,LOW); } } } } Но , я не могу совместить ее с вышеописаной (автономной ) программой. Чтобы с кнопки пульта программа переключалась между автономной и ручной. Что я только не делал и два TSOPA через два прерывания , и последовательный опрос и т.д. Программы вместе не работают вообще. У кого какие мысли ?>У кого какие мысли ?
Мысли:
1.Не работает
2. Названия переменных я , конечно же , меняю.
3.Не совсем понял. Пульт и TSOP работают на одной частоте .
Датчик препятствий распознает пульт как препятствие.
У меня стоят два TSOPа (по одному на каждое прерывание).
4.При разных вариантах "неработает" по разному.
Но чаще всего пульт вообще не работает , а автономная программа постоянно фиксирует препятствие и бесконечно совершает
маневр.
5.Попробую
6.Только в пределах микросекунд , а я счатываю милисекунды.
Ложных срабатываний пульта нет .Несрабатываний ( в прграмме ручного управления )тоже не было.
7.Думал об этом.Наверное попробую.
8.Памяти хватает . ATmega 328 на борту.
Максимум что я , пока , придумал это переключать режимы не командой с пульта а кнопкой на цифровом пине.
Мне кажется что конструкция "считывания импульсов в переменные" (если она крутится в автономной программе)
сильно забивает цикл и мешает работе сервы.
Вот один из примеров.
Вот так работает (вкл/выкл фар)
прерывание (само собой ) не работает.
unsigned long val=0; unsigned long val2=0; unsigned long val3=0; unsigned long val4=0; unsigned long val5=0; unsigned long val6=0; unsigned long val7=0; unsigned long val8=0; volatile int state = LOW; #include <Servo.h> Servo myservo; void setup() { pinMode(4,INPUT); pinMode(1,OUTPUT); pinMode(13,OUTPUT); pinMode(11,OUTPUT); pinMode(12,OUTPUT); pinMode(10,OUTPUT); pinMode(9,OUTPUT); pinMode(6,OUTPUT); pinMode(7,OUTPUT); pinMode(8,OUTPUT); pinMode(2,INPUT); pinMode(19,INPUT); pinMode(17,INPUT); pinMode(18,OUTPUT); attachInterrupt(0, blink, CHANGE); } void loop() { if(state==HIGH) { digitalWrite(1,HIGH); } else { digitalWrite(1,LOW); } if(pulseIn(4,LOW)<1) { digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,LOW); digitalWrite(13,LOW); } val=pulseIn(4,LOW); val=(val/1000); if(val==2) { val2=pulseIn(4,LOW); val3=pulseIn(4,LOW); val4=pulseIn(4,LOW); val5=pulseIn(4,LOW); val6=pulseIn(4,LOW); val7=pulseIn(4,LOW); val8=pulseIn(4,LOW); if((val2/1000)==0&&(val3/1000)==0&&(val4/1000)==1&&(val5/1000)==0&& (val6/1000)==1&&(val7/1000)==1&&(val8/1000)==1) { digitalWrite(18,!digitalRead(18)); delay(500); } } } void blink() { state = !state; }А вот так не работает (включил частоту на ИК светодиоде).
На пкльт не реагирует , на датчик реагирует с большим опозданием.
unsigned long val=0; unsigned long val2=0; unsigned long val3=0; unsigned long val4=0; unsigned long val5=0; unsigned long val6=0; unsigned long val7=0; unsigned long val8=0; volatile int state = LOW; #include <Servo.h> Servo myservo; void setup() { pinMode(4,INPUT); pinMode(1,OUTPUT); pinMode(13,OUTPUT); pinMode(11,OUTPUT); pinMode(12,OUTPUT); pinMode(10,OUTPUT); pinMode(9,OUTPUT); pinMode(6,OUTPUT); pinMode(7,OUTPUT); pinMode(8,OUTPUT); pinMode(2,INPUT); pinMode(19,INPUT); pinMode(17,INPUT); pinMode(18,OUTPUT); attachInterrupt(0, blink, CHANGE); } void loop() { tone(9,36000); if(state==HIGH) { digitalWrite(1,HIGH); } else { digitalWrite(1,LOW); } if(pulseIn(4,LOW)<1) { digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,LOW); digitalWrite(13,LOW); } val=pulseIn(4,LOW); val=(val/1000); if(val==2) { val2=pulseIn(4,LOW); val3=pulseIn(4,LOW); val4=pulseIn(4,LOW); val5=pulseIn(4,LOW); val6=pulseIn(4,LOW); val7=pulseIn(4,LOW); val8=pulseIn(4,LOW); if((val2/1000)==0&&(val3/1000)==0&&(val4/1000)==1&&(val5/1000)==0&& (val6/1000)==1&&(val7/1000)==1&&(val8/1000)==1) { digitalWrite(18,!digitalRead(18)); delay(500); } } } void blink() { state = !state; }Может , и правда , забивает ? Завтра проверю.
Попробуйте сделать так (выключив tone, естественно при нем работать не будет)
if(state==HIGH) { digitalWrite(1,HIGH); delay(500); state=LOW; } else { digitalWrite(1,LOW); }....
void blink(){ state=HIGH; }Что-бы он включал на заметное время фары при любом импульсе на IR приемнике. Тогда, если при включенном TSOP и, не трогая пульт, фары будут гореть или мограть, вы будете знать что IR-приемник ловит ваш TSOP.
>>IR-приемник ловит ваш TSOP.<<
TSOP это и есть IR приемник.
Так и есть частота светодиодов создает устойчивую помеху .
При включиеных ИК светодиодах робот на пульт не реагирует.
Но .
1.Даже если на TSOPах нет отраженного (или еще какого либо) сигнала - то же самое , на пульт не реагирует.
2.У меня два TSOPa один -датчик препятствий (впереди) , второй я делал специально для пульта , он смотрит вверх .
Эти TSOPы подклчены к разным ногам МК (прерываниям) и опрашиваются раздельно.
>второй я делал специально для пульта , он смотрит вверх
Боюсь что этого "мало", все это излучение хорошо отражается-переотражается от стен/потолка. Попробуйте сделать такой финт ушами:
1. Выключаете несколько раз в секунду излучатель головного TSOP-a.
2. В этот момент делаете включаете "опрос пульта" и выключаете "опрос головного", если "там тихо" , опять включаете головной.
Вообщем работаете с ними "попеременно". Возможно, в итоге, вообще одним TSOP-пом обойдется, играясь только включением-выключением излучателя и по разному интерпретирую его срабатывания. Естественно опрашивать пульт прийдется, все-таки через прерывания. pulseIn тут уже не подойдет никак. На нем программа будет "останавливаться и ждать".
Ну и посмотрите все-таки еще раз в сторону IRRemote. Там именно через прерывания и сделано. Объявлен массив rawbuf в него, при обработке прерывания, закидывают временные интервалы между пойманными тиками, а потом уже анализируются и пытаются декодировать в код клавиши (если известен протокол пульта).
Плюс есть еще есть нюанс, что с пульта первый импульс, как правило, идет более длинный чем остальные. Стартовый. Что-бы определить "начало передачи" и не "зависать" если вы услышали команду "с середины".
Ну и еще подводным камнем может быть как пульт шлет "удержание кнопки". Просто повторяет ее, повторяет сменив один бит, шлет специальный код "повторение" и т.п. В IRRemote есть семпл IRrecvDump им можно посмотреть-сдампить что-же именно шлет ваш пульт.
>>1. Выключаете несколько раз в секунду излучатель головного TSOP-a.
2. В этот момент делаете включаете "опрос пульта" и выключаете "опрос головного", если "там тихо" , опять включаете головной.<<
Вы читаете мои мысли.
Я придумал вот что.
Сделать генератор частоты на внешней микросхеме (что бы он совершенно не зависил от МК).
Сделать импульсную модуляцию этого генератора.
У меня длинна пакета импульсов с пульта составляет 9мс.
Так вот сделать модуляцию - 10мс горит , 10мс не горит .
Вот в эти самые "не горит" ловить пакет с пульта.
Теоретически все гладко , посмотрим что будет на практике.
Дело ваше. Но IMHO, это гиморней. Если не считать того что "нужно еще одну железку вкорячить", то вылезет еще куча вопросов: а как синхронизировать эту железку с МК? и т.п. Помоему "программно" все-таки намного проще будет и гибче будет. Можно подбирать соотношение времени опросов пульта/головного. Можно делать что-то типа "выключили головной на 2 мкс." если на "пульте" тишина, включили обратно головной, если "что-то есть на пульте", то "послушаем дополнительное время, что-бы наверняка". Такой гибкости "в железе" вы вряд ли добъетесь.
>Так вот сделать модуляцию - 10мс горит , 10мс не горит
Зачем? Вы сможете давить пульт с такой частотой? IMHO "прислушиваться к пульту" несколько раз в секунду будет вполне достаточно. А остальное время отдать на "голову", что-бы "не разбить свое лицо о камни" :)
К тому же "длинна пакета импульсов с пульта составляет 9мс" и "10мс не горит". А если начало пакета не совпадет по времени с периодом "10 мс не горит", что будет? Пульт-то вы нажимать будете "когда в голову взбредет", а не "в строгом соотвествии".
Поэтому, возможно, прийдется (если пульт будет "сбивать с толку" головной TSOP), добавлять логику типа "если головной задетектил что-то", выключить его, убедится что "это не пульт", и только тогда решать что "это препятствие".
Получается такая логика (и возможно на одном TSOP-е):
В этом случае даже не прийдется решать "как делить между ними время".
Не очень хороший вариант.
Дело в том что солнце и энергосберегающие лампы дают постоянную засветку на несущей частоте TSOPа (36-38КГц).
В таком случае программа будет постоянно входить в состояние опроса пульта.
Функция pulseIn отказывается работать вместе сфункцией tone.
Определять сигнал свой/чужой лучше всего по длинне , заранее сгенерированого , импульса.
Допустим .
1.пришел сигнал - меряем длинну импульса .
2.Если длинна равна 3мс (собственная ИК модуляция) - препятствие.
3.Если 2мс (начальный импульс в пачке пульта) - пульт.
4. Если больше/меньше - фоновая засветка.
>Дело в том что солнце и энергосберегающие лампы дают постоянную засветку на несущей частоте TSOPа
Вполне возможно. Только любопытно как же тогда пульты бытовой техники так спокойно работают. Сберегайки-то счас на каждом шагу.
Да и я какое-то время назад, монстрячил IR-приемник для управления компом - люстра из 6-сти сберегаек по 25ват никак не мешала. Ну да ладно, примем на веру. Раз у вас "засвечивает", значит так и есть.
>Функция pulseIn отказывается работать вместе сфункцией tone.
Скорее всего потому что используют одно и тоже прерывание.
Ну даже если бы "работала", то лучше было-бы отказатся от нее. Она фактически "останавливает программу и ждет", лучше избегать этого.
>лучше всего по длинне , заранее сгенерированого , импульса
Лучше всего то что "заработает" :) Описанная вами логика, выглядит здраво. Я бы попробовал.
Ну разве что разницу между стартовым импульсом и "собственная ИК модуляция" увеличил, для более четкого "различия" (если это не приводит к ухудшению обнаружения препятсвия).
leshak , я тут , как оказалось , легко и просто решил проблему с энергосберегающими лампами.
Проанализировал что с них идет , так вот : частота от 34 КГц до 40КГц , беспорядочные импульсы от 1до 100 мс
(в среднем около 7-20мс).
Излучение от них слабое , но TSOPу хватает. Поставил кондер 0.1мкф между сигнальной ногой и плюсом
(когда сигнала нет , на выходе TSOPа лог1 , когда сигнал появляется - лог0).
Осталась проблема с лонцем , но ее отложим .
В ближайшие пол года солнца не предвидится.
И вообще , что то думаю я в сторону полностью "железного" датчика с хорошей (многоимпульсной ) модуляцией ,
чтоб все проблемы засветки , ложных срабатываний и т.д. решались в нем а на МК выходил чистый логический уровень.
Видел я подобные проекты ИК бамперов . Можно и на отдельном МК датчик соорудить.
Вобщем посмотрим. Если и буду делать то только в следующем роботе.
>>Да и я какое-то время назад, монстрячил IR-приемник для управления компом - люстра из 6-сти сберегаек по 25ват никак не мешала. Ну да ладно, примем на веру. Раз у вас "засвечивает", значит так и есть. <<
Моя автономная программа просто выдает частоту 36КГц , TSOP реагирует на эту частоту
(хот на импульсы , хоть на постоянный сигнал).
А в пультах идет импульсная кодировка.
И импульсы от лампы не могут , чудесным образом , сложиться в код кнопки .
Потому лампы пультам и не мешают.
Спасибо за разъяснение.
Но у меня от ламп вообще не ловилось никаких импульсов. Пока пульт не нажмешь - на TSOP-пе тишина. Правда покопался в памяти, вспомнил что подключал его тоже с кондером. Не особо понимая зачем. Просто "так было в даташите". Видимо это спасло меня "от ламп".
А вот что пришло в голову: а может для головного, взять TSOP с другой частотой? Есть же, вроде и с несущей на 50Кгц.
Кстати, раскажите а от чего вы шасси (колеса, гусеницы) брали?
Гусеницы от Tamiya похоже
>> Кстати, раскажите а от чего вы шасси (колеса, гусеницы) брали?<<
Шасси полностью самодельное , выточил из текстолита , фурнитура и некоторые детали из детского (металического) конструктора.
Гусеницы , звезды , катки - Tamiya.
Моторы - переделаные сервы.
Выкусил ограничитель на ведущей шестерне , снял всю электронику.
Так что теперь это просто мотор-редукторы.
Позже выложу отдельные фото деталей платформы.
Браво! А не скажешь, что за двигатели там стоят? Мотор-редуктора, если я понял?
>>Браво! А не скажешь, что за двигатели там стоят? Мотор-редуктора, если я понял? <<
Я же писал , это переделаные (под постоянное вращение) сервоприводы Tower pro sg5010.
Попробовал совместить программу пульта и автономную , но и здесь грабли.
Программа состоит из двух больших подпрограмм .
Переключение между ними происходит посредством нажатия кнопки с фиксированым положением.
Программа нормально переходит из ручной в автономную , но при переходе из автономной в ручную - ручная не работает
(не отвечает на команды пульта) хотя переход произошел (это показывает сигнальный светодиод).
#include <Servo.h> Servo myservo; volatile int state = LOW; int val=0; int val2=0; int val3=0; int val4=0; int val5=0; int val6=0; int val7=0; int val8=0; int pos=0; int val11=0; int val22=0; int val33=0; int val44=0; void setup () { pinMode(4,INPUT); pinMode(3,INPUT); pinMode(7,OUTPUT); pinMode(1,OUTPUT); pinMode(13,OUTPUT); pinMode(11,OUTPUT); pinMode(12,OUTPUT); pinMode(10,OUTPUT); pinMode(9,OUTPUT); pinMode(6,OUTPUT); pinMode(7,OUTPUT); pinMode(8,OUTPUT); pinMode(2,INPUT); pinMode(19,INPUT); pinMode(17,INPUT); pinMode(18,OUTPUT); randomSeed(analogRead(0)); myservo.attach(5); } void loop () { if(digitalRead(4)==HIGH) { digitalWrite(7,HIGH); if(pulseIn(2,LOW)==0) { digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,LOW); digitalWrite(13,LOW); digitalWrite(18,LOW); } val=pulseIn(2,LOW); val=(val/1000); if(val==2) { val2=pulseIn(2,LOW); val3=pulseIn(2,LOW); val4=pulseIn(2,LOW); val5=pulseIn(2,LOW); val6=pulseIn(2,LOW); val7=pulseIn(2,LOW); val8=pulseIn(2,LOW); if((val2/1000)==0&&(val3/1000)==0&&(val4/1000)==0&&(val5/1000)==0&& (val6/1000)==0&&(val7/1000)==0&&(val8/1000)==0) { digitalWrite(18,HIGH); } if((val2/1000)==1&&(val3/1000)==0&&(val4/1000)==0&&(val5/1000)==0&& (val6/1000)==0&&(val7/1000)==0&&(val8/1000)==0) { digitalWrite(1,!digitalRead(1)); delay(500); } if((val2/1000)==0&&(val3/1000)==0&&(val4/1000)==1&&(val5/1000)==0&& (val6/1000)==1&&(val7/1000)==1&&(val8/1000)==1) { digitalWrite(13,HIGH);//вперд digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,HIGH); } if((val2/1000)==0&&(val3/1000)==0&&(val4/1000)==1&& (val5/1000)==0&&(val6/1000)==1&&(val7/1000)==1&&(val8/1000)==0) { digitalWrite(13,HIGH);//лево digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); } if((val2/1000)==1&&(val3/1000)==1&&(val4/1000)==0&& (val5/1000)==0&&(val6/1000)==1&&(val7/1000)==1&&(val8/1000)==0) { digitalWrite(13,LOW);//вправо digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,HIGH); } if((val2/1000)==1&&(val3/1000)==0&&(val4/1000)==1&& (val5/1000)==0&&(val6/1000)==1&&(val7/1000)==1&&(val8/1000)==1) { digitalWrite(13,LOW);//назад digitalWrite(12,HIGH); digitalWrite(11,HIGH); digitalWrite(10,LOW); } } } else { digitalWrite(7,LOW); tone(9,36000); if(analogRead(17)<11)//если на фоторезисторе меньше 9 то... { digitalWrite(18,HIGH);//включаем фары } else//если на фоторезисторе больше 9 то... { digitalWrite(18,LOW);//выключаем фары } //***********************ДВИЖЕНИЕ************************// digitalWrite(13,HIGH);//вперед digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,HIGH); val33=random(12,17); for(pos = 30; pos < 150; pos +=3) // с права на лево { myservo.write(pos); delay(val33); if(digitalRead(3)==HIGH) { digitalWrite(13,LOW);//назад digitalWrite(12,HIGH); digitalWrite(11,HIGH); digitalWrite(10,LOW); delay(500+val44); digitalWrite(13,HIGH);//влево digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); delay(1000+val44); } if(digitalRead(2)==LOW&&(pos>=30&&pos<=85)) { val22=random(0,100); digitalWrite(13,LOW);//вправо digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,HIGH); delay(val22); } if(digitalRead(2)==LOW&&(pos>=88&&pos<=95)) { digitalWrite(13,LOW);//назад digitalWrite(12,HIGH); digitalWrite(11,HIGH); digitalWrite(10,LOW); delay(1000+val44); digitalWrite(13,HIGH);//влево digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); delay(1000+val44); } if(digitalRead(2)==LOW&&(pos>=95&&pos<=150)) { val22=random(0,100); digitalWrite(13,HIGH);//влево digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); delay(val22); } } //2************************************************************// val33=random(12,17); for(pos = 150; pos >30; pos -=3) // с лева на право { myservo.write(pos); delay(val33); if(digitalRead(3)==HIGH) { digitalWrite(13,LOW);//назад digitalWrite(12,HIGH); digitalWrite(11,HIGH); digitalWrite(10,LOW); delay(500+val44); digitalWrite(13,HIGH);//влево digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); delay(1000+val44); } if(digitalRead(2)==LOW&&(pos>=95&&pos<=150)) { val22=random(0,100); digitalWrite(13,HIGH);//влево digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); delay(val22); } if(digitalRead(2)==LOW&&(pos>=85&&pos<=95)) { digitalWrite(13,LOW);//назад digitalWrite(12,HIGH); digitalWrite(11,HIGH); digitalWrite(10,LOW); delay(1000+val44); digitalWrite(13,LOW);//вправо digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,HIGH); delay(1000+val44); } if(digitalRead(2)==LOW&&(pos>=30&&pos<=85)) { val22=random(0,100); digitalWrite(13,LOW);//вправо digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,HIGH); delay(val22); } } } }Честно горя скетч такого объема трудно "прокрутить в голове". Попробуйте сделать "рефакторинг кода", глядишь и сами увидите "где что-то не так".
Разделите "принятие решения" и "выполнение решение". Сделайте для команда константы
Объявите две функции getAutoCommand (в которой будет автономная логика) и getManualCommand (в которой будет логика из пульта). Вызываете ту функцию "какой режим сейчас включен", примерно так
if(manualMode) cmd=getManualCommand() else cmd=getAutoCommand() switch(cmd) { case CMD_RIGHT: //... включаем пины для поворота влево break; case CMD_LFFT //... включаем пины для поворота вправо .... break; // .... }
Все эти серии из digitalWrite тоже можно "причесать", посмотрите ветку arduino.ru/forum/apparatnye-voprosy/binarnye-chasy, как там человек хранит в коде "какие леды нужно включить, какие выключить". Немного расточительно на каждый пин, по целому байту отводить, но все равно "намного читабельный".
Можно через прямую запись в порт сделать, тогда код еще читабельней будет.
Сейчас же скет изобилует кучей "магических цифр", дублированием кода. Код "не читается". Ну хотя-бы эти все "влево", "вправо" в отдельные функции повыносить. val22, val33 какие-то более осмысленные имена дать и т.п.
Вот эти
тоже можно упрятать в какие-то константы, и оформить в виде функции которая возвращает "код клавиши".
Да и сами val2,val3, val4 не нужны. Можно объявить массив byte vals[7], тогда и вычивать их можно будет не кучей pulseIn, а
циклом
for(i=0;i<7;i++)vals[i]=pulseIn(2,LOW).
И "сравнивать" потом тоже будет удобней (сделать массив в котором "ожидаемые значение", пробежались по двум массивам, сравнили каждый элемент, а не выписывать "длинющие условие if-a").
>>>Объявите две функции getAutoCommand (в которой будет автономная логика) и getManualCommand (в которой будет логика из пульта). Вызываете ту функцию "какой режим сейчас включен", примерно так<<<
Думал об этом - попробую.
А то я тут уже в такие дебри полез ...
"При переходе на ручное управление опрашивать ячейку ипрома и если там 1 то пишем туда 0 , включаем релюшку
(сброс питания с МК).
А при входе в автономную программу пишем в ячейку 1."
Спаял попробовал -работает , но в готовое устройство я такое , конечно же , не поставлю.
>>val22, val33 какие-то более осмысленные имена дать и т.п.<<
Это все в порядке эксперимента , лоск буду наводить когда функционал будет нормально работать.
>(сброс питания с МК)
Да жесткач. Но за умение добиватся цели любыми средствами - уважение :)
>Это все в порядке эксперимента
Это понятно. Все мы знаем откуда это возникает. Более того, на начальных этапах именно так и нужно. Криво-косо, абы живо. Пока "идея не протухла".
>лоск буду наводить когда функционал будет нормально работать
Подходы к программированию типа XP, говорят что так нельзя. Когда "код большой", вы уже не сможете его нормально отрефакторить (тем более с ArduinoIDE которое практически не имеет инструментов для "работы с кодом"). Велик страх "что-то поломать" (и довольно обоснованный), да и "работает - не трогай". Но развивать такой кодом все "трудней и трудней" (вот даже сейчас, ошибка скорее всего где-то в логика, а "увидеть" ее не получается). Поэтому обычно рекомендую идти "маленькими шагами".
Этап первый: сделал какую-то фичу. как угодно, лишь-бы "быстрее". Этап второй: поведение кода не меняется, но стараешься сделать его красивым, читабельным и удобным для поддержки. Потом следующая фича: опять два этапа....
И они "не разрывны", хотя конечно, это все, в довольно большой степени "религиозные" подходы к написанию кода. Дело вкуса. Но лично мне такая парадигма очень помогает (плюс Unit Tesiting, но в ардуине на него "ресурсов не хватит").
Кажется нашел проблему .
Щас еще поковыряю - посмотрим.
Дело в том что при запуске автономной программы включается выдача частоты (ИК светодиоды).
При переходе в ручную программу частота остается т.к. не была отключена функцией noTone.
А , как я уже писал выше , pulseIn напрочь отказывается работать когда работает частота (то же самое и с сервами).
Даже вот такой , простенький , таймер , вместе с pulseIn работает крайне некорректно (да и pulseIn в это время тоже)
long previousMillis = 0; void setup() { pinMode(13,OUTPUT); } void loop() { if (millis() -previousMillis >1000) { previousMillis = millis(); digitalWrite(13, !digitalRead(13)); } }Видать pulseIn "сжирает" все системные таймеры и если хоть один таймер занят чем то другим то отказывается работать.
На досуге надо заняться изысканием замены pulseIn , пусть менее элеганттным зато более функциональным.
Но как ни крути таймеры придется использовать.
Все !
Это последняя версия этого робота - Tankbot v7 (седьмая версия платы !).
Я так и не смог сделать переключение между режимами с ИК пульта .
Сделал переключение на кнопке.
Сделал два нижних датчика (впереди).
Один датчик работал плохо , теперь если и упадет , то только при движении назад.
Так же добавил управление головной сервой с пульта.
Поставил подстроечный резистор на ИК свотодиоды , теперь можно регулировать дальность от 5см до 40см.
В конце видео фотик сдох , так что других фото/видео материалов , в ближайшее время ,не будет.
Видео
video.mail.ru/mail/heruvim219/Tank-Bot/21.html