Pull to refresh
0
Golf Robotics
Производство роботов для сбора мячей для гольфа

[Краудкосилка]-газонокосилка, которой может управлять любой желающий через интернет

Reading time 8 min
Views 15K

У Вас есть минутка? Не могли бы Вы покосить мой газон?


Краткая история разработки на коленке робота-газонокосилки. Управлять ей можно с любой точки земли через интернет. Мечтали почувствовать себя оператором марсохода или лунохода? Всего лишь нужно зайти на сайт mowmylawn.ru и Вы сможете управлять газонокосилкой у меня во дворе!




Предыстория


Вся история с газонокосилками началась летом 2015, мой первый пост на GT как раз был о моем опыте реализации робокосилки из того, что было в гараже.

ТВ



После этого представители компании Robomow предложили использовать их платформу для дальнейшей разработки. Это очень удобно, потому что все вопросы по железу и механике требуют особых навыков и занимают очень много времени.

Я очень хотел организовать конкурс роботов-газонокосилок. Как оказалось дело это нелегкое. Команд было зарегистрировано более 15, но в итоге только трое участников показали ход работ.

Роман Сакович, Минск (Беларусь), 'Belmower'
Шасси: трехколесный робот. Два ведущих колеса, одно свободное.

Электроника: Две платы. Raspberrry Pi — в качестве управляющей системы верхнего уровня. В ее задачи входит планирование маршрута, построение траекторий, и тд. Nucleo stm32 — в качестве исполнительной системы нижнего уровня. В ее задачи входит навигация, опрос датчиков, управление моторами итд.

Навигация: Система комплексирования данных RTK, одометров и ИНС. Это система собственной разработки.

Датчики: Навигационные приемники GPS/GLONASS. Энкодеры моторов для одометрии. Инерциальная система навигации. Ультразвуковые датчики.



Феофанов И.А., Тверь


К сожалению должен сообщить что наша команда, скорее всего, не сможет принять участие в конкурсе. Дело в том что во время первых полевых испытаний в конструкции нашего робота были выявлены определенные недочеты, на исправление которых уйдет некоторое время. Работу над проектом мы приостанавливать не собираемся, но на фоне грядущей сессии, представить даже минимальную версию робота к намеченному сроку — вряд ли сможем(что уж говорить про использование машинного обучения, которое должно было стать нашем сильным преимуществом).

Николай Миронников, Новосибирск



Все усилия по проведению конкурса в Сколково оказались зря. В конце концов оказалось, что свободных газонов для конкурса по робототехнике в Сколково нет. Все возможные спонсоры не хотят связываться с новым конкурсом с неясными перспективами. На письма в муниципальные организации я даже не получил ответ. В итоге у нас была туманная перспектива организовать конкурс для 4 участников из разных городов. Хотя конкурс получался международный, все-таки целесообразней было его отменить, как это не жаль.

Робокосилка 2016. ROS & FUN


Я осваиваю ROS и пишу лаунчер для робокосилки, использую Kinect и SLAM, только на визуальной одометрии робот строит карту и прокладывает маршрут. Kinect в солнечную погоду работает плохо. С ROS Вы за один вечер сделаете «Hello World!», а дальше тьма. Я так и не нашел нормального руководства для новичка как сделать робота, а не просто писать в топики. Кто-нибудь задумывался, почему на карте сообщества ROS нет ВООБЩЕ ни одной точки в РФ? Я открыл группу ВК.


В свободное время прикрутил к тягам своей «рабочей лошадки» два сервопривода, ультразвуковой сенсор и Arduino. Простой тест объезда березы и остановки пройден! А дальше бездна, эту штуку опасно просто так пускать по своему участку! Ее даже не получится пинать как роботов сами знаете откуда.


