Видео полета команды Robodem
http://www.youtube.c...h?v=lZ1qMFPPiY4
и алгоритм полета
На самом деле, как таковой навигации, в классическом понимании, у нас практически не было. Мы проходим сей "лабиринт", подобно человеку, который идёт вперёд по коридору и ему неинтересно знать где север, где юг и в скольких метрах находится его цель. Он просто шагает прямо, стараясь не биться головой об стены и поворачивает когда видит поворот. Всё что мы позволили нашим алгоритмам знать о полигоне, это то что летя "вперёд", надо поворачивать налево, летя "назад", направо, а ширина коридора примерно 4-5 метров. И вот почему:
1) Сделать правильный алгоритм осмотра стен, а делаем мы это исключительно ко камере, к нашему сожалению, мы не успели. Правильно было бы смотреть по сторонам и выбирать проход, куда можно пролететь. Вместо этого, что-бы уложиться в сроки, мы сделали правило левой и правой руки, меняя его при каждой посадке. За что, собственно, и были наказаны дополнительными двумя посадками, пусть и, как я понял по реакции публики, довольно зрелищными. Увидев на обратном пути перегородку и придерживаясь правила правой руки, дрон решил что это поворот и повернул направо, увидев стенку снова, ещё раз, а дальше полетел прямо по коридору, где нас ожидал уже посещённый нами крест. Сев и взлетев, мы полетели по правилу левой руки, поворачивая налево, что было видно в самом конце прохождения поворота. Наконец то после третьей посадки опять включилось правило правой руки и преодолев препятствие мы полетели правильно.
2) У нас не было подходящего пространства похожего на полигон. Так же, левая стена полигона состояла из пено-блоков и давала помехи из линий между ними. Эти линии вполне походили на границу пола на некотором отдалении от нас. Тогда мы решили ограничить выбор расстояния между прямыми, формирующих коридор, расстояниями равными реальным размерам полигона, то есть, ~4 метра.
В остальном, наш дрон просто летел прямо и поворачивал когда перед ним была стена, а при виде креста, с удовольствием совершал на него посадку.
http://forum.rcdesig...d291488-51.html
Программирование на квадрокоптере AR.Drone
#141
Отправлено 25.08.2013, 11:42:49
#143
Отправлено 25.08.2013, 22:12:16
Дисторсия
http://ru.wikipedia.org/wiki/Дисторсия
Калибровка камеры
http://ru.wikipedia....либровка_камеры
11.3 Удаление искажений
http://locv.ru/wiki/...ление_искажений
#144
Отправлено 27.08.2013, 11:38:56
#146
Отправлено 27.08.2013, 11:42:17
Результат выполнения калибровки видеокамеры помещаем в файл с расширением xml
Он содержит данные о двух матрицах
Матрице intrinsic (размерность 3*3) и матрице distortion (размерность 1*4)
Вот содержимое этого файла
<?xml version="1.0"?> <opencv_storage> <intrinsic type_id="opencv-matrix"> <rows>3</rows> <cols>3</cols> <dt>f</dt> <data> 5.63349854e+002 0. 3.24438904e+002 0. 5.65041321e+002 1.64898773e+002 0. 0. 1.</data></intrinsic> <distortion type_id="opencv-matrix"> <rows>1</rows> <cols>4</cols> <dt>f</dt> <data> -5.51602602e-001 3.91032815e-001 -1.13318418e-003 2.73855217e-003</data></distortion> </opencv_storage>
#147
Отправлено 27.08.2013, 12:01:34
#include // Parameter for calibration pattern // Параметы для калибровочного шаблона #define PAT_ROW (7) // Rows of pattern #define PAT_COL (10) // Columns of pattern #define PAT_SIZE (PAT_ROW*PAT_COL) #define CHESS_SIZE (24.0) // Size of a pattern [mm] // -------------------------------------------------------------------------- // cvDrawText(Image, Drowing point, Messages) // Description : Draw the specified text. // Return value : NONE // -------------------------------------------------------------------------- inline void cvDrawText(IplImage *image, CvPoint point, const char *fmt, ...) { // Font static CvFont font = cvFont(1.0); // Apply format char text[256]; va_list ap; va_start(ap, fmt); vsprintf(text, fmt, ap); va_end(ap); // Draw the text cvPutText(image, text, point, &font, cvScalarAll(255)); } // -------------------------------------------------------------------------- // cvAsk(Message) // Description : Show a question. // Return value : NO:0 YES:1 // -------------------------------------------------------------------------- inline int cvAsk(const char *message, ...) { char *arg; char str[256]; // Apply format va_start(arg, message); vsprintf(str, message, arg); va_end(arg); // Show message box return (MessageBox(NULL, str, "QUESTION", MB_YESNO|MB_ICONQUESTION|MB_TOPMOST|MB_SETFOREGROUND) == IDYES); } // -------------------------------------------------------------------------- // main(Number of arguments, Argument values) // Description : This is the entry point of the program. // Return value : SUCCESS:0 ERROR:-1 // -------------------------------------------------------------------------- int main(int argc, char **argv) { // AR.Drone class ARDrone ardrone; // Initialize if (!ardrone.open()) { printf("Failed to initialize.\n"); return -1; } // Images std::vector<IplImage*> images; printf("Press space key to take a sample picture !\n"); // Main loop while (1) { // Key input int key = cvWaitKey(1); if (key == 0x1b) break; // Update if (!ardrone.update()) break; // Get an image IplImage *image = ardrone.getImage(); // If you push Space key if (key == ' ') { // Convert the camera image to grayscale IplImage *gray = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1); cvCvtColor(image, gray, CV_BGR2GRAY); // Detect the chessboard int corner_count = 0; CvSize size = cvSize(PAT_COL, PAT_ROW); CvPoint2D32f corners[PAT_SIZE]; int found = cvFindChessboardCorners(gray, size, corners, &corner_count); // Detected if (found) { // Draw corners. cvDrawChessboardCorners(image, size, corners, corner_count, found); // Add to buffer images.push_back(gray); Beep(3000, 100); printf("Good\n"); /* BOOL Beep ( DWORD dwFreq, // звуковая частота DWORD dwDuration // длительность звучания ); Beep(440, 100); 440 -- частота 100 -- длительность (миллисекунды) У ноты "Ля", например, частота 440 Гц. */ } // Failed to detect else { // Release the image // освобождаем ресурсы cvReleaseImage(&gray); Beep(100, 100); printf("Bad\n"); } } // Display the image cvDrawText(image, cvPoint(15, 20), "NUM = %d", (int)images.size()); cvShowImage("camera", image); } // Destroy the window cvDestroyWindow("camera"); // At least one image was taken if (!images.empty()) { // Total number of images const int num = (int)images.size(); //// For debug //for (int i = 0; i < num; i++) { // char name[256]; // sprintf(name, "images[%d/%d]", i+1, num); // cvShowImage(name, images[i]); // cvWaitKey(0); // cvDestroyWindow(name); //} // Ask save parameters or not if (cvAsk("Do you save the camera parameters ?\n")) { // Detect coners int *p_count = (int*)malloc(sizeof(int) * num); CvPoint2D32f *corners = (CvPoint2D32f*)cvAlloc(sizeof(CvPoint2D32f) * num * PAT_SIZE); for (int i = 0; i < num; i++) { // Detect chessboard int corner_count = 0; CvSize size = cvSize(PAT_COL, PAT_ROW); int found = cvFindChessboardCorners(images[i], size, &corners[i * PAT_SIZE], &corner_count); // Convert the corners to sub-pixel cvFindCornerSubPix(images[i], &corners[i * PAT_SIZE], corner_count, cvSize(3, 3), cvSize(-1, -1), cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS, 20, 0.03)); p_count[i] = corner_count; } // Set the 3D position of patterns CvPoint3D32f *objects = (CvPoint3D32f*)cvAlloc(sizeof(CvPoint3D32f) * num * PAT_SIZE); for (int i = 0; i < num; i++) { for (int j = 0; j < PAT_ROW; j++) { for (int k = 0; k < PAT_COL; k++) { objects[i * PAT_SIZE + j * PAT_COL + k].x = j * CHESS_SIZE; objects[i * PAT_SIZE + j * PAT_COL + k].y = k * CHESS_SIZE; objects[i * PAT_SIZE + j * PAT_COL + k].z = 0.0; } } } // Create matrices CvMat object_points, image_points, point_counts; cvInitMatHeader(&object_points, num * PAT_SIZE, 3, CV_32FC1, objects); cvInitMatHeader(&image_points, num * PAT_SIZE, 1, CV_32FC2, corners); cvInitMatHeader(&point_counts, num, 1, CV_32SC1, p_count); // Estimate intrinsic parameters and distortion coefficients printf("Calicurating parameters..."); CvMat *intrinsic = cvCreateMat(3, 3, CV_32FC1); CvMat *distortion = cvCreateMat(1, 4, CV_32FC1); cvCalibrateCamera2(&object_points, &image_points, &point_counts, cvGetSize(images[0]), intrinsic, distortion); printf("Finished !\n"); // Output a file printf("Generating a XML file..."); CvFileStorage *fs = cvOpenFileStorage("camera.xml", 0, CV_STORAGE_WRITE); cvWrite(fs, "intrinsic", intrinsic); cvWrite(fs, "distortion", distortion); cvReleaseFileStorage(&fs); printf("Finished !\n"); // Release the matrices free(p_count); cvFree(&corners); cvFree(&objects); cvReleaseMat(&intrinsic); cvReleaseMat(&distortion); } // Release the images for (int i = 0; i < num; i++) cvReleaseImage(&images[i]); } // See you ardrone.close(); return 0; }
#148
Отправлено 27.08.2013, 12:31:03
#include "ardrone/ardrone.h" int main(int argc, char **argv) { // AR.Drone class ARDrone ardrone; // Initialize if (!ardrone.open()) { printf("Failed to initialize.\n"); return -1; } // Image of AR.Drone's camera IplImage *image = ardrone.getImage(); // Read intrincis camera parameters CvFileStorage *fs = cvOpenFileStorage("camera.xml", 0, CV_STORAGE_READ); CvMat *intrinsic = (CvMat*)cvRead(fs, cvGetFileNodeByName(fs, NULL, "intrinsic")); CvMat *distortion = (CvMat*)cvRead(fs, cvGetFileNodeByName(fs, NULL, "distortion")); // Initialize undistortion maps CvMat *mapx = cvCreateMat(image->height, image->width, CV_32FC1); CvMat *mapy = cvCreateMat(image->height, image->width, CV_32FC1); cvInitUndistortMap(intrinsic, distortion, mapx, mapy); // Main loop while (1) { // Key input int key = cvWaitKey(1); if (key == 0x1b) break; // Update if (!ardrone.update()) break; // Get an image image = ardrone.getImage(); // Remap the image cvRemap(image, image, mapx, mapy); // Display the image cvShowImage("camera", image); } // Release the matrices cvReleaseMat(&mapx); cvReleaseMat(&mapy); cvReleaseFileStorage(&fs); // See you ardrone.close(); return 0; }
#149
Отправлено 27.08.2013, 16:20:00
#151
Отправлено 01.09.2013, 14:44:23
Из работающих алгоритмов видеораспознавания меток и выработки реакции на них пока только две штуки
1. Первый алгоритм. Метка - белая полоса на черной. Drone увидев полосу через вертикальную камеру тормозит и останавливается
2. Второй алгоритм. Та же метка. Drone пролетая через нее обнуляет координату х вектора перемещения. Вектор перемещения рассчитывается как произведение интервала времени на текущую скорость. Текущую скорость берем через навигационные данные получаемые с drone. Временной интервал рассчитываем
#152
Отправлено 02.09.2013, 15:52:29
Внимание, набираю команду для участия в соревнованиях типа "Летающие роботы"
Нужны программисты, которые смогут писать программы по управлению роботом и его ориентированию в пространстве по датчикам различным, в первую очередь подразумевается обработка видео с целью определения маршрута и текущего положения робота
Используемое устройство - AR.Drone 2.0
ПО - Visual C++ и и проект Puku
Условия конкурса http://www.robots.croc.ru/about/
Обсуждение различных проблем связанных с проведением конкурса
http://forum.rcdesig...read291488.html
Мои темы связанные с программированием летающих роботов
#153
Отправлено 02.09.2013, 20:52:46
Трекинг объектов
http://robocraft.ru/...c.php?f=7&t=425
#154
Отправлено 08.09.2013, 11:40:50
Фильтр_Калмана
Фильтр Кальмана. Постановка задачи
Пусть нас интересует состояние тела которое движется по прямой, без трения. То есть внешних воздействий на тело нет. То есть нужно найти способ как можно точнее определить координату х тела
Данные о текущей скорости поступают с датчика дискретно, через одинаковый интервал времени. Измерения скорости тела неточные. Закон распределения вероятностей значений измеренной скорости тела относительно истинной скорости тела пусть соответствует стандартному нормальному Гауссову распределению с математическим ожиданием 0 и стандартным отклонением 1.
http://ru.wikipedia....е_распределение
http://ru.wikipedia....множение_матриц
Тогда состояние тела в любой момент дискретный времени (через 0,1, 2,... сек после старта) определятся с помощью двух чисел - координаты тела на прямой и скоростью. Зная изменение скорости за интервал времени можно найти ускорение.
Зная эти две величины при условии, что ускорение между двумя моментами времени константа можно сделать прогноз, то есть модель для данного процесса существует.
Формула для расчета координаты
dx = v*dt + a*dt^2/2
x = x0 + dx
--------------------------
Вот просто отличная статья Малинникова про фильтр Кальмана
http://malinnikov.ru...a/#comment-2012
--------------------------
Рассуждения об измерениях. Путь у нас имеется отрезок прямой который нужно измерить с помощью двух линеек. Тогда в зависимости от точности линеек результат измерений будет разный.
1. Если точность линеек одинаковая тогда результат измерений будет равен среднему арифметическому двух измерений. Пусть например при измерении отрезка первой линейкой результат равен 5,5 см , а при измерении второй линейкой результат равен 5,7 см. Тогда среднее значение результата равно 5,6 см.
2. Если точность измерений разная тогда меняется значение среднеквадратичного отклонения. Пусть одна линейка дает точный результат, а вторая врет. Тогда результат измерений будет равен измерению точной линейки и не будет зависеть от результата измерений неточной линейки.
Я хотел логический вывод придумать для общего случая разных сигм (среднеквадратичных отклонений) , но не получилось. Так что просто буду пользоваться формулой которая использована в публикации Малинникова
Для дисперсии результата по двум измерениям с помощью разных инструментов имеем
new_var = 1 / (1 / var1 + 1 / var2)
Для среднего значения
new_mean = (var2 * mean1 + var1 * mean2) / (var1 + var2)
Первому инструменту и результату измерения соответствует синее распределение. Второму - красное. Результат - график с зеленой линией .
#156
Отправлено 18.09.2013, 18:27:22
Отчет об участии команды Robodem в соревнованиях летающих роботов компании КРОК.
http://habrahabr.ru/post/193304/
#157
Отправлено 19.09.2013, 20:02:28
#include <stdio.h> void update(double& mean1, double& var1, double& mean2, double& var2) { mean1 = (var2 * mean1 + var1 * mean2) / (var1 + var2); var1 = 1/(1/var1 + 1/var2); } void predict(double& mean1, double& var1, double& mean2, double& var2) { mean1 = mean1 + mean2; var1 = var1 + var2; } int main(int argc, char **argv) { double mean1[5] = {5, 6, 7, 9, 10}; double mean2[5] = {1, 1, 2, 1, 1}; double measurement_sig = 4; double motion_sig = 2; double mean = 0; double m_sig = 10000; for (int i = 0; i < 5; i ++ ){ update(mean, m_sig, mean1[i], measurement_sig); printf("update: mean = %3.18f, m_sig = %3.18f\n", mean, m_sig); predict(mean, m_sig, mean2[i], motion_sig); printf("predict: mean = %3.18f, m_sig = %3.18f\n", mean, m_sig); } }
#158
Отправлено 22.09.2013, 16:32:36
Вот алгоритм нахождения "точки схода" из статьи
http://dasl.mem.drex...rs_and_hallways
Шаг 1: Обнаружение линий в кадре
Шаг 2: Находим наклон линии
Шаг 3: Используя фильтр наклона линий избавляемся от горизонтальных и вертикальных линий.
Шаг 4: Оставляем только диагональные линии
Шаг 5: Расчет пересечения диагональных линий.
Шаг 6: Выбираем точку с наибольшим количеством пересечений - "точку схода"
#159
Отправлено 02.10.2013, 16:21:53
#160
Отправлено 02.10.2013, 16:22:35
Постановка.
Пусть имеется многоугольник.
Рис. 1
Надо найти вершины с помощью функции cvGoodFeaturesToTrack. Сложность задачи в том, что надо удалить весь шум, то есть особые точки которые располагаются на линиях соединяющих вершины многоугольника и в то же время оставить особые точки которые располагаются в вершинах
Функция ищет на рисунке точки которые лежат в вершине углов. Линии соединяющие вершины если они не строго вертикальны или горизонтальны тоже состоят из углов
Рис. 2
Задача состоит в том, чтобы подбором параметров функции избавится от ненужных особых точек, которые расположены не в вершинах многоугольника, а на его сторонах.
1. Качественные точки получаются при условии что лучи угла являются вертикальными или горизонтальными линиями
Рис. 3
Это результат поиска точек функцией при следующих значениях параметров
cvGoodFeaturesToTrack(prev, eig_img, tmp_img, corners1, &corner_count, 0.99, 4.0, NULL, 3, 0, 0.4);
то есть параметр quality_level равен 0.99
С картинкой изображенной на рис. 3 проблем при поиске "особых точек" не возникает. На всем интервале значений параметра quality_level от 0.99 до 0.01 отбираются только точки лежащие в вершинах прямоугольников.
Для многоугольника у которого вертикальные стороны имеют наклон 10 градусов имеем
Рис. 4
cvGoodFeaturesToTrack(prev, eig_img, tmp_img, corners1, &corner_count, 0.81, 4.0, NULL, 3, 0, 0.4);
quality_level равен 0.81
Рис. 5
quality_level равен 0.99
Рис. 6
quality_level равен 0.5
Рис. 7
quality_level равен 0.1
Количество пользователей, читающих эту тему: 4
пользователей: 0, неизвестных прохожих: 4, скрытых пользователей: 0