В очередном нашем уроке мы создадим управляемого жука Божью коровку, которого заставим двигаться с помощью команд со смартфона. В итоге мы получим устройство дистанционного управления с поддержкой Wi-Fi, которое обеспечивает как движение, так и простоту управления. Жук будет использовать смартфон на iOS, заблокированный в портретном режиме (мы тестировали только на устройствах iOS, см. раздел «Программное обеспечение» ниже), а для управления нужно будет просто перетаскивать красный курсор-кнопку.
Также мы включили исходный код в виде эскиза Arduino для Adafruit Feather Huzzah ESP8266 (плата от компании Adafruit), если вы захотите изменить его для использования с другими устройствами. Кроме того, вам понадобятся навыки пайки и паяльное оборудование, провод и все части, перечисленные на первом шаге, плюс система Arduino IDE с соответствующими библиотеками.
Игрушка разработана с использованием Autodesk Fusion 360, нарезана с использованием Cura 3.0.4 и напечатана (PLA) на Ultimaker 2+ Extended и Ultimaker 3 Extended.
Шаг 1: Комплектующие
Мы приложили файл PDF (в архиве), содержащий две таблицы. Первая таблица содержит список трехмерных печатных деталей с настройками и цветами, которые мы использовали. Вторая таблица содержит список приобретенных деталей.
Обратите внимание, что тело (либо «Body.3mf», либо «Body.stl») должно быть напечатано с помощью опоры из-за того, что 4 монтажные башни внутри корпуса на 2 мм выше, чем у корпуса. Также обратите внимание, что Cura 3.0.4 не будет размещать «Body.3mf» на строительной пластине, поэтому пришлось отключить настройку «Automatically drop models to the build plate», а затем вручную опустить корпус до тех пор, пока он не соприкоснется со сборной пластиной.
Шаг 2: Электроника
Осторожно отрежьте положительный (красный) провод на батарее посередине, а затем зачистите как показано на рисунке. Припаяйте часть красного провода, идущего от батареи, к центру двумя клеммами переключателя.
Припаяйте красный провод между внешними парами контактов переключателя, как показано на рисунке. Припаяйте часть красного провода, идущего от разъема к любому из двух внешних контактов переключателя.
Для питания сервоприводов оба сервоположительных (красных) провода припаиваются к контакту «BAT» на лицевой панели платы Feather Huzzah, а оба серво-отрицательных (коричневых) провода припаиваются к контакту «GND» (земля).
Для управления сервоприводами левый сервосигнал (оранжевый) провод припаивается к контакту «12 / MISO» на лицевой панели Feather Huzzah, а провод сигнала с сервоприводом (оранжевый) прикрепляется к контакту «13 / MOSI».
Шаг 3: Программное обеспечение
Наше устройство использует элемент html «canvas» для графики, а также события холста «touchstart», «touchmove» и «touchhend» для управления (см. Https://www.w3schools.com/graphics/canvas_intro.asp). Мы полагаем, что программное обеспечение должно работать на устройствах с сенсорным экраном отличных от iOS, но из-за нехватки времени не смогли подтвердить.
Мы разработали программное обеспечение для работы в беспроводных режимах AP (точка доступа) и станции (Wi-Fi-маршрутизатор). Если вы решили управлять Жуком в режиме AP, беспроводной маршрутизатор не требуется, так как ваше устройство iOS напрямую связывается с игрушкой. Чтобы работать в этом режиме, вы перейдете на настройки Wi-Fi на устройстве iOS и выберите сеть «LadyBuggy». После подключения откройте веб-браузер на устройстве iOS и введите IP-адрес «192.128.20.20» в поле url.
Если вы решите управлять игрушкой в режиме станции, вы будете общаться с ней через беспроводной маршрутизатор и, следовательно, вам нужно будет изменить программное обеспечение, чтобы установить «sSsid =» на ваш беспроводной маршрутизатор ssid и «sPassword =» к вашему паролю беспроводного маршрутизатора.
Вам нужно будет изменить эти параметры, используя редактор IDE Arduino, прежде чем компилировать и загружать его в вашу игрушку. Обратите внимание, что при использовании режима станции мы также включили поддержку MDNS, которая позволяет вам общаться с Жуком по ip-адресу ladybug.local, поэтому физический IP-адрес не требуется. Однако, если вы хотите использовать физический IP-адрес, назначенный вашим беспроводным маршрутизатором, вам нужно будет подключиться к серийному монитору Arduino при включении Жука (убедитесь, что «#define USE_SERIAL 1» находится в верхней части исходного кода файл перед компиляцией и отправкой кода), чтобы просмотреть IP-адрес, назначенный устройству вашим беспроводным маршрутизатором.
После того, как вы решите, в каком режиме вы будете управлять своей игрушкой и внесете необходимые изменения в программное обеспечение, соедините USB компьютера и micro usb на игрушке, используйте ползунковый переключатель для питания на Божьей коровке, затем скомпилируйте и загрузите программное обеспечение в неё.
////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // // Buggy // // // ////////////////////////////////////////////////////////////////////////////////////////////////////////////// #define USE_SERIAL 1 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Library includes. // ////////////////////////////////////////////////////////////////////////////////////////////////////////////// #include <Adafruit_FeatherOLED.h> // for the Adafruit Featherwing oled #include <ESP8266WebServer.h> // for the html web server (web page) #include <ESP8266mDNS.h> // for MDNS #include <WebSocketsServer.h> // for the socket server (data transmission) #include <Servo.h> // for servo drive ////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Constants. // ////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Buttons on Oled. #define BUTTON_A 0 // button A pin #define BUTTON_B 16 // button B pin #define BUTTON_C 2 // button C pin // Oled display. // Dimensions. #define DISPLAY_HEIGHT 32 // height of afOled display in pixels #define DISPLAY_WIDTH 128 // width of afOled display in pixels // Font dimensions (estimated). #define FONT_ONE_HEIGHT 8 // height of font one character #define FONT_ONE_WIDTH 6 // width of font one character #define FONT_TWO_HEIGHT 14 // height of font two character #define FONT_TWO_WIDTH 12 // width of font two character // Port numbers. #define PORT_HTTP 80 // port number for http #define PORT_WS 2205 // port number for socket // Servo. #define SERVO_OFF 90 // value to stop servo ////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Variables. // ////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Buttons. static int nButtonA = 0; // button a pressed (1 = pressed) static int nButtonB = 0; // button b pressed (1 = pressed) static int nButtonC = 0; // button c pressed (1 = pressed) // Oled. Adafruit_FeatherOLED afOled = Adafruit_FeatherOLED(); // oled display // Servos. Servo ServoLeft; // left servo Servo ServoRight; // right servo // Wifi. // Acccess point ssid. IPAddress IpAddress(192,168,20,20); // access point ip address IPAddress IpGateway(192,168,20,1); // access point gateway IPAddress IpSubnet(255,255,255,0); // access point subnet mask String sSsidLadyBuggygy = "LadyBuggygy"; // access point ssid // Servers (http and sw). int nX = 50; // servo x int nY = 50; // servo y ESP8266WebServer wsWebServer(PORT_HTTP); // html server WebSocketsServer webSocket = WebSocketsServer(PORT_WS); // socket server // Wifi router password, wifi router ssid and access point ssid. String sPassword = "your_router_password"; // router and access point password String sSsidAccessPoint = "LadyBuggy"; // access point ssid String sSsidRouter = "your_router_ssid"; // router ssid ////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Lady Buggy web page (client). // ////////////////////////////////////////////////////////////////////////////////////////////////////////////// // The Lady Buggy web page string consists of both Javascript (for touch control, touch control graphics // and data transmission), and html (for the web page). String LadyBuggyWebPage= ////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Javascript content of web page string. // ////////////////////////////////////////////////////////////////////////////////////////////////////////////// "<script type='text/javascript'>\n" // // Variables. // "var canvasLadyBuggy;\n" "var canvasLadyBuggyHeight = 0;\n" "var canvasLadyBuggyWidth = 0;\n" "var contextLadyBuggy;\n" "var nLadyBuggyDelay = 0;\n" "var nLadyBuggyPort =" + String(PORT_WS) + ";\n" "var nLadyBuggyX = 0;\n" "var nLadyBuggyXN1 = -1;\n" "var nLadyBuggyY = 0;\n" "var nLadyBuggyYN1 = -1;\n" "var touchlistLadyBuggy = [];\n" "var wsLadyBuggy = new WebSocket('ws://' + location.hostname + ':' + nLadyBuggyPort + '/');\n" // // Utilities. // // // sendLadyBuggyXY() // Send the nLadyBuggyX and nLadyBuggyX values to the server. // Entry : nothing // Returns : nothing // // Notes : // // The server (the lady buggy itself) is expecting the header "zpllc" immediately // followed by the x and y touch coordinates in the range of 0 through 99, with // leading zeros if necessary. "function sendLadyBuggyXY()\n" "{\n" // Convert x and y ints to strings. "var stringX = String(nLadyBuggyX);\n" "var stringY = String(nLadyBuggyY);\n" // The server is expecting 2 digit values for x and y (00 through 99), // so add leading zero(s) to the strings as required. "while(stringX.length < 2)\n" "stringX = '0' + stringX;\n" "while(stringY.length < 2)\n" "stringY = '0' + stringY;\n" // Combine the strings with the server validation header. // // Notes: // // Again, the server is expecting an ascii string formatted as follows: // // "zpllcXXYY" // // where: // // "zpllc": is a header for server validation of the message string, // "XX" : is the x value, // "YY" : is the y value. // "stringX = 'zpllc' + stringX + stringY;\n" // Send the result to the server. "wsLadyBuggy.send(stringX);\n" "}\n" // // drawLadyBuggyTouchImage(x, y) // Draw the touch image on the canvas. // Entry : x and y location of where to draw the image // Returns : nothing // "function drawLadyBuggyTouchImage(x, y)\n" "{\n" // Start a drawing path. "contextLadyBuggy.beginPath();\n" // Draw a circle. "contextLadyBuggy.arc(x, y, 40, 0, 2*Math.PI, true);\n" "contextLadyBuggy.fillStyle = 'rgba(200, 0, 0, 0.2)';\n" "contextLadyBuggy.fill();\n" "contextLadyBuggy.lineWidth = 2.0;\n" "contextLadyBuggy.strokeStyle = 'rgba(200, 0, 0, 0.8)';\n" // Present the drawing path. "contextLadyBuggy.stroke();\n" "}\n" // // onloadLadyBuggy() // Called by the html code when the web page is loaded. // Entry : nothing // Returns : nothing // "function onloadLadyBuggy()\n" "{\n" // Obtain the canvas from the html portion of the web page. "canvasLadyBuggy = document.getElementById('canvasLadyBuggy');\n" // Obtain a drawing context for the canvas. "contextLadyBuggy = canvasLadyBuggy.getContext('2d');\n" // Initialize the canvas. "canvasLadyBuggyWidth = window.innerWidth;\n" "canvasLadyBuggyHeight = window.innerHeight;\n" "canvasLadyBuggy.style.width = canvasLadyBuggyWidth +'px';\n" "canvasLadyBuggy.style.height = canvasLadyBuggyHeight + 'px';\n" "canvasLadyBuggy.width = canvasLadyBuggyWidth;\n" "canvasLadyBuggy.height = canvasLadyBuggyHeight;\n" // Draw the initial touch image. "drawLadyBuggyTouchImage(window.innerWidth / 2, window.innerHeight / 2);\n" // Create a function for the "touchstart" event. "canvasLadyBuggy.addEventListener('touchstart', function(event)\n" "{\n" // Obtain list of touch points (we only use the first one in Lady Buggy). "touchlistLadyBuggy = event.touches;\n" // Check for existance of a touch point. "if(touchlistLadyBuggy.length)\n" "{\n" // Have a touchpoint, update x. "nLadyBuggyX = parseInt((100 * touchlistLadyBuggy[0].pageX) / canvasLadyBuggyWidth);\n" "nLadyBuggyX = (nLadyBuggyX > 0) ? (nLadyBuggyX < 99) ? nLadyBuggyX : 99 : 0;\n" // Update y. "nLadyBuggyY = parseInt((100 * touchlistLadyBuggy[0].pageY) / canvasLadyBuggyHeight);\n" "nLadyBuggyY = (nLadyBuggyY > 0) ? (nLadyBuggyY < 99) ? nLadyBuggyY : 99 : 0;\n" // Send x and y position data to the server. // Update n-1 values. "nLadyBuggyXN1 = nLadyBuggyX;\n" "nLadyBuggyYN1 = nLadyBuggyY;\n" "nLadyBuggyDelay = 8;\n" // Send x, y. "sendLadyBuggyXY();\n" // Update the touch image position. "contextLadyBuggy.clearRect(0, 0, canvasLadyBuggyWidth, canvasLadyBuggyHeight);\n" "drawLadyBuggyTouchImage(touchlistLadyBuggy[0].pageX, touchlistLadyBuggy[0].pageY);\n" "}\n" "});\n" // Create a function for the "touchmove" event. "canvasLadyBuggy.addEventListener('touchmove', function(event)\n" "{\n" // No scrolling during touch moves. "event.preventDefault();\n" // Obtain list of touch points. "touchlistLadyBuggy = event.touches;\n" // Check for existance of a touch point. "if(touchlistLadyBuggy.length)\n" "{\n" // Have a touchpoint, update x. "nLadyBuggyX = parseInt((100 * touchlistLadyBuggy[0].pageX) / canvasLadyBuggyWidth);\n" "nLadyBuggyX = (nLadyBuggyX > 0) ? (nLadyBuggyX < 99) ? nLadyBuggyX : 99 : 0;\n" // Update y. "nLadyBuggyY = parseInt((100 * touchlistLadyBuggy[0].pageY) / canvasLadyBuggyHeight);\n" "nLadyBuggyY = (nLadyBuggyY > 0) ? (nLadyBuggyY < 99) ? nLadyBuggyY : 99 : 0;\n" // Send x and y position data to the server. // // Notes: // // In this application, there is no need to continuously send data to the server, // so nLadyBuggyDelay is incorporated to send data to the server every 16 passes if // either the x or y values have changed. "if(((nLadyBuggyXN1 != nLadyBuggyX) || (nLadyBuggyYN1 != nLadyBuggyY)) && ((nLadyBuggyDelay --) <= 0))\n" "{\n" // x or y has changed and delay is up, update n-1 values and reset delay. "nLadyBuggyXN1 = nLadyBuggyX;\n" "nLadyBuggyYN1 = nLadyBuggyY;\n" "nLadyBuggyDelay = 16;\n" // Send x, y. "sendLadyBuggyXY();\n" "}\n" // Update the touch image position. "contextLadyBuggy.clearRect(0, 0, canvasLadyBuggyWidth, canvasLadyBuggyHeight);\n" "drawLadyBuggyTouchImage(touchlistLadyBuggy[0].pageX, touchlistLadyBuggy[0].pageY);\n" "}\n" "});\n" // Create a function for the "touchend" event. "canvasLadyBuggy.addEventListener('touchend', function()\n" "{\n" // At the end of the touch, return to center thus stopping Lady Buggy. "nLadyBuggyX = 50;\n" "nLadyBuggyY = 50;\n" // Send x, y. "sendLadyBuggyXY();" // Draw the touch image. "contextLadyBuggy.clearRect(0, 0, canvasLadyBuggyWidth, canvasLadyBuggyHeight);\n" "drawLadyBuggyTouchImage(canvasLadyBuggyWidth / 2, canvasLadyBuggyHeight / 2);\n" "});\n" "};\n" "</script>\n" ////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // HTML content of web page. // ////////////////////////////////////////////////////////////////////////////////////////////////////////////// "<!DOCTYPE html>\n" "<html>\n" "<head>\n" "<title>Lady Buggy</title>\n" "<meta name='viewport' content='width=device-width, user-scalable=no'>\n" "<style type='text/css'>\n" "body { margin: 0px; overflow: hidden; }\n" "canvas { border: none; }\n" "</style>\n" "</head>\n" "<body onload='onloadLadyBuggy()'>\n" "<canvas id='canvasLadyBuggy' width='300' height='300' style='top:0px; left:0px; width: 300px; height: 300px;'></canvas>\n" "</body>\n" "</html>" ; ////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Lady Buggy setup. // ////////////////////////////////////////////////////////////////////////////////////////////////////////////// void setup() { // Serial. // // Serial is only necessary for debugging. #if USE_SERIAL Serial.begin(115200); while(!Serial){}; #endif // Buttons (the buttons are located on the Adafruit afOled module). pinMode(BUTTON_A, INPUT_PULLUP); pinMode(BUTTON_B, INPUT_PULLUP); pinMode(BUTTON_C, INPUT_PULLUP); // Display. afOled.init(); afOled.clearDisplay(); // Wifi. // Set the wifi mode to access point and station mode. WiFi.mode(WIFI_AP_STA); // Set the station mode ssid and password. WiFi.begin(sSsidRouter.c_str(), sPassword.c_str()); // Set the access point ip address, gateway and subnet. WiFi.softAPConfig(IpAddress, IpGateway, IpSubnet); // Set the access point ssid and password. WiFi.softAP(sSsidAccessPoint.c_str(), sPassword.c_str()); // Server. // Root is the webpage. // // "/" is sent from the http client and is a request for a complete webpage refresh. wsWebServer.on("/", []() { wsWebServer.send(200, "text/html", LadyBuggyWebPage); }); // Start the server. wsWebServer.begin(); // Start the socket. webSocket.begin(); webSocket.onEvent(LadyBuggySocketEvent); // Add http and ws services to MDNS. // // Notes: // // 1) "http" service is for the html portion of the web page and is serviced on port number PORT_HTTP. // 2) "ws" service is for the javascript socket portion of the web page and is serviced on port nomber PORT_WS. MDNS.begin("LadyBuggy", WiFi.localIP()); MDNS.addService("http", "tcp", PORT_HTTP); MDNS.addService("ws", "tcp", PORT_WS); // Servos. ServoLeft.write(SERVO_OFF); ServoLeft.attach(12); ServoRight.write(SERVO_OFF); ServoRight.attach(13); // Send the ip address to the serial monitor. #if USE_SERIAL Serial.print("Lady Buggy: waiting for wifi connect"); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("\nLady Buggy: wifi connect with IP Address : " + WiFi.localIP().toString()); #endif } ////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Lady Buggy Main loop. // ////////////////////////////////////////////////////////////////////////////////////////////////////////////// void loop() { // Update server. wsWebServer.handleClient(); // Update socket. webSocket.loop(); // Update oled display. LadyBuggyDisplay(); // Update buttons. LadyBuggyButtons(); // Give up some time. delay(20); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // LadyBuggyButtons // Update and process push buttons. // Entry : nothing // Returns : nothing // ////////////////////////////////////////////////////////////////////////////////////////////////////////////// void LadyBuggyButtons() { // Variables. static int nButtonAN1 = 1; static int nButtonBN1 = 1; static int nButtonCN1 = 1; // Read buttons. int nDigitalReadA = digitalRead(BUTTON_A); int nDigitalReadB = digitalRead(BUTTON_B); int nDigitalReadC = digitalRead(BUTTON_C); // Process button A. if(nDigitalReadA != nButtonAN1) { // State changed. if(nButtonAN1) { // Pressed. nButtonAN1 = 0; nButtonA = 1; } else { // Released. nButtonAN1 = 1; nButtonA = 0; } } // Process button B. if(nDigitalReadB != nButtonBN1) { // State changed. if(nButtonBN1) { // Pressed. nButtonBN1 = 0; nButtonB = 1; } else { // Released. nButtonBN1 = 1; nButtonB = 0; } } // Process button C. if(nDigitalReadC != nButtonCN1) { // State changed. if(nButtonCN1) { // Pressed. nButtonCN1 = 0; nButtonC = 1; } else { // Released. nButtonCN1 = 1; nButtonC = 0; } } } ////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // LadyBuggyDisplay // Update afOled display. // Entry : nothing // Returns : nothing // ////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // LadyBuggyDisplay // Update the oled display // Entry : nothing // Returns : nothing // void LadyBuggyDisplay() { // Oled display. afOled.clearDisplay(); String sString = WiFi.localIP().toString(); afOled.setTextSize(1); afOled.setCursor((DISPLAY_WIDTH / 2) - ((sString.length() * FONT_ONE_WIDTH) / 2), 0); afOled.print(sString); sString = String(String(nButtonA) + ", " + String(nButtonB) + ", " + String(nButtonC)); afOled.setTextSize(1); afOled.setCursor((DISPLAY_WIDTH / 2) - ((sString.length() * FONT_ONE_WIDTH) / 2), (DISPLAY_HEIGHT / 2) - (FONT_ONE_HEIGHT / 2)); afOled.print(sString); sString = String(String((100 * (nX - 50)) / 50) + ", " + String((100 * (50 - nY)) / 50)); afOled.setTextSize(1); afOled.setCursor((DISPLAY_WIDTH / 2) - ((sString.length() * FONT_ONE_WIDTH) / 2), DISPLAY_HEIGHT - FONT_ONE_HEIGHT); afOled.print(sString); // Present the display. afOled.display(); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // LadyBuggySocketEvent // Process socket client events. // Entry : client number // : event type // : pointer to message received from client // : length of message received from client // Returns : nothing // ////////////////////////////////////////////////////////////////////////////////////////////////////////////// void LadyBuggySocketEvent(unsigned char ClientNumber, WStype_t EventType, unsigned char * Message, int MessageLength) { // Process event type. switch(EventType) { // Process event type connect. case WStype_CONNECTED: { // Display connected client ip and url. IPAddress ip = webSocket.remoteIP(ClientNumber); #if USE_SERIAL Serial.printf("Client #%u connect :\n", ClientNumber); Serial.printf(" ip address : %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]); // Serial.printf(" url : %s\n", Message); #endif // Send a message to client webSocket.sendTXT(ClientNumber, "You are connected."); } break; // Process event type client text. case WStype_TEXT: { // Validate the incoming Lady Buggy data string by checking the first 5 characters for "zpllc". if((Message[0] == 'z') && (Message[1] == 'p') && (Message[2] == 'l') && (Message[3] == 'l') && (Message[4] == 'c')) { // Valid Lady Buggy header, convert incoming Lady Buggy data string to x and y. // Convert the string to double. double data = strtod((const char *) & Message[5], NULL); // Derive and limit the x component. nX = (int)data / 100; nX = (nX > 0) ? (nX < 99) ? nX : 99 : 0; // Derive and limit the y component. nY = (int)data % 100; nY = (nY > 0) ? (nY < 99) ? nY : 99 : 0; // Set the servo values based on the x and y components. int nServoLeftScale = (((nX < 50) ? nX : 50) * 100) / 50; int nServoRightScale = (((nX > 50) ? (100 - nX) : 50) * 100) / 50; ServoLeft.write(SERVO_OFF + ((nServoLeftScale * (nY - 50)) / 100)); ServoRight.write(SERVO_OFF - ((nServoRightScale * (nY - 50)) / 100)); // Send x and y components to the serial monitor. #if USE_SERIAL Serial.printf("Client #%u sent: x = %02d, y = %02d\n", ClientNumber, nX, nY); #endif } else { // Invalid Lady Buggy header, send data to serial monitor. #if USE_SERIAL Serial.printf("Client #%u invalid data: %s\n", ClientNumber, Message); #endif } } break; // Process event type disconnect. case WStype_DISCONNECTED: { // Process client disconnect. #if USE_SERIAL Serial.printf("Client #%u disconnected.\n", ClientNumber); #endif } break; } }
Шаг 4: Сборка
Процесс сборки показан на рисунках выше. Прикрепите два каждого из уплотнительных колец к каждому из «Gear Wheel.stl», как показано на рисунке. Прикрепите один узел шестерни («Gear Wheel.stl» плюс два O-образных кольца) к «Chassis.stl», используя один «Axle Gear Wheel.stl». Повторите процесс с оставшимся узлом шестерни и осью.
Прикрепите один «Gear Servo.stl» к одному из сервоприводов с помощью винта, поставляемого с сервомеханизмом. Эта сборка должна оставаться герметичной, поэтому при необходимости используйте свой любимый клей. Повторите процесс с помощью оставшегося сервопривода. Вставьте левый сервопривод в левый слот сервопривода в корпусе, как показано на рисунке. Вставьте правый сервопривод в правый слот сервопривода в корпусе.
Поместите батарею в отсек аккумулятора шасси. Закрепите скользящий переключатель на шасси с помощью небольших винтов или клея.Поместите «Battery Cover.stl» на аккумулятор, как показано на рисунке. Оберните проволочный пучок между сервоприводами и платой с помощью электрической ленты, затем поместите микроконтроллер в крышку батарейного отсека.
Поместите шарикоподшипник в шасси и зафиксируйте его с помощью «Шарикоподшипника Cap.stl». Не затягивайте, так как шаровой подшипник должен легко вращаться в шасси. Прикрепите штекер удлинителя кабеля micro usb в Huzzah ESP8266, как показано на рисунке. Закрепите конец шасси с помощью прилагаемых винтов. Используя четыре «Bolt.stl», прикрепите корпус Божьей коровки к шасси.
Шаг 5: Результат
Включите игрушку, используя переключатель. Переключатель, который мы использовали, является центральным выключателем, поэтому его перемещение в любое из положений включает игрушку.
Подключитесь к LadyBuggy с помощью устройства iOS и выбранного вами метода, как описано на шаге "Программное обеспечение".
На дисплее iOS сдвиньте красную кнопку в направлении верхней части дисплея для движения вперед, в направлении нижней части дисплея для обратного движения и влево или вправо для перемещения влево или вправо. Надеемся, вам понравится!
Шаг 6: Итоговое видео
Что у нас получилось и процесс управления вы можете посмотреть на видео ниже.