Оказывается роботы — вещи достаточно скучные в понимании большинства людей, особенно сервисные роботы. Да, знаю о великой дружбе роботов-пылесосов и котиков. Знаю о супер творениях от Boston Dynamics, Darpa и российском боевом роботе-аватаре, это все больше похоже на роботов, чем коробочка, в которой некий алгорим взаимодействует с реальным миром.

В понимании моей дочки роботы — это как минимум трансформеры, а не та еруда, на которую я трачу время. Я принял тяжелое решение и «временно» сделал из робокосилки игрушку на bluetooth управлении.



Управление работает так же как и у снегоуборщика. Оказалось это весело! Особенно для папы.

Видео со снегоуборщиком




Дальше — больше! Меня заинтересовала идея реализации управления не на bluetooth, а через интернет, с телеметрией. Скучно, пресно и идея избитая!

А что если дать возможность любому пользователю интернета управлять моей газонокосилкой? Знаете такие идеи, которые потом трудно выкинуть из головы? Это как раз была такой...Сhallenge accepted!

Краудкосилка



Железо





В волшебную коробочку аккуратно добавлены Raspberry pi, USB хаб, wifi-адаптер, веб-камера.
Из интересных моментов по железу. У меня не оказалось драйвера с нужными характеристиками для двигателей. Обычно в качестве драйвера используют H-мост на полевых транзисторов или (хардкор) на реле. Я выбираю более жесткий вариант, потому что именно реле были в наличии.



Обычная схема подключения подразумевает 4 ключа на каждый двигатель, т.е. 8 на 2 ходовых двигателя.



Учитывая, что можно использовать так же и нормально-открытое состояние реле, а так же тот факт, что нет необходимости приводить двигатели в движение по отдельности можно обойтись всего лишь 5 реле для двух ходовых двигателей.

Кроме самого робота установлена на доме камера, которая с частотой 3 кадра/сек. загружает на ftp-сервер в интернете обзорное фото участка для лучшей ориентации. Но впоследствии просто заменил на решение от ivideon.

Программа


Как и прежде Arduino получает по serial-порту сообщения в один символ, которые обозначают необходимое действие. Так же для тестирования и отладки, полученные от raspberry коды отправляются по bluetooth, можно подключить телефон в режиме терминала и получать данные с сервера еще и на телефон.

Скетч Arduino
int m1=2;
int m1b=3;
int m2=4;
int m2b=5;
int mk=6;
int pis=7;


char a,b;

void setup()  
{
Serial.begin(9600);
Serial1.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }
  while (!Serial1) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }
  Serial.println("Start");

 pinMode(statpin, OUTPUT);
 pinMode(m1, OUTPUT);
 pinMode(m1b, OUTPUT);
 pinMode(m2, OUTPUT);
 pinMode(m2b, OUTPUT);
 pinMode(mk, OUTPUT);
 pinMode(pis, OUTPUT);

analogWrite(pis,  1000);
delay(100);
analogWrite(pis,  700);
delay(200);
analogWrite(pis,  300);
delay(300);
analogWrite(pis,  1000);
delay(100);
analogWrite(pis,  100);
digitalWrite(pis,  HIGH);
 digitalWrite(statpin, LOW);
digitalWrite(m1, LOW);
digitalWrite(m1b,  LOW);
digitalWrite(m2, LOW);
digitalWrite(m2b,  LOW);
digitalWrite(mk,  LOW);
digitalWrite(pis,  HIGH);

}

