Ломаем квадрик: вандализация с элементами реверс-инжиниринга

В последнее время авторы взялись ранее купленные ненужные вещи раздербанивать и смотреть, что там внутрях. Подержу-ка и я эту инициативу — у меня много лет назад купленный баксов за 10 квадрик завалялся, и он мне, как есть, явно абсолютно не нужен. Но может для чего и сгодится — ниже вы найдете что-то наподобие реверс-инжиниринга с кучей библиотек.

Для чего я это все делал — в статью не вошло, и так слишком много получается, не у каждого хватит терпения прочитать.

Вот в таком виде квадрик сохранился — и коробка есть, и запасная батарейка, и запасные винты. Помнится, я его купил, когда еще здоров был, и даже несколько раз игрался. Буквально через месяц после покупки все началось — и первым поехало зрение. Картинка раздвоилась и что к чему — уже было непонятно. И каким из двух мультикоптеров управлять, и как далеко он находится — оставалось только гадать.





Берем картину мироздания и тупо смотрим, что к чему.

При раскурочивании игрушки целью было все-таки понять все протоколы, чтобы потом плату можно было использовать в мирных целях.
Раскручиваем пульт управления. В качестве приемо-передатчика используется микросхема XN297, регистры управления похожи на Nordic Semiconductor nRF24L01 с некоторыми дополнениями, но по формату посылки не совсем совместима. С микроконтроллера название сошлифовано, но мы же не лыком шиты, и чувствуем, что это TG54528.



К сожалению, от этого знания толку нуль. Что она из себя представляет и как ее программировать гугл не знает или не захотел мне рассказать. Придется использовать пульт как есть, протокол мы раскопаем позднее.



Дисплейчик используется некий BAOMEI BM-8025A. К сожалению, издевательств не выдержал и после сборки уже не работал.

Собираем пульт и пытаемся разобраться с управлением квадрика.



Обнаруживаем LDO XC6206P282MR на 2.8 Вольта.
Микроконтроллер STM32F031K4 (ARM®32-bit Cortex®-M0 up to 48 MHz, 4 Kbytes of SRAM, 16 Kbytes Flash), гироскоп с акселерометром MPU6881 (оказался вполне совместим с MPU6150, наверняка у DMP прошивка другая, но так как ее описания все равно нет, то и не заботит) и приемопередатчик — тот же XN297, что и в пульте управления.



Рисуем схему соединений — получается что-то типа такого, остальное нас мало волнует:



Подключаем контрольные точки — потенциальным критикам пайки могу только заметить — попробуйте сделать так с жуткой атаксией.



Точки подпайки — используем провод от дохлых наушников-вкладышей.



Вид снизу:



Для начала подключаемся к SPI и смотрим инициализацию XN297

Инициализация

160us
-----
0x200F/0xE00 *
-----
160us
-----
0x2009/0xE00 *
0x2A26/0xE00 0xA867/0x00 0x35CC/0x00 *
0xAFF/0xE26 *
0x3026/0xE00 0xA867/0x00 0x35CC/0x00 *
0x10FF/0xE26 *
0x390B/0xE00 0xDFC4/0x00 0xA703/0x00 *
0x3EC9/0xE00 0x9AB0/0x00 0x61BB/0x00 0xAB9C/0x00 *
0x1EFF/0xEC9 *
0x3F4C/0xE00 0x846F/0x00 0x9C20/0x00 *
0x1FFF/0xE4C *
0x2607/0xE00 *
0x310F/0xE00 *



А теперь, как пульт управления биндится с квадриком — для этого пульт нужно включить с ручкой trottle внизу, поднять ее до упора вверх и снова опустить. В это время нужно посмотреть, что происходит с SPI.

Bind

