Що значить робота розробити

Ви читаєте про роботів і програмуванні і думаєте: «Було б здорово зробити щось подібне самому!» Тими, ким ця ідея опановує трохи більше просто думок дивляться, хто і як робив свого робота. Читають статті, дивляться відео. На картинках все зрозуміло. У відеороликах теж зазвичай показуються вже готові продукти, а також стисло показуються технології їх виготовлення. І начебто то все зрозуміло: відпиляв, прикрутив, припаяв, з'єднав, запрограмував он на тій програмі ось цим кодом. Ще більш захоплені, вибравши цікавий і, з першого погляду, простий варіант, переходять до дії і, часто копіюючи, роблять свого першого робота. Це вольове і дуже значуще рішення — головне почати хоч щось зробити самому! В процесі виготовлення виявляється купа технологічних заковырок аж до того, що оказыается для замовлення/купівлі какуй-то штукенции, треба дізнатися як вона точно називається. А ще — роз'єми не паяються нормально — і як на відео в одне торкання все виходить? Процес створення нерідко затягується, але наполегливий початківець робототехнік так чи інакше добиває результат до якогось осмисленого першого запуску хоча б «по прямій».



Потім, коли робот закінчений, приходить розуміння, чому все робиться саме так і саме в такій послідовності. Процес створення вже можна якось усвідомити, формалізувати, розписати. Ось з цього моменту і починається розробка моделі наступного, другого покоління.



Так, я теж раніше з інтересом читав статті. І зараз читаю! Особливо мені подобаються статті про коптеры: із землі, та в небо! Проте, якщо бути чесним, вони викликали в мені тільки думки. Тим більше, треба було розбиратися в програмуванні, а останній раз я працював з Сі в інституті, все вже геть забулося. Я знаю, що таке Arduino, але я ніколи не бачив її «живцем». І так далі. У мене технічна освіта, я займаюся питаннями ЦГЗ на FPGA. Технічно для мене немає перешкод взяти і розібратися, але… по суті я займаюся всім цим на роботі і мені там всього цього діла, як кажуть, «вище даху» :) В результаті потрібен був якийсь хороший стимул, щоб цим якось почати займатися. Стимул з'явився, коли це стало потрібно комусь ще: правду кажуть, що справжнє творення — коли віддаєш іншим.

Мій хороший знайомий, який є одним із засновників молодий (можна сказати свіжоспеченої) компанії Endurance, знаючи характер моєї роботи, звернувся до мене по ряду технічних питань. Виявилося, що хлопці мають розробників в США і вже представили свій прототип супердешевого (телефон + пластикова платформа з колесами на ардуине — начебто вже дешевше і нікуди) робота телеприсутності. Але вони захотіли не просто займатися маркетингом і бізнесом в стилі «купив — продав», а захотіли більш докладно зануритися в технічну тему і навіть планують розробити свою модель (нехай навіть еквівалентну за принципом і функціоналу), але вже тут, у нас в Росії, з метою одержання не тільки готового результату, але і зрозумілою самим технології його виготовлення. Така передумова участі в цій справі вашого покірного слуги (це я на себе натякаю).

Спочатку я теж почитав статті, подивився де і що купують і як роблять. Але не було єдиної картини. Начебто, загалом-то, все зрозуміло, але одночасно і не всі. Незрозуміло як керувати з комп'ютера, як відео на комп'ютер доставити. Тим більше, я ж не софтовик і не хотілося б «розкопувати» цю, софтовую, тему з нуля, хоча це було б цікаво звичайно; так-то я всі свої потреби як успішно задовольняв скриптовою мовою AutoIt. В результаті пошуків я знайшов два ключових ресурсу, які стали для мене ключовими: інтернет-магазин carduino форум cyber-place. У магазині можна було купити всі необхідні комплектуючі — все в одному місці. Ціни, порівняно з ebay або ali, звичайно, дикі, але головне було не в цьому — можна було придбати платформу і необхідний обвіс до неї, також як і всю мелочевку. І це було зручно забирати/замовляти. На форумі в розділі «Зроби сам»\«Робототехніка» і «Зроби сам»\«CyberWrt» можна почерпнути інформацію загального характеру, а також як детально організувати зв'язок комп'ютера з роботом через Wi-Fi. Десятирічний досвід роботи за спеціальністю дав про себе знати, і я замість того, щоб негайно почати копіювати що-небудь скручуючи або програмуючи, взяв у руки олівець і папір…

Що значить «розробити»? От зрозуміло, що таке «зробити робота» — береш і робиш...! А «розробити» це як?
Нижче я спробував описати процес, саме, розробки, а не створення робота. Створення робота, як конструювання, спочатку інтуїтивно зрозуміло і представляемо. По мірі створення прикручується те — то, те — це. Понакрутил так — і раптом виявилося, що ту, другу деталь, треба інакше прикрутити, тоді восьма деталь постане як влита, треба тільки проводки від батарейок пересунути ліворуч, ближче до п'ятої деталі, а щоб не бовталися, краще прикріпити до четвертої, трохи їх підігнувши, так як там поруч буде десята деталь. Суцільне творчість. А давайте спробуємо по-дорослому: спочатку уявимо, що будемо робити, а потім зробимо це :)

Отже, про що піде мова в даній статті. Я вирішив не писати про те, як я робив робота, таких статей чимало сенсу появу ще однієї, швидше всього, ні. Я вже точно не перший і навіть не десятий, хто на покупної платформі, понавесив датчиків зробив іграшку на радість собі і оточуючим. Я вирішив спробувати, так скажемо, викласти свою технологію мислення. Я постарався донести до читачів не просто той факт, що зробити робота не так і складно, а викласти методику, за якою можна взяти і спробувати зробити свого робота з нуля, причому починаючому робототехніку будуть зрозумілі етапи створення спочатку, а не відкриватися в міру просування в незвідане.

Уявімо собі людину, яка ніколи не займався робототехнікою. У нього є друг-паяльник, мультиметр і всякий ручний інструмент типу кусачок, викруток та іншого. Представили себе? Відмінно! Поїхали…




Перший етап — осмислення

Що ми хочемо зробити? І навіщо це потрібно?

