Что это?
Прогуливаясь в городских парках, часто можно встретить людей, которые с радостью и интересом бросают корм в воду и наблюдают как утки ныряют за ним. Вы также можете поучаствовать в этом забавном процессе, собрав катер, управляемый с мобильного устройства, который плавает по воде и по сигналу кормит уток всякими вкусняшками, тем самым привлекая и удивляя прохожих.
Исходный код
- bottleboat.ino
// библиотека для работы с платформой Strela#include <Strela.h> // библиотека для работы с I2C-расширителем портов#include <Wire.h> // EEPROM — энергонезависимая память// библиотека для записи и считывания информации с EEPROM#include <EEPROM.h> // библиотека для работы с сервоприводами#include <Servo.h> // создадим объект для управления сервоприводом Servo myservo; // это число мы будем использовать в логике поворотовint defaultSpeed =100; // w1 и w2 - это скорость вращения первого и второго мотора// скорость регулируется в пределах от -255 до 255// если это число положительное - мотор будет вращаться вперёд// если отрицательное - назад// если баланс скорости вращения моторов не бы совершен// по умолчанию равны 100int w1 =100;int w2 =100; // значение поправочного коефициента// скорости одного мотора к другомуfloat k =1; // переменная хранит контрольную сумму// проверка на то, было ли что нибудь записано в EEPROMint sum; // переменные состояния каждой из 4 кнопок// была ли кнопка отпущена? boolean button1WasUp =true; boolean button2WasUp =true; boolean button3WasUp =true; boolean button4WasUp =true; void setup(){// я неправильно прикрутил один мотор// поэтому, чтобы их не перекручивать// можно воспользоваться этой функцией.// направление вращения мотора 2 будет изменено. motorConnection(0, 1); // открываем последовательный порт со скоростью 9600 бод Serial.begin(9600);// Bluetooth Bee по умолчанию использует скорость 9600 бод Serial1.begin(9600); // пикнем зуммером с частотой 1000 Гц, 100 мс tone(BUZZER, 1000, 100); delay(500); // считываем значение из 4 ячейки памяти EEPROM sum = EEPROMReadInt(4); // записывали ли мы в EEPROM значение баланса скоростейif(sum ==777){// чтение из памяти значение баланса скоростей w1 = EEPROMReadInt(0); w2 = EEPROMReadInt(2);} delay(100);// нажата ли кнопка S1// вход в меню настройки баланса скорости моторовif(uDigitalRead(S1)){// пищим 3 раза зуммером tone(BUZZER, 500, 50); delay(300); tone(BUZZER, 500, 50); delay(300); tone(BUZZER, 500, 50); delay(300); // вызываем функцию баланса скорости моторов balanceMotors();} // зажгём первый и четвёртый светодиод uDigitalWrite(L1, HIGH); uDigitalWrite(L4, HIGH); // вызываем функцию нахождение поправочного коефициента// скорости одного мотора к другому correction();} void loop(){// если появились новые команды// вызываем функцию управленияif(Serial1.available()>0){ control();}// вывод скоростей serialPrint();} // функция настройки баланса скорости моторовvoid balanceMotors(){while(1){// зажгём второй и третий светодиод uDigitalWrite(L2, HIGH); uDigitalWrite(L3, HIGH); // если левое колесо (мотор 1) медленнее правого (мотор 2) // нам нужно определить клик кнопки// определить момент «клика» несколько сложнее, чем факт того,// что кнопка сейчас просто нажата. Для определения клика мы// сначала понимаем, отпущена ли кнопка прямо сейчас boolean button2IsUp = uDigitalRead(S2); // если кнопка была отпущена и не отпущена сейчас// и значение первого мотора менее 255if(!button2WasUp && button2IsUp && w1 <255){// может это «клик», а может и ложный сигнал (дребезг),// возникающий в момент замыкания/размыкания пластин кнопки,// поэтому даём кнопке полностью «успокоиться» delay(10);// и считываем сигнал снова button2IsUp = uDigitalRead(S2);// если она всё ещё нажата, значит это клик!if(button2IsUp){// Скорость первого мотора увеличиваем, а второго уменьшаем w1 ; w2--;}} // запоминаем последнее состояние кнопки для новой итерации button2WasUp = button2IsUp; // если правое колесо (мотор 2) медленнее левого (мотор 1) // нам нужно определить клик кнопки// определить момент «клика» несколько сложнее, чем факт того,// что кнопка сейчас просто нажата. Для определения клика мы// сначала понимаем, отпущена ли кнопка прямо сейчас boolean button4IsUp = uDigitalRead(S4); // если кнопка была отпущена и не отпущена сейчас// и значение второго мотора менее 255if(!button4WasUp && button4IsUp && w2 <255){// может это «клик», а может и ложный сигнал (дребезг),// возникающий в момент замыкания/размыкания пластин кнопки,// поэтому даём кнопке полностью «успокоиться» delay(10);// и считываем сигнал снова button4IsUp = uDigitalRead(S4);// если она всё ещё нажата, значит это клик!if(button4IsUp){// Скорость второго мотора увеличиваем, а первого уменьшаем w1--; w2 ;}} // запоминаем последнее состояние кнопки для новой итерации button4WasUp = button4IsUp; // Индикация увеличение скорости первого мотораif(uDigitalRead(S2)){ uDigitalWrite(L4, HIGH);}else{ uDigitalWrite(L4, LOW);} // Индикация увеличение скорости второго мотораif(uDigitalRead(S4)){ uDigitalWrite(L1, HIGH);}else{ uDigitalWrite(L1, LOW);} // вывод скоростей serialPrint(); // ход по значениям скоростей w1 и w2 drive(w1, w2); // если нажата кнопка S1// пишем CANCEL в Serial// и выходим из бесконечного цикла while(1) без сохраненияif(!button1WasUp && uDigitalRead(S1)){ Serial.println("CANCEL");break;} button1WasUp = uDigitalRead(S1); // если нажата кнопка S3if(!button3WasUp && uDigitalRead(S3)){// сохраняем значение первого мотора EEPROMWriteInt(0, w1);// сохраняем значение второго мотора EEPROMWriteInt(2, w2);// сохраняем значение контрольной суммы EEPROMWriteInt(4, 777);// Пишем SAVE в Serial и выходим из бесконечно цикла Serial.println("SAVE");break;} button3WasUp = uDigitalRead(S3);}/// while (1) // останавливаем моторы drive(0, 0); // погасим второй и третий светодиод uDigitalWrite(L2, LOW); uDigitalWrite(L3, LOW); // пикнем 3 раза зуммером tone(BUZZER, 1000, 50); delay(100); tone(BUZZER, 1000, 50); delay(100); tone(BUZZER, 1000, 50); delay(100);}/// balanceMotors //запись двухбайтового числа в памятьvoid EEPROMWriteInt(int address, int value){ EEPROM.write(address, lowByte(value)); EEPROM.write(address 1, highByte(value));} //чтение двухбайтового из числа из памятиunsignedint EEPROMReadInt(int address){ byte lowByte = EEPROM.read(address); byte highByte = EEPROM.read(address 1);return(highByte <<8)| lowByte;} void serialPrint(){ Serial.print("speed w1 = "); Serial.print(w1); Serial.print(" "); Serial.print("speed w2 = "); Serial.println(w2);} // пуск сервопривода постоянного вращенияvoid servoStart(void){ myservo.attach(11); myservo.write(0);} // остановка сервоприводаvoid servoStop(void){// Самый простой способ остановить серву постоянного вращения// отсоединиться от неё myservo.detach();} void control()// функция управления{// считаем значение пришедшей командыchar dataIn = Serial1.read(); if(dataIn =='F'){// пришла команда "F", едем вперёд drive(w1, w2);}elseif(dataIn =='B'){// пришла команда "B", едем назад drive(-w1, -w2);}elseif(dataIn =='L'){// пришла команда "L", поворачиваем налево на месте drive(-w1, w2);}elseif(dataIn =='R'){// пришла команда "R", поворачиваем направо на месте drive(w1, -w2);}elseif(dataIn =='I'){// пришла команда "I", едем вперёд и направо drive(defaultSpeed w1, defaultSpeed - w2);}elseif(dataIn =='J'){// пришла команда "J", едем назад и направо drive(-defaultSpeed - w1, -defaultSpeed w2);}elseif(dataIn =='G'){// пришла команда "G", едем вперёд и налево drive(defaultSpeed - w1, defaultSpeed w2);}elseif(dataIn =='H'){// пришла команда "H", едем назад и налево drive(-defaultSpeed w1, -defaultSpeed - w2);}elseif(dataIn =='S'){// если пришла команда "S", стоим на месте drive(0, 0);}elseif(dataIn =='X'){// пришла команда "X", крутим серву servoStart();}elseif(dataIn =='x'){// пришла команда "x", останавливаем серву servoStop();}elseif(dataIn =='V'){// пришла команда "V", пищим tone(BUZZER, 1000);}elseif(dataIn =='v'){// пришла команда "v", не пищим noTone(BUZZER);}elseif(((dataIn -'0')>=0)&&((dataIn -'0')<=9)){// настройка скорости вращения обоих моторов от 0 до 9// если первый мотор быстрееif(w1 > w2){// сохраняем новое значение скорости обоих моторов// второй с поправкой на баланс w1 =(dataIn -'0')*25; w2 =(dataIn -'0')*25*k;}else{// сохраняем новое значение скорости обоих моторов// первый с поправкой на баланс w1 =(dataIn -'0')*25*k; w2 =(dataIn -'0')*25;}}elseif(dataIn =='q'){// если "q" - полный газif(w1 > w2){// первый мотор максимум, второй с поправкой на баланс w1 =255; w2 =255*k;}else{// второй мотор максимум, первый с поправкой на баланс w1 =255*k; w2 =255;}}}/// end control // функция нахождения поправочного коефициента// скорости одного мотора к другомуvoid correction(){float m1 = w1;float m2 = w2;if(m1 > m2){ k = m2 / m1;}else{ k = m1 / m2;}}
Как собрать?
Перейдём к изготовлению корпуса катера:
Теперь можно смело ставить катер на воду, загружать его вкусняшками и отправлять в плаванье. Если катер при движении клонит в сторону, повторите процесс калибровки.
Катер на arduino с радиоуправлением своими руками
Настройка управления
В управлении моторов всё интуитивно понятно (вперёд, назад, влево, вправо). В правом верхнем углу есть ползунок настройки скорости моторов. По нажатию на кнопку
Δ
сервопривод начнёт вращаться и утиные угощения посыпятся в воду. Повторное нажатие остановит процесс. Также можно посигналить уткам с помощью зуммера, нажав на кнопку с изображением пищалки.
Радиоуправление для прикормочного карпового кораблика с автопилотом. sc-a2. arduino. своими руками. вторая версия
И, когда она в очередной раз вышла на балкон позвать меня, я услышал как Толька Коршунов выкрикнул: “Гвардеец кардинала на посту!” И я вцепился в него, хотя Тольке было целых одиннадцать лет и он даже уже был влюблен в Таньку, о чем поведал всему двору вырезанным на тополе объявлением “Я люблю тебя”.Имя вырезать не стал, проявив не детскую мудрость.
Толька валялся в пыли, совершенно не сопротивляясь, а только удивленно таращась на меня. Я пытался молотить его, приговаривая: “Гад, гад!” Под очередное “гад” меня подняла в воздух неведомая сила. Мелькнул яркий рукав, бицепс, усы и я оказался за обеденным столом с моей “не моей” бабой Феней.
Мама назвала ее официально — Феодосия Николаевна и всегда повторяла: “Она не твоя бабушка”.Моя бабушка была первая жена деда, баба Женя. Она жила в одном городе с нами, в центре России, а дед с Феней жили у моря.
Оно — море — и стало причиной нашего знакомства. Я был худющим болезненным ребенком, и педиатр убедила мать, что море положительно скажется на моем здоровье. “Но обязательно не меньше месяца,” — повторяла она. Когда мне было почти четыре года, меня повезли знакомить с дедом, морем и Феней. Феодосией Николаевной. Как бы не хотели мама с “моей” бабушкой изъять ее из этого уравнения. В первый раз мама была со мной две недели, натянуто общаясь с дедом и Феней. Убедившись, что старики вполне способны управиться с ее чахлым “цветком” жизни, она начала часто уходить в гости к подругам детства и задерживаться там допоздна.
Я не хотел спать без нее. Ходил по квартире, поднывая. Дед уговаривал спать, а Феня сгребалав охапку, и говорила: “Борык, не куксись. Пойдем встречать маму!” Мы выходили в притихший двор, она сажала меня на качели.
Качелей я боялся, мне казалось, что меня, такого легкого, подхватит ветер и унесет, но Феня мощной фигурой вставала ровно напротив качелей и и заключала подвешенное сиденье в свои уверенные руки, прежде,чем снова толкнуть. “Будешь наверху — смотри маму,” — напутствовала она и легонько толкала качель. “Не виднооо,” — ныл я, а она отвечала: “Значит, надо повыше. Не боишься?” Я мотал головой в разные стороны, и она толкала сильней. И в один день, взлетая до ветки тополя, я понял, что хочу, чтоб мама не торопилась.
И мама, наверное, поняла. Она уехала, оставив меня с дедом и Феней на лето. Мы посадили ее на поезд,помахали в окошко и пошли домой обедать. А вечером мне почему-то захотелось плакать. Я помню ощущение полной опустошенности, и помню, как оно появилось. Оно появилось, когда я думал, что сегодня вечером не надо встречать маму и мы с Феней не пойдем качаться. Но после ужина она объявила:”Борык, не куксись, пойдем смотреть, как мама едет на паровозе.”
Мы ходили качаться каждый вечер. Дед поначалу говорил, что поздно, и “ребенку нужен режим”, но Феня обрывала его на полуслове: “Не гунди, охламон, рыбенку много чего нужно.”
Охламон улыбался внутрь себя и капитулировал. Мы с Феней выходили, когда последние бабульки снимались с лавочек у подъезда, а возвращались к полуночи, покусанные комарами и абсолютно счастливые.
Качели были моим личным раем. Качели которые качала Феня. Она раскачивала меня, а потом притормаживала и влепляла поцелуй в неожиданное место. Когда качели начинали останавливаться, а я просить: “Еще, еще!”, Феня принималась щекотать меня. Я вертелся волчком, заливался на весь тихий гулкий двор, но не слезал с сиденья.
Здоровье мое, несмотря на отсутствие режима, улучшилось. Встретив меня, загоревшего и слегка отъевшегося, на вокзале, бабушка Женя поджала губки. Стройность была одной из основных ее добродетелей, и она весьма боялась жирного и сдобного греха.
Очень скоро после приезда домой я спросил, когда снова поеду к деду и Фене.
— Лен, ты слышала?— крикнула бабушка моей маме, и не дождавшись ответа повторила:
—Ты это слышала?
— Мам, не начинай снова, это ребенок, — мама подошла ко мне и внезапно погладила по голове. Она редко так делала, мне стало так хорошо, и я снова вспомнил качели. Мне хотелось повторить свой вопрос маме, но я не стал. А в конце длинной-длинной зимы, когда я свалился с ужасной ангиной, мама сидя у моей кровати сказала: “Бобка, ну что же ты, выздоравливай!Скоро ведь поедем к деду!”
Я выздоровел и мы поехали. Мама уехала через три дня. Была середина мая. Раз в месяц Феня наряжала нас с дедом “в парадное”, и мы шли в переговорный пункт: попросить маму оставить меня еще на месяц. Вышло три раза.
Дед работал сутки через трое, и в свободные дни старательно просаливал меня в море. А вечера были мои с Феней. И качелями. Взлет— посадка — поцелуй, взлет — посадка — объятия.
— Борык, маму видишь?
— Вижу! В окно! Она спит!
— А Москву видишь?
— Вижу!
— Кремль красный?
— Синий!
— Значит, вечер!
Смех-посадка-поцелуй, тихий подъезд, мы играем в шпионов, и, чтобы не будить деда, укладываемся вместе спать на диване.
Находясь между этим хитросплетением взрослых, я совершал детские ошибки, но учился на них. Однажды я попросил бабушку Женю испечь оладушки как у Фени. “Борис, питаться жареным — вредно!” — выпалила она, но не преминула заметить под нос: “Своих детей сгубила, за моего взялась…”В моем сознании эта фраза повисла вопросом, но я промолчал. Летом меня снова отправили “на море”: у мамы появился перспективный кавалер, и без меня было сподручней.
Вопрос, зародившийся после обмолвки “моей” бабушки терзал меня, и я не знал, как поступить. Мне было уже шесть лет,и я начал ощущать какую-то неловкость в стальных объятиях Фени. К тому же я маялся, гадая, как она сгубила своих детей.Решился однажды спросить у деда. Он вздохнул, но ответил: “Утонули они на лодке с отцом их. Она с тех пор на море и несмотрит.И забудь, что я сказал, и с ней не говори.”Я и не говорил, и даже позабыл, ибо мучивший меня вопрос разрешился. А качели так и были нашими, хоть я и мог уже качаться сам. Но не мог же я сам себя целовать?
К следующему лету у деда начались проблемы со здоровьем, и вместо моря я отправлялся гулять во двор. А после драки с Толькой Коршуновым из-за Фени меня приняли в дворовое сообщество и я даже был частью “живой пирамиды”, на которой стоял Толька, чтобы вырезать на тополе сердце, пронзенное стрелой, под своим “я люблю тебя”. Да что там, и на море мы тоже гоняли, и строили шалаши, и даже пробовали влюбляться, и я еще не раз подрался из-за женщин. Было не до качелей.
Феня ухаживала за дедом, и в квартире поселился тонкий, но устойчивый запах лекарств. А мама вышла замуж. За Толика. За другого, конечно, но вроде он тоже намекал, что “я люблю тебя”. Эту новость мне сообщила Феня и, глядя на меня, добавила: “Не куксись! Это хорошо. Вы подружитесь.” Я подумал:”Никогда!”, а она оказалась права.
Все эти события: дедова болезнь, замужество мамы, драка с Толькой и дворовая дружба подвели итог моего дошкольного детства. Остались лишь воспоминания: разрозненные, малосвязные, но при этом яркие до осязаемости. И в главном из них я подлетаю на качелях вверх, а потом меня целует в макушку Феня.
Больше выездов “на море” не было, потому что началась другая жизнь. Мы приехали к деду через четыре года. На похороны.Я помню, как зашел в ту самую квартиру, а посреди большой комнаты стоял гроб. Феня провела нас с мамой мимо него в спальню и уложила спать с дороги. Назавтра была суета, похороны, поминки, и во всем этом я затерялся и чувствовал себя лишним.
Я потихоньку вышел из-за поминального стола и пошел в маленькую комнату. Сел на кровать, уставился в стену. Не знаю, сколько так просидел, но зашла Феня. Она обняла меня, и внезапно я разрыдался. Феня гладила меня по голове, а затем внимательно посмотрев в глаза, сказала: “Борык, деда все равно тебя любит. Ну, не куксись…”
Мы с мамой уехали после девятого дня. Феня предлагала мне остаться. Я выжидательно посмотрел на мать, рассчитывая, что она заявит о полной невозможности оставить меня…Но она молчала… Я отрицательно мотнул головой.
— Ну поезжайте, поезжайте, выберете время еще приехать… — Феня была тише, чем обычно, да и понятно почему.
А потом жизнь меня закружила. Это был, наверное, не тот танец, который я хотел, но отказаться не получалось. Свадьбы, рождения, болезни, похороны, встречи, расставания… Жизненное колесо неслось все быстрей, пока не застопорилось о диагноз моего собственного сына. Лейкоз. Помню глаза жены как провалы в ад и ее же бесстрастный голос, когда она перечисляла, что нужно купить в больницу. Еще доктора помню, который сказал, что “большинство случаев разрешаются благоприятно”. В интернете писали, что большинство — это семьдесят процентов. И наш ребенок должен был в них попасть. Должен! И не должен в тридцать… Пусть не он…Мы стали командой по попаданию в семьдесят процентов: жена взяла на себя всё, связанное с сыном, а я должен был зарабатывать. Общение превратилось в сводки анализов. Лучше, хуже, хуже, лучше, лучше, немного хуже, немного лучше, еще немного лучше.
Мы победили. Мы попали в семьдесят. А я понял, что не чувствую ничего.
Я боялся посмотреть в глаза сыну и жене, потому что они бы это поняли. На работе подвернулась командировка, поехал. И вдруг как током дернуло: “А ведь Феня еще может быть жива! Есть шанс!”Не сама собой, конечно, эта мысль пришла, я рядом с теми местами оказался. Сделал крюк, нашел тот двор… Дверь в квартиру никто не открыл. Значит, не выпал шанс. Она бы точно дома была.
Вышел из подъезда — на лавочке тип алкоголического вида сидит. Аккуратно у него поинтересовался, не знает ли он, кто в шестьдесят четвертой квартире живет.
А он как заорет:
— Боб, ты? Точно ты! Ну ты же!
Друган детства оказался. В квартире пара молодая живет, дальние родственники Фени. А она сама давно уж померла. А до того как будто с ума сошла немного. Выходила вечерами гулять до ночи. На качелях раскачивалась и улыбалась. А потом соседи по запаху нашли ее.
— Боб, на пиво не подкинешь? Давай за встречу, — закончил он свой рассказ вполне ожидаемо.Я подкинул, а “за встречу” не стал. Он сразу побежал отовариваться, и я оглядываясь, как шпион, подошел к качелям. Всё те же. Вечная металлоконструкция. Сел боком, оттолкнулся ногой. Тополь тот же, вон на нем вырезано “Я люблю тебя” и сердце, пронзенное стрелой… Только еще что-то сверху накарябали, раньше не было. “Не куксись”. “Не куксись. Я люблю тебя”…Нет, не может быть… Точно: “Не куксись”.
Я уперлся лбом в ствол дерева,а потом обхватил руками. Меня трясло. Нет, меня “типало”. Так говорила Феня в минуты особого волнения: “Меня типает”. Внезапно с утробным рыком я набрал полную грудь воздуха и разрыдался.
Я тоже люблю тебя, Феня. Я люблю тебя, дед. Я люблю жену и сына. И маму, и отчима, и сестру. И даже когда меня не станет, эта любовь останется. Но еще рано, я еще должен сказать им всем об этом хотя бы раз.