DIY: Робот-подводная лодка для исследования акватории Москвы-реки. Часть 1

в 12:09, , рубрики: android, arduino, DIY, diy или сделай сам, Блог компании Битва робокосилок, велосипедостроение, подводная лодка, метки: ,

Это краткая история создания подводного автономного робота менеджером очень среднего звена. Текущей целью является создание актуальной карты фарватера Москвы-реки. При поиске нет проблем найти такую карту, но вызывает вопрос ее актуальность. Русло реки постоянно меняется. Происходит эрозия берегов реки и меняется карта фарватера. Эти процессы особенно заметны, учитывая питание Москвы-реки снеговое (61 %), грунтовое (27 %) и дождевое (12 %). Конечной целью является создание многофункционального подводного робота для исследование морских глубин. Мировой океан, покрывающий 2/3 поверхности Земли, изучен всего на 5%. Для создания автономного робота нужен простой «автопилот».

Как сделать доступный и простой автопилот для DIY-проектов и проплыть на нем по Москве-реке?

DIY: Робот-подводная лодка для исследования акватории Москвы-реки. Часть 1 - 1


Москва-река это главная водная артерия города Москвы, длина в пределах города 80 км. Ширина реки внутри города меняется от 120 до 200 м, от самой узкой части возле Кремля до самой широкой вблизи Лужников. Принято считать, что скорость течения реки 0,5 м/с. Вполне благоприятные условия для испытания робота.
Возможно, было бы эффективнее и проще сделать лодку, но задача сделать подводного робота кажется много интереснее.

Конструкция

Робот-подводная лодка для исследования акватории Москвы-реки.
DIY: Робот-подводная лодка для исследования акватории Москвы-реки. Часть 1 - 2
Примерное расположение элементов я видел таким.
DIY: Робот-подводная лодка для исследования акватории Москвы-реки. Часть 1 - 3

Установка коллекторного двигателя
DIY: Робот-подводная лодка для исследования акватории Москвы-реки. Часть 1 - 4

Серво-привод управления рулем
DIY: Робот-подводная лодка для исследования акватории Москвы-реки. Часть 1 - 5

Серво-привод управления рулем глубины
DIY: Робот-подводная лодка для исследования акватории Москвы-реки. Часть 1 - 6

В шутку можно сказать что я готовлюсь к конкурсу X-Prize.

Осталось накопить 2000$. :)
DIY: Робот-подводная лодка для исследования акватории Москвы-реки. Часть 1 - 7

The registration deadline is 30 June, 2016 (11:59 PM UTC/4:59 PM PST). The registration fee is $2,000.00 USD.

Целью является разработка автономного подводного робота, а не ROV'а. (Remotely operated underwater vehicle).

Электронная часть не отличается сложностью и качеством сборки
Arduino nano + L293D + Bluetooth + 3 серво + Power bank (Отдельное спасибо интернет-магазину, который продавал такие по 3 цента). Отдельно подключается к Power bank смартфон Samsung Galaxy S3 для поддержания заряда. Связь смартфона с Arduino осуществляется по Bluetooth.

Программная часть управления

«Мы встречаем свою судьбу на пути, который избрали, чтобы уйти от нее»
Жан де Лафонтен

Я всегда старался избегать программирования на Android. Когда появлялась возможность разработки даже легкого приложения с возможностью в действии познакомится с Android, я пасовал.
Но час настал! Действительно, хватит тратить деньги на шильды для Arduino. Все что нужно уже есть в отслуживших смартфонах. Под рукой оказался Samsung Galaxy S3 и немного магии.
Как порядочный ГИК я задал вопрос на тостере. Возможно я спрашивал сложно. Возможно плохо сформулировал вопрос. И похоже это было скорее не на вопрос. Но в ответ я получил совсем не то, что ожидал.
Яндекс мне в бухту! Все запросы «Android GPS», «Программирование Android GPS» и прочее давали ответы, которые решительно не работали на Android Studio.
Каким же облегчением для меня стала находка SL4A. Оказывается можно прототипировать и программировать на Android, используя Python. Управляют, ведь, даже ракетами.

SL4A Python

Если у Вас есть телефон Android, а он у Вас есть. Вы же ГИК, а не любитель приторных фруктов.
Устанавливаем на выбор программу для распознавания QR-кодов.
Для использования SL4A необходимо установить на телефон приложение.
DIY: Робот-подводная лодка для исследования акватории Москвы-реки. Часть 1 - 8
Интерпретатор языка Python находится здесь.
DIY: Робот-подводная лодка для исследования акватории Москвы-реки. Часть 1 - 9
Или QPython3

Писать программы на телефоне возможно, но занятием увлекательным это не назовешь.

Есть выход

Источник: http://habrahabr.ru/post/134184/
Перенаправим весь локальный трафик, поступающий на порт 9999 в Android-устройство (примем, что сервер слушает порт 46136):
$ adb forward tcp:9999 tcp:46136
Осталось создать переменную окружения и настройка закончена:
$ AP_PORT=9999
Осталось добавить файл android.py в папку с библиотеками Python'а, и все, теперь можно писать приложения на компьютере, запускать их, и результат можно буждет видеть сразу на телефоне. Для запуска helloWorld на Android-устройстве теперь достаточно ввести в интерпретаторе Python:
>>>import android
>>>droid = android.Android()
>>>droid.makeToast(«Hello, world!»)

