메뉴 전체보기

회원메뉴

DIY 원격 조종 물총 로봇 > 게시판

본문 바로가기

쇼핑몰 검색

NO. 3066
제목 : DIY 원격 조종 물총 로봇
2026-08-24 10:30

소개: DIY 원격 조종 물총 로봇


지난 여름, 친구들이 예고도 없이 우리 집 문 앞에 나타나 물총으로 나를 기습했다. 이번 여름에는 미리 대비를 해두기로 했다.

물총은 아이들에게 빼놓을 수 없는 여름철 필수품입니다. 많은 사람들이 잔디밭을 뛰어다니며 친구들에게 가차 없이 물을 뿌리던 추억을 간직하고 있습니다. 전장을 가로지르는 끊임없는 물줄기 덕분에 무더운 여름날이 훨씬 더 즐겁고 상쾌해집니다.

하지만 공대를 다니는 대학생인 지금은 예전만큼 여기저기 뛰어다닐 힘이 별로 없어요. 그래서 물총 로봇이라는 아이디어를 떠올렸죠. 바로 원격 조종이 가능한 로봇으로, 제가 대신 친구들(그리고 식물들)에게 물을 뿌려줄 수 있는 로봇이에요.




STEP 1. 준비물


준비물


전자 제품:

구동 모터 2개 Amazon

서보 모터 Amazon

ESP32 Amazon (참고: 코드를 약간 수정하면 어떤 ESP32를 사용해도 됩니다)

워터 펌프 Amazon

배터리 Amazon

벅 컨버터 Amazon

H 브리지 Amazon

방수 스위치 Amazon


전기 부품:

브레드보드 Amazon

전선 Amazon

전기 커넥터 Amazon

전원 분배 보드 Amazon

납땜용 납 Amazon


로봇 본체:

워터 튜브 Amazon

핫 글루건 Amazon

덕트 테이프 Amazon

너트와 볼트 Amazon

식품 용기 (주방에서 구함) Amazon

플라스틱 물병 (주방에서 구함)

3D 프린터 (선택 사항, DIY 대안은 2단계를 참조)


소프트웨어

Arduino IDE arduino.cc/en/software/




STEP 2. 전자 부품 연결하기


전자 부품 연결하기


전자 부품 연결하기


각 전자 부품은 물을 펌핑하거나 신호를 수신하는 등 간단한 작업을 수행합니다. 이러한 모든 전자 부품을 하나로 통합하면 정교한 로봇을 만들 수 있습니다.

이러한 전자 부품들을 연결하기 위해 XT 30 커넥터를 사용했습니다. 이 커넥터는 조립이 간편하고 안정적으로 연결할 수 있게 해 줍니다. 전선이 미리 연결된 커넥터를 구입하거나 직접 납땜할 수도 있습니다.

물과 전기는 당연히 섞이지 않으므로, 나중에 이 부품들을 방수 식품 용기에 넣을 것입니다.


연결 1: 배터리에서 스위치로

스위치는 배터리를 나머지 전자 부품들과 연결합니다. 스위치를 전환하면 로봇의 전원이 켜지거나 꺼집니다.

연결 2: 스위치에서 전원 분배 보드로

이 보드는 나머지 전자 부품들에 전원을 안정적으로 분배합니다.

연결 3: 전원 분배 보드에서 L298N (x2)으로

L298N 모터 드라이버의 12V와 GND를 전원 분배 보드에 연결하십시오. 그런 다음 나사 단자를 사용하여 모터 드라이버를 펌프 및 구동 모터에 연결하십시오.

연결 4: 전원 분배 보드에서 벅 컨버터로

ESP32와 서보는 5볼트 정격입니다. 배터리는 약 12볼트이므로, 벅 컨버터를 사용하여 5볼트를 효율적이고 안전하게 출력합니다.

연결 5: 벅 컨버터에서 서보로 연결

서보의 전원 핀과 접지 핀을 벅 컨버터의 출력 측에 연결하십시오.

연결 6: 벅 컨버터에서 ESP32로

벅 컨버터의 출력을 ESP32의 5V 및 GND 핀에 연결하십시오.




STEP 3. ESP32 배선하기


ESP32 배선하기