void loop() // run over and over
{

  if (Serial.available()){
     a=Serial.read();
     Serial1.println(a);

    if(a=='B'){
digitalWrite(m1, HIGH);
digitalWrite(m1b,  LOW);
digitalWrite(m2, HIGH);
digitalWrite(m2b,  LOW);
    }
    if(a=='F'){
digitalWrite(m1, HIGH);
digitalWrite(m1b, HIGH);
digitalWrite(m2, HIGH);
digitalWrite(m2b,  HIGH);
    }
    if(a=='R'){
digitalWrite(m1, HIGH);
digitalWrite(m1b, LOW);
digitalWrite(m2, HIGH);
digitalWrite(m2b,  HIGH);
    }
    if(a=='L'){
digitalWrite(m1, HIGH);
digitalWrite(m1b, HIGH);
digitalWrite(m2, HIGH);
digitalWrite(m2b,  LOW);
    }

       if(a=='S'){
digitalWrite(m1, LOW);
digitalWrite(m1b, LOW);
digitalWrite(m2, LOW);
digitalWrite(m2b,  LOW);
    }

       if(a=='W'){
digitalWrite(mk, HIGH);
    }  
       if(a=='w'){
digitalWrite(mk, LOW);
    }   

       if(a=='V'){
digitalWrite(pis, LOW);
    }  
       if(a=='v'){
digitalWrite(pis, 700);
    }   
  
    }else{
      
    }
  
}




На raspberry работают два python скрипта. Один из скриптов с помощью opencv захватывает видео с веб-камеры, установленной на ровере и загружает ее по ftp на сервер. Так же, с какой-то долью вероятности, фото вместе с рандомным сообщением из списка загружается в twitter-аккаунт.

Первый скрипт
import numpy as np
import sys
import pygame
import pygame.camera
from pygame.locals import *
from twython import Twython
from random import random
import ftplib


pygame.init()
pygame.camera.init()
cam = pygame.camera.Camera("/dev/video0",(550,400))
cam.start()

CONSUMER_KEY = '-------MBZDT1PwibFeIcSp'
CONSUMER_SECRET = '-----------------1ZGHgBRz6aEr4YhUVuO84CuEV'
ACCESS_KEY = '-----------------4MCjSkny9Y6rJj5I32ulXctISQF'
ACCESS_SECRET = '------------------------cDadRY3He5Kv6CXVuqy2Dh'
api = Twython(CONSUMER_KEY,CONSUMER_SECRET,ACCESS_KEY,ACCESS_SECRET)
api.verify_credentials()

host = "-.--.---.196"
ftp_user = "ftp_user"
ftp_password = "ftp_password"
con = ftplib.FTP(host, ftp_user, ftp_password)
con.cwd("/mowmylawn.ru/webcam")

a={0:'Всем привет! Какой чудесный день!',1:'Опять трудовые будни. Скорее бы выходной!',2:'Верблюд может не пить две недели...А у меня бензин заканчивается',3:'Ну почему опять я должен заниматься газоном?',4:'Улыбаемся, снимает скрытая камера!',5:'Работа не волк, а вот я могу в лес убежать :)) !',6:'Врум, врум...стригу газон!',7:'Не плачь, на Марсе тоже жизни нет.',8:'Эйнштейн был прав: выходные - понятие относительное',9:'Самое сложное — не знать, правильно ли ты сделал...',10:'Меня одну волнует этот вопрос: Когда у меня отпуск?',11:'Начинаю обработку территории',11:'Кто-куда, а я работать',12:'Судьба - это то, что мы получаем в результате наших решений и поступков.',13:'— У тебя не все дома! — Конечно, я же на работе!',14:'Хозяин, батарейки на исходе! Сжалься...:(((!',15:'Хочешь меня сделать? robogazon.ru',16:'Всё возможно, пока не сделан выбор!'}

def twit():
    image = cam.get_image()
    pygame.image.save(image,'webcam.jpg')
    photo = open('webcam.jpg','rb')
    b = random() * (len(a)-1)
    b = int(round(b,0))
    #api.upload_media(media=photo)
    #api.update_status(status=a[b])
    api.update_status_with_media(media=photo, status=a[b])

def ftpimg():
    image = cam.get_image()
    pygame.image.save(image,'webcam.jpg')
    photo = open('webcam.jpg','rb')
    send = con.storbinary("STOR "+ 'webcam.jpg', photo)

while 1 :
    ftpimg()
    b = random() * (500)
    b = int(round(b,0))
    if b==107:
        twit()

con.close