Для мене це питання було спочатку вирішено за мене — мені потрібно зробити машинку з відеокамерою, яка б могла підключатися через Wi-Fi або інтернет до комп'ютера, на комп'ютері я б бачив картинку з машинки і керував їй, змушуючи її рухатися. Начебто зрозуміло, але як-то нудно і чогось не вистачає. Віддалене управління — робот що якийсь? Робот? Що таке робот? Робот — це якась автономна штука, яка виконує роботу самостійно. Як це застосувати для даної задачі? А нехай машинка буде їздити сама! Як такої постановки завдання немає — ну нехай їздить як захоче. Однак, якщо вона буде їздити як заманеться, то буде стикатися з предметами. Це якось недобре, неправильно. Значить, машинка повинна вміти бачити попереду себе і об'їжджати перешкоди, запобігаючи зіткнення. Як це можна зробити? Можна обробляти дані з відеокамери. Е-еее… як-то взагалі незрозуміло як до цього підступатися. Напевно це непросто. Що у нас ще є? Продаються всякі інфрачервоні і лазерні вимірювачі відстані! Можна купити такий і як-то отримувати відстань з нього. Маячня ніби, але щось в цьому є…

Виходячи з міркувань, народжується задум, концепція пристрою. Результат роздумів повинен бути викладений в загальному вигляді стисло і коротко, концентруючи суть. Необхідно отримати пристрій, що:
— вміє переміщатися по поверхні по командах оператора транслюючи йому відео попереду себе;
— має автономний режим «існування»: вміє самостійно рухатися в довільному напрямку;
— контролює обстановку попереду себе;
— у разі виявлення попереду якогось об'єкта не дає собі з ним зіткнутися, ігноруючи команди опреатора, або змінює напрямок руху в автономному режимі.

Здається визначилися з метою. Беремо паяльник і влаштовуємо його на столі. Можна в ганчірочку укутати — йому пом'якше буде, позатишніше. Нехай прывыкает поки до обстановки.

Другий етап — вивчення реальності

Після того, як визначилися з базовим функціоналом і стало зрозуміло, що потрібно зробити, постає питання: як це зробити, як це буде виглядати?

Можна взяти молоток в руки і, обвівши суворим поглядом своє житло, безапеляционным тоном заявити оточенню: кришка від столу, коліщатка від крісел, гумка з трусів, пара китайських паличок, 20 сантиметрів тканини від штори, засувки з босоніжок, ноутбук розбираємо на запчастини — все здати мені в ім'я прогресу! Щоб не було зайвих питань голосу можна надати відтінки загрози і одухотворення одночасно. Однак, пропоную більш ефективний метод для цієї мети ідеально підходить створений людьми інструмент під назвою «Інтернет». Набираємо слово «Робот своїми руками» в тій пошуковій системі, яку дозволяє використовувати ваша релігія, і починаємо читати, дивитися, слухати і вивчати. Цей етап може тривати набагато довше попереднього, так як придумати щось зробити набагато простіше, ніж придумати, як це зробити що-то. Тим більше, мимохідь можна ще стільки цікавого дізнатися!

Отже, результатом цього етапу має бути більш детальний тезовий список, який буде визначати вид того, що ми придумали на минулому етапі. Наш пристрій буде мати наступний вигляд:
— триколісна платформа з двома двигунами: два провідних колеса, третє — як підпора;
— живлення від акумуляторів АА (1,2-1,3 В х 4 = приблизно 5 вольт — як раз підходить для двигунів);
— пристроєм буде керувати мікроконтролер Arduino Nano (управління двигунами — через драйвер двигунів, живити мікроконтроллер можна від 5В);
— дальність визначати будемо використовуючи ультразвуковий датчик (живлення 5В);
— перепрошитий маршрутизатор (живлення 5В) буде працювати як точка доступу, під'єднуючись до якої можна підключитися до вебсерверу і видавати команди на мікроконтролер, при цьому нам буде доступна зображення з вебкамери, підключеної до маршрутизатора;
— на пристрої встановлено два перемикача: ВКЛ/ВИКЛ харчування і ВКЛ/ВИКЛ автономний режим — з цього моменту ніяких пристроїв, раз автономно вміє працювати — значить робот;
— робот забезпечений світлодіодом, який буде загорятися при виявленні перешкоди;
— на роботі будуть присутні спереду два яскравих білих світлодіода — фари — чому б і ні: коли темно, роботу не повинно бути страшно, а з яскравим світлом завжди якось бадьоріше, тут головне — не озиратися назад зайвий раз — значить відеокамера буде спрямована тільки вперед;
— на роботі буде встановлена веб-камера, яка буде підключена до маршрутизатора.

Цей, поданий нами зовнішній вигляд базується на тих уявленнях, які ми отримали вивчаючи ринок комплектуючих для роботів. Тут немає детального представлення робота до гвинтика — тільки спільні риси, проте, вони дозволяють уявити собі, що вийде в результаті. В цілому, приходимо до висновку, що можна все купити в магазині carduino, а також організувати зв'язок з роботом, використовуючи маршрутизатор і налаштувавши його приблизно так, як зазначено на форумі cyber-place. Поки не розбиралися в тонкощах підключення окремих комплектуючих і не розбиралися як програмувати маршрутизатор. Але зрозуміли, що окремі комплектуючі можна один до одного підключити (електрично та інформаційно), а також визначилися, як мінімум, зі структурою і зовнішнім виглядом.

Компоненти роботаПлатформа з колесами, двигунами і кріпленням:



Плата для електроніки:



Мікроконтролер Carduino Nano v.7:



Ультразвуковий датчик HC-SR04:



Драйвер керування двигунами:



Маршрутизатор TP-Link MR3020:



Хаб (компактний і мініатюрний хаб невідомої моделі):



Вебкамера (Logitech C270):




Паяльник лежить на столі і зацікавлено дивиться на картинки вище. Інтерес зрозумілий — паяти-то це все йому!

Третій етап — творчість: загальна розробка

Стільки часу портрачено, а результату не видно! Результат тільки у нас в голові у вигляді образів і думок. Може бути варто якось матеріалізувати ці думки? Як буде виглядати зовнішній вигляд робота вже, приблизно, зрозуміло. Також визначено набір комплектуючих. Як це буде з'єднуватися? Як це все буде спілкуватися між собою? Робот — це ж не лампочка — клацнув вимикачем і вона загорілася. Тут клацнув тумблером, харчування подалося — а далі що? І ось тут, шановні читачі, розробка починає розгалужуватися на три складові: конструкторська, електротехнічна і програмна.

Конструкторської розробки як такої у повному обсязі у нас не буде, так як ми використовуємо повністю все готове. Вся осяжна конструкторська робота буде полягати у вдалому приклеюванні окремих коробочок на двосторонній скотч і загвинчування болтів у спеціально відведені для цього місця. По хорошому рахунку, звичайно, повинен бути складальне креслення з тих компонентів, які є. А ось, якщо б у нас не було платформи або підстави, то слід було б прикинути розміри всіх встановлюваних компонент, порахувати габарити і зрозуміти, яких розмірів робити плату-основа, і як до неї будуть кріпитися інші компоненти робота і так далі. Але, у нас все просто, роль складального креслення виконують картинки кінцевого вигляду робота, тому цей напрямок розробки в даній статті не розглядається взагалі.

