Материал: Автоматизация системы управления квадрокоптера

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

Заключение

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

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

Тем не менее, устройство имеет реальные перспективы развития и использования в практических целях.

Разработка устройства потребовала навыки в областях радиофизики, программирования, обработки сигналов, робототехники, электроники и аэродинамики.

Список использованных источников

1.       Герасимов В.Г. Электротехника и электроника. Кн. 2. Электромагнитные устройства и электрические машины. / В.Г. Герасимов, Э.В. Кузнецов, О.В. Николаева. - М: Энергоатомиздат, 1997. - 288 с.

2.       Корнилов В. А. Система управления мультикоптером / В.А. Корнилов, Д.С. Молодяков, Ю.А. Синявская. // Электронный журнал «Труды МАИ». - 2015. - № 62. - С. 1-8.

3.       Ang K.H. PID control system analysis, design, and technology / K.H. Ang, G. Chong, Y. Li. // IEEE Transactions on Control Systems Technology. -2005.- № 4. - C. 559-576.

.        Kalman R.E. A new approach to linear filtering and prediction problems / R.E. Kalman. // Journal of Basic Engineering. - 1960. - №82.-С. 35-45

5.       ФорсайтД.А. Компьютерноезрение. Современныйподход. / Д.А. Форсайт, Ж. Понс. - М :Издательскийдом «Вильямс», 2004. - 982с.

.        Шапиро Л. Компьютерное зрение. / Л. Шапиро,000 Дж. Стокман. - М : Бином. Лаборатория знаний, 2013. - 752 с.

.        Желтов С.Ю. Обработка и анализ изображений в задачах машинного зрения. / С.Ю. Желтов [и др.]; ред. С.Ю. Желтов. - М : Физматкнига, 2010. - 672 с.

9.       G. Bradski. LearningOpenCV. / GaryBradskiandAdrianKaehler. - M :O’ReillyMedia, Inc, 2008. - 571 c.

.        OpenCVdocumentationindex [Электронныйресурс] :сайт. - URL: https://docs.opencv.org.

.        E. R. Davies. Machine Vision: Theory, Algorithms, Practicalities. M: - Morgan Kaufmann, 2004. - 579 c.

12.     IMU-сенсор на 10 степеней свободы [Электронныйресурс] :сайт. - URL: http://wiki.amperka.ru/продукты:troyka-imu-10-dof

Приложения

Приложение 1

Main.java

package sample;

// импортирование JavaFX-классов

import javafx.application.Application;

import javafx.fxml.FXMLLoader;

import javafx.scene.Parent;

import javafx.scene.Scene;

import javafx.scene.layout.BorderPane;

import javafx.stage.Stage;

// импортирование библиотеки OpenCV

import org.opencv.core.Core;

public class Main extends Application {

@Override

public void start(Stage primaryStage) throws Exception{

// связываем с FXML-документомloader = new FXMLLoader(getClass().getResource("sample.fxml")); // load the FXML resourceroot = FXMLLoader.load(getClass().getResource("sample.fxml"));

// заголовок окна.setTitle("Gesture Detection 0.1");

// создаем окно с параметрами высоты и ширины

primaryStage.setScene(new Scene(root, 517, 441));

// запрет изменения размеров окна.setResizable(false);

// создаем сцену и выводим на экран

primaryStage.show();

}

public static void main(String[] args) {

// загружаем OpenCV.loadLibrary(Core.NATIVE_LIBRARY_NAME);

// запускаем JavaFX-код(args);

}

}.java

package sample;

// импортирование средства для буферизации изображений

import java.awt.image.BufferedImage;

import java.awt.image.DataBufferByte;

// импортирование JavaFX-классов

import javafx.application.Platform;

import javafx.beans.property.ObjectProperty;

import javafx.embed.swing.SwingFXUtils;

import javafx.scene.image.Image;

// импортирование библиотеки OpenCV

import org.opencv.core.Mat;

public final class Utils

{

//Конвертирует Mat-объект из OpenCV в Image из JavaFX

public static Image mat2Image(Mat frame)

{

try

{

return SwingFXUtils.toFXImage(matToBufferedImage(frame), null);

}

catch (Exception e)

{.err.println("Cannot convert the Mat obejct: " + e);

return null;

}

}

// метод для импортирования элементов в "нить" JavaFX

// взят из открытых источников

public static <T> void onFXThread(final ObjectProperty<T> property, final T value)

{.runLater(() -> {.set(value);

});

}

// буферизация изображения

private static BufferedImage matToBufferedImage(Mat original)

{image = null;

int width = original.width(), height = original.height(), channels = original.channels();

byte[] sourcePixels = new byte[width * height * channels];.get(0, 0, sourcePixels);

if (original.channels() > 1)

{= new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);

}

else

{= new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);

}

final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();.arraycopy(sourcePixels, 0, targetPixels, 0, sourcePixels.length);