ESP32는 모든 모터에 신호를 전송합니다. ESP32에는 많은 핀이 있지만, 그중 일부는 다른 기능을 수행하므로 사용 중인 ESP32 보드의 핀 배열도를 확인하는 것이 중요합니다. 간단한 전기 연결을 위해 ESP32를 브레드보드에 배치했습니다.

이 단계에서는 ESP32의 핀을 모터 드라이버와 서보에 연결합니다. 점퍼선을 사용하면 브레드보드와 전자 부품을 쉽게 연결할 수 있습니다.

다음 핀을 사용했습니다:
// ------------------------------------------------------------
// LEFT MOTOR
// ------------------------------------------------------------

const int LEFT_IN1 = 4;
const int LEFT_IN2 = 5;
const int LEFT_PWM = 21;

// ------------------------------------------------------------
// RIGHT MOTOR
// ------------------------------------------------------------

const int RIGHT_IN1 = 6;
const int RIGHT_IN2 = 7;
const int RIGHT_PWM = 8;

// ------------------------------------------------------------
// PUMP
// ------------------------------------------------------------

const int PUMP_IN1 = 41;
const int PUMP_IN2 = 42;
const int PUMP_PWM = 2;

// ------------------------------------------------------------
// SERVO
// ------------------------------------------------------------

const int SERVO_PIN = 1;




STEP 4. 플랫폼 구축


플랫폼 구축


이 프로젝트를 진행하던 중 3D 프린터가 고장 나서, 우리는 Instructables 특유의 꺾이지 않는 DIY 정신을 발휘해 집안 곳곳에 있는 물건들을 활용하여 3D 모델링 부품 대부분을 대체하기로 했습니다. 3D 프린터를 사용할 수 없는 경우를 위한 일반적인 대체 재료도 함께 목록으로 제시했습니다. 그렇지 않다면 3D 모델은 이 단계 하단에 첨부되어 있습니다.


로봇 본체 (1개)

로봇의 나머지 부분을 지지하고 모터와 바퀴를 부착할 지점을 제공하는 플랫폼.

DIY 대체품: 골판지 상자 - 음식 용기와 크기가 비슷한 골판지 상자를 찾아 본체 모델에 맞게 구멍을 자릅니다.

바퀴 (4개)

D자형 축에 맞는 구멍이 있는 원형 부품입니다. 아래에는 바퀴 CAD 파일이 두 개 있습니다. 하나는 모터에 연결되는 바퀴용이고, 다른 하나는 피동 바퀴(모터가 없는 바퀴)용입니다.

DIY 대체품: 병뚜껑 - 축이 들어갈 수 있도록 뚜껑 중앙에 구멍을 잘라냅니다. 그런 다음 핫멜트 접착제로 뚜껑을 축에 연결합니다.

축 (2개)

자유롭게 회전하면서 피동 바퀴를 부착할 수 있게 합니다.

DIY 대체품: 너트와 볼트 - 피동 바퀴와 본체에 볼트를 관통시킵니다. 그런 다음 반대편에 너트를 조입니다.

모터 홀더 (2개)

모터를 본체에 고정합니다. 너트와 볼트를 끼울 수 있는 구멍이 있습니다.

DIY 대체품: 케이블 타이와 핫멜트 접착제 - 모터 주변의 구멍에 케이블 타이를 끼워 고정합니다. 그런 다음 핫멜트 접착제로 연결 부위를 안정시킵니다.


참고: 이 부품들은 마찰 끼워 맞춤 방식으로 설계되었습니다. 부품이 너무 크게 출력된 경우 약간의 사포질이 필요할 수 있습니다.




STEP 5. 프로그래밍 및 제어


프로그래밍 및 제어


3. 프로그래밍 및 제어

Arduino IDE를 사용하여 C++로 모터, 서보 및 펌프 제어 프로그램을 작성했습니다. 이 프로그램을 직접 사용하려면 아래 코드를 다운로드한 후 Wi-Fi 인증 정보와 핀 번호를 변경하세요.

PC가 ESP로 명령을 전송할 수 있도록 웹 서버를 사용했으며, ESP는 이 명령에 따라 이동하고 물총을 조정하거나 물을 분사하는 등의 동작을 수행합니다. 이를 위해서는 Wifi 및 WebServer 라이브러리를 사용해야 하며, 이 라이브러리에는 네트워크 정보가 필요합니다.

참고: ssid와 password를 자신의 네트워크 인증 정보에 맞게 변경해야 합니다.