Посидівши і порисовав можна прийти до наступного функціональним увазі робота:



Заздалегідь вибачаюся за якість картинок. Картинок у мене вийшло багато, а роздувати трафік під катом не хотілося, тому я прийшов до деякого компромісу між якістю і об'ємом, який виражається в тому, щоб важив мало, але було читаемо і зрозумілі.

Що ми бачимо на картинці?
Наш робот буде складатися з двох незалежних частин: блок зв'язку і блок управління. Блок зв'язку зв'язується із зовнішнім оператором, приймає від нього команди і видає їх на блок управління. Блок управління, приймаючи команди, виконує їх. Тобто, ми поділили управління на два рівня — низькорівневе (управління платформою, взаємодія з датчиками) і високорівневе (взаимодейтвие з оператором і командне управління низькорівневої частиною). Завдання з управління розбилася на дві частини, які можна вирішувати окремо: спочатку розібратися з рухомою платформою у вигляді мікроконтролера Arduino, потім — зі зв'язком у вигляді перенастроенного маршрутизатора.

Блок зв'язку.
1) Элеткротехника.Тут, ніби як, в цілому все ясно: камера дає відео і звук і підключається через хаб до маршрутизатора. До нього ж через хаб підключається і Arduino. Невелика премудрість втикнути кабель USB роз'єм, ймовірність зробити це не так, або навпаки, досить мала Щоправда, деяким і такої ймовірності вистачає, але це ж не про нас!!! Ми ж дивимося, куди вставляємо, якщо не лізе просто сильніше дожмемо — має влазити, це ж USB!
2) Програмування. Тут ніякої розробки немає, так як використовується вже готова прошивка під маршрутизатор і готові модулі для робота. Інтерфейсний протокол з блоком управління вже визначили за нас — теж треба тільки розібратися. Як саме прошивати і що саме там налаштовувати — розберемося потім.

Блок управління.
1) Електротехніка. Начебто, теж, все зрозуміло. У нас є материнська плата, на якій всі розпаювали. Треба тільки розібратися, куди приєднуються датчики до Arduino і при цьому ніде не накоїти зайвої роботи, переплутавши землю з харчуванням. З точки зору підключення, начебто, немає особливих проблем. Правда, відразу і не зрозумієш куди на платі що підключається, але подивившись роботи масетров, а також, знайшовши нижчеподану картинку, все стає на свої місця. Як там і що розведено — потім розберемося, тим більше правило напилка ніхто не відміняв: якщо чого — доопрацюємо!



2) Програмування. А ось тут проблема. Як і чого там повинно робитися. Ось прийшла команда. Чого робити? Беремо знову олівчик з папірцем і малюємо. В результаті можна отримати наступну функціональну програмну схему (тільки платформи):



Вийшли чергові квадратики. Але тепер це вже чисто програмні модулі. Якась матеріалізація того, що не можна помацати і помацати, але воно є, так як робот рухається виходячи з логіки цього рівня абстракції.
Команда повинна прийматися інтерфейсним модулем. Саме він повинен розпізнати, що приходять дані мають сенс, що це не перешкоди або невірна команда. При ідентифікації команди модуль повинен повідомити модуля керування, що за команда до нас прийшла. Модуль управління по команді повинен буде виконати якісь дії — почати рух, зупинитися, «подивитися» немає попереду перешкоди, включити фари або вимкнути їх та інше. Якщо натиснута кнопка автономного режиму, то модуль управління повинен буде визначати немає попереду перешкоди і рухатися вперед видаючи відповідну команду на модуль моторів, а також приймати якісь дії, якщо є перешкода. Функції безпосередньо управління кінцевими пристроями частково делеговані іншим модулям виходячи з рівня складності. Модуля керування, щоб наказати модулю двигунів рухатися вперед, потрібно знати чи можна рухатися вперед. Усього швидше, просто так, з ультразвукового датчика дані не отримаєш — та й навіщо нам цим займатися? Ми тільки командувати вміємо — для роботи з датчиком є модуль сонара! Ось у нього і запитуємо доповідь про оперативну обстановку попереду робота — їхати то вперед можна?

Паяльник радісно і непомітно вибрався з-під ганчірочки, зацікавлено дивлячись на розетку: цікаво, скільки там вольт — 110 або 220?

Четвертий етап — творчість: детальна розробка

Що і як робити зрозуміло. Зрозуміло з чого. Зрозуміло, як саме, це має і буде виглядати функціонально. Пора! Пора вже почати щось робити! Стільки всього прочитали, переглянули, оцінили, обдумали, придумали, забракували, розмалювали. Ех… он, паяльник неподалік лежить. На нас дивиться. Дивується — здавалося б бери та паяй, чого всякої фігньою займатися? Зітхаємо і накриваємо паяльник листком паперу: поспи рідний поки, ще не все готово. Мало зрозуміти, як буде виглядати все функціонально, потрібно зрозуміти, як буде виглядати все структурно. Треба максимально деталізувати своє розуміння.

Блок зв'язку.
Практично всі з'ясували на минулому етапі. Все зрозуміло. На форумі cyber-place ознайомимося з цією темою і розуміємо як перепрошити маршрутизатор TP-Link MR3020 і налаштувати його. Викачуємо прошивку для маршрутизатора. Створюємо файлики з описом куди який IP вводити, що і де натискати. Єдина проблема — не зрозуміло які саме команди будуть надсилатися на мікроконтролер. Посидівши на форумі, почитавши і поспілкувавшись стає все зрозумілим (більше спасибі всім, хто мені відповідав і намагався допомогти). Записуємо всі команди так само в текстовий файл і помічаємо, яка команда за що відповідає. Виявилося все просто — при натисканні на кнопку, наприклад, «вперед», надсилається певна рядок ASCII коду, а при відпусканні кнопки видається інша команда — «стоп» (які саме байти передаються наведено нижче).

Блок управління.
На минулих етапах визначили що саме буде підключено до блоку управління. Серце блоку управління — Arduino nano. Що це таке? За що відповідають ті лампочки і ось ці роз'єми? До яких висновків підключені ніжки від сонара? Та й взагалі: а з сонаром-то як спілкуватися?

Починаємо наполегливо вивчати інформацію по комплектуючим. Благо, в бібліотеку ходити не потрібно при наявності інтернету. Складаємо для себе технічні описи використаних компонентів. Можна вичитувати на російськомовних ресурсах яка плата як працює і конспектувати. Для того, щоб зрозуміти, як підключати і як працювати з кінцевими пристроями, створюються свої «даташиты», в яких все гранично коротко, ясно і зрозуміло. Можливо, достатньо буде просто вивчення англомовних datasheet від виробника, але деколи буває, що мовами китайська або сам по собі datasheet досить об'ємний (сторінок десь на 200), тому робити свої короткі записи розумно.

