Статьи

Kinetis Drone: пульт дистанционного управления с SUMD

Плохая новость: мой ESC (см. « Kinetis Drone: Graupner ESC S3055 Failure «) для моего дрона Kinetis все еще не ремонтируется  🙁 . В любом случае, у меня есть много других вещей, которые нужно сделать для моего проекта дрона. Один из них — работать над пульт дистанционного управления:

Испытательная установка

Испытательная установка

У меня есть Bluetooth и трансивер Nordic nRF24L01 +, подключенный к плате FRDM-22F, который обеспечивает хорошую связь на коротком расстоянии с Bluetooth около 10 м и nRF24L01 + в диапазоне 50-100 м. Для наружного использования мне нужно что-то для диапазона 200-300 м. Поэтому я организовал   контроллер Graupner mx-16 : 8-канальный пульт дистанционного управления, идеально подходящий для полета на квадрокоптере:

В комплект поставки mx-16  входит  приемник Graupner GR-16 :

Граупнер ГР-16

Граупнер ГР-16

GR-16 имеет один порт телеметрии / программирования и может управлять до 8 сервоканалами. Так что было бы возможно напрямую подключить 4 ESC квадрокоптера к четырем первым каналам, но тогда у меня не было бы никакой гиростабилизации. Вместо этого я хочу, чтобы Freescale FRDM-K22F считывал сервосигналы и управлял ESC с помощью Kinetis K22F с помощью датчиков.

Поэтому я хотел бы использовать «стандартный» пульт дистанционного управления со «стандартным» приемником, но читать сигнал приемника с помощью микроконтроллера и управлять двигателями с помощью микроконтроллера.

Серво Сигналы

Выходными сигналами трансивера является обычный сервосигнал: 50 Гц с длительностью 1-2 мс:

Типичный сервосигнал

Типичный сервосигнал

Но 50 Гц довольно медленно для динамической системы, такой как квадрокоптер. Кроме того, это означало бы, что мне нужно выбрать / прочитать по крайней мере четыре таких сигнала, которые были бы выполнимы, но болезненны.

SUMD протокол

Контроллеры полета нуждаются в лучшем способе получения входных сигналов, и для этого существуют несколько аналоговых и сигнальных шинных систем, например,  Futaba SBUS  или  Graupner SUMD .

Вместо отправки значения ШИМ с частотой 50 Гц протокол SUMD представляет собой цифровой сигнал и отправляет несколько каналов с частотой 100 Гц (каждые 10 мс). Захват логического анализатора показывает два 8-канальных пакета данных:

SUMD Data Frames

SUMD Data Frames

С SUMD действительно здорово то, что это обычный протокол UART / Serial: 8N1, 115200 бод  🙂

Пакет данных SUMD

Пакет данных SUMD

Данные имеют заголовок, за которым следуют данные и контрольная сумма. Для приведенного выше кадра вот что означают значения:

  • 0xA8 : идентификация заголовка для Graupner
  • 0x01 или 0x81 : Идентификация для кадра данных с передатчиком в отказоустойчивом (0x81) или нормальном (0x01) состоянии
  • 0x08 : количество каналов с 16- битными данными каждый
  • 0x2EE0… .0x2EE0 : пакеты данных
  • 0xF90F : контрольная сумма CRC

: idea:  Я бы ожидал, что 0x81 отправляется, когда получение находится в безопасном режиме (см. ниже ниже). Но в моих выводах 0x81 отправляется только в том случае, если приемопередатчик включен без сигнала приемника. В противном случае он отправляет 0x01, даже если он потерял радиосигнал. Это не имеет смысла для меня?

Пакеты данных находятся в диапазоне от 0x1c20 (-150%, 900 мкс, расширенная нижняя позиция) до 0x41a0 (+ 150%, 2100 мкс) для расширенной высокой позиции.

Уровень напряжения

Приемник питается от 5 В постоянного тока, но я не нашел документации об уровне напряжения выходных сигналов. К моему удивлению, сигнал SUMD имеет напряжение 3 В, поэтому нет необходимости использовать преобразователь уровня для использования его с микроконтроллером 3,3 В :-):

SUMD Уровень напряжения

SUMD Уровень напряжения

Конфигурация сигнала SUMD

Приемник должен быть настроен на выдачу сигнала SUMD. Сигнал всегда подается на сервопорт номер 8. Настройка скрыта в настройках телеметрии:

Меню телеметрии на mx-16

Меню телеметрии на mx-16

Затем выберите меню настроек:

Меню настроек телеметрии

Меню настроек телеметрии

Настройка, которую я ищу, находится на странице «RX Servo», за « CH OUT TYPE », который по умолчанию «ONCE» для GR-16:

CH OUT TYPE (по умолчанию)

CH OUT TYPE (по умолчанию)