#include <WiFi.h>
#include <WebServer.h>
#include <ESP32Servo.h>

// ============================================================
// WIFI
// ============================================================

const char* ssid = "*********";
const char* password = "*********";

부품의 핀 번호를 확인한 후, 로봇이 실행할 함수(예: moveForward, setPumpPower)를 만들었습니다.

핀 번호를 전역 상수로 지정

참고: 자신의 배선에 맞게 이 값을 변경하세요.
// ------------------------------------------------------------
// LEFT MOTOR
// ------------------------------------------------------------

const int LEFT_IN1 = 4;
const int LEFT_IN2 = 5;
const int LEFT_PWM = 21;

// ------------------------------------------------------------
// RIGHT MOTOR
// ------------------------------------------------------------

const int RIGHT_IN1 = 6;
const int RIGHT_IN2 = 7;
const int RIGHT_PWM = 8;

// ------------------------------------------------------------
// PUMP
// ------------------------------------------------------------

const int PUMP_IN1 = 41;
const int PUMP_IN2 = 42;
const int PUMP_PWM = 2;

// ------------------------------------------------------------
// SERVO
// ------------------------------------------------------------

const int SERVO_PIN = 1;

함수 예시(모든 함수는 코드를 참조하세요):

void moveForward() {

// Left motor forward
digitalWrite(LEFT_IN1, HIGH);
digitalWrite(LEFT_IN2, LOW);

// Right motor forward
digitalWrite(RIGHT_IN1, LOW);
digitalWrite(RIGHT_IN2, HIGH);

ledcWrite(LEFT_PWM, motor_speed);
ledcWrite(RIGHT_PWM, motor_speed);
}

void setPumpPower(int percent) {

pumpPowerPercent = constrain(
percent,
0,
100
);

if (pumpFiring) {

int duty = map(
pumpPowerPercent,
0,
100,
0,
255
);

ledcWrite(PUMP_PWM, duty);
}
}

컴퓨터에서 전송된 명령을 처리하는 함수를 작성하세요.

void handleCommandRequest() {

if (!server.hasArg("c")) {

server.send(
400,
"text/plain",
"Missing command"
);

return;
}

String command = server.arg("c");

handleCommand(command);

server.send(
200,
"text/plain",
"OK"
);
}

// ============================================================
// STATUS
// ============================================================

void handleStatus() {

String response = "";

response += "{";

response += "\"motor_speed\":";
response += String(motor_speed);

response += ",";

response += "\"pump_power\":";
response += String(pumpPowerPercent);

response += ",";

response += "\"pump_firing\":";
response += pumpFiring ? "true" : "false";

response += ",";

response += "\"ip\":\"";
response += WiFi.localIP().toString();
response += "\"";

response += "}";

server.send(
200,
"application/json",
response
);
}

각 명령을 함수와 연결하는 if-else if 문 체인을 만드세요.

// ============================================================
// COMMAND PROCESSING
// ============================================================

void handleCommand(String cmd) {

cmd.trim();

Serial.print("Command: ");
Serial.println(cmd);

// ----------------------------------------------------------
// MOVEMENT
// ----------------------------------------------------------

if (cmd == "F") {

moveForward();

}

else if (cmd == "B") {

moveBackward();

}

else if (cmd == "L") {

turnLeft();

}

else if (cmd == "R") {

turnRight();

}

else if (cmd == "STOP") {

stopMotors();
}

// ----------------------------------------------------------
// SERVO
// ----------------------------------------------------------

else if (cmd.startsWith("SERVO:")) {

int angle = cmd.substring(6).toInt();

angle = constrain(
angle,
0,
180
);

gunServo.write(angle);

Serial.print("Servo: ");
Serial.println(angle);
}

// ----------------------------------------------------------
// MOTOR SPEED
// ----------------------------------------------------------

else if (cmd.startsWith("SPEED:")) {

int percent = cmd.substring(6).toInt();

setMotorSpeed(percent);

Serial.print("Motor speed: ");
Serial.println(percent);
}

// ----------------------------------------------------------
// PUMP
// ----------------------------------------------------------

else if (cmd == "FIRE:START") {

fire(true);

}

else if (cmd == "FIRE:STOP") {

fire(false);

}

else if (cmd.startsWith("PUMP:")) {

int percent = cmd.substring(5).toInt();

setPumpPower(percent);

Serial.print("Pump power: ");
Serial.println(percent);
}

else {

Serial.println("Unknown command");
}
}