0x7FF/0x4040
0x2009/0x4000
0x61FF/0x40AA 0xFFFF/0xE62 0xFFFF/0x00 0xFFFF/0xBC 0xFFFF/0x7F7F 0xFFFF/0x201E 0xFFFF/0x4040 0xFFFF/0x00
0x2740/0x4E00
0xE200/0xE00
0x200F/0xE00
-------
0x2009/0xE00
0x2511/0xE00
0x200F/0xE00
0x7FF/0xE0E



После этого переключаемся на I2C и смотрим инициализацию MPU6881 — собственно, чтобы убедиться в совместимости с MPU6150.

Инициализация MPU6881

write to 0x68 ack data: 0x6B 0x02 
write to 0x68 ack data: 0x19 0x01 
write to 0x68 ack data: 0x1A 0x01 
write to 0x68 ack data: 0x1B 0x18 
write to 0x68 ack data: 0x1C 0x18 
write to 0x68 ack data: 0x1D 0x00 
write to 0x68 ack data: 0x1E 0x0A 
write to 0x68 ack data: 0x3B 
read to 0x68 ack data: 0xFF 0xD3 0xFF 0x8A 0x08 0xF9 0x09 0xF9 0xFF 0x7F 0x00 0x24 0xFF 0xFE
write to 0x68 ack data: 0x3B 
read to 0x68 ack data: 0xFF 0xD3 0xFF 0x8A 0x08 0xF9 0x09 0xF9 0xFF 0x7F 0x00 0x24 0xFF 0xFE
write to 0x68 ack data: 0x3B 
read to 0x68 ack data: 0xFF 0xD3 0xFF 0x8A 0x08 0xF9 0x09 0xF9 0xFF 0x7F 0x00 0x24 0xFF 0xFE



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



Теперь как все это будем программировать? Самое простое — использовать Microsoft Visual Studio Code — бесплатная среда, которая прекрасно работает с Linux, если вам это важно. Ставим плагин PlatformIO и создаем любой проект на базе любого контроллера STM32. Во время создания этого проекта PlatformIO сам натащит из интернета все нужные вам инструменты и библиотеки. К сожалению, STM32F031K4 там отсутствует. Но где наша не пропадала?
В каталоге .platformio/platforms/ststm32/boards создаем файл genericSTM32F031K4.json
со следующим содержимым:
genericSTM32F031K4.json

{
  "build": {
    "cpu": "cortex-m0",
    "extra_flags": "-DSTM32F031x4",
    "f_cpu": "48000000L",
    "mcu": "stm32f031k4",
    "product_line": "STM32F031x4",
    "variant": "STM32F0xx/F031K4"
  },
  "debug": {
    "jlink_device": "STM32F031K4",
    "openocd_target": "stm32f0x",
    "svd_path": "STM32F031.svd"
  },
  "frameworks": [
    "arduino",
    "cmsis",
    "stm32cube",
    "libopencm3"
  ],
  "name": "generic STM32F031K4",
  "upload": {
    "maximum_ram_size": 4096,
    "maximum_size": 16384,
    "protocol": "stlink",
    "protocols": [
      "jlink",
      "cmsis-dap",
      "stlink",
      "blackmagic",
      "serial"
    ]
  },
  "url": "https://www.hotmcu.com/stm32f030f4p6-minimum-systerm-boardcortexm0-p-208.html",
  "vendor": "Generic"
}



Теперь можно даже с помощью ардуино программировать этот контроллер, но не рекомендую. Сама по себе не особо эффективная среда ардуино будет работать поверх HAL. Не буду высказывать свое мнение, кубологи будут недовольны — но у такой связки простейшая моргалка светодиодом съест больше 50% доступной памяти. Поэтому я дальше буду пользоваться старой, как дерьмо мамонта, библиотекой libopencm3 или вообще напрямую в регистры писать.



Как всегда, начинаем с самого тупого — поморгаем светодиодами. Для этого нужно написать подпрограммы инициализации и выводы в порты ввода-вывода. Лиха беда начало, пишем:

system.cpp

#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/cm3/systick.h>
#include <system.h>