return image;

}

}.FXML

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.text.*?>

<?import java.lang.*?>

<?import javafx.geometry.*?>

<?import javafx.scene.control.*?>

<?import javafx.scene.image.*?>

<?import javafx.scene.layout.*?>

<?import javafx.geometry.Insets?>

<?import javafx.scene.control.Button?>

<?import javafx.scene.control.Slider?>

<?import javafx.scene.image.ImageView?>

<?import javafx.scene.layout.BorderPane?>

<?import javafx.scene.layout.ColumnConstraints?>

<?import javafx.scene.layout.GridPane?>

<?import javafx.scene.layout.RowConstraints?>

<GridPane alignment="center" hgap="10" maxHeight="600.0" maxWidth="726.0" minHeight="426.0" minWidth="517.0" prefHeight="441.0" prefWidth="517.0" vgap="10" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">

<columnConstraints>

<ColumnConstraints />

</columnConstraints>

<rowConstraints>

<RowConstraints />

</rowConstraints>

<children>

<BorderPane maxHeight="600.0" maxWidth="700.0" minHeight="438.0" minWidth="530.0" prefHeight="438.0" prefWidth="530.0">

<bottom>

<Button fx:id="button" mnemonicParsing="false" onAction="#startCamera" text="Start Camera" BorderPane.alignment="CENTER">

<BorderPane.margin>

<Insets bottom="15.0" />

</BorderPane.margin>

</Button>

</bottom>

<center>

<ImageView fx:id="currentFrame" fitHeight="325.0" fitWidth="431.0" pickOnBounds="true" preserveRatio="true" BorderPane.alignment="CENTER">

<BorderPane.margin>

<Insets right="-300.0" />

</BorderPane.margin></ImageView>

</center>

<top>

<Slider fx:id="slider" max="300.0" maxWidth="400.0" minWidth="100.0" prefHeight="14.0" prefWidth="100.0" value="150.0" BorderPane.alignment="TOP_RIGHT">

<BorderPane.margin>

<Insets right="5.0" top="10.0" />

</BorderPane.margin></Slider>

</top>

<left>

<Label alignment="TOP_LEFT" text="Threshold" BorderPane.alignment="TOP_LEFT">

<font>

<Font size="17.0" />

</font>

<padding>

<Insets left="30.0" top="-20.0" />

</padding>

</Label>

</left>

<right>

<Slider fx:id="sliderBlur" max="20.0" min="2.0" prefHeight="14.0" prefWidth="402.0" value="5.0" BorderPane.alignment="CENTER">

<padding>

<Insets right="5.0" top="-350.0" />

</padding>

</Slider>

</right>

</BorderPane>

<Label text="Blur">

<GridPane.margin>

<Insets left="50.0" top="-365.0" />

</GridPane.margin>

<font>

<Font size="17.0" />

</font>

</Label>

</children>

</GridPane>.java

package sample;

// импортирование JavaFX-классов

import javafx.event.ActionEvent;

import javafx.fxml.FXML;

import javafx.scene.control.Button;

import javafx.scene.control.Slider;

import javafx.scene.image.Image;

import javafx.scene.image.ImageView;

// импортирование библиотеки OpenCV

import org.opencv.core.*;

import org.opencv.imgproc.Imgproc;

import org.opencv.videoio.VideoCapture;

// импортирование утилит Java

import java.util.ArrayList;

import java.util.LinkedList;

import java.util.List;

import java.util.concurrent.Executors;

import java.util.concurrent.ScheduledExecutorService;

import java.util.concurrent.TimeUnit;