제어 페이지 웹사이트 만들기

// ============================================================
// WEB CONTROL PAGE
// ============================================================

void handleRoot() {

String html = R"rawliteral(

<!DOCTYPE html>

<html>

<head>

<meta name="viewport"
content="width=device-width, initial-scale=1">

<title>ESP32-S3 Tank</title>

<style>

body {
font-family: Arial;
text-align: center;
background: #222;
color: white;
}

button {
width: 120px;
height: 70px;
margin: 8px;
font-size: 20px;
}

input {
width: 300px;
}

</style>

</head>

<body>

<h1>ESP32-S3 Tank</h1>

<h2>Movement</h2>

<div>

<button onclick="cmd('F')">
Forward
</button>

</div>

<div>

<button onclick="cmd('L')">
Left
</button>

<button onclick="cmd('STOP')">
STOP
</button>

<button onclick="cmd('R')">
Right
</button>

</div>

<div>

<button onclick="cmd('B')">
Backward
</button>

</div>

<h2>Motor Speed</h2>

<input
type="range"
min="0"
max="100"
value="50"
oninput="speed(this.value)"
>

<p id="speedValue">50%</p>

<h2>Servo</h2>

<input
type="range"
min="0"
max="180"
value="90"
oninput="servo(this.value)"
>

<p id="servoValue">90°</p>

<h2>Pump</h2>

<input
type="range"
min="0"
max="100"
value="50"
oninput="pumpPower(this.value)"
>

<p id="pumpValue">50%</p>

<button onclick="cmd('FIRE:START')">
FIRE
</button>

<button onclick="cmd('FIRE:STOP')">
PUMP OFF
</button>

<script>

function cmd(command) {

fetch(
'/cmd?c=' +
encodeURIComponent(command)
);

}

function speed(value) {

document.getElementById(
'speedValue'
).innerText = value + '%';

cmd('SPEED:' + value);

}

function servo(value) {

document.getElementById(
'servoValue'
).innerText = value + '°';

cmd('SERVO:' + value);

}

function pumpPower(value) {

document.getElementById(
'pumpValue'
).innerText = value + '%';

cmd('PUMP:' + value);

}

</script>

</body>

</html>

)rawliteral";

server.send(
200,
"text/html",
html
);
}
웹 서버용 HTTP 경로
// ==========================================================
// HTTP ROUTES
// ==========================================================

server.on(
"/",
HTTP_GET,
handleRoot
);

server.on(
"/cmd",
HTTP_GET,
handleCommandRequest
);

server.on(
"/status",
HTTP_GET,
handleStatus
);

server.onNotFound(
handleNotFound
);


모터, 서보, 펌프 및 Wi-Fi 연결을 초기화하고 설정하세요.

// ============================================================
// SETUP
// ============================================================

void setup() {

Serial.begin(115200);

delay(500);

Serial.println();
Serial.println("==============================");
Serial.println("ESP32-S3 TANK CONTROLLER");
Serial.println("==============================");

// ==========================================================
// SERVO
// ==========================================================

gunServo.setPeriodHertz(50);

gunServo.attach(
SERVO_PIN,
500,
2500
);

gunServo.write(90);

Serial.println("Servo initialized");


// ==========================================================
// MOTOR GPIO
// ==========================================================

pinMode(LEFT_IN1, OUTPUT);
pinMode(LEFT_IN2, OUTPUT);

pinMode(RIGHT_IN1, OUTPUT);
pinMode(RIGHT_IN2, OUTPUT);


// ==========================================================
// PUMP GPIO
// ==========================================================

pinMode(PUMP_IN1, OUTPUT);
pinMode(PUMP_IN2, OUTPUT);


// ==========================================================
// PWM
//
// Arduino ESP32 Core 3.x:
//
// ledcAttach(pin, frequency, resolution)
// ==========================================================

ledcAttach(
LEFT_PWM,
1000,
8
);

ledcAttach(
RIGHT_PWM,
1000,
8
);

ledcAttach(
PUMP_PWM,
1000,
8
);


// ==========================================================
// SAFE INITIAL STATE
// ==========================================================

stopMotors();

pumpOff();

setMotorSpeed(50);


// ==========================================================
// WIFI
// ==========================================================

WiFi.mode(WIFI_STA);

WiFi.begin(
ssid,
password
);

Serial.print("Connecting to WiFi");

while (
WiFi.status() != WL_CONNECTED
) {

delay(500);

Serial.print(".");
}

Serial.println();

Serial.println("WiFi connected!");

Serial.print("IP address: ");

Serial.println(
WiFi.localIP()
);


// ==========================================================
// START SERVER
// ==========================================================

server.begin();

Serial.println(
"HTTP server started"
);

Serial.println("==============================");
Serial.println("TANK CONTROLLER READY");
Serial.println("==============================");

Serial.print("Open: http://");
Serial.print(WiFi.localIP());
Serial.println("/");
}