volatile uint32_t TimeCounter; 

void system_init(void)
{
  rcc_clock_setup_in_hsi_out_48mhz();  // set STM32 to clock by 48MHz from HSI oscillator 
  TimeCounter=0;
  systick_set_clocksource(STK_CSR_CLKSOURCE_AHB);
  STK_CVR = 0;                                   // clear counter 
  systick_set_reload(rcc_ahb_frequency / 1000);  // Set up timer interrupt 
  systick_counter_enable();
  systick_interrupt_enable();
}

void delay_us(uint16_t del_us) 
{
  uint32_t cnt = del_us << 2;
  do
  {
    asm volatile("nop");
    asm volatile("nop");     
    asm volatile("nop");       
    asm volatile("nop");     
  } while (--cnt);
}

void delay(uint32_t time)
{
  TimeCounter = time;
  while(TimeCounter != 0);
}

void sys_tick_handler(void)
{
  if (TimeCounter |= 0) TimeCounter--;
}

void init_LEDs(void)
{
  // Enable clocks to the GPIO subsystems 
  rcc_periph_clock_enable(RCC_GPIOB);
  rcc_periph_clock_enable(RCC_GPIOA);  
  // LED OUTPUTS
  gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO2 | GPIO4 | GPIO12);
  gpio_mode_setup(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO0 | GPIO2);
  gpio_clear(GPIOA, GPIO2 | GPIO4 | GPIO12);
  gpio_clear(GPIOB, GPIO0 | GPIO2);
}

void LedMask(uint8_t mask)
{
  if (mask & 0x01) gpio_set(GPIOA, GPIO2); else gpio_clear(GPIOA, GPIO2);
  if (mask & 0x02) gpio_set(GPIOA, GPIO4); else gpio_clear(GPIOA, GPIO4);  
  if (mask & 0x04) gpio_set(GPIOB, GPIO0); else gpio_clear(GPIOB, GPIO0);  
  if (mask & 0x08) gpio_set(GPIOA, GPIO12); else gpio_clear(GPIOA, GPIO12);   
  if (mask & 0x10) gpio_set(GPIOB, GPIO2); else gpio_clear(GPIOB, GPIO2); 
}

void LedSet(uint8_t mask)
{
  if (mask & 0x01) gpio_set(GPIOA, GPIO2);
  if (mask & 0x02) gpio_set(GPIOA, GPIO4); 
  if (mask & 0x04) gpio_set(GPIOB, GPIO0);  
  if (mask & 0x08) gpio_set(GPIOA, GPIO12);
  if (mask & 0x10) gpio_set(GPIOB, GPIO2); 
}

void LedClear(uint8_t mask)
{
  if (mask & 0x01) gpio_clear(GPIOA, GPIO2);
  if (mask & 0x02) gpio_clear(GPIOA, GPIO4);  
  if (mask & 0x04) gpio_clear(GPIOB, GPIO0);  
  if (mask & 0x08) gpio_clear(GPIOA, GPIO12);   
  if (mask & 0x10) gpio_clear(GPIOB, GPIO2); 
}

void LedToggle(uint8_t mask)
{
  if (mask & 0x01) gpio_toggle(GPIOA, GPIO2);
  if (mask & 0x02) gpio_toggle(GPIOA, GPIO4);  
  if (mask & 0x04) gpio_toggle(GPIOB, GPIO0);  
  if (mask & 0x08) gpio_toggle(GPIOA, GPIO12);   
  if (mask & 0x10) gpio_toggle(GPIOB, GPIO2); 
}



Используем часть этих подпрограмм в основном цикле:
Blink

#include <system.h>

main(void)
{
  system_init();
  init_LEDs();
  while (1)
  {
    uint8_t mask = 1;
    for(uint8_t i=0; i<5; i++)
    {
      LedMask(mask);
      mask <<=1;
      delay(500);
    }
  }
}



Моргает!