Створюємо для себе «хелп» по мікроконтролеру:
Carduino Nano v.7

Потім розбираємося як підключаються і керовані периферійні пристрої. Драйвер двигунів:
Драйвер двигунів на базі мікросхеми L9110S


І ультразвуковий датчик:
Сонар HC-SR04



Після всього цього осмислення малюється структурна схема з'єднання програмних модулів, яка відображає взаємодію з ними та містить інформацію, що і куди підключений (до яких ніжок мікроконтролера):



Малювання цієї схеми вимагає хороших розумових зусиль — адже задається по суті каркас, на який потім буде лягає код. Тут необхідно зробити ремарку. Справа в тому, що я займаюся розробкою на ПЛІС, тому, спочатку я і розмалював структуру так, як робив би для ПЛІС. Треба розуміти, що для СІ-подібного програмування кількість сигналів на схемі взагалі-то забагато. Але зате ми отримуємо якусь платформонезалежність — можна все реалізувати на ПЛІС спробувати, тим більше є доступні варіанти.

Давайте прочитаємо цю схему зліва направо. Інтерфейсний модуль UART отримає дані. Якщо дані є командою, то він видає керуючий байт CTRL під імпульсним стробом SCTRL на модуль управління. Модуль управління, отримавши строб, розуміє, що прийшла якась команда, читає вхід CTRL і виконує команду. Припустимо, прийшла команда «вперед». На вихід видається імпульсний сигнал Get_Dist і очікуються дані дальності по входу Dist. В принципі, нам не заборонено постійно видавати імпульси Get_Dist, в цьому випадку значення дальності ми можемо просто знімати з вхідного порту Dist в потрібний час. Припустимо з дальністю все в порядку — до перешкоди ще далеко, можна і покататися з вітерцем. Модуль управління двигунами по шині Mode видається сигнал, що говорить про те, що потрібно рухатися вперед із заданою швидкість Speed. При вимірюванні дальності і при русі на відповідні світлодіоди так само видається високий рівень (логічна одиниця) для індикації роботи і розуміння що відбувається з системою (корисно при налагодженні).

Модульна схема є! В голові порядок! Зрозуміло, як і що. Тепер треба тільки це описати — що кожен модуль повинен робити і при яких умовах.

Інтерфейсний модуль:



Модуль управління:





Модуль вимірювання дальності:



Модуль керування двигунами:



З-під краю аркуша за кут столу вивалився хвостик з вилкою від паяльника. Лист трохи сповз і відкрилася його мордочка. Паяльник дивиться з виразом навіть не вимагає жесту «покрутити пальцем біля скроні»: «сам собі ТЗ пише — че за єресь… ось „пощастило“ мені з власником, проте» — сумно подумав він, непомітно похитуючи виделкою харчування за столом.

П'ятий етап — створення

Розробка майже завершена. Всі моменти з'ясовані до межі. Залишилося створити диво — з цієї купи запчастин і невеликий стопки листочків з картинками, табличками, схемами і діаграмами зібрати щось таке, заради чого все затівалося.

Хапаємо сумний паяльник і вмикаємо в розетку. Він починає грітися і шипіти від задоволення в ті моменти, коли ми очищаємо жало про губку. Флюс з припоєм дружний хоровод водять на столі. Сонце заглядає у вікно, підсвічуючи місце точкової пайки SMD резистора на платі. Життя прекрасне, коли паяешь не поспішаючи!




Самий веселий і видовищний етап розробки, який нікого не залишить байдужим. Тут вже на очах виходить щось цікаве, всім очевидне. Цей етап контрастує з усіма попередніми, так як малювання якихось картинок з табличками, мало того, що нецікаво спостерігачеві так ще і щиро незрозуміло, як з цього може щось вийти. А тут… це ж так здорово, коли твій перший робот проїде свій перший сантиметр на столі і шанобливо зупиниться від краю рівно за 20 сантиметрів тільки тому, що ти долонею затулив край столу. Розумна тварюшка вийшла — розуміє, що далі йому не можна!




На цьому етапі збираємо всю механічну конструкцію, паяємо дроти, програмуємо мікроконтролер. Тестуємо, що вийшло. Не розуміємо. Думаємо. Правимо ТЗ, так як в реальності виявляється, може бути, зовсім інакше, ніж написано і напридумано! Повертаємося знову до складання. Тестуємо. Не розуміємо. Не сумуємо. Тикаємо мультиметром і замінюємо разрядившиеся батарейки. Радіємо…





Строго кажучи, по завершенні цього етапу повинен бути сформований список, який совокупе з вищенаведеної документацією забезпечував би повторюваність результату. Великі комплектуючі я наводив вище, однак, при формуванні замовлення я попросив покласти також необхідну «рассыпуху»: перемикач живлення, роз'єм для підключення батарейного відсіку, колодки роз'ємів 2,54 мм…




Крім цього в роботі використовувалися витратні матеріали — дроти, припій, флюс, а також інструменти. Якщо є якісь технологічні нюанси, на них теж має бути акцентовано увагу.



Програму я писав два рази.
Перший раз так написалося того, як написалося того. Активно читав сайт arduino.uk Я і не програму більше писав, а розбирався з синтаксисом, згадував Сі та постійно матюкався на послідовність виконання програмного коду (я звик до паралельності виконання коду, коли за тактів/циклам працюють всі обчислювальні блоки, а не відпрацьовується тільки одна рядок).
Другий раз я підійшов до орагнізації програми жорстко структурно. Не завжди це виявилося виправдано, але якщо задали початковий стиль, то його треба дотримуватися. Сенс полягає в… повторенні в коді структури програмних моделей намальованих вище. У коді спочатку у нас оголошуються всі змінні і прописуються настроювальні константи. Потім слід блок ініціалізації «void setup». А потім варто основний цикл «void loop», завданням якого є безперервний опитування модулів. Кожен модуль має свої вхідні і вихідні змінні, які впливають на його роботу. В основному циклі відбувається управління цими змінними. Опитувана кнопка задає режими роботи всіх модулів. Якщо по інтерфейсу прийшла команда, то вона транслюється на інші модулі управління, якщо не активовано режим «офлайн». Спочатку у мене було тільки два модуля управління двигуном і світлом. Потім з'явився модуль формування звуку, який я зробити не встиг. Тут як раз і позначилася закладена структура — просто і зрозуміло додавати/виключати модулі: блок оголошення змінних сходинку в ініціалізацію, сходинку в основний цикл та код самого модуля. Модуль визначення дальності і модуль реалізує алгоритм поворотів викликаються з інших модулів по необхідності.

