Продвинутый дистанционно управляемый манипулятор-робот для точной работы
Компоненты и материалы
| Шасси Runt Rover Half-pint | × | 1 |
| Arduino UNO | × | 1 |
| V5 Shield (сенсорный шилд) | × | 1 |
| Перемычки Female/Female | × | 1 |
| Драйвер двигателей L9110S | × | 1 |
| Уголок 90° Single Angle Channel Bracket (585424) | × | 1 |
| Легкая серво-втулка, Futaba | × | 1 |
| Набор стандартного гриппера Kit A (637094) | × | 1 |
| Сервопривод MG995 | × | 1 |
| Стандартная серво-пластина | × | 1 |
| Уголок 90° Single Angle Channel Bracket | × | 1 |
| Короб для 5 АА батарей | × | 1 |
| Накопители АА (NiMH) | × | 5 |
| Нейлоновые распорки .750" 8-32 | × | 2 |
| Винты .500" 6-32 с гайками | × | 8 |
| Винты .3125" 6-32 | × | 8 |
Приложения и сервисы
| Arduino IDE |
О проекте
Несколько месяцев назад сын попросил сделать радиоуправляемого бота. Он дал список желаний, мы сузили его до реалистичного. Вот что получилось...
- Соедините UNO и V5 Sensor Shield
- Установите собранную плату в держак в центре бота
- Двусторонним скотчем зафиксируйте драйвер двигателей на левой внутренней стенке, Bluetooth-модуль — на правой
Шасси можно сделать самим или выбрать другое — на ваш выбор.
Шаг 1: Необходимое ПО
- Arduino IDE
- Python 2.7 (полная установка с tkinter)
- Библиотека pySerial
- Библиотека L9110S motor controller (приложен .zip — см. файлы шага)
- Код робота (ниже или .zip в файлах шага)
- Python-приложение для удаленного управления (файлы шага)
Шаг 2: Спецификация железа (BOM)
- Шасси Runt Rover Half-pint или подходящий 4WD закрытый аналог
- Arduino Uno или похожая плата с USB-кабелем
- V5 sensor shield
- Драйвер двигателей L9110S (возьмите пару — дешево)
- Сервопривод MG995 или аналогичный ×2
- Bluetooth-модуль HC-05 или HC-06 ×1
- Стандартная серво-пластина B ×1
- Уголок 90° ×1
- Одинарный уголок ×2
- Легкая серво-втулка (525125 для Futaba) ×1
- Набор стандартного гриппера Kit A ×1
- Перемычки Female-Female
- 5 аккумуляторов АА (NiMH) и зарядное устройство
- Двусторонний скотч и небольшие стяжки
- Короб для 5 АА (если выбираете NiMH)
- Аккумуляторный пак 6V NiMH или 7.4V Li-ion с зарядкой
- Винты 1.250" 6-32 ×2
- Нейлоновые распорки .750" 8-32 ×2
- Винты .500" 6-32 с гайками ×8
- Винты .3125" 6-32 ×8
Детали можно заказать на eBay или у Sparkfun, Adafruit, ServoCity.
Шаг 3: Сборка шасси
Соберите шасси по инструкции или видео. Плата контроллера установите в средние отверстия — так останется место спереди и сзади.
ВАЖНО: Перед дальнейшей работой снимите все 4 колеса, чтобы не повредить моторы при установке остальных компонентов.
Шаг 4: Сборка гриппера
Соберите гриппер по инструкции из видео.
Шаг 5: Монтаж гриппера — Этап 1
Нужен: уголок 90°, серво-втулка, 4 винта .3125".
- Установите серво-втулку на одну сторону уголка, закрепите винтами .3125". Отложите.
- Накрутите гайки на два коротких винта.
- Возьмите два одинарных уголка, винты 1.250", два винта .500" с гайками, 2 нейлоновые распорки, серво-пластину B.
- Один одинарный уголок поставьте внутри бота, пройдите 2 винта 1.250" в левые отверстия (изнутри) и 2 винта .500" в правые. Головки винтов — внутри.
- Второй одинарный уголок навиньте на винты снаружи бота.
- Нанесите нейлоновые распорки на длинные винты (1.250"), закрепите серво-пластину.
- Затяните винты до серво-пластины hex-ключом или отверткой.
Используйте фото для ориентации.






Шаг 6: Монтаж гриппера — Этап 2
- Установите оставшийся сервопривод в серво-крепеж с валом вверх. Закрепите 4 винтами .3125".
- Установите гриппер на уголок 90° с серво-втулкой: 4 винта .500" с 2 гайками 8-32 как распорки между уголком и гриппером. Закрепите гайкой сверху.
- Наденьте гриппер на вал сервопривода, закрепите серво-винтом (из комплекта сервопривода).
Пропустите провода сервоприводов через отверстие пластины внутрь бота.





Шаг 7: Монтаж электроники
- Соедините UNO и V5 Sensor Shield
- Установите в центральный держак
- Двусторонним скотчем: драйвер двигателей — левая стенка, Bluetooth — правая



Шаг 8: Проводка — Моторы
- A-1A (драйвер) → пин 5 (шилд)
- A-1B → пин 6
- B-1A → пин 3
- B-1B → пин 11
Робот смотрит от вас. ЛЕВАЯ сторона:
- Два ЧЕРНЫХ провода → первый клеммник Motor A
- Два КРАСНЫХ провода → второй клеммник Motor A
ПРАВАЯ сторона:
- Два ЧЕРНЫХ провода → первый клеммник Motor B
- Два КРАСНЫХ провода → второй клеммник Motor B
Сервоприводы:
- Y (вертикаль) → пин 2 шилда (белое/оранжевое — сигнал)
- X (гриппер) → пин 7 шилда (белое/оранжевое — сигнал)
Шаг 9: Проводка Bluetooth-модуля
- Bluetooth Tx → пин 0 шилда
- Bluetooth Rx → пин 1 шилда
Шаг 10: Питание
- Питание от 5 АА (или 6V пак) → клеммник питания шилда: Красный → Vcc, Черный → GND
- Джампер на V5 sensor shield должен быть на месте
- GND на L9110S → GND на шилде
- Плюс от моторного аккумулятора (6V или 7.2V) → Vcc на L9110S
- Минус (GND) от моторного аккумулятора → GND на моторном шилде
Шаг 11: Настройка HC05/HC06 Bluetooth
Зайдите в настройки Bluetooth на ПК (Панель управления / Система) или погуглите для вашей ОС: Windows, Linux (blueman на Mint), Mac. Запишите имя/номер последовательного порта, присвоенный модулю.
Шаг 12: Загрузка кода
Проверив проводку дважды, загружаем код. Установите Arduino IDE по инструкции на сайте Arduino.
Установите библиотеку L9110 Driver: скачайте L9110Driver.zip (ШАГ 1), распакуйте в папку libraries Arduino или следуйте инструкции по добавлению библиотеки.
Загрузите код робота из blue_t_slave.zip (ШАГ 1) в Arduino IDE. Файлы также в этом шаге.
Подключите ПК и Arduino USB. В IDE: Tools → Board → Uno (или ваша плата). Tools → Port → ваш COM-порт. Нажмите Upload. Если все ок — код загружен, иначе — см. помощь по IDE.
Шаг 13: Запуск Python-приложения управления
Скачайте zip из этого шага, распакуйте. Откройте терминал (cmd.exe), перейдите в папку. Запустите: python rover.py. Должно появиться окно управления. Если нет — проверьте ошибки Python (библиотеки и т.д.).
Включите бота. Введите COM-порт адаптера, нажмите «Connect». Через несколько секунд элементы управления активируются, кнопка Connect отключается — вы подключены. Если не подключается — гуглите настройку Bluetooth.
Управление мышью или клавиатурой:
- Стрелки: вперед, назад, поворот влево 90°, вправо 90°
- a — поворот влево 45°
- s — поворот вправо 45°
- h — стоп
- y — установка оси Y гриппера
- u — открыть/закрыть гриппер
- c — гриппер в домашнюю позицию
Вперед/Назад — постоянные (бот едет до новой команды или Halt). Повороты 90° и 45° — временные (остановка через задержку). Ползунки гриппера не двигают его автоматически — нужно нажать «Set» или клавишу. Диапазон 0-180:
- Y Axis: 0 — полностью вверх, 180 — полностью вниз
- Open/Close: 0 — закрыто, 180 — открыто
Кнопка «Disconnect» останавливает бота и возвращает гриппер домой.

Код
Python Driver GUI
#!/usr/bin/env python
# For Linux, BSD, Mac OSX: chmod +x для исполнения
###########
# Rover control app
# Written by Scott Beasley - 2015
# Free to use or modify. Enjoy.
###########
import sys
import serial
import time
from Tkinter import *
import tkFont
import tkMessageBox
class App(Frame):
def createWidgets(self):
self.connected = False
self.message = StringVar()
helv6 = tkFont.Font(family='Helvetica', size=6, weight='normal')
self.frame = Frame(self.master)
self.frame.pack()
self.f1 = Frame(self.frame)
self.l1 = Label(self.f1, text="Comm Port: ")
self.l1.pack(side=LEFT)
self.comm_entry = Entry(self.f1, bd=5, name="comm_entry")
self.comm_entry.pack(side=LEFT)
self.connectButton = Button(self.f1, text="Connect", command=self.SerialConnect, name="b_connect")
self.connectButton.pack(side=LEFT)
self.disconnectButton = Button(self.f1, text="Disconnect", command=self.SerialDisconnect, name="b_disconnect")
self.disconnectButton.pack(side=RIGHT)
self.f1.grid(row=0, column=0)
self.f2 = LabelFrame(self.frame, bd=3, relief="groove", text="Ground Control")
self.g_vert_fm = Frame(self.f2)
self.grip_vert = Scale(self.g_vert_fm, from_=0, to=180)
self.grip_vert.grid(row=0, column=0, rowspan=4, sticky=W)
self.grip_vert_set = Button(self.g_vert_fm, text="Set", command=self.GripperY, name="b_grip_vert_set", width=1, height=2, font=helv6)
self.grip_vert_set.grid(row=5, column=0, sticky=W)
self.master.bind("", self.GripperY)
self.g_vert_fm.grid(row=0, column=0, rowspan=4, sticky=W)
self.leftforwardButton = Button(self.f2, text="\\", command=self.TurnLeft45, name="b_left_forward")
self.leftforwardButton.grid(row=0, column=1)
self.master.bind("", self.TurnLeft45)
self.leftButton = Button(self.f2, text="<", command=self.TurnLeft, name="b_left")
self.leftButton.grid(row=1, column=1)
self.master.bind("", self.TurnLeft)
self.rightforwardButton = Button(self.f2, text="/", command=self.TurnRight45, name="b_right_forward")
self.rightforwardButton.grid(row=0, column=3)
self.master.bind("", self.TurnRight45)
self.haltButton = Button(self.f2, text="Halt!", command=self.Halt, name="b_halt")
self.haltButton.grid(row=1, column=2)
self.master.bind("", self.Halt)
self.rightButton = Button(self.f2, text=">", command=self.TurnRight, name="b_right")
self.rightButton.grid(row=1, column=3)
self.master.bind("", self.TurnRight)
self.upButton = Button(self.f2, text="^", command=self.Forward, name="b_forward")
self.upButton.grid(row=0, column=2)
self.master.bind("", self.Forward)
self.leftdownButton = Button(self.f2, text="/", command=self.TurnRight45, name="b_left_down")
self.leftdownButton.grid(row=2, column=1)
self.downButton = Button(self.f2, text="V", command=self.Reverse, name="b_reverse")
self.downButton.grid(row=2, column=2)
self.master.bind("", self.Reverse)
self.f2.grid(row=1, column=0, pady=25)
self.rightdownButton = Button(self.f2, text="\\", command=self.TurnLeft45, name="b_right_down")
self.rightdownButton.grid(row=2, column=3)
self.g_horz_fm = Frame(self.f2)
self.grip_horz = Scale(self.g_horz_fm, from_=0, to=180, orient=HORIZONTAL)
self.grip_horz.grid(row=0, column=0, columnspan=7, sticky=E)
self.grip_horz_set = Button(self.g_horz_fm, text="Set", command=self.GripperX, name="b_grip_horz_set", width=1, height=2, font=helv6)
self.grip_horz_set.grid(row=0, column=8)
self.master.bind("", self.GripperX)
self.g_horz_fm.grid(row=4, column=0, columnspan=7, sticky=E)
self.master.bind("", self.GripperHome)
self.f3 = Frame(self.frame)
self.l2 = Label(self.f3, text="Last action: ")
self.l2.pack(side=LEFT)
self.l3 = Label(self.f3, text=" ", textvariable=self.message)
self.l3.pack(side=RIGHT)
self.f3.grid(row=3, column=0, pady=8)
def CtrlButtonsState(self, bstate):
for btn in [self.leftforwardButton, self.leftButton, self.rightforwardButton, self.rightButton,
self.upButton, self.leftdownButton, self.downButton, self.rightdownButton,
self.haltButton, self.disconnectButton,
self.grip_horz, self.grip_vert, self.grip_horz_set, self.grip_vert_set]:
btn.config(state=bstate)
def ConnCtrlsState(self, bstate):
self.connectButton.config(state=bstate)
self.comm_entry.config(state=bstate)
def SerialConnect(self):
try:
self.ser = serial.Serial(self.comm_entry.get(), 9600)
except IOError:
tkMessageBox.showerror("Invalid comm port", "Comm port not found.")
return
self.ConnCtrlsState(DISABLED)
self.CtrlButtonsState(NORMAL)
self.message.set("SerialConnect")
self.connected = True
time.sleep(3)
def SerialDisconnect(self):
try:
self.send_cmd('h', "Halt!")
time.sleep(1)
self.ser.close()
except IOError:
print("Could not close port...")
self.message.set("SerialDisconnect")
self.ConnCtrlsState(NORMAL)
self.CtrlButtonsState(DISABLED)
self.connected = False
time.sleep(2)
def send_cmd(self, action, msg):
if self.connected:
for val in action:
self.ser.write(val)
self.ser.flush()
self.message.set(msg)
def TurnLeft(self, event=None): self.send_cmd('a', "Left")
def TurnLeft45(self, event=None): self.send_cmd('q', "Left45")
def TurnRight(self, event=None): self.send_cmd('s', "Right")
def TurnRight45(self, event=None): self.send_cmd('e', "Right45")
def Forward(self, event=None): self.send_cmd('w', "Up")
def Reverse(self, event=None): self.send_cmd('z', "Down")
def Halt(self, event=None): self.send_cmd('h', "Halt!")
def GripperX(self, event=None):
grp_change = ('>', chr(self.grip_horz.get()), chr(255))
self.send_cmd(grp_change, "Gripper X")
def GripperY(self, event=None):
grp_change = ('^', chr(self.grip_vert.get()), chr(255))
self.send_cmd(grp_change, "Gripper Y")
def GripperHome(self, event=None):
self.send_cmd(('c', chr(255)), "Gripper Home")
def __init__(self, master=None):
Frame.__init__(self, master)
self.pack()
self.createWidgets()
self.CtrlButtonsState(DISABLED)
def main():
root = Tk()
root.geometry("450x350")
root.wm_title("Rover Control Center (RCC)")
app = App(master=root)
app.mainloop()
if __name__ == '__main__':
main()
Rover code (Arduino)
/* Bluetooth Rover. Следует командам, посланным магически через воздух! Или через USB :)
Written by Scott Beasley - 2015. Free to use or modify. Enjoy. */
#include <L9110Driver.h>
#include <Servo.h>
#define SERVO_Y 2 // Пин сервопривода Y гриппера
#define SERVO_CLAW 7 // Пин сервопривода клешни
#define pinAIN1 5 // I1 интерфейс
#define pinAIN2 6 // I2 интерфейс
#define pinBIN1 3 // I3 интерфейс
#define pinBIN2 11 // I4 интерфейс
// Скорости
#define MAXFORWARDSPEED 225
#define MAXBACKWARDSPEED 225
#define TOPSPEED 255 // Для лучшего поворота на ковре/шероховатостях
// Задержки
#define TURNDELAY 475
#define TURNDELAY45 235
#define BACKUPDELAY 400
#define SERVOMOVEDELAY 200
#define SERVOSEARCHDELAY 85
L9110_Motor motor_left(pinAIN1, pinAIN2);
L9110_Motor motor_right(pinBIN1, pinBIN2);
Servo grip_y_servo;
Servo grip_servo;
void setup() {
Serial.begin(9600);
grip_y_servo.attach(SERVO_Y);
grip_y_servo.write(90);
grip_servo.attach(SERVO_CLAW);
grip_servo.write(90);
delay(500);
}
void loop() {
byte command = 0, val = 0;
if (Serial.available() > 0) {
command = Serial.read();
}
switch (command) {
case 'w': go_forward(); break;
case 'z': go_backward(); break;
case 'a': go_left(); delay(TURNDELAY); halt(); break;
case 's': go_right(); delay(TURNDELAY); halt(); break;
case 'q': go_left(); delay(TURNDELAY45); halt(); break;
case 'e': go_right(); delay(TURNDELAY45); halt(); break;
case 'h': halt(); break;
case '>':
val = Serial.read();
grip_servo.write(constrain(val, 64, 179));
break;
case '^':
val = Serial.read();
grip_y_servo.write(constrain(val, 53, 179));
break;
case 'c':
grip_y_servo.write(90);
grip_servo.write(90);
break;
case 255:
Serial.flush();
break;
}
Serial.flush();
delay(125);
}
void go_forward() {
ramp_it(MAXFORWARDSPEED, FORWARD, FORWARD);
motor_left.setSpeed(MAXFORWARDSPEED);
motor_right.setSpeed(MAXFORWARDSPEED);
motor_left.run(FORWARD|RELEASE);
motor_right.run(FORWARD|RELEASE);
}
void go_backward() {
ramp_it(MAXBACKWARDSPEED, BACKWARD, BACKWARD);
motor_left.setSpeed(MAXBACKWARDSPEED);
motor_right.setSpeed(MAXBACKWARDSPEED);
motor_left.run(BACKWARD|RELEASE);
motor_right.run(BACKWARD|RELEASE);
}
void go_left() {
ramp_it(TOPSPEED, BACKWARD, FORWARD);
motor_left.setSpeed(TOPSPEED);
motor_right.setSpeed(TOPSPEED);
motor_left.run(BACKWARD|RELEASE);
motor_right.run(FORWARD|RELEASE);
}
void go_right() {
ramp_it(TOPSPEED, FORWARD, BACKWARD);
motor_left.setSpeed(TOPSPEED);
motor_right.setSpeed(TOPSPEED);
motor_left.run(FORWARD|RELEASE);
motor_right.run(BACKWARD|RELEASE);
}
void halt() {
motor_left.setSpeed(0);
motor_right.setSpeed(0);
motor_left.run(BRAKE);
motor_right.run(BRAKE);
}
void ramp_it(uint8_t speed, uint8_t lf_dir, uint8_t rt_dir) {
uint8_t ramp_val = 0, step_val = 0;
step_val = abs(speed / 4);
if (!speed) step_val = -step_val;
for (uint8_t i = 0; i < 4; i++) {
ramp_val += step_val;
motor_left.setSpeed(ramp_val);
motor_right.setSpeed(ramp_val);
motor_left.run(lf_dir|RELEASE);
motor_right.run(rt_dir|RELEASE);
delay(25);
}
}
L9110 Driver
Драйвер L9110 для Arduino: GitHub
Печатные платы и корпуса
4wdgripperbt2.fzz
Схемы
4wdgripperbt2.fzz
Производственный процесс
- Многопозиционная система датчиков температуры для интеграции в умный дом
- DIY-контроллер паяльника 862D+ — точность и надёжность
- MotionSense: умная система обнаружения проникновения на Arduino и ESP8266
- Пожарная безопасность 3D-принтера: умная система обнаружения дыма
- Магнитная левитация на отталкивании с Arduino: Простая схема и DIY-руководство
- Высокопроизводительный регистратор данных для метеозонда на Arduino
- ArduFarmBot Часть 2: Удалённая IoT-станция управления фермой
- CoroFence: термический детектор на GridEye + PIR с IoT
- Облачный мониторинг: система удаленного контроля для управления активами в реальном времени
- 5 ключевых преимуществ удаленного контроля производства для современной промышленности