Для дальнейшей отладки нам не помешает последовательный вывод, одним светодиодиком придется пожертвовать, вместо него подключим вывод UART — это будет вывод PA2. Когда все будет готово, эту библиотеку нужно будет прибить насмерть, чтобы место не занимала и не мешала могралкам.

UART.cpp

#include <UART.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/usart.h>
#include <math.h>

void init_USART(void)
{
  // only tx at PA2
  rcc_periph_clock_enable(RCC_GPIOA);
  rcc_periph_clock_enable(RCC_USART1);
  // Setup GPIO pins for USART transmit.  
  gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO2);
  gpio_set_af(GPIOA, GPIO_AF1, GPIO2);
  // Setup USART parameters. 
  usart_set_baudrate(USART1, 115200);
  usart_set_databits(USART1, 8);
  usart_set_parity(USART1, USART_PARITY_NONE);
  usart_set_stopbits(USART1, USART_CR2_STOPBITS_1);
  usart_set_mode(USART1, USART_MODE_TX_RX);
  usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);
  usart_enable(USART1);
}


uint8_t num2sym(uint8_t symb)
{
  symb &= 0x0F;
  if (symb<10) symb+='0';
  else         symb+='A'-10; 
  return symb;
}  

void tx_byte_UART(uint8_t c)
{
  tx_UART('0');
  tx_UART('x');
  tx_UART(num2sym(c>>4));
  tx_UART(num2sym©);  
}

void tx_word_UART(uint16_t c)
{
  tx_UART('0');
  tx_UART('x');
  tx_UART(num2sym(c>>12));
  tx_UART(num2sym(c>>8));
  tx_UART(num2sym(c>>4));   
  tx_UART(num2sym©);  
}

void tx_UART(uint8_t c)
{
  while ((USART_ISR(USART1) & USART_ISR_TXE)==0); // TX empty
  usart_send(USART1, c);  
}

void buff_UART(uint8_t *pointer, uint8_t length)
{
  do
  {
    uint8_t data= *pointer;
    tx_UART(num2sym(data>>4));
    tx_UART(num2sym(data));      
    tx_UART(' ');
    pointer++;
  } while(--length);
  tx_UART(0xa);
  tx_UART(0xd);
}



void int2s(uint8_t *String, int16_t Data)
{
  ldiv_t DivNum; 
  uint8_t * Pointer;
  bool sign = false;
  if(Data<0) 
  {
    sign = true;
    Data = -Data;
  }
  
  Pointer = String; 
  for(uint8_t i=0; i<5; i++) *Pointer++ = ' ';
  *Pointer = 0;
  Pointer = String+4; 
  for(uint8_t i=0; i<4; i++)
  {
    if (Data<10)
    {
      *Pointer--= (char)Data+'0'; 
      break;
    }  
    else
    {  
      DivNum = ldiv(Data, 10);    
      *Pointer-- = (char)DivNum.rem+'0'; 
      Data = DivNum.quot;
    }       
  }  
  if (sign) *Pointer = '-';
}  

void str2UART(uint8_t *pointer)
{
  uint8_t maxl=16;
  do
  {
    uint8_t data= *pointer;
    if (data==0) break;
    tx_UART(data);
    pointer++;
  } while(--maxl);
}

void int2UART(uint16_t Number)
{
  uint8_t tx_buff[16];
  int2s(tx_buff, Number);
  str2UART(tx_buff);
}



Больше большие куски кода в текст вставлять не буду, все можно загрузить отсюда. Так как неизвестно, что когда отключат и запретят, лежит на майлрушном облаке, его вряд ли тронут. Вроде как гитхаб уже грозился пакость с отключением устроить. Хотя если бы Муське была бы возможность сохранять небольшие файлы — это было бы намного удобно.

Теперь пробуем поиграться с пультом управления, заодно разберемся со структурой пакетов, которые пульт отправляет. Библиотеку, написанную для XN297 найдете в архиве, ссылка выше. Сам тест выглядит так:

