Система автоматической разгрузки и загрузки дрона(Часть 1)

Проблема разгрузки и загрузки грузов на дрон без участия человека — это основная проблема автоматизации доставки грузов с помощью дронов. Ключевой этап доставки, который требует присутствия человека, заключается в процессе физической загрузки и разгрузки грузов на дрон. Но у нас есть решение!

Рис. 1 источник изображения: Drone career – Artofit

Множество разработок имеется на этот счёт, но все они работают или в условиях идеального позиционирования (до 2 см), или не могут долго хранится в плохую погоду (например картонные коробки).

Одним из решений этой проблемы может быть разработка автоматизированной системы для загрузки и разгрузки грузов на дрон. Такая система может быть основана на использовании нашего решения данной проблемы.

Конструкция

Для начала нужно понять, что нам требуется (задачи):

  1. Дрон должен иметь возможность «промахнуться» до 10 см. (порывы ветра никто не отменял)

  2. Конструкция посадочного место не должна затопляться (выше уровня земли/асфальта)

  3. Крепление груза должно быть надёжным (мы же не хотим, чтобы наша посылка упала кому-то на голову)

В начале пути, мы определились с формой корпуса и посадочного места, была выбрана форма усечённого конуса (Рис. 2), задача данной формы в том, чтобы, при отклонении дрона на дистанцию D (Рис. 2), грузовой модуль, прикреплённый к дрону «скатится» в центр посадочного места.

Рис.2 Посадочное место (синий цвет), Грузовой модуль (зелёный цвет)

Рис. 2 Посадочное место (синий цвет), Грузовой модуль (зелёный цвет)

В нашей реализации это выглядит так:

Рис.3 Внешний вид посадочного места и грузового модуля

Рис. 3 Внешний вид посадочного места и грузового модуля

Грузовой контейнер соответственно принял такой внешний вид:

Рис.4 Грузовой отсек

Рис. 4 Грузовой отсек

Рис.5 Способ открытия грузовой отсека

Рис. 5 Способ открытия грузовой отсека

«Убив двух зайцев разом» (задачи 1 и 2), перейдём к замку (нет, он пока засекречен, к сожалению, пока ждём окончательного оформления патента).

Программирование

Теперь перейдём к дрону, который использовался в данном проекте, это Pioneer max от Geoscan. Было потрачено много времени, для того чтобы его оживить. Для начала мы подключили сервопривод (сразу обращайте внимание, что некоторые пины используются по умолчанию и их использование не даст нормального результат (тряски, ложные срабатывания)). Более подробнее я напишу про этот «танец с бубнами» в будущем, а пока вернёмся к программированию. Тем более мы реализовали полностью автономный полёт!

Ниже представлены программы для работы сервопривода, все коды составлялись на основе документации (Программирование на Lua — Документация Pioneer December update 2022 (geoscan.aero)), НО информация там не вся рабочая, поэтому мы прикрепили свои коды:

-----------------------------------Lua код--------------------------------------------
local uart = Uart.new(4, 57600) -- объявляем uart для общения с pyhon кодом
local servo_stat = 'o'    -- статус сервопривода(например 'o'(открыто),'c'(закрыто))
local rc = Sensors.rc     -- подключаем пульт

local inp = ''            -- переменная для хранения информации для отправки на Python
local rec = ''            -- переменная для хранения ответа(для будущего применения)

local function rotate_servo_open() -- функция открытия сервопривода
    servo_stat='o'
end


local function rotate_servo_close() -- функция закрытия сервопривода
    servo_stat='c'
end


local function main()               -- цикл
    rc_chans = table.pack(rc())     -- получаем иинформацию с пульта
    if rc_chans[8] < -0.8 then      --открытие (канал посмотри на пульте)
        rotate_servo_open()
    elseif rc_chans[8] > 0.8 then   --закрытие (канал посмотри на пульте)
        rotate_servo_close()
    end
    inp = servo_stat..'\n' -- пусть разделитель '\n'
    uart:write(inp, #inp)  -- отправляем на Python
    rec = uart:read(20)    -- в скобка пишем сколько принимаем байт
end

t = Timer.new(0.08, main) --устанавливаем частоту цикла 
---!ВРЕМЯ СИНХРОНИЗАЦИИ ДОЛЖНО БЫТЬ ОДИНАКОВО НА LUA и PYTHON!

t:start() -- начинаем цикл

----------!!!КОВЫЧКИ ОДИНАРНЫЕ ОБЯЗАТЕЛЬНО, ИНАЧЕ РАБОТАТЬ НЕ БУДЕТ !!!---------------
####################################Python код########################################

import serial             # библиотека для общения
from time import sleep    # библиотека для синхронизации
import RPi.GPIO as GPIO   # библиотека для общения

ser = serial.Serial("/dev/ttyS0", 57600, timeout=5) # открываем порт, бездумно не меняй
GPIO.setmode(GPIO.BCM)    # объявляем для общения
GPIO.setup(25, GPIO.OUT)  # объявляем для общения
sg = GPIO.PWM(25, 50)     # объявляем сервопривод
sg.start(8.06)            # объявляем задаём начальный угол

servo_opened = True       # по умолчанию замок открыт


def uart_read():          # функция чтения с Lua
    data = ser.readline().decode().replace('\n', "") # читаем, разделяем, убираем мусор

    if ser.in_waiting > 20:      # чтобы не зависало, бездумно не меняй
        ser.reset_input_buffer() # чтобы не зависало, бездумно не меняй

    print('Read data: ') # вывод в терминал
    print(data)          # вывод в терминал

    return data

def uart_write(answer): # функция ответа для Lua
    ser.write(answer.encode()) # кодируем, пишем 
    print('UART writed') # вывод в терминал


def servo_control(event): # функция управления сервоприводом
    global servo_opened   # подключаем глобальные переменные
    global sg             # подключаем глобальные переменные

    if event == "c" and servo_opened: # закрываем серво если получили 'c'
        sg.ChangeDutyCycle(2.5)
        servo_opened = False
        print('closed')

    elif event == "o" and not (servo_opened): # открываем серво если получили 'o'
        sg.ChangeDutyCycle(8.06)
        servo_opened = True
        print('opened') # вывод в терминал


def auto_p_control(data):
    servo_event = data[0]

    servo_control(servo_event) # вызов функции для поворота сервопривода

    print("ANS : " + str(ans)) # вывод в терминал
    uart_write(ans)  # отправка данных на Lua
    sleep(0.08)  # синхронизация

while True: # бесконечный цикл
    uart_data = uart_read() # вызываем функцию чтения

    if uart_data != ['']:  #если прочитанные данные не пустые
        auto_p_control(uart_data) # вызываем функцию ответа

Перейдём к результату, для дальнейшего обдумывания.

© Habrahabr.ru