В первой строчке импортируется библиотека android, затем создается объект droid, с помощью которого используются API Android'a. Крайняя строка выводит сообщение «Hello, World!» на экран устройства.
Теперь самое время, чтобы познакомиться поближе с API, которое предоставляет SL4A.

Построение пути. Выбор точек

DIY: Робот-подводная лодка для исследования акватории Москвы-реки. Часть 1 - 10
Используя Яндекс.карты или Google.maps выбираем точки по центру реки. Это примерный маршрут. Для тестов и наладки использую усеченную версию точек.
[55.671110, 37.686625],[55.668448, 37.675467],[55.660847, 37.671776],[55.654649, 37.671175]

Как сделать доступный и простой автопилот для DIY-проектов из andoid телефона и 70 строк кода?

DIY: Робот-подводная лодка для исследования акватории Москвы-реки. Часть 1 - 11

Код автопилота

import math,android,time
coordmas = [[55.671110, 37.686625],[55.668448, 37.675467],[55.660847, 37.671776],[55.654649, 37.671175]]
droid = android.Android()
droid.startSensingTimed(1,200)
droid.startLocating(5000, 30)
def getgps():
	locs = droid.getLastKnownLocation()
	gpspos = locs.result["gps"]
	return gpspos
def distazim(llat1,llong1,llat2,llong2):
	rad=6372795
	#врадианах
	lat1=llat1*math.pi/180.
	lat2=llat2*math.pi/180.
	long1=llong1*math.pi/180.
	long2=llong2*math.pi/180.
	cl1=math.cos(lat1)
	cl2=math.cos(lat2)
	sl1=math.sin(lat1)
	sl2=math.sin(lat2)
	delta=long2-long1
	cdelta=math.cos(delta)
	sdelta=math.sin(delta)
	y=math.sqrt(math.pow(cl2*sdelta,2)+math.pow(cl1*sl2-sl1*cl2*cdelta,2))
	x=sl1*sl2+cl1*cl2*cdelta
	ad=math.atan2(y,x)
	dist=ad*rad
	x=(cl1*sl2)-(sl1*cl2*cdelta)
	y=sdelta*cl2
	z=math.degrees(math.atan(-y/x))
	if(x<0):
		z=z+180.
	z2=(z+180.)%360.-180.
	z2=-math.radians(z2)
	anglerad2=z2-((2*math.pi)*math.floor((z2/(2*math.pi))))
	angledeg=(anglerad2*180.)/math.pi
	return [dist,angledeg]
def servoangle(azdiff):
	if azdiff>10 or azdiff<-10:
		deg=azdiff
		if deg>90:
			deg=90
		if deg<-90:
			deg=-90
	return deg
gpspos=getgps()
oldlat = gpspos["latitude"]
oldlon = gpspos["longitude"]
for c in range(len(coordmas)):
	#получение координат текцщей целевой точки
	curcoord=coordmas[c]
	targetlat=curcoord[0]
	targetlon=curcoord[1]
	darange=11;
	while darange>10:
		gpspos=getgps()
		curlat = gpspos["latitude"]
		curlon = gpspos["longitude"]
		time.sleep(0.5)
		da=distazim(curlat,curlon,targetlat,targetlon)
		darange = da[0]
		dazimut = round(da[1])
		pol=droid.sensorsReadOrientation()
		pol2=pol.result
		turn = round(pol2[0])
		turn = (-turn) *180/ 3.2
		azdiff=turn-dazimut
		deg=servoangle(azdiff)
	oldlat = curlat
	oldlon = curlon

Код с комментариями

import math,android,time

#Массив координат
coordmas = [[55.671110, 37.686625],[55.668448, 37.675467],[55.660847, 37.671776],[55.654649, 37.671175]]

#Инициализация, запуск GPS, сенсоров
droid = android.Android()
droid.startSensingTimed(1,200)
droid.startLocating(5000, 30)

#Функции
#GPS
def getgps():
	locs = droid.getLastKnownLocation()
	gpspos = locs.result["gps"]
	return gpspos
#Функция определения расстояния и азимута между двумя GPS-точками
def distazim(llat1,llong1,llat2,llong2):
	rad=6372795
	#врадианах
	lat1=llat1*math.pi/180.
	lat2=llat2*math.pi/180.
	long1=llong1*math.pi/180.
	long2=llong2*math.pi/180.

	#косинусыисинусыширотиразницыдолгот
	cl1=math.cos(lat1)
	cl2=math.cos(lat2)
	sl1=math.sin(lat1)
	sl2=math.sin(lat2)
	delta=long2-long1
	cdelta=math.cos(delta)
	sdelta=math.sin(delta)

	#вычислениядлиныбольшогокруга
	y=math.sqrt(math.pow(cl2*sdelta,2)+math.pow(cl1*sl2-sl1*cl2*cdelta,2))
	x=sl1*sl2+cl1*cl2*cdelta
	ad=math.atan2(y,x)
	dist=ad*rad

	#вычислениеначальногоазимута
	x=(cl1*sl2)-(sl1*cl2*cdelta)
	y=sdelta*cl2
	z=math.degrees(math.atan(-y/x))

	if(x<0):
	z=z+180.

	z2=(z+180.)%360.-180.
	z2=-math.radians(z2)
	anglerad2=z2-((2*math.pi)*math.floor((z2/(2*math.pi))))
	angledeg=(anglerad2*180.)/math.pi

	return [dist,angledeg]