Тест XN297

#include <XN297.h>
#include <SPI.h>
#include <UART.h>
#include <system.h>

void CheckVoltage(void)
{
  adc_read();
  delay(100);
  adc_read();
  if (adc_read()<CODE_MIN)
  {  
    for(uint8_t j=0; j<6; j++)
    {
      uint8_t mask = 1;
      for(uint8_t i=0; i<5; i++)
      {
        LedMask(mask);
        mask <<=1;
        delay(100);
      }
    }
    standby();
  }
}

void TestRadio(void)
{
  static bool binded = false;
  uint16_t out16;
  static uint8_t blink_cnt=0;
  out16 = transfer_word_SPI(0x07, 0xFF);
  if (out16 & 0x40)
  { 
    if (binded) rx_pack();
    else 
    {
      bind();
      binded = true;
      LedClear(0x10);
    }
    buff_UART(rx_buff,16);
  }
  else
  {
    if (!binded) 
    {
      blink_cnt++;
      if (blink_cnt==50)
      {
        blink_cnt=0;
        LedToggle(0x10);
      }
    }
  }
  delay(2);
}
  

int main(void)
{
  system_init();
  init_LEDs();
  adc_init();
  init_USART();
  init_SPI();
  init_XN297();
  CheckVoltage();
  uint8_t mask = 1;
  for(uint8_t i=0; i<5; i++)
  {
    LedMask(mask);
    mask <<=1;
    delay(500);
  }
  while (1)
  {
    TestRadio(); 
  }
}



Теперь можно очень просто разобраться с посылкой пульта управления, у меня получилось вот так:





Управлять можно моторчиками с помощью PWM или сервами с PPM — в библиотеках все есть.

Крутим моторчики и включаем светодиодики с пульта


uint8_t u8map(int16_t x, int16_t in_min, int16_t in_max, int16_t out_min, int16_t out_max) 
{
  return  (x - in_min) *(out_max - out_min) / (in_max - in_min) + out_min;
}


int main(void)
{
  system_init();
  init_LEDs();
  init_PWM();
  init_SPI();
  init_USART();
  init_XN297();

  bool binded = false;
  while (1)
  {
    uint16_t out16;
    out16 = transfer_word_SPI(0x07, 0xFF);
    if (out16 & 0x40)
    { 
      if (binded) 
      {
        rx_pack();
        buff_UART(rx_buff,16);    
        uint8_t status;
        status = rx_buff[14];
        if(status &0x04) gpio_set(GPIOA, GPIO2);  else gpio_clear(GPIOA, GPIO2);
        if(status &0x08) gpio_set(GPIOA, GPIO4);  else gpio_clear(GPIOA, GPIO4);
        if(status &0x10) gpio_set(GPIOA, GPIO12); else gpio_clear(GPIOA, GPIO12);
        if(status &0x20) gpio_set(GPIOB, GPIO0);  else gpio_clear(GPIOB, GPIO0);
        if(status &0x40) gpio_set(GPIOB, GPIO2);  else gpio_clear(GPIOB, GPIO2);
        status = rx_buff[6];
        status = u8map(status, 0, 0xff, 0, 100);
        timer_set_oc_value(TIM1, TIM_OC1, status);
        status = rx_buff[7];
        status = u8map(status, 0x43, 0xbb, 0, 100);
        timer_set_oc_value(TIM1, TIM_OC2, status);
        status = rx_buff[8];
        status = u8map(status, 0x43, 0xbb, 0, 100);
        timer_set_oc_value(TIM2, TIM_OC1, status);
        status = rx_buff[9];
        status = u8map(status, 0x43, 0xbb, 0, 100);
        timer_set_oc_value(TIM2, TIM_OC2, status);        
      }
      else 
      {
        bind();
        binded = true;
      }
    }
    delay(100);
  }
}