Текст програми
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// Robot Platform RASH 1 © AlSHex
// 1.0
//
// Create: 23/03/2015
// Modification: 11/04/2015
//
// Опис: Програма управління платформою RASH 1
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////

//припиновка
const int LEDtech = 13; //висновок технологічного сигналу на світлодіод
const int LEDdist = 3; //виведення сигналу від сонара на світлодіод
const int Sonar_t = 14; //дані на сонар
const int Sonar_r = 15; //дані від sonar
const int Mode = 16; //підключення кнопки установки режиму - автономний або ручного: =0 - ручний; 1= автономний режим
const int MB1 = 4; //лівий мотор - digital
const int MB2 = 5; //лівий мотор - pwm
const int MA1 = 6; //правий мотор - pwm
const int MA2 = 7; //правий мотор - digital
const int HDL = 17; //вивід сигналу на фари
const int SPK = 11; //вивід сигналу на динамік
//const int LGHT = ; //дані від датчика освітленості

//налаштування модуля інтерфейсу
const long UART_Speed = 9600; //Швидкість UART

//налаштування модуля сонара
const int D1 = 20; //коефіцієнти функції ШІМ для виведення даних сонара на світлодіод
const int D2 = 110;
const float A = 2.5;
const float B = 305;

//налаштування модуля управління
const byte Byte_forward = byte('W'); //команда: вперед
const byte Byte_back = byte('S'); //команда: назад
const byte Byte_left = byte('A'); //команда: вліво
const byte Byte_right = byte('D'); //команда: вправо
const byte Byte_stop = byte('x'); //команда: стоп
const byte Byte_sound = byte('C'); //команда: звуковий сигнал/мелодія
const byte Byte_light = byte('V'); //команда: фари
const int Dist_min = 40; //мінімальна дистанція, при якій робот запустить алгоритм об'їзду перешкод [см]
const int Cycle_lightoff = 1000; //кількість циклів повтору програми після якого відключаються включені фари в автономному режимі
const int Speed_default = 255; //значення за замовчуванням, яке буде використовуватися після увімкнення поки не прийде команда, швидкість скидається в значення за замовчуванням при переході на автономний режим

//загальні налаштування
const int Delay_prog = 10; //затримка виконання повтору програми, [мс]
const int M_stop = 0; //константи для модуля двигуна (для зручності застосування)
const int M_forward = 1;
const int M_back = 2;
const int M_left = 3;
const int M_right = 4;

//оголошення та опис модулів - функцій

//========== Interface==========
void _UART_Interf(unsigned int RST, unsigned int *Data); //дані від інтерфейсу: Data[0]=1 - наявність команди; Data[1] - дані команди
//RST - скидання: 0= нормальна робота; 1= скидання
//Data - масив даних від інтерфейсу: Data[0]=1 - наявність команди; Data[1] - дані команди
//
//Подсоединенеи до UART відбувається з допомогою бібліотеки Serial

//========== Motor==========
void _Motor(unsigned int RST, unsigned int Mode, unsigned int Speed);
//RST - скидання: 0= нормальна робота; 1= скидання
//Mode - режим роботи: 0= стоп; 1= рух вперед; 2= рух назад; 3= поворот ліворуч; 4= поворот направо
//Speed: швидкість обертання двигунів - рівень, фомируемый ШІМ: 0= нульовий рівень; 255= максимальний рівень
//
//MA1, MA2, MB1, MB2 - сигнали припиновки двигунів, MB1 і MA2 - цифрові, MB2 і MA1 - аналогові (0/255)
//LEDtech - цифровий сигнал припиновки для технологічного світлодіода, загоряється при виконанні команди і гасне при отриманні команди "стоп"

//========== Sonar==========
unsigned int _Sonar(unsigned int RST);
//RST - скидання: 0= нормальна робота; 1= скидання
//
//Sonar_t - цифровий сигнал припиновки для сонара Trig
//Sonar_r - цифровий сигнал припиновки для сонара Echo
//LEDdist - аналоговий (0/255) сигнал припиновки для світлодіода, на який буде виводитися ШІМ-сигнал для візуалізації дальності - чим ближче об'єкт, тим світлодіод буде горіти яскравіше

//========== Control Motor==========
void _ControlM(unsigned int RST, unsigned int SCTRL, unsigned int DCTRL, unsigned int Mode);
//RST - скидання: 0= нормальна робота; 1= скидання
//SCTRL - сигнал актуальності даних DCTRL: 0= неактулальны; 1= актуальні
//DCTRL - дані (команда) від модуля інтерфейсу
//Mode - режим управління: 0= управління по командам; 1= автономний режим
//
//Модуль звертається до модулів Sonar, Motor і Rotate
//LEDtech - цифровий сигнал припиновки для технологічного світлодіода, спалахує на 1 секунду при отриманні команди установки швидкості

//========== Light Control==========
void _ControlL(unsigned int RST, unsigned int SCTRL, unsigned int DCTRL, unsigned int Mode);
//RST - скидання: 0= нормальна робота; 1= скидання
//SCTRL - сигнал актуальності даних DCTRL: 0= неактулальны; 1= актуальні
//DCTRL - дані (команда) від модуля інтерфейсу
//Mode - режим управління: 0= управління по командам; 1= автономний режим
//
//HDL - цифровий сигнал припиновки для управління фарами: 0= фари вимкнені; 1= фари включені

//========== Sound Control==========
void _ControlS(unsigned int RST, unsigned int SCTRL, unsigned int DCTRL, unsigned int Mode);
//RST - скидання: 0= нормальна робота; 1= скидання
//SCTRL - сигнал актуальності даних DCTRL: 0= неактулальны; 1= актуальні
//DCTRL - дані (команда) від модуля інтерфейсу
//Mode - режим управління: 0= управління по командам; 1= автономний режим
//
//SPK - аналоговий (0/255) сигнал припиновки для виведення ШІМ сигналу

//========== Rotate========== - алгоритм обертання, модуль виділений зі складу модуля ControlM в самостійний
void _Rotate(unsigned int RST, unsigned int Speed);
//RST - скидання: 0= нормальна робота; 1= скидання
//Speed: швидкість обертання двигунів - рівень, фомируемый ШІМ: 0= нульовий рівень; 255= максимальний рівень

//оголошення змінних
unsigned int CMD[2] = {0,0}; //дані від інтерфейсу: CMD[0]=1 - наявність команди; CMD[1] - дані команди
unsigned int CTRL[8] = {0,0,0,0,0,0,0,0}; //масив сигналів управління
//CTRL[0]: 0= нормальна робота; 1= скидання модулів
//CTRL[1]: 0= ручний режим; 1= автономний режим