프로그램을 실행하는 루프를 만드세요.

void loop() {

server.handleClient();

}

참고: Arduino IDE의 라이브러리 관리자에서 라이브러리를 설치해야 할 수도 있습니다.




STEP 6. 모든 것을 종합해 보면


모든 것을 종합해 보면


모든 것을 종합해 보면


모든 것을 종합해 보면


ESP32 코드를 다운로드하고 수정한 후, USB-C 케이블을 통해 프로그램을 ESP32에 업로드하세요. 그 다음, 방수 식품 용기 안에 배터리, 전원 분배 보드, 모터 드라이버, 벅 컨버터, ESP32를 넣으세요. 그런 다음 모터를 장착할 구멍을 뚫고, 용기를 3D 프린팅으로 제작한 본체에 접착제로 고정하세요.

스위치, 서보, 펌프, 물병을 용기 뚜껑에 부착하고, 전선이 통과할 수 있도록 뚜껑에 구멍을 뚫습니다. 전선을 넣은 후 물이 새지 않도록 이 구멍들을 핫멜트 접착제로 메워주세요. 그런 다음 핫멜트 접착제와 덕트 테이프로 부품을 단단히 고정하세요. 작업이 끝나면 뚜껑을 식품 용기에 덮어 모든 것을 밀봉하세요.

그런 다음, 물병에 구멍을 뚫고 물 호스를 이용해 펌프에 연결합니다. 펌프의 출력을 서보 모터에 접착제로 붙이거나 묶어 발사 각도를 조절합니다. 마지막으로 구동 모터를 로봇 본체에 부착하고 바퀴를 장착합니다.




STEP 7. 친구들에게 스프레이 뿌리기 + 결론


친구들에게 스프레이 뿌리기 + 결론


물병을 채우고, 배터리를 충전한 다음, 물총 로봇을 보내 친구들(혹은 식물들)에게 물을 뿌려보세요! 이런 로봇을 몇 대만 있으면 뒷마당 전장을 완전히 장악할 수 있어요.

이 인스트럭터블의 끝이 이 프로젝트의 끝은 아닙니다. 다양한 노즐을 만들어 물이 얼마나 멀리 뿜어져 나오는지 확인해 보며 물총 로봇을 나만의 스타일로 꾸며보세요. 다양한 구동 시스템을 적용하거나, 나만의 프로그램을 만들거나, 무시무시한 함대를 구성하는 등 계속해서 실험해 볼 수 있습니다.

이 프로젝트를 통해 특히 두드러진 점은 공학의 다재다능함이었습니다. 3D 프린터가 고장 났을 때, 저는 이 프로젝트가 끝날 수도 있겠다고 생각했습니다. 하지만 재빨리 머리를 굴려 집 주변에 있는 이것저것으로 대신할 수 있는 물건을 찾아냈습니다. 창작자로서 우리는 어떤 일이든 해결할 방법을 찾아낼 수 있습니다. 무더운 여름날, (물 분사로) 친구와 가족을 시원하게 해주는 일을 막을 수 있는 건 아무것도 없습니다.


원문: https://www.instructables.com/DIY-Remote-Controlled-Water-Gun-Robot/

좋아요 0
게시판

회사명 공방유니언 주소 각 공방 주소 참조
사업자 등록번호 0000 대표 공방유니언 전화 019-60105846 팩스 0000 이메일 gongbangunion@gmail.com
통신판매업신고번호 0000 개인정보관리책임자 공방유니언
Copyright © 2017 공방유니언. All Rights Reserved.