public class Controller {

@FXML

private Button button; // кнопка

@FXML

private Slider slider; // слайдер выбора порога

@FXML

private Slider sliderBlur; //слайдер размытия

@FXML

private ImageView currentFrame; //объект просмотра изображения

private ScheduledExecutorService timer; // таймер для контроля видеострима

private VideoCapture capture = new VideoCapture(); // объект OpenCV, захватывающий видео

private boolean cameraActive = false; // флаг, меняющий поведение кнопки

private static int cameraId = 0; // id используемой камеры

Serial serial = new Serial(); // объект для работы с серийным портом

// событие нажатия кнопки

@FXML

protected void startCamera(ActionEvent event)

{

if (!this.cameraActive) //если камера в данный момент выключена

{

// начинаем захват видео

this.capture.open(cameraId);

// видео доступно?

if (this.capture.isOpened())

{

this.cameraActive = true; //флажок поднимается

// захватываем 30 кадров в секунду (33 мс)

Runnable frameGrabber = new Runnable()

{

@Override

public void run()

{

// захватываем отдельный кадрframe = grabFrame();

// теперь в изображение егоimageToShow = Utils.mat2Image(frame);(currentFrame, imageToShow);

}

};

// настройка таймера

this.timer = Executors.newSingleThreadScheduledExecutor();

this.timer.scheduleAtFixedRate(frameGrabber, 0, 33, TimeUnit.MILLISECONDS);

// надпись на кнопке меняется

this.button.setText("Stop Camera");.initialize();

}

else

{

// ошибка.err.println("Impossible to open the camera connection...");

}

}

else

{

// выключаем камеру

this.cameraActive = false;

// меняем надпись на кнопке

this.button.setText("Start Camera");

// останавливаем таймер

this.stopAcquisition();

}

}

//функция, захватывающая кадр из видео, возвращает переменную frame

private Mat grabFrame()

{

// создаем объект фреймаframe = new Mat();

// объявляем переменную, которая будет отправляться по серийному порту

Byte sendByte = 0;

// если захват работает

if (this.capture.isOpened())

{

// прочитать текущий кадр

this.capture.read(frame);

// если кадр не пустой, обрабатываем его

if (!frame.empty())

{

// переводим в оттенки серого

Imgproc.cvtColor(frame, frame, Imgproc.COLOR_BGR2GRAY);

// переводим в черное и белое.threshold(frame, frame, slider.getValue(), 5000, 1);

// сглаживаем (избавляемся от шумов).medianBlur(frame, frame, ((int) sliderBlur.getValue() * 2) - 1);

// объявляем массив контуров и очищаем<MatOfPoint> contours = new LinkedList<>();.clear();

// вспомогательный массивhierarchy = new Mat();

// ищем контуры.findContours(frame, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_TC89_KCOS);

// Выделяем самый большой контур<MatOfPoint> finalContours = new LinkedList<>();.addFirst(contours.get(0));

for (int j = 0; j < contours.size(); j++)

{

if (Imgproc.contourArea(contours.get(j)) > Imgproc.contourArea(finalContours.getFirst()))

{.removeFirst();.addFirst(contours.get(j));

}

}

// Находим обводящие контуры<MatOfInt> convexHull = new LinkedList<>();.add(new MatOfInt());.convexHull(finalContours.get(0), convexHull.get(0));

// конвертируем MatOfInt в Point для рисования обводок

// цикл по всем контурам<Point[]> hullpoints = new ArrayList<>();

for (int j = 0; j < convexHull.size(); j++)

{[] points = new Point[convexHull.get(j).rows()];

// цикл по всем выпуклостям

for (int k = 0; k < convexHull.get(j).rows(); k++)

{

int index2 = (int) convexHull.get(j).get(k, 0)[0];[k] = new Point(finalContours.get(j).get(index2, 0)[0], finalContours.get(j).get(index2, 0)[1]);

}.add(points);

}

// конвертируем массив Point в MatOfPoint<MatOfPoint> hullmop = new ArrayList<>();

for (int j = 0; j < hullpoints.size(); j++)

{m = new MatOfPoint();.fromArray(hullpoints.get(j));

hullmop.add(m);

}

// ищем дефекты контуров

List<Integer> cdList;<MatOfInt4> convDef = new LinkedList<>();.add(new MatOfInt4());

// функция ищет дефекты.convexityDefects(finalContours.get(0), convexHull.get(0),.get(0));

// оставляем только первый= convDef.get(0).toList();data[] = finalContours.get(0).toArray();

// разбираем дефекты на состанвые точкиdefect[] = new Point[20];

Point start[] = new Point[20];end [] = new Point [20];

int defectCounter = 0;

int defectFilteredCounter = 0;

// переносим в массив точек

for (int j = 0; j < cdList.size(); j = j + 4)

{[defectCounter] = data[cdList.get(j + 2)];[defectCounter] = data[cdList.get(j + 1)];[defectCounter] = data[cdList.get(j)];++;

}

// массивы для отфильтрованных точекdefectFiltered[] = new Point[15];

Point startFiltered[] = new Point[15];

// переменная для угла и ее счетчик

double angle;

double angleCount = 0;

// фильтрация

for (int i = 0; i < defectCounter; i++)

{

// координаты, по которым считается угол

double dx1 = Math.abs (start[i].x - defect[i].x);

double dy1 = Math.abs (start[i].y - defect[i].y);

double dx2 = Math.abs (defect[i].x - end[i].x);

double dy2 = Math.abs (defect[i].y - end[i].y);

// вычисление угла= (dx1*dx2 + dy1*dy2)/Math.sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2));

// вычисление расстояния между соответствующими точками end и start

double lenght = Math.sqrt (Math.pow((start[i].x - end[i].x), 2) + Math.pow((start[i].y - end[i].y), 2);

// условие с подобранными значениями

if ((start[i].y < 450 || start[i].y > 50) && angle > 4.6 && lenght < 5.1)

{

// записываем точки в массив[defectFilteredCounter] = defect [i];[defectFilteredCounter] = start [i];

Источник: https://www.bibliofond.ru/view.aspx?id=903210