Программирование приложений на android
Создана: 31 Октября 2011 Пон 13:25:33.
Раздел: "Компьютерный раздел"
Сообщений в теме: 223, просмотров: 34647
-
Коммуникации между классами приложения
В приложении три класса. Activity, View, Thread
Класс activity используется как форма для отображения представления и для расположения элементов управления – кнопок, также этот класс будет использоваться для обработки данных получаемых с вертолета
View отображает джойстик и параметры полета
Thread для получения данных с вертолета.
Надо создать коммуникации для обмена данными между этими классами
В activity вызываем конструктор конструктор класса NavData и передаем ему в качестве аргумента экземпляр класса
Код: SomeView sv;
NavData navdata;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
sv = (SomeView) findViewById(R.id.sv);
navdata = new NavData(this);
navdata.start();
}
SomeView, это расширение класса View, а NavData расширение класса Thread. Их экземпляры sv и navdata являются полями класса Test и поэтому можем передавать нужные данные из класса Test в классы SomeView и NavData
Для старта экземпляра sv класса SomeView используется инструкция
setContentView(R.layout.activity_test);
Так как он описан в файле ресурса activity_test.xml
Код: <com.example.test.SomeView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/sv"
/>
Также поступаем и в остальных классах
Для SomeView
Код: Test test;
public SomeView(Context context, AttributeSet attrs)
{
super(context,attrs);
this.test= (Test) context;
}
Для NavData
Код: Test mAct;
// SomeView someView;
public NavData(Test mAct) {
this.mAct = mAct;
} -
Сегодня работал над своей программой по управлению drone. Выполнил команду взлет-Take Off , вертолет поднялся на 0,8 метра, потому говорю посадка-Landing, он не реагирует. Еще раз попробовал взлет-посадка не реагирует - висит в воздухе и тихонько сдвигается к дивану. Вышел из программы, мысль пронеслась, что при прекращении связи с вертолетом, он сам сядет, типа - умный. Нет, висит в воздухе и потихоньку дрейфует к дивану. Адреналин начинает заполнять сознание, не могу сосредоточится, руки дрожат.
Стал отталкивать его ракеткой от дивана. Зря, он еще сильнее двигается к дивану. Ракеткой стал подталкивать его вверх. Защитного корпуса не надел, поэтому боялся попасть под винты. В результате вертолет поднялся к потолку и стал буровить винтами потолочную плитку.
Уже от бессилия сильно подтолкнул его ракеткой , он резанул винтом плитку потолочную и резко спланировал кувырком на пол.
Шок. Потитоньку отходил минут десять. -
Выполняю проверку битов состояния drone
Бит MYKONOS_TRIM_COMMAND_MASK почему то всегда равен единице, но это в общем и не мешает нормальной работе с вертолетом.
Еще бывает такое, что сокет принимающий сообщения с порта 5554 (NavData) не может этого сделать. Закрываю периодически оба сокета (на передачу команд в порт 5556 и на прием навигационных данных 5554), открываю снова - результата никакого
Вот сервис для перевода десятичных чисел в формат IEEE-754
For online conversion do this:
[внешняя ссылка]
enter the value (0.2) and press rounded
take the hexadecimal result (3E4CCCCD) and convert it to decimal. Thats the value
This seems right -
То что drone имеет свой SDK это конечно большой плюс. Это избавляет программиста от необходимости изучать конкретное устройство сенсоров и моторов вертолета , не надо знать какие сигналы управляют этими устройствами и какие сигналы используются для передачи информации с сенсоров, и конечно не надо беспокоится о правильной интерпретации этих сигналов.
SDK это своего рода драйвер который берет на себя все общение с аппаратами устройства. Общаться с таким драйвером можно с помощью абстрактной модели устройства которую он создает для пользователя.
Например: прочитать, удалить , записать информацию на устройство.
Удобство использования SDK основано на хорошем описании модели устройства, гибкости модели и так далее.
Описание SDK drone не сказать что хорошее. Приходится сидеть на форумах чтобы определять те абстракции которые он использует для обмена данными с клиентом
За время работы с drone определил, что пакет навигационных данных в режиме demo имеет длину 500 байт.
В случае если что то идет не так, то drone может присылать пакет длиной 32 и 24 байта
Если пакет имеет длину 24 байта это означает что порт 5554 находится в режиме BOOTSTRAP и необходимо заново подсоединится к порту чтобы перевести его режим Demo
drone может передавать клиенту навигационные данные в двух формах
1. Сокращенной или demo, размер 500 байт
2. Полной
Чтобы получать demo версию данных надо отправить на порт 5554 сначала четыре байта 0x01, 0x00, 0x00, 0x00, а затем на порт 5556 команду
AT*CONFIG="+(seq++)+",\"general:navdata_demo\",\"TRUE\"
где seq - порядковый номер команды
Мне представляется такая логика поведения drone. Постоянно прослушивается порт 5554 на предмет получения сигнала прерывания (четыре байта - 0x01, 0x00, 0x00, 0x00). После того как сигнал прерывания получен drone, он ждет команды определяющей формат навигационных данных, типа так
AT*CONFIG="+(seq++)+",\"general:navdata_demo\",\"TRUE\"
Эту команду надо послать на порт 5556 -
Философия общения с drone
Так как для общения с вертолетом используется udp протокол, разработчик должен сам побеспокоится о надежной доставке своих сообщений. Лучшее что приходит в голову это дублирование важных сообщений.
Допустим если мы хотим посадить вертолет то надо отправить соответствующую команду несколько раз. Допустим так:
Код:
send("AT*PCMD=" + (seq++) + ",0,0,0,0,0");
Thread.sleep(INTERVAL);
send("AT*REF=" + (seq++) + ",290717696");
send("AT*REF=" + (seq++) + ",290717696");
Thread.sleep(INTERVAL);
В том смысле, что если вероятность попадания одной ракеты в цель - 0.9, то две ракеты сбивают эту цель с вероятностью - 0.99
Команда AT*PCMD=" + (seq++) + ",0,0,0,0,0 говорит drone, что надо зависнуть в одной точке
Команда AT*REF=" + (seq++) + ",290717696 говорит, что надо совершить посадку в режиме авторотации. Дублируем ее для верности.
Thread.sleep(INTERVAL); задает временной интервал между отправкой команд. Разработчики говорят, что задержка в 30 мс улучшает выполнение команд веротолетом -
Еще о движении
Команда AT*PCMD используется для определения скорости движения в разных направлениях. Она имеет шесть аргументов. Каждый их них имеет имя - sequence number, flag, roll, pitch, gaz, yaw
Первый аргумент - порядковый номер команды. Для его определения при запуске программы инициализируем переменную целого типа и далее в каждой команде отправляемой вертолету на порты 5554, 5556 просто выполняем инкремент этой величины, то есть увеличиваем ее на единицу
Далее, второй аргумент. AR.Drone Developer Guide, p. 36. С помощью этого аргумента задается способ пилотирования вертолета.
Я знаю пока только два - обычный и так называемый "Абсолютный контроль". Способ вождения "абсолютный контроль" удобен тем, что направление перемещения ручки джойстика совпадает в реальным перемещением вертолета, независимо от того каким боком он находится по отношению к пилоту.
flag это 32-х значное двоичное число. Для задания способа пилотирования используется три младших бита. Относительно нулевого бита в руководстве сказано так :
Always set the flag (argument 2) bit zero to one to make the drone consider the other argu-
ments. Setting it to zero makes the drone enter hovering mode (staying on top of the same point
on the ground).
Перевод google : Всегда устанавливайте флаг (аргумент 2) бит нуля до единицы, чтобы сделать дрон рассмотреть другие аргументы. Установка в ноль делает дрон ввести режиме висения (пребывание на вершине той же точке на земле).
Постановка задачи - повернуть вертолет вокруг вертикальной оси на нужный угол.
У летчиков угол поворота вокруг вертикальной оси называется yaw
Но у меня при использовании команды
AT*PCMD=" +(seq++)+",1,0,0,0,1036831949
вертолет хотя и вращался вокруг вертикальной оси, но больше все таки дрейфовал по прямой.
Попробовал поставить вместо единицы ноль, получилось то что надо
То есть для вращения вокруг вертикальной оси я использую команду
AT*PCMD=" +(seq++)+",0,0,0,0,1036831949
1036831949 это число 0,1 в формате IEEE-754. Это число задает скорость вращения в интервале от 1 до -1. В долях максимальной скорости которая принимается за единицу. -
У AR.Drone есть трехосевой магнитометр который используется для полета в режиме "Абсолютный контроль".
В режиме Demo вертолет примерно пятнадцать раз в секунду отправляет навигационные данные клиенту, в режиме отладки (Debug) отправка данных происходит около двухсот раз в секунду.
TCP порт 5559 используется для отправки важных данных, он используется вертолетом для отправки данных о конфигурации
В AR.Drone 2 появилась новая команда AT*PCMD_MAG. Она имеет восемь аргументов и используется для управления движением в режиме "Абсолютный контроль". В этом режиме используется магнитометр и команды вперед/назад/влево/вправо исполняются не относительно вертолета, а относительно джойстиков управления движением клиента. В руководстве по использованию SDK Drone система управления движением клиента называется контроллером. -
Структура пакета навигационных данных. Обязательно в начале пакета присутствуют 4 именованных величины: Заголовок пакета, флаги состояния вертолета , порядковый номер последней команды переданной вертолету клиентом, vison flag и далее может идти еще что-либо. В моем случае это "что-либо" имеет длину 4 байта.
Заголовок пакета 32 бита, флаги состояния - 32 бита, порядковый номер команды - 32 бита и vision flag - 32 бита. Всего 16 байт.
Разбивка по байтам
Header : 0 - 3 (байты с нулевого по третий)
Drone State : 4 - 7
Sequence number : 8 - 11
Vision flag : 12 - 15
"Что-либо" : 16 - 19
Заголок опции navdata : 20-23.
Navdata это структура состоящая из восьми значений
BATTERY : 24 - 27 (восемь байтов, из них 2 первых байта отводятся под идентификатор опции, два следующих содержат размер передаваемой величины и далее идет значение величины, в нашем случае под него отводится четыре байта)
Собственно пакет предназначен для передачи клиенту текущих показаний сенсоров установленных на вертолете
Обратимся опять к схеме из руководства по применению SDK
Пакет навигационных данных имеет блоковую структуру, то есть состоит из отдельных опций (субпакетов, тегов). Каждая опция имеет свое название и структуру, то есть порядок следования значений отдельных величин.
Все блоки (субпакеты) имеют общую структуру. Вот как об этом говорится в руководстве
All the blocks share this common structure :
Listing 7.1: Navdata option structure
typedef struct _navdata_option_t {
uint16_t tag; /* Tag for a specific option */
uint16_t size; /* Length of the struct */
uint8_t data[]; /* Structure complete with the special tag */
} navdata_option_t;
The most important options are navdata_demo_t, navdata_cks_t, navdata_host_angles_t and
navdata_vision_detect_t. Their content can be found in the C structure, mainly in the navdata_common.h.
Опция navdata имеет следующие поля
BATTERY = 24; заряд батареи в процентах
PITCH = 28; угол поворота по поперечной оси, тета, тангаж
ROLL = 32; угол поворота относительно продольной оси, гамма, крен
YAW = 36; угол поворота относительно вертикальной оси, пси, рысканье. Угол пси меняется в диапазоне от +180 до -180 градусов. Положительное направление соответствует движению стрелки часов если смотреть сверху на вертолет. Ноль градусов соответсвует направлению на север.
ALTITUDE = 40; высота
VX = 44; скорость по оси Х
VY = 48; скорость по оси Y
VZ = 52; скорость по оси Z
После знака равно указано смещение относительно начала пакета. Каждая величина в субпакете занимает четыре байта. Общая длина субпакета navdata равна 16+16+8*8*4 = 288 бит -
Еще можно сказать что частота отправки данных в вертолета в режиме demo примерно 15 раз в секунду, а в режиме all data - 200 раз в секунду.
Все данные доходят и коррелируют с поведением вертолета. Только скорость вертолета по оси Z всегда почему то равна нулю. Возможно это связанно с тем что для вычисления скорости используется барометр, может быть он включается на высотах выше 6 метров, а на более низких используется ультразвуковой сенсор, а я летаю в квартире.
В режиме demo общая длина пакета - 500 байт, в режиме all data - 1924 байта -
При включенном питании и выключенных двигателях гироскопы работают. То есть вертолет передает данные об углах pitch, roll и yaw. Высота и скорость по осям не определяются, то есть равны нулю при перемещении вертолета, пробовал поднимать его и перемещать в разных направлениях
-
Самое простое что приходит в голову относительно программного (субъектного) управления полетом вертолета это поворот на месте на заданный угол.
Постановка : пусть нам нужно научить вертолет поворачивать на 90 градусов относительно вертикальной оси.
Действия - ставим вертолет носом на север, взлетаем, даем команду поворота на малой скорости и считываем периодически значение угла поворота, как только он достигает нужного значения даем команду - зависнуть в точке без движений (hovering)
Вторая задача это контроль высоты полета. Ультразвуковой сенсор довольно точно работает, так что будем ориентироваться на его данные
Третья задача это облет прямоугольника. Неизвестно насколько точно вертолет измеряет скорость по осям x и y. Надо поэкспериментировать с моделью корректировки движения по прямой. -
Так, кажется дошли до цели путешествия. Теперь творческие задачи пошли. Творческие задачи это я называю написание правил поведения в той или иной конкретной ситуации.
Теперь можно сделать привал и описать основные структуры которые используются при приеме и обработке данных передаваемых с drone
Специально чтобы получать и обрабатывать данные передаваемые с вертолета создан класс типа thread (поток, нить). У этого класса есть метод run, который используется для связи с вертолетом через два сокета. Один используется для передачи команд вертолету, второй для получения навигационных данных -
Задачи управления вертолетом.
Пусть нужно повернуть парящий в точке вертолет вокруг вертикальной оси.
Наши действия.
1. Извлекаем из пакета данных передаваемых с вертолета текущий угол поворота yaw. Нуль это направление на север. По часовой стрелке, если смотреть сверху на вертолет отсчитываются положительные значения угла, от нуля до ста восьмидесяти градусов, против часовой от нуля до минус ста восьмидесяти. Таким образом в точке происходит переход от плюс 180 до -180.
2. Определяем сумму начальный угол (фи нач) плюс угол поворота (пси). Если сумма положительная, то периодически проверяем условие фи нач + пси < фи тек. Где "фи тек" это текущий угол поворота вертолета. Как только условие выполнено прекращаем поворот.
3. Если сумма отрицательная, то при "фи тек" > 0 продолжаем поворот без проверки условия, Как только "фи тек" становится меньше нуля начинаем проверять условие фи нач + пси > фи тек. Как только условие выполнено прекращаем поворот
4. Для того чтобы определить знак суммы берем остаток от целочисленного деления суммы на 180. Если он равен нулю, то знак суммы не меняется. Если больше нуля, то сумма равна -180 + остаток.
Все.
Да, еще значение суммы фи нач + пси равно 180, то вместо него берем значение минус 180значение минус 180