Для полноты картины добавим в библиотеки функции для работы с MPU6881. Вообще-то он мне не нужен, но уж раз есть — надо иметь возможность пользоваться. Общеизвестно, что определить положение движущегося объекта при помощи только акселерометра достоверно нельзя, нужен еще гироскоп и, если совсем по-хорошему, и магнетометр. И арифметику вспомнить придется. Вы еще помните, что такое кватернионы? Я — нет.



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

Тест IMU

cImu IMU;
uint8_t cout;

void TestImu(void)
{
    IMU.readAccelData();  // Read the x/y/z adc values
    IMU.readGyroData();  // Read the x/y/z adc values
    IMU.Mahony_no_mag_Update();
    delay(20);
    cout++;
    if (cout==50)
    {
      IMU.quater2euler();
      cout=0;
      int16_t Angles[3];
      Angles[0] = (int16_t)(IMU.roll);
    	Angles[1] = (int16_t)(IMU.pitch);
      Angles[2] = (int16_t)(IMU.yaw);
      
      for(uint i=0; i<3; i++)
      {
        int2UART(Angles[i]);
        tx_UART(' ');  
      }
      tx_UART(0xa);
      tx_UART(0xd);       
    }   
}


int main(void)
{
  system_init();
  init_LEDs();
  init_USART();
  init_i2c();
  
  
	IMU.resetMPU9250(); // Reset registers to default in preparation for device calibration
	IMU.calibrateMPU9250(IMU.gyroBias, IMU.accelBias); // Calibrate gyro and accelerometers, load biases in bias registers
	IMU.initMPU9250();
  IMU.deltat = 0.02;
  cout=0;
  while(1) TestImu();
}



В этой библиотеке вы также найдете общеизвестный трюк по извлечению обратного квадратного корня из Quake III Arena.



Для чего я этот квадрик расковырял — может, в другой раз расскажу. А пока позвольте на этом откланяться — может, кто-то чего-нибудь полезного найдет в моем рассказике.
Добавить в избранное +111 +161
+
avatar
+27
Ну не знаю, какое-то противоречивое ощущение после обзора осталось.
С одной стороны конечно хороший реверсинг, а с другой — зачем вот это двукратное упоминание про «а зачем это всё было — я вам не скажу», и отмазка про «длинный обзор» тут не актуальна — видали раз в 10 больше, от того-же Кирича.
Так что осталось такое себе кликбейтовское послевкусие. Извини ДонБатон, ничего личного, просто моё мнение.
+
avatar
+3
В другой раз — это потому, что процесс еще идет, и что получится или ничего — еще не знаю. Собственно, и то, что уже написано, мало кого заинтересовало.
+
avatar
  • greyyo
  • 02 мая 2022, 17:18
0
специально зарегистрировался, чтобы поставить +, жду продолжения.
+
avatar
+2
Собственно, и то, что уже написано, мало кого заинтересовало
Да нормальный обзор. Просто специфичный, не для широкого круга читателей, так сказать.
+
avatar
+8
NightPrizrak
-знаешь как заинтересовать дурака?
-как?
-завтра расскажу…

© ничего личного, просто моё мнение

Умейте ждать, и не искать во всём кликбейт или подвох.

Интересный обзор и понятно дело что такой реверс быстро не делается, что по железу, что по софту.

P. S. Дон, спасибо за отличный обзор, с нетерпением буду ждать продолжения.
+
avatar
  • iraa
  • 02 мая 2022, 23:51
+2
А смысл?
+
avatar
+1
Масса.

Например возможность дорабатывать прошивку и купив коптер за 10$, дать ему возможности, которые вам нужны, а не те, что сделали и ленивые китаясы.

Возможность прикрутить нормальную аппу, или вообще управлять с ББ и тд.

А ещё это просто интересно — разобраться как что-то сделано и работает.
+
avatar
  • macau
  • 03 мая 2022, 13:30