def servoangle(azdiff):
	if azdiff>10 or azdiff<-10:
		deg=azdiff
		if deg>90:
			deg=90
		if deg<-90:
			deg=-90
	return deg

#принятие текущего положения за старую точку
gpspos=getgps()
oldlat = gpspos["latitude"]
oldlon = gpspos["longitude"]

#Цикл
for c in range(len(coordmas)):
	#получение координат текцщей целевой точки
	curcoord=coordmas[c]
	targetlat=curcoord[0]
	targetlon=curcoord[1]

	#выполняем цикл пока расстояние больше 10 метров до след.точки
	darange=11;
	while darange>10:
		#определение координат	
		gpspos=getgps()
		curlat = gpspos["latitude"]
		curlon = gpspos["longitude"]
		time.sleep(0.5)
		#сравнение дальности и азимута до след. точки.
		da=distazim(curlat,curlon,targetlat,targetlon)
		darange = da[0]
		dazimut = round(da[1])
		#определяем угол телефона
		pol=droid.sensorsReadOrientation()
		pol2=pol.result
		turn = round(pol2[0])
		#[1.57=left, 0=stop, -1.57=right]
		turn = (-turn) *180/ 3.2
		#если угол точки отличается от угла телефона на 10 градусов готовим команду на поворот
		azdiff=turn-dazimut
		#готовим данные для угла поворота сервы руля
		deg=servoangle(azdiff)
		#отправляем по блютус угол поворота серво

	#Меняем координаты старой точки, т.к. ожидается смена координат текущей цели
	oldlat = curlat
	oldlon = curlon

Python For Android. Функции, которые я долго искал

Батарея:
droid.batteryStartMonitoring() — началo работы с батареей.
droid.batteryStopMonitoring()
droid.batteryGetHealth() — возвращает состояние батареи (1-неизвестно, 2-хорошее, 3 — перегрев, 4 — мёртвая, 5 — перегрузка, 6 — неизвестный сбой)
droid.batteryGetStatus() — возвращает статус батареи (1 — неизвестно, 2 — заряжается, 3 — разряжается, 4 — не заряжается, 5 — максимальный заряд)
droid.batteryGetTechnology()
droid.readBatteryData() — данные о батарее.
droid.batteryGetTemperature()
droid.batteryGetVoltage()
droid.batteryGetLevel()

Bluetooth:
droid.checkBluetoothState() — проверяет включён ли Bluetooth
droid.toggleBluetoothState() — включает если в скобках True и выключает, если False
droid.bluetoothAccept() — принимает соединение
droid.bluetoothActiveConnections() — проверяет, есть ли подключения
droid.bluetoothGetConnectedDeviceName()
droid.bluetoothMakeDiscoverable() — в скобках можно указать промежуток времени в секундах
droid.bluetoothStop()

Wi-Fi:
droid.checkWifiState() — проверяет включён ли Wi-Fi
droid.toggleWifiState() — включает если в скобках True и выключает, если False
droid.wifiStartScan()
droid.wifiGetScanResults()
droid.wifiGetConnectionInfo()

Другие настройки:
droid.checkAirplaneMode() — проверяет включён ли режим «В самолёте»
droid.checkRingerSilentMode() — проверяет включён ли беззвучный режим
droid.checkScreenOn() — включён ли экран
droid.toggleRingerSilentMode() — включает беззвучный режим
droid.toggleAirplaneMode()
droid.toggleVibrateMode()

Получение информации о настройках:
droid.getMaxMediaVolume()
droid.getMaxRingerVolume()
droid.getMediaVolume()
droid.getRingerVolume()
droid.getScreenBrightness()
droid.getScreenTimeout()
droid.getVibrateMode()

Установка параметров:
droid.setMediaVolume()
droid.setRingerVolume()
droid.setScreenBrightness()
droid.setScreenTimeOut()

В планах:

  • Настройка отправки данных по Bluetooth на arduino.
  • Получение с arduino данных о глубине. Глубину буду измерять ультразвуковым датчиком.
  • Отправка данных о текущем положении и измерений глубины на сервер.
  • Доработка конструкции. Лодка должна быть с нулевой плавучестью, чтобы глубину можно было изменять рулями глубины. Возможно от конструкции подводной лодки придется уйти к надводному аппарату.
  • Тест, тест, тест

P.S.: Почему я решил написать пост до запуска робота? Я хочу найти единомышленников. Если у Вас есть желание — делайте своего робота. Отличный повод собраться на майских праздниках на аквапробег по Москве-реке на роботах! По всем вопросам можете писать мне ВК

Автор: Битва робокосилок

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js