void setup() {
//припиновка
pinMode(MB1, OUTPUT); digitalWrite(MB1, LOW);
pinMode(MB2, OUTPUT); analogWrite(MB2, 0);
pinMode(MA1, OUTPUT); analogWrite(MA1, 0);
pinMode(MA2, OUTPUT); digitalWrite(MA2, LOW);
pinMode(Sonar_t, OUTPUT); digitalWrite(Sonar_t, LOW);
pinMode(Sonar_r, INPUT); digitalWrite(Sonar_r, LOW);
pinMode(LEDdist, OUTPUT); analogWrite(LEDdist, 0); 
pinMode(Mode, INPUT); digitalWrite(Mode, LOW);
pinMode(LEDtech, OUTPUT); digitalWrite(LEDtech, LOW);
pinMode(HDL, OUTPUT); digitalWrite(HDL, LOW);
pinMode(SPK, OUTPUT); analogWrite(SPK, 0);

//початкова ініціалізація модулів
Serial.begin(UART_Speed);
_UART_Interf(1, CMD);
_UART_Interf(0, CMD);
_Sonar(1);
_Sonar(0);
_Motor(1, 0, 0);
_Motor(0, 0, 0);
_Rotate(1, 0);
_Rotate(0, 0);
_ControlM(1, 0, 0, 0);
_ControlM(0, 0, 0, 0);
_ControlL(1, 0, 0, 0);
_ControlL(0, 0, 0, 0);
_ControlS(1, 0, 0, 0);
_ControlS(0, 0, 0, 0); 
}



void loop() {
//опитування кнопки режиму та встановлення режиму роботи
if (digitalRead(Mode) == LOW) {
if (CTRL[1] == 1) { CTRL[0] = 1; } else { CTRL[0] = 0; } //якщо було перемиканні з іншого режиму, то буде виданий reset на всі схеми при проході програми, на слід. проході reset зніметься
CTRL[1] = 0;
} else {
if (CTRL[1] == 0) { CTRL[0] = 1; } else { CTRL[0] = 0; }
CTRL[1] = 1;
}

//опитування інтерфейсу, результат буде доступний в D_Interf
_UART_Interf(CTRL[0], CMD);

//виконання схеми управління
//управління моторами
_ControlM(CTRL[0], CMD[0], CMD[1], CTRL[1]);
//управління фарами
_ControlL(CTRL[0], CMD[0], CMD[1], CTRL[1]);
//управління звуком
_ControlS(CTRL[0], CMD[0], CMD[1], CTRL[1]); 

delay(Delay_prog);
}



//========== Interface module==========
void _UART_Interf(unsigned int RST, unsigned int *Data) { 

unsigned int DUART;
static unsigned int cnt_byte;

if (RST == 0) {
if (Serial.available() != 0) {
DUART = Serial.read();

switch (cnt_byte) { //перевірка цілісності пакета, якщо хоч один збій - скидаємо прийом і починаємо пошук нового заголовка пакета
case 0:
if (DUART == byte('t')) { cnt_byte++; } else { cnt_byte = 0; }
Data[0] = 0; Data[1] = 0;
break;

case 1:
if (DUART == byte('x')) { cnt_byte++; } else { cnt_byte = 0; }
Data[0] = 0; Data[1] = 0;
break;

case 2:
if (DUART == byte('_')) { cnt_byte++; } else { cnt_byte = 0; }
Data[0] = 0; Data[1] = 0;
break;

case 3:
if (DUART == byte('c')) { cnt_byte++; } else { cnt_byte = 0; }
Data[0] = 0; Data[1] = 0;
break;

case 4:
if (DUART == byte('o')) { cnt_byte++; } else { cnt_byte = 0; }
Data[0] = 0; Data[1] = 0;
break;

case 5:
if (DUART == byte('m')) { cnt_byte++; } else { cnt_byte = 0; }
Data[0] = 0; Data[1] = 0;
break;

case 6:
if (DUART == byte('=')) { cnt_byte++; } else { cnt_byte = 0; }
Data[0] = 0; Data[1] = 0;
break;

case 7: //якщо дійшли до кінця, то пакет вірний і можна видати команду
cnt_byte = 0;
Data[0] = 1; Data[1] = DUART;
break;
}
} else {
Data[0] = 0; Data[1] = 0; 
}
} else {
cnt_byte = 0;
Data[0] = 0; Data[1] = 0;
}
}



//========== Sonar module==========
unsigned int _Sonar(unsigned int RST) {

unsigned int Duration;

if (RST == 0) {
digitalWrite(Sonar_t, HIGH); //ініціалізація роботи УЗ датчика
delayMicroseconds(10);
digitalWrite(Sonar_t, LOW);
Duration = pulseIn(Sonar_r, HIGH); //прийом даних з УЗ датчика (ширина імпульсу в мс)

//висновок дальності на світлодіод
if (Duration/58 > D1 && Duration/58 < D2) {
analogWrite(LEDdist,int((-A*float(Duration/58)+B)));
} else {
if (Duration/58 < D1) {
analogWrite(LEDdist, HIGH);
} else {
analogWrite(LEDdist, LOW);
}
}

return Duration/58; //видача відстані в сантиметрах
} else {
digitalWrite(LEDdist, LOW);
return 0;
}
}



//========== Control Motor module==========
void _ControlM(unsigned int RST, unsigned int SCTRL, unsigned int DCTRL, unsigned int Mode) {

unsigned int Dist;
static unsigned int Speed;
static unsigned long Time_forward; 

if (RST == 0) {

if (Mode == 0) { //"ручний" режим роботи по командам 
if (SCTRL == 1) { //якщо отримали команду
switch (byte(DCTRL)) { //розшифровуємо команду
case Byte_forward:
Dist = _Sonar(0);
if (Dist > D1) { _Motor(0, M_forward, Speed); } //якщо можна їхати вперед - їдемо
break;

case Byte_back:
_Motor(0, M_back, Speed);
break;

case Byte_left:
_Motor(0, M_left, Speed);
break;

case Byte_right:
_Motor(0, M_right, Speed);
break;

case Byte_stop:
_Motor(0, M_stop, Speed);
break;

default:
break;
}

if (DCTRL > 47 && DCTRL < 58) { //отримання швидкості
Speed = (DCTRL-47)*25+5;
digitalWrite(LEDtech, HIGH);
delay(1000);
digitalWrite(LEDtech, LOW);
}
}
}

if (Mode == 1) { //автономний режим
Speed = Speed_default;
Dist = _Sonar(0);

if (Dist > Dist_min) {
if (millis()-Time_forward < 21000) {
_Motor(0, M_forward, Speed);
} else { //якщо 20 сек рухається тільки прямо, то потрібно здати назад, т. к. напевно застрягли в невеликій кімнаті :)
_Motor(0, M_stop, Speed);
delay(300);
_Motor(0, M_back, Speed);
delay(600);
_Motor(0, M_stop, Speed);
delay(300);
_Rotate(0, Speed);
_Motor(0, M_stop, Speed);
delay(300);

Time_forward = millis()-1; //-1 для гарантії, що millis()-Time_forward буде точно завжди додатне число
} 
} else {
_Motor(0, M_stop, Speed);
delay(300);
_Rotate(0, Speed);
delay(300);

Time_forward = millis()-1;
}
}
} else {
Dist = 0;
Speed = Speed_default;
Time_forward = 0;

_Sonar(1);
_Motor(0, 0, 0);
_Rotate(1, 0);

digitalWrite(LEDtech, LOW);
}
}



//========== Light Control==========
void _ControlL(unsigned int RST, unsigned int SCTRL, unsigned int DCTRL, unsigned int Mode) {

static unsigned int Light; // 0= фари вимкнені; 1= фари включені

if (RST == 0) {

if (Mode == 0) { //"ручний" режим роботи по командам
if (SCTRL == 1) { //якщо отримали команду
switch (byte(DCTRL)) { //розшифровуємо команду
case Byte_light:
if (Light == 0) {
Light = 1;
digitalWrite(HDL, HIGH);
} else {
Light = 0;
digitalWrite(HDL, LOW);
}
break;

default:
break;
}
}
}

if (Mode == 1) { //автономний режим
//block operations
}
} else {
Light = 0;
digitalWrite(HDL, LOW);
}
}


//========== Sound Control==========
void _ControlS(unsigned int RST, unsigned int SCTRL, unsigned int DCTRL, unsigned int Mode) {

if (RST == 0) {

if (Mode == 0) { //"ручний" режим роботи по командам
if (SCTRL == 1) { //якщо отримали команду
switch (byte(DCTRL)) { //розшифровуємо команду
case Byte_sound:
//block operations
break;

default:
break;
}
}
}

if (Mode == 1) { //автономний режим
//block operations
}
} else {
analogWrite(SPK, 0);
}
}



//========== Motor module==========
void _Motor(unsigned int RST, unsigned int Mode, unsigned int Speed) {
if (RST == 0) {
switch (Mode) { //розшифровка команди управління і виконання дії
case 0: //stop
digitalWrite(LEDtech, LOW);

digitalWrite(MB1, LOW);
analogWrite(MB2, 0);

analogWrite(MA1, 0);
digitalWrite(MA2, LOW);

break;

case 1: //forward
digitalWrite(LEDtech, HIGH);

digitalWrite(MB1, HIGH);
analogWrite(MB2, 255-Speed);

analogWrite(MA1, Speed);
digitalWrite(MA2, LOW);

break;

case 2: //back
digitalWrite(LEDtech, HIGH);

digitalWrite(MB1, LOW);
analogWrite(MB2, Speed);

analogWrite(MA1, 255-Speed);
digitalWrite(MA2, HIGH);

break;

case 3: //left
digitalWrite(LEDtech, HIGH);

digitalWrite(MB1, LOW);
analogWrite(MB2, Speed);

analogWrite(MA1, Speed);
digitalWrite(MA2, LOW);

break;

case 4: //right
digitalWrite(LEDtech, HIGH);

digitalWrite(MB1, HIGH);
analogWrite(MB2, 255-Speed);

analogWrite(MA1, 255-Speed);
digitalWrite(MA2, HIGH);
break;

default:
break;
}
} else {
digitalWrite(LEDtech, LOW);

digitalWrite(MB1, LOW);
analogWrite(MB2, 0);

analogWrite(MA1, 0);
digitalWrite(MA2, LOW);
}
}



//========== Rotate========== - алгоритм повороту
void _Rotate(unsigned int RST, unsigned int Speed) {

unsigned int Dist;
static unsigned int Num;
unsigned int cnt;
unsigned long Now_time;

if (RST == 0) {
do {
if (Num%2 == 0) { //визначення парності
if (Num >= 0 && Num < 128) {
_Motor(0, M_right, Speed);
delay(100);
_Motor(0, M_stop, Speed);
delay(100);
}
if (Num >= 128 && Num < 255) {
_Motor(0, M_right, Speed);
delay(200);
_Motor(0, M_stop, Speed);
delay(100); 
}
} else {
if (Num >= 0 && Num < 128) {
_Motor(0, M_left, Speed);
delay(250);
_Motor(0, M_stop, Speed);
delay(100);
}
if (Num >= 128 && Num < 255) {
_Motor(0, M_left, Speed);
delay(150);
_Motor(0, M_stop, Speed);
delay(100); 
}
}
cnt++;

Dist = _Sonar(0);

} while (Dist < Dist_min && cnt <= 3); //виходимо якщо дальність дозволена або якщо 3 рази провернули (на слід. циклі програми зайдемо сюди знову і будемо знову крутитися може бути по-іншому з-за іншого Num)

cnt = 0;

Now_time = millis(); //читання
while (Now_time > 255) { //обмеження часу
Now_time -= 255;
}
Num += Now_time; //отримання нового випадкового числа: старе+час
while (Num > 255) { //обмеження нового числа при необхідності
Num -= 255;
}

} else {
Dist = 0;
Num = 0;
cnt = 0;
Now_time = 0;
_Motor(1, 0, 0);
_Sonar(1);
}
}



Шостий етап — осмислення творіння

Що ми хотіли зробити?
Давайте подивимося:



В цілому, начебто нічого. Їздить. Зупиняється. Крутиться. Але… не все так добре. Робот досить бадьоро їздить без «другого поверху», але при установці другого явно «стає нудним». Крім того, він постійно забирає вліво натякаючи, що одному в житті дуже погано взагалі-то, і раз вже створив, то непогано було б зайнятися цим самим… різноманітністю видів.