0
Что такое ББ?
+
avatar
0
Большой брат, так иногда называют стационарный комп)
+
avatar
  • slv55
  • 03 мая 2022, 20:08
0
Не сделаете
У проца мозгов слишком мало
Стм32-103 это ну совсем ни о чем и копеечно

Если хотите дорабатывать прошивку — курите в сторону ardupilot или PX4, оно в исходниках на гитхабе
+
avatar
+3
Не сделаете
Сделаю ;)

Это вам говорит человек, сделавший на спор на attiny опрос аналогового ик-приемника и одновременную работу WS-ленты. Тоже все говорили — «мощности проца не хватит, коды не будут распознаваться!», только на деле спорящим не мощности проца не хватает, а знаний.
+
avatar
  • slv55
  • 04 мая 2022, 21:18
-2
И оно летает? А на улице против ветра тоже летает ваш квадрокоптер на аттини? Покажете?
+
avatar
+6
При чем тут квад на аттини? Я где-то писал, что я на нем сделал квад?

Проц из обзора — это не топ стм-а, но имя мозги и зная асм и не полагаясь на сгенерированый идехой стартап-код и не копипастя со стэковерфлоу и гита из него можно выжать куда больше, чем выжали китайцы на данный момент. Если не умеете — то нефиг всех ровнять по себе.

А тинька, уважаемый, была дана для примера того, что можно сделать, когда все другие будут кричать, что «невозможно».
+
avatar
  • slv55
  • 06 мая 2022, 05:08
-6
+
avatar
+2
Нормально там мозгов. Это при использовании всяческого ардуино… и с гитхаба — маловато. А если самому писать и то, что нужно — более чем достаточно.
+
avatar
  • slv55
  • 06 мая 2022, 05:11
-4
Окей
Напишите сами тогда более продвинутый мозг квадру чтобы мог летать по маршруту используя GPS. Вы я вижу специалист по самостоятельному написанию полетных контроллеров для квадрокоптеров :)
+
avatar
+1
Я не зацикливаюсь на чем-то одном.
+
avatar
  • slv55
  • 06 мая 2022, 21:25
-3
Это по этому вы пишите левоту не по теме?
+
avatar
0
Тоже подумалось об апгреде квадрика, но сам ни разу не разберусь с программированием, а просить кого-то, даже представить не берусь. А уж если за деньги, то за 1000₽ мне рассмеются в глаза. Поэтому самый простой способ апгрейда — купить другой квадрик, чуть дешевле — плату аналогичного, но более продвинутого квадрика.
+
avatar
  • wwest
  • 03 мая 2022, 12:19
+1
Управление крылатой ракетой.
+
avatar
0
немного оффтопа, есть нонейм контроллер mi-light 1809-28 (1at159) подозреваю, что общается по протоколу SPI, но как обнаружить среди ножек какая за что отвечает


какими инструментами пользоваться? (осциллографа конечно же нет)
+
avatar
+13
Логическим анализатором — дешево и сердито
+
avatar
  • ewavr
  • 02 мая 2022, 16:53
+1
Логическим анализатором, стоит копейки.
+
avatar
+3
Интересный прикол насчёт mpu6881. Мышковичь выставил ценник 4 бакса за 1000 шт, китай выставил 1 бакс за 1 шт.
Все чипы изготавливаются в китае, но всё что есть на али — со следами лазерной гравировки.
Оригинальный чип имеет горячее тиснение краской.
И ещё — он жутко шумный, использовать без магнитометра нет смысла.
+
avatar
  • ksiman
  • 02 мая 2022, 18:48
+1
Буквально через месяц после покупки все началось — и первым поехало зрение.
Это с коптером никак не связано?
+
avatar
+2
Нет, конечно.
+
avatar
  • Eeyore
  • 02 мая 2022, 20:24