Второй скрипт по http получает на сервере текущую команду для действия и отправляет эту команду по serial на arduino.
  • «S» — стоп
  • «F» — вперед
  • «B» — назад
  • «L» — влево
  • «R» — вправо
  • «W» — включить двигатели кошения
  • «w» — выключить двигатели кошения
  • «V» — включить сигнал
  • «v» — выключить сигнал


Второй скрипт
import serial,time
import urllib3

http = urllib3.PoolManager()


ser = serial.Serial("/dev/ttyUSB0",9600)
ser.writelines("S");

olddata=0
countolddata=0
while 1 :
    r = http.request('GET', 'http://mowmylawn.ru/1.php')
    
    if r.data!=olddata:
        olddata=r.data
        countolddata=0
    else:
        countolddata+=1
    
    if countolddata>20:
        ser.writelines("S")
    else:
        ser.writelines(r.data)

ser.close()
con.close



Веб-сервис


На bootstrap накидал страничку. На странице два .jpg файла, которые обновляются по мере загрузки. Факторов, влияющих на задержки в управлении и телеметрии много, это и Ваша скорость соединения, и канал на сервере, и канал у меня дома.

Код обновления .jpg
<script>
setInterval(function(){
var im1='http://mowmylawn.ru/webcam/webcam.jpg?s='+Math.random();
var im2='http://kosmos-podolsk.ru/webc1.jpg?s='+Math.random();
var tmpImg = new Image() ;
    tmpImg.src = im1 ;
    tmpImg.onload = function() {
         $("#w1dd").attr('src',im1 );
    } ;

    tmpImg.src = im2 ;
    tmpImg.onload = function() {
         $("#w2dd").attr('src',im2 );
    } ;	

}, 200);
</script>



Максимальная частота обновления, которую удалось добиться мне:
  • камера на ровере 4 Гц;
  • камера на доме 3 Гц.

База данных Mysql состоит из 2 таблиц, в первой хранится одна пара ключ/значение, это команда для робота. Вторая таблица — users.
Когда Вы встаете в очередь на сайте — отправляется ajax get запрос на добавление пользователя, в базу заносится запись с отметкой timestamp, вашим ip и сгенерированным ключом для управления.

Управлять косилкой одновременно может только один человек (кроме меня) — это пользователь с самым маленьким timestamp. Когда приходит Ваша очередь и Вы начинаете управлять косилкой — в базу заносить timestamp начала управления, каждому отведено на управление 60 сек…



Каждый раз когда Вы наводите на кнопки управления отправляется ajax get запрос с командой и Вашим ключом на управление, при этом проверяется разница между текущим временем и временем, когда Вы начали «игру», если разница больше 60 сек, для Вас игра заканчивается, Ваша запись удаляется из базы и Вы опять можете встать в очередь, «игра» переходит к следующему игроку.

Промо видео




Потом думаю, надо снять на английском...и тут Остапа понесло.








Мой первый пост на reddit. Попробуйте управление mowmylawn.ru. В случае большой очереди или хабраэффекта — прошу понять и простить.

P.S.: На забывайте, что Вы можете принять участие в совместном проекте по разработке фитнес-трекер для ударных видов спорта KickBrick. В команде ждут Вас!

UPD: У меня было три проблемы, две уже решил.
1)При слишком активных маневрах провод питания ходовых двигателей ~27В отсоединился и один из двигателей не двигался вперед.
2)Видимо, из-за этого же провода сгорел wi-fi адаптер
3)Большое кол-во пользователей с GT и reddit сначала привели к очереди более 1000 пользователей, затем сервер рухнул. Оптимизация — наше все!

UPD: Пришлось заменить arduino и почистить очередь. Можете пробовать.

UPD:

Tags:
Hubs:
+21
Comments 17
Comments Comments 17

Articles

Information

Website
golf-robotics.com
Registered
Founded
Employees
2–10 employees
Location
Россия
Representative
Вячеслав Голицын