Підвівши підсумок, можна чесно зізнатися, що розвиватися є куди.
1) Робот завжди забирає вліво при прямолінійному русі. Чим сильніше розряд джерела живлення, тим сильніше відхилення. Очевидно, це відбувається через розкиду параметрів двигунів, можливо — з-за різної роботи каналів драйвера двигунів. Для виключення подібної поведінки робота необхідно підключати оптичні енкодери і, отримуючи інформацію від них, коректувати алгоритм модуля керування двигунами при русі вперед або назад. Крім того, для джерела живлення необхідно мати інтегральний стабілізатор напруги, наприклад, можна перевести харчування на пару Li-ION елементів з використанням понижуючого перетворювача напруги.
2) Робот досить часто не бачить попереду стоїть об'єкт. Це пов'язано з вузьким кутом огляду ультразвукового вимірювача відстані. Очевидно, що точність і надійність визначення відстані до об'єктів можна підвищити, встановивши два-три УЗ датчика. Для визначення відстані датчики опитуються послідовно з невеликими паузами для виключення впливу перевідбиттів УЗ сигналів один на одного.
3) Пару раз на прошивці версії 1.0 спостерігалася ситуація зависання алгоритму повороту – робот постійно крутився і не рухався вперед, навіть якщо попереду не було перешкоди. Якщо робота примусово утримувати у вільному напрямку, то через деякий час він починав нормально працювати. Для виключення таких ситуацій необхідно розширити критерії самодіагностики поведінки робота з його примусової переинициализацией у разі виникнення проблем. Для виключення зависання МК необхідно використовувати WatchDog.
4) При дистанційному керуванні часто виникає ситуація, коли після відпускання кнопки на клавіатурі, задає рух, робот не зупинявся. Тоді потрібно було швидко натиснути і відпустити клавішу руху. Можливо, команда «стоп» губилася в приймальному буфері, можливо, команда не видавалася з маршрутизатора. Для виключення подібних ситуацій, з маршрутизатора необхідно видавати команду «стоп» кілька разів підряд при відпусканні кнопки руху.
5) При створенні прошивки для МК специфіку вносить послідовне виконання програми. Для того, щоб відпрацювати команду «вперед», треба послідовно опитати модулі інтерфейсу, визначення дальності, управління і потім викликати модуль руху. При такому опитуванні модуль визначення дальності вносить затримку до півсотні мілісекунд, гальмуючи прийняття рішення за прийшла команді. У разі надмірного розростання функціоналу або появи додаткових модулів дальності затримка може стати неприйнятною. У ПЛІС такої проблеми немає – всі блоки в кожен момент часу працюють паралельно, тобто допустимо в один момент часу приймати команду, обробляти дальність і виводити її на світлодіод, а також виконувати безліч інших операцій. У МК ж паралельне виконання навіть не пов'язаних функцій один з одним неможливо, або треба постійно використовувати переривання з зовнішнім подіям, що не завжди зручно. Однак, розробка прошивки для ПЛІС – це, істотно, більш трудомістка робота, яка вимагає певної кваліфікації, т. к. написати код на Сі може практично будь-який програміст, а для написання коду VHDL/Verilog потрібне розуміння суті роботи логіки мікросхеми.
6) При дистанційному керуванні зображення з бортовою камери занадто сильно змінюється, ускладнюючи орієнтування в просторі. Для зниження цього ефекту необхідно застосовувати згладжування та/або зменшення вікна відображення.
7) У процесі тестування виявилася невдала конструкція механічної частини. При повному завантаженні (платформа + «другий поверх») динаміка платформи знижується, чути скрип при поворотах. Можливо ситуацію можна виправити, піднявши живляча напруга. Крім того, заднє колесо часто заклинює при поворотах і мастило шарикопідшипників не допомагає зважаючи невдалої конструкції.
8) При ручному управлінні на максимальній швидкості при русі вперед, у разі необхідності зупинки і швидкому русі тому, робот міг різко нахилятися вперед, при цьому задня точка опори відривалася від землі.

І як нам тепер бути?
1) Реалізація видачі звукового сигналу – розробка генератора звукових сигналів з певною частотою.
2) Вирівнювання швидкості коліс при прямолінійному русі, використовуючи оптичні датчики і оптичні енкодери для коліс.
3) Реалізація автоматичного включення/вимикання фар, використовуючи датчик освітленості.
4) Підвищення надійності визначення відстаней до попереду стоять об'єктів шляхом збільшення УЗ датчиків до трьох.
5) Організація харчування на базі двох Li-Ion акумуляторів типорозміру 18650 та інтегрального стабілізатора напруги.
6) Розібрати і змастити редуктори двигунів силіконовою змазкою для усунення скрипів.
7) Оцінити збільшення живлячої напруги до 6,0-7,5 В. При цьому врахувати, що доведеться перераховувати і перепоювати резистори для світлодіодів, щоб не допустити перевищення максимального вихідного струму виводу МК.
8) При різкій зміні стану (початок руху або зупинка) реалізувати плавну зміну швидкості руху, функція зміни може бути лінійною або експоненційної.

Сьомий етап — розвиток

go to «Другий етап» ;-)




Ну, ось, ми добралися і до фіналу історії.
Робота я успішно продемонстрував і передав його разом із, скажімо так, супровідною документацією, а також з описом виявлених недоліків та шляхів їх усунення. На мою думку, знайомство з цими технічними описами та технічними завданнями має скласти правильне уявлення про роботу електронних пристроїв «всередині», а так само зняти переважна більшість «тонких» технічних питань. Начебто, всі залишилися задоволені.
На жаль, у мене не завжди достатньо вільного часу, щоб серйозно брати участь у розробках компанії Endurance. Наскільки я знаю, компанія в пошуку зацікавлених і в міру самостійних розробників і якщо ви не тільки цікавитеся даною тематикою, але і маєте якийсь досвід, можливості та бажання взяти участь у роботостроении, то вам там будуть напевно ради.

Звичайно, використання робота в даному виконанні бачиться в іронічному світлі з точки зору якихось промислових завдань. Однак і ця платформа може бути корисною. Я думаю, що мені було б непогано мати такого робота на дачі в цілях віддаленого моніторингу. Якщо на нього встановити сервоприводи, що дозволяють обертати відеокамерою, продумати систему харчування, то я би міг у будь-який момент проінспектувати обстановку в будинку. А якщо зробити заїзд на підвіконня до вікон (так, хоч дощок покласти, зробивши похилу площину), то і поза домом. Якщо батареї поміняти на Li-ION акумулятори, то їх можна буде без проблем заряджати, т. к. подібні контролери доступні в готовому вигляді. У першій версії подібного робота після інспекції його можна просто підганяти до зарядної станції вручну, і він буде з'єднувати контактори з допомогою, наприклад, мініатюрних електромагнітів (навскидку: робот може, взагалі, в момент перемикання переходити на харчування від мережі, а акумулятори будуть ізольовані від електросхеми і заряджатися автономно). У другій версії робота можна навчити робити це самостійно — підігнав до зарядної станції і натиснув кнопку «паркування» (навскидку: можна по центру паркувальної мішені намалювати якусь яскраву фігуру, робот буде орієнтуватися по ній використовуючи датчик визначення кольору, а в нічний час все буде підсвічуватися фарами).

Удачі в роботостроении!
Не бійтеся починати)

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.