+2
Спасибо, вас всегда очень интересно читать, неважно- есть практический смысл или нет.
+
avatar
+6
mysku как способ бегства от окружающей действительности.
+
avatar
0
В каком софте рисовали схему?
+
avatar
+3
Kicad
+
avatar
  • RW9UAO
  • 03 мая 2022, 08:56
+3
привет, батон!
в проекте www.multi-module.org/basics/supported-protocols или www.deviationtx.com/wiki/supported_models посмотри, возможно будет тебе щасте =)

кстати, F0 процы читаются. только уметь надо.
+
avatar
0
Два раза на одной странице на самом интересном месте. Вы издеваетесь?
+
avatar
  • RW9UAO
  • 04 мая 2022, 05:47
0
а что конкретно вы хотите видеть в продолжении =)))
+
avatar
0
«F0 процы читаются. только уметь надо»
Мне пока не нужно, но вдруг в копилочку знаний попадётся :)
комментарий скрыт

комментарий скрыт

комментарий скрыт

+
avatar
+3
Килобайта карл :))) это просто кусок примитивного и тупого мусора.
Ек-макарек, чеж вы тогда про attiny думаете? :D
+
avatar
  • slv55
  • 04 мая 2022, 21:16
-1
Квадрокоптер? На аттини? Летать? Управляться?
Вы такое сами делали? Правда или это ваша фантазия?
+
avatar
+3
Простите, у вас пунктик какой-то за людей домысливать или приписывать им что-то?

Там есть цитата, на то, на что я комментарий писал.
Цитата, причем, вашего комментария — попробуйте разобрать буковки, тогда может и мой ответ дойдет :D
+
avatar
  • slv55
  • 06 мая 2022, 19:12
-2
Точно.
Попробуйте прочитать буковки о чем идет речь, а потом уж встревать.
Ииии… я жду от вас вами построенный квадрокоптер на аттини :)
+
avatar
  • wwest
  • 13 мая 2022, 14:58
+1
Вся память боевого управляющего процессора вертолёта КА-50 была аж!!!
12 килобайт! И летал и управлялся, находил цели и стрелял, и сам после убийства пилота возвращался на точку старта и садился.
Для тех кто программировал в СССР на ассемблере или в машинных кодах и этого было МНОГО!
Кстати вся игра с цветной 3Д графикой и генерацией бесконечных вселенных и планет, с симулятором космического истребителя, Элита на пк Синклер Спектрум занимала всего 48 килобайт!
+
avatar
0
Кстати вся игра с цветной 3Д графикой и генерацией бесконечных вселенных и планет, с симулятором космического истребителя, Элита на пк Синклер Спектрум занимала всего 48 килобайт!
Там всей памяти «на борту» было 48 Кб, а игра «весила» чуть меньше 42-х. насколько я помню. :)
+
avatar
+1
49 вроде на загрузке весила. Я дизассемблеровал Elite в 1994(5) году. Дизассемблер аж писал сам. На бейсике. Комьютер «Байт» с офигенной документацией на Z80. Бобинный мафон, ламповый телек, всё ручками чуть не с мусорки достано и починено. Там было два загрузчика. Первый 17 байт стандартный, потом шёл свой загрузчик (там разница была, уже не помню, на байт 30-40), который сперва рисовал картинку, потом грузил тело игры, потом в видеопамять(!) (начальные 6192 байта после ПЗУ). Дальше шла магия, которую я записывал в тетрадки, но уже, увы, не вспомню.
Кстати, из-за картинки Elite грузилась дольше всех намного, учитывая всякие помехи, ещё и не спервого раза. А если вспомнить мигание света в то время, и сохранения на на магнитофон :)

Ах да. В конце-концов она, конечно же, занимала свои 42кб, ибо 6192 — видеопамять.
+
avatar
0
Добаьте описание протокола на открытый проект Multiprotocol Tx Module если не сложно github.com/pascallanger/DIY-Multiprotocol-TX-Module/blob/master/Protocols_Details.md
Автор принимает комиты если есть возможность протестить потом.