В этом проекте мы рассмотрим создание на основе платы Arduino небольшого робота, который умеет ходить и танцевать. Проект имеет целью научить вас создавать подобных роботов на основе Arduino, а также программировать сервомоторы для подобных применений. В конце этой статьи вы научитесь создавать шагающего и танцующего робота, который умеет принимать команды от мобильного телефона на Android чтобы выполнять некоторый заранее определенный набор действий.
Также вы можете использовать программу, приведенную в конце статьи, чтобы управлять движениями робота с помощью положения его сервомоторов и используя для этого последовательный монитор (Serial monitor). Если у вас есть 3D принтер, то вы можете сделать этот проект очень впечатляющим, но если у вас его нет, то вы можете изготовить компоненты корпуса робота из любого доступного материала: пластмасса, дерево, жесткий картон и т.д.
Необходимые компоненты
- Плата Arduino Nano (купить на AliExpress).
- Сервомотор SG90 (4 шт.) (купить на AliExpress).
- Bluetooth модуль (HC-05/HC-06) (купить на AliExpress).
- Соединительные колодки (типа папа).
- 3D принтер (опционально).
Реклама: ООО "АЛИБАБА.КОМ (РУ)" ИНН: 7703380158
Внешний вид всех необходимых комплектующих для сборки этого робота вы можете увидеть на следующем рисунке.
Как вы видите, этот робот требует минимального количества электронных компонентов – это сделано с той целью чтобы максимально удешевить проект. Проект имеет обучающую цель и не претендует на то, чтобы его можно было использовать в каких-нибудь практических применениях.
Печать на 3D принтере необходимых компонентов
3D принтеры, появившиеся сравнительно недавно, дают большой простор для разнообразных DIY (сделай сам) проектов.
Мы в нашем проекте полностью напечатали тело робота на 3D принтере. Все необходимые STL файлы для этого вы можете скачать по следующей ссылке. Вы можете загрузить эти файлы программным обеспечением вашего 3D принтера (например, Cura) и непосредственно напечатать их. Принтер, который мы использовали, называется FABX v1, который доступен по приемлемой цене и может печатать в объеме до 10 кубических сантиметров. Мы использовали программное обеспечение Cura чтобы напечатать STL файлы. Мы сделали следующие настройки в данном программном обеспечении для печати нашего проекта:
Напечатанные нами части корпуса робота выглядят следующим образом:
После печати удостоверьтесь в том, что отверстия на ногах и туловище робота достаточны для того, чтобы через них прошел шуруп (винт). Если это не так, то расширьте их с помощью шила.
Работа схемы
Схема устройства представлена на следующем рисунке.
Мы использовали перфорированную плату чтобы облегчить создание соединений между компонентами схемы. Также следите за тем, чтобы созданная вами плата помещалась внутрь корпуса робота.
Сборка робота
После того как электрические соединения в схеме робота сделаны и корпус робота готов можно приступать к его окончательной сборке. Перед закреплением сервомоторов убедитесь в том что их оси повернуты на углы, указанные в следующей таблице:
Motor Number (номер мотора) | Motor place (место мотора) | Motor position (позиция мотора) |
1 | Left Hip motor | 110 |
2 | Right Hip motor | 100 |
4 | Right Ankle Motor | 90 |
5 | Right Hip motor | 80 |
Эти углы можно выставить с помощью программы, приведенной в конце статьи. Просто загрузите программу в плату Arduino (когда все соединения уже сделаны) и напечатайте в окне последовательного монитора (serial monitor) (бодовая скорость: 57600):
1, 100, 110
2,90,100
4,80,90
5,70,80
Окно последовательного монитора у вас после установки всех сервомоторов в необходимые позиции должно выглядеть примерно так:
После того как оси сервомоторов повернуты на необходимые углы смонтируйте их на роботе как показано на следующем рисунке.
Если у вас возникли какие либо затруднения, то посмотрите видео, приведенное в конце статьи. После того как робот собран можно приступать к написанию программы чтобы заставить его танцевать.
Объяснение программы для Arduino
Если вы не уверенно чувствуете себя в программировании действий сервомоторов, то вначале рекомендуем изучить следующую статью – подключение сервомотора к плате Arduino. Также вы можете посмотреть на нашем сайте все статьи, связанные с управлением сервомоторами.
Полный текст программы приведен в конце статьи, либо вы можете скачать его по этой ссылке. Здесь же объяснены наиболее важные части программы. С помощью этой программы можно управлять движениями робота при помощи монитора последовательной связи (serial monitor) или технологии Bluetooth. Также вы на основе этой программы можете запрограммировать свой собственный набор движений для робота.
В следующих строчках кода мы укажем плате Arduino какие сервомоторы к каким ее контактам подключены. В нашем случае сервомоторы 1, 2, 4 и 5 подключены к контактам 3, 5, 9 и 10.
1 2 3 4 |
servo1.attach(3); servo2.attach(5); servo4.attach(9); servo5.attach(10); |
В следующих строчках кода инициализируем последовательную связь с Bluetooth на скорости 9600 бод/с (под именем “Bot_BT”) и последовательную связь на скорости 57600 (для управления через монитор последовательного порта).
1 2 |
Bot_BT.begin(9600); //start the Bluetooth communication at 9600 baudrate Serial.begin(57600); |
В следующем участке кода используется оператор switch для управления индивидуально каждым сервомотором, что дает нам огромную свободу движений в управлении роботом. С помощью этого участка кода вы можете дать команду сервомотору с заданным номером повернуться на заданный угол (в нужную позицию).
К примеру, если мы хотим повернуть сервомотор №1 (left hip motor) с его позиции по умолчанию (60 градусов) на позицию 110 градусов, то мы можем просто написать в окне монитора последовательной связи (serial monitor) команду “1,110,60” и нажать клавишу ввода (Enter). Пробуя разные команды таким образом вы можете составить свой индивидуальный набор движений для робота и потом оформить их в виде функции.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
switch (motor) { case 1: // For motor one { Serial.println("Executing motor one"); if(num1<num2) // Clock wise rotation { for ( pos =num1; pos<=num2; pos+=1) { servo1.write(pos); delay( 20); }} if(num1>num2) // вращение против часовой стрелки { for ( pos =num1; pos>=num2; pos-=1) { servo1.write(pos); delay( 20); }} break; } ////////JUST DUPLICATE FOR OTHER SERVOS//// case 2: // For motor 2 { Serial.println("Executing motor two"); if(num1<num2) { for ( pos =num1; pos<=num2; pos+=1) { servo2.write(pos); delay( 20); }} if(num1>num2) { for ( pos =num1; pos>=num2; pos-=1) { servo2.write(pos); delay( 20); }} break; } case 4: // for motor four { Serial.println("Executing motor four"); if(num1<num2) { for ( pos =num1; pos<=num2; pos+=1) { servo4.write(pos); delay (20); }} if(num1>num2) { for ( pos =num1; pos>=num2; pos-=1) { servo4.write(pos); delay (20); }} break; } case 5: // for motor five { Serial.println("Executing motor five"); { for ( pos =num1; pos<=num2; pos+=1) if(num1<num2) { servo5.write(pos); delay (20); }} if(num1>num2) { for ( pos =num1; pos>=num2; pos-=1) { servo5.write(pos); delay (20); }} break; } |
Следующие строки позволяют расшифровать поступающие команды по последовательному порту (из окна монитора последовательной связи) и распределить поступающие параметры по необходимым переменным.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
if(Serial.available()>0) // считываем что поступает по последовательному порту { gmotor= Serial.parseInt(); Serial.print(" selected Number-> "); Serial.print(gmotor); Serial.print(" , "); gnum1= Serial.parseInt(); Serial.print(gnum1); Serial.print(" degree , "); gnum2= Serial.parseInt(); Serial.print(gnum2); Serial.println(" degree "); flag=1; } |
Если мы получаем информацию по Bluetooth, то мы сохраняем ее в переменной “BluetoothData”. Затем значение этой переменной сравнивается с заранее определенными значениями чтобы выполнить необходимые действия.
1 2 3 4 5 6 |
if (Bot_BT.available()) //считываем что поступает по Bluetooth { BluetoothData=Bot_BT.read(); Serial.print("Incoming from BT:"); Serial.println(BluetoothData); } |
В следующем участке кода происходит вызов необходимой функции в соответствии с командой, поступившей по последовательному порту или через Bluetooth. Как было показано раньше, переменная gmotor будет содержать данные, поступившие по последовательному порту, а переменная BluetoothData – данные, поступившие через Bluetooth. Числа с 10 по 13 и с 49 по 54 – это заранее определенные значения.
К примеру, если вы введете в окне монитора последовательной связи число 49, то произойдет вызов функции say_hi() и робот выполнит соответствующие движения.
Все запрограммированные функции доступны на странице “Bot_Functions” – вы можете открыть ее и посмотреть что происходит внутри каждой функции. Все эти функции составлены с учетом наших экспериментов по управлению серводвигателями робота.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
if (flag ==1 ) call(gmotor,gnum1,gnum2); //вызов соответствующего сервомотора для действия //выполнение функции в соответствии с командой, поступившей по последовательному порту или через Bluetooth if (gmotor ==10) left_leg_up(); if (gmotor ==11) right_leg_up(); if (gmotor ==12) move_left_front(); if (gmotor ==13) move_right_front(); if (BluetoothData ==49 || gmotor ==49) say_hi(); if (BluetoothData ==50 || gmotor ==50) walk1(); if (BluetoothData ==51 || gmotor ==51) walk2(); if (BluetoothData ==52 || gmotor ==52) dance1(); if (BluetoothData ==53 || gmotor ==53) dance2(); if (BluetoothData ==54 || gmotor ==54) {test();test();test();} |
Программирование Android приложения с помощью Processing
Android приложение для управления этим роботом было написано с помощью бесплатной программной среды Processing. Если вы хотите внести какие-нибудь свои изменения в его код, то исходный код данного приложения вы можете скачать по данной ссылке.
Если же вы просто хотите скачать его и использовать в качестве приложения то, скачайте его APK файл и установите его на свой мобильный телефон (в настройках телефона следует включить опцию разрешения установки приложений из непроверенных источников).
Примечание: ваш Bluetooth модуль должен иметь имя “HC-06”, иначе приложение не сможет с ним соединиться.
После установки приложения на мобильный телефон вы можете соединить ваш телефон по Bluetooth с Bluetooth модулем (подключенным к Arduino) и после этого запустить приложение. Это будет выглядеть примерно следующим образом:
Если же вы хотите сделать приложение более привлекательным или соединить его с другим Bluetooth-устройством (названным не “HC-06”), то вам в этом случае будет необходимо внести изменения в исходный код приложения.
Принцип работы танцующего робота
После того как схема собрана и программа загружена в плату Arduino вы можете насладиться управлением роботом. Для управления из Android приложения вам необходимо нажимать в нем соответствующие кнопки (см. рисунок выше), а для управления из окна монитора последовательной связи вам следует в этом окне вводить необходимые команды как показано на следующем рисунке:
Каждая команда заставит робота выполнять определенные действия, также вы можете запрограммировать свой набор этих действий.
Робота можно запитать от адаптера на 12V или с помощью батареи на 9V, которую несложно будет разместить внутри корпуса робота.
Более подробно весь этот процесс можно посмотреть в видео в конце статьи.
Исходный код программы для Arduino
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 |
#include <Servo.h> //header to srive servo motors #include <SoftwareSerial.h>// import the serial library SoftwareSerial Bot_BT(12, 11); // RX, TX int ledpin=13; // led on D13 will show blink on / off int BluetoothData; // the data given from Computer //lets declare the servo objects Servo servo1; Servo servo2; Servo servo3; Servo servo4; Servo servo5; //End of declaration long gmotor,gnum1,gnum2; int pos,pos2; int flag=0; int poss1,poss2,poss3,poss4; void setup() { servo1.attach(3); servo2.attach(5);; servo4.attach(9); servo5.attach(10); //**Initial position of all four servo motors**// servo1.write(110); servo2.write(100); servo4.write(90); servo5.write(80); //**inititialised**// Bot_BT.begin(9600); //start the Bluetooth communication at 9600 baudrate Bot_BT.println("Blue Bob is ready to take actions"); Serial.begin(57600); Serial.println("Biped Servo programming by CircuitDigest.com"); Serial.println("Enter any of the following commands for theier respective actions"); Serial.println("1. Servomotor Number, From angle, To angle -> To control one particular Servo"); Serial.println(" Servomotor Number -> 1,2,4,5"); Serial.println(" From angle -> 0 to 180"); Serial.println(" To angle -> 0 to 180"); Serial.println("2. Servomotor Number, From angle, To angle -> To control one particular Servo"); Serial.println("3. Enter 10 -> To lift left leg up"); Serial.println("4. Enter 11 -> To lift right leg up"); Serial.println("5. Enter 12 -> To move left leg front"); Serial.println("6. Enter 13 -> To move right leg front"); Serial.println("7. Enter 49 -> To say Hi ;-)"); Serial.println("8. Enter 50 -> To Walk with style 1"); Serial.println("9. Enter 51 -> To Walk with style 2"); Serial.println("10. Enter 52 -> To Dance with style 1"); Serial.println("11. Enter 53 -> To Dance with style 2"); Serial.println("12. Enter 54 -> To Say Bye!!"); } //***Function for each Servo actions**// void call(int motor, int num1, int num2) // The values like Motor number , from angle and to angle are received { Serial.println("Passing values..."); flag =0; switch (motor) { case 1: // For motor one { Serial.println("Executing motor one"); if(num1<num2) // Clock wise rotation { for ( pos =num1; pos<=num2; pos+=1) { servo1.write(pos); delay( 20); }} if(num1>num2) // Anti-Clock wise rotation { for ( pos =num1; pos>=num2; pos-=1) { servo1.write(pos); delay( 20); }} break; } ////////JUST DUPLICATE FOR OTHER SERVOS//// case 2: // For motor 2 { Serial.println("Executing motor two"); if(num1<num2) { for ( pos =num1; pos<=num2; pos+=1) { servo2.write(pos); delay( 20); }} if(num1>num2) { for ( pos =num1; pos>=num2; pos-=1) { servo2.write(pos); delay( 20); }} break; } case 4: // for motor four { Serial.println("Executing motor four"); if(num1<num2) { for ( pos =num1; pos<=num2; pos+=1) { servo4.write(pos); delay (20); }} if(num1>num2) { for ( pos =num1; pos>=num2; pos-=1) { servo4.write(pos); delay (20); }} break; } case 5: // for motor five { Serial.println("Executing motor five"); { for ( pos =num1; pos<=num2; pos+=1) if(num1<num2) { servo5.write(pos); delay (20); }} if(num1>num2) { for ( pos =num1; pos>=num2; pos-=1) { servo5.write(pos); delay (20); }} break; } } } void loop() { if(Serial.available()>0) //Read whats coming in through Serial { gmotor= Serial.parseInt(); Serial.print(" selected Number-> "); Serial.print(gmotor); Serial.print(" , "); gnum1= Serial.parseInt(); Serial.print(gnum1); Serial.print(" degree , "); gnum2= Serial.parseInt(); Serial.print(gnum2); Serial.println(" degree "); flag=1; } if (Bot_BT.available()) //Read whats coming in through Bluetooth { BluetoothData=Bot_BT.read(); Serial.print("Incoming from BT:"); Serial.println(BluetoothData); } if (flag ==1 ) call(gmotor,gnum1,gnum2); //call the respective motor for action //Execute the functions as per the commond received through the Serial monitor or Bluetooth// if (gmotor ==10) left_leg_up(); if (gmotor ==11) right_leg_up(); if (gmotor ==12) move_left_front(); if (gmotor ==13) move_right_front(); if (BluetoothData ==49 || gmotor ==49) say_hi(); if (BluetoothData ==50 || gmotor ==50) walk1(); if (BluetoothData ==51 || gmotor ==51) walk2(); if (BluetoothData ==52 || gmotor ==52) dance1(); if (BluetoothData ==53 || gmotor ==53) dance2(); if (BluetoothData ==54 || gmotor ==54) {test();test();test();} //End of executions// gmotor=0; //To prevet repetetion BluetoothData = 0; //To prevet repetetion //stay_put(); //bring the Bot to initial posotion if required } /*---------------------------------------------------------------------------*/ // Code for Bot Functions...... //***Function to lift the left leg**// void stay_put() { servo5.attach(10); servo1.write(110); servo2.write(100); servo4.write(90); servo5.write(80); delay(20); } //**_____End of Function______**// //***Function to lift the left lef**// void left_leg_up() { Serial.println("left leg up"); poss1 = 80; poss2 = 110; do{ servo5.write(poss1); servo4.write(poss2); poss1++; poss2++; delay(20); }while(poss1 <100 || poss2<140); call(4,130,100); } //**_____End of Function______**// //***Function to lift the left lef**// void right_leg_up() { Serial.println("right leg up"); poss1 = 80; poss2 = 100; do{ servo4.write(poss2); servo5.write(poss1); poss1--; poss2--; delay(20); }while(poss1 >50 || poss2>60); call(5,50,80); } //**_____End of Function______**// //***Function to lift the left lef**// void move_left_front() { Serial.println("moving left front"); poss1=120;poss2=110;poss3=110; do{ servo2.write(poss1); servo1.write(poss2); servo5.write(poss3); poss1--; poss2--; poss3--; delay(20); }while(poss1 >100 || poss2>80 || poss3>80 ); } //**_____End of Function______**// //***Function to lift the left lef**// void move_right_front() { poss1=80;poss2=100;poss3=60; do{ servo1.write(poss1); servo2.write(poss2); servo4.write(poss3); poss1++; poss2++; poss3++; delay(20); }while(poss1 <110 || poss2<120 || poss3<90); } //**_____End of Function______**// //***Function to lift the left lef**// void say_hi() { stay_put(); right_leg_up(); call(5,80,50); //wave up call(5,50,80); //wave down call(5,80,50); //wave up call(5,50,80); //wave down stay_put(); } //**_____End of Function______**// //***Function to lift the left lef**// void walk1() { stay_put(); char temp=10; //number of steps to make * 2 do{ right_leg_up(); move_right_front(); left_leg_up(); move_left_front(); temp--; }while(temp>0); } //**_____End of Function______**// //***Function to lift the left lef**// void walk2() { stay_put(); char temp=10; //number of steps to make * 2 do{ move_right_front(); move_left_front(); temp--; }while(temp>0); } //**_____End of Function______**// //***Function to lift the left lef**// void dance1() { stay_put(); char temp=3; //number of steps to make * 2 do{ poss1 = 80; poss2 = 60; do{ servo1.write(poss1); servo2.write(poss2); poss1++; poss2++; delay(20); }while(poss1 <140 || poss2<120); poss1 = 140; poss2 = 120; do{ servo1.write(poss1); servo2.write(poss2); poss1--; poss2--; delay(20); }while(poss1 >80 || poss2>60); temp--; }while(temp>0); stay_put(); } //**_____End of Function______**// //***Function to lift the left lef**// void dance2() { stay_put(); char temp=3; //number of steps to make * 2 do{ right_leg_up(); right_leg_up(); stay_put(); left_leg_up();left_leg_up(); stay_put(); temp--; }while(temp>0); stay_put(); } //**_____End of Function______**// //***Function to lift the left lef**// void test() { poss1 = 40; poss2 = 130; do{ servo5.write(poss1); servo4.write(poss2); poss1++; poss2--; delay(5); }while(poss1 <120 || poss2>50); poss1 = 120; poss2 = 50; do{ servo5.write(poss1); servo4.write(poss2); poss1--; poss2++; delay(5); }while(poss1 >40 || poss2<130); } //**_____End of Function______**// |