Следующие типы поддерживаются прошивкой моего ресивера (информация от

  1. ONCE : выходы приемника передаются в последовательности: рекомендуется для аналоговых сервоприводов. Этот параметр обеспечивает автоматическое управление сервоприводами с использованием цикла 20 мсек — 30 мсек для двенадцатиканального приемника (заказ № 33512) — независимо от значения, установленного и отображаемого на дисплее RX SERVO под пунктом меню ‘ СРОК.
  2. ЖЕ : выходы приемника передаются в параллельных блоках по четыре, то есть каналы с 1 по 4 и каналы с 5 по 8 принимают сигнал передатчика одновременно в каждом случае: рекомендуется для цифровых сервоприводов. Это особенно полезно, когда несколько сервоприводов используются для определенной функции (например, элеронов), так что все сервоприводы движутся абсолютно синхронно. Также возможно подключение аналоговых сервоприводов; в этом случае вы должны установить 20 мс в пункте меню «PERIOD» на дисплее RX SERVO. Примечание: если вы выберете параметр SAME, особенно важно установить систему питания приемника большой емкости, поскольку почти четыре сервопривода почти всегда работают одновременно, что увеличивает нагрузку на аккумулятор.
  3. SUMI : (входной сигнал суммы): вход для спутникового ресивера. В этом режиме для резервирования можно использовать «спутниковый» приемник, см.  Http://fluggeil.de/articles.php?article_id=116  (на немецком языке).
  4. SUMD : (Sum digital out) Создает цифровой суммарный сигнал, который может быть считан, например, микроконтроллером. Сигнал суммы содержит все сервосигналы в одном пакете данных, поэтому мне нужно только прочитать этот сигнал. Сигнал SUMD всегда выдается на сервоканале 8 на GR-16, и этот канал может отличаться для каждого приемника.

В режиме SUMD я могу настроить  тип отказоустойчивости  и  количество каналов . В отказоустойчивом режиме я могу указать, что произойдет, если приемник не получит сигнал.

  1. SUMD OF ( Failsafe OFF ): в случае потери связи сигнал не подается .
  2. SUMD FS ( Failsafe POSITION ): в случае потери связи отправляются предварительно сконфигурированные отказоустойчивые позиции сервопривода. Например, я могу настроить «безопасные» настройки сервопривода, и если приемник выходит за пределы диапазона, он по умолчанию будет использовать безопасные настройки.
  3. SUMD HD ( Failsafe HOLD ): в этом режиме приемник будет продолжать излучать последние полученные значения.

Я настроил его для  SUMD-FS-08  (SUMD, Failsafe Position с 8 каналами):

Конфигурация SUMD

Конфигурация SUMD

Сигнал SUMD всегда находится на разъеме сервопривода / канале 8 GR-16:

Сигнал SUMD на 8 канале

Сигнал SUMD на 8 канале

SUMD декодер

Используемый мной SUMD-декодер взят из проекта  PX4 PixHawk Autopilot  ( https://pixhawk.ethz.ch/docs/sumd_8c.html ).

: idea:  Исходная реализация PX4 SUMD не обрабатывает отказоустойчивый байт 0x81. Я расширил реализацию, чтобы охватить этот случай.

SUMD Rx Input

Я настроил компонент UART ( AsynchroSerial ) для чтения данных SUMD. Поскольку это только Rx, мне не нужен контакт Tx. Я настроил его для использования UART2 с Rx на PTD2 и 115200 бод. Кроме того, я включил прерывания UART с внутренним буфером в 128 байтов (меньше будет делать это тоже):

Конфигурация SUMD Rx Pin

Конфигурация SUMD Rx Pin

На рисунке ниже показано подключение с помощью SUMD к UART2 / PTD2:

SUMD проводка

SUMD проводка

При использовании модуля Bluetooth можно использовать UART0 с RxD на PTD6:

SUMD с Bluetooth в сочетании

SUMD с Bluetooth в сочетании

Удаленный модуль

Чтобы читать сигналы SUMD, я создал «Удаленный» модуль. Он запускает задачу FreeRTOS для считывания данных из UART. У меня добавлен интерфейс оболочки, чтобы я мог проверить полученные данные канала:

Состояние удаленного канала

Состояние удаленного канала

/*
 * Remote.c
 *
 * Created on: 31.10.2015
 * Author: Erich Styger
 */

#include "Platform.h"
#if PL_HAS_REMOTE
#include 
#include "Remote.h"
#include "FRTOS1.h"
#include "SUMDRx.h"
#include "UTIL1.h"
#if PL_HAS_SUMD
 #include "SUMD.h"
#endif
#if PL_HAS_SHELL
 #include "Shell.h"
#endif

static uint16_t REMOTE_channels[SUMD_MAX_CHANNELS];

#if PL_HAS_SUMD
const uint8_t testSUMD[] = /* test message */
{
 0xA8, /* Graupner ID, start */
 0x01, /* SUMH/SUMD */
 0x08, /* number of channels */
 0x2E, 0xE8, /* data channel 1 */
 0x2E, 0xD0, /* data channel 2 */
 0x2E, 0xF0, /* data channel 3 */
 0x2E, 0xe0, /* data channel 4 */
 0x2E, 0xE0, /* data channel 5 */
 0x2E, 0xE0, /* data channel 6 */
 0x2E, 0xE0, /* data channel 6 */
 0x2E, 0xE0, /* data channel 8 */
 0x57, 0xB4, /* CRC */
};

static uint8_t ReadSUMD(void) {
 int res;
 int i;
 uint8_t rssi=0; /* Received Signal Strength Indicator, not used as SUMD does not provide this */
 uint8_t rx_count=0; /* counter of received packets, will be incremented for each received packet */
 uint16_t channel_count; /* number of received channels in data packet */
 uint16_t channels[SUMD_MAX_CHANNELS]; /* here the channel data get stored */
 uint8_t ch;

 res = 1; /* preset to accumulating */
 while(res==1){
   if (SUMDRx_RecvChar(&ch)==ERR_RXEMPTY) {
     break;
   }
   res = sumd_decode(ch, &rssi, &rx_count, &channel_count, &channels[0], sizeof(channels)/sizeof(channels[0]));
   /* @return 0 for success (a decoded packet), 1 for no packet yet (accumulating), 2 for unknown packet, 3 for out of sync, 4 for checksum error */
 }
 if (res!=0) {
   return ERR_FAILED;
 }
 /* copy data */
 FRTOS1_taskENTER_CRITICAL();
 memcpy(REMOTE_channels, channels, sizeof(REMOTE_channels));
 FRTOS1_taskEXIT_CRITICAL();
 return ERR_OK;
}
#endif

static void Remote(void *pvParameters) {
 (void)pvParameters; /* parameter not used */
 uint8_t res;

 for(;;) {
 #if PL_HAS_SUMD
   res = ReadSUMD();
 #endif
   FRTOS1_vTaskDelay(10/portTICK_RATE_MS);
 }
}

#if PL_HAS_SHELL
static void REMOTE_PrintHelp(const CLS1_StdIOType *io) {
 CLS1_SendHelpStr((unsigned char*)"remote", (unsigned char*)"Group of remote commands\r\n", io->stdOut);
 CLS1_SendHelpStr((unsigned char*)" help|status", (unsigned char*)"Shows remote help or status\r\n", io->stdOut);
}

static void REMOTE_PrintStatus(const CLS1_StdIOType *io) {
 int i;
 uint8_t buf[32];

 CLS1_SendStatusStr((unsigned char*)"remote", (unsigned char*)"\r\n", io->stdOut);

 CLS1_SendStatusStr((unsigned char*)" channels", "", io->stdOut);
 for(i=0;i<sizeof(remote_channels) sizeof(remote_channels[0]);i++)="" {="" cls1_sendnum16u(remote_channels[i],="" io-="">stdOut);
   CLS1_SendStr(" ", io->stdOut);
 }
 CLS1_SendStr("\r\n", io->stdOut);
}

uint8_t REMOTE_ParseCommand(const unsigned char *cmd, bool *handled, const CLS1_StdIOType *io) {
 uint8_t res = ERR_OK;
 int32_t val;
 const unsigned char *p;

 if (UTIL1_strcmp((char*)cmd, (char*)CLS1_CMD_HELP)==0 || UTIL1_strcmp((char*)cmd, (char*)"remote help")==0) {
   REMOTE_PrintHelp(io);
   *handled = TRUE;
 } else if (UTIL1_strcmp((char*)cmd, (char*)CLS1_CMD_STATUS)==0 || UTIL1_strcmp((char*)cmd, (char*)"remote status")==0) {
   REMOTE_PrintStatus(io);
   *handled = TRUE;
 }
 return res;
}
#endif /* PL_HAS_SHELL */


void REMOTE_Init(void) {
 if (FRTOS1_xTaskCreate(
   Remote, /* pointer to the task */
   "Remote", /* task name for kernel awareness debugging */
   configMINIMAL_STACK_SIZE, /* task stack size */
   (void*)NULL, /* optional task startup argument */
   tskIDLE_PRIORITY+2, /* initial priority */
   (xTaskHandle*)NULL /* optional task handle to create */
   ) != pdPASS)
  {
     for(;;){} /* error! probably out of memory */
  }
}
#endif /* PL_HAS_REMOTE */

Первые тестовые прогоны

И вот моя грубая тестовая установка: квадрокоптер (плата FRDM-K22F, двигатели и приемник) питается от батареи. Пульт дистанционного управления используется для воздействия на скорость двигателя (-ов).

Тестовая установка Kinetis Drone с Graupner MX-16

Тестовая установка Kinetis Drone с Graupner MX-16

По соображениям безопасности только один мотор, а квадрокоптер привязан к земле :-):

  1. Включение питания для вертолета
  2. Включение пульта дистанционного управления и включение радио
  3. Перемещение палки, чтобы повлиять на двигатель

Резюме

Теперь у меня есть возможность использовать обычный пульт управления с приемником для отправки сигналов в микроконтроллер. Используя сигнал SUMD, я могу использовать UART для считывания сигнала суммы, а затем обработать его микроконтроллером. Таким образом, у меня есть удобный способ управлять моим квадрокоптером, любым роботом или чем-то еще, для чего я хочу иметь удаленный контроллер  🙂 .

Одним из следующих шагов будет очистка аппаратной проводки и использование датчиков, чтобы помочь мне управлять этим зверем  😉 . И да, мне тоже нужно починить ESC…

Счастливого удаления  🙂

ССЫЛКИ: