倒车 2.4Ghz 四轴飞行器遥控器

逆向工程 尖峰 阿杜伊诺 偏僻的
2021-06-28 07:33:04

TL; DR - 我不明白为什么在窃听遥控器上的 SPI 命令后,我无法用 Arduino 和 NRF24L01 复制四轴飞行器的遥控器。

所以我得到了这个便宜的四轴飞行器,实际上有 3 种不同的型号(这个这个这个,三个模型的原理都是一样的)所有模型都使用BK2423 无线电,它应该与NRF24l01空气兼容- 这就是我所拥有的.

因此,由于我在网上(令人惊讶地)发现有关此事的信息很少,因此我在遥控器的 MPU 和它的 BK2423 之间放置了一些探针,并使用 Saleae Logic Analyzer 读取两者之间在 SPI 总线上运行的通信。我发现它有 3 个主要阶段:配置、搜索/绑定和命令,其中 MCU 执行一些调整,如下所述。

在配置阶段,正在设置一些寄存器,例如 Rx 的管道编号和地址、RF 通道等。这是配置捕获的一部分: 配置阶段

所以初始 Tx(和 Rx)地址是 5 个字节:0xCCCCCCCCCC并且初始 RF 通道是0x2D两个芯片的默认地址长度为 5 字节,由于遥控器不会改变它,因此长度应保持为 5 字节。

然后是搜索阶段。在那个阶段,遥控器一遍又一遍地发送基本相同的数据,只是改变了射频信道。这是最后一个搜索包:

搜索阶段

因此,在使用不同的 RF 通道进行多次传输后,会发生一些奇怪的事情。遥控器击中了四轴飞行器的正确 RF 通道,但我无法弄清楚他是如何理解这一点的,因为状态寄存器(在 MISO 通道上)在最后一个搜索数据包中保持不变。这是远程控制 MCU 告诉 BK2423 更改射频通道的地方,周围没有任何其他证据:

搜索阶段后

然后 MCU 告诉 BK2423 将地址和 RF 通道更改为正确的。它一定是正确的,因为四轴飞行器反应正确:

再次更改地址和射频通道

从此,遥控器发出指令包,四轴飞行器愉快地飞来飞去。我无法正确通过搜索阶段。

我使用了这个项目中的一些代码(取自这个页面)并更改了 HCD.cpp 以匹配我嗅探到的内容。这里仅是我更改的两种方法(该文件中的其余代码保持不变):

void HCD::bind(unsigned char *ID)
{
  for(unsigned char i=0;i<4;i++)
    noteID[i]=ID[i];

  state=HS_CONNECT;
  radio.offline();
    radio.txbuf[0] = 0x3F;
    radio.txbuf[1] = 0x4C;
    radio.txbuf[2] = 0x84;
    radio.txbuf[3] = 0x6F;
    radio.txbuf[4] = 0x9C;
    radio.txbuf[5] = 0x20;
    radio.sendBuffer(6); 
    radio.txbuf[0] = 0x3E;
    radio.txbuf[1] = 0xC9;
    radio.txbuf[2] = 0x9A;
    radio.txbuf[3] = 0xB0;
    radio.txbuf[4] = 0x61;
    radio.txbuf[5] = 0xBB;
    radio.txbuf[6] = 0xAB;
    radio.txbuf[7] = 0x9C;
    radio.sendBuffer(8); 
    radio.txbuf[0] = 0x39;
    radio.txbuf[1] = 0x0B;
    radio.txbuf[2] = 0xDF;
    radio.txbuf[3] = 0xC4;
    radio.txbuf[4] = 0xA7;
    radio.txbuf[5] = 0x03;
    radio.sendBuffer(6); 

    radio.txbuf[0] = 0x30;
    radio.txbuf[1] = 0xCC;
    radio.txbuf[2] = 0xCC;
    radio.txbuf[3] = 0xCC;
    radio.txbuf[4] = 0xCC;
    radio.txbuf[5] = 0xCC;
    radio.sendBuffer(6);

    radio.txbuf[0] = 0x2A;
    radio.txbuf[1] = 0xCC;
    radio.txbuf[2] = 0xCC;
    radio.txbuf[3] = 0xCC;
    radio.txbuf[4] = 0xCC;
    radio.txbuf[5] = 0xCC;
    radio.sendBuffer(6);

    radio.txbuf[0] = 0xE1;
    radio.txbuf[1] = 0x00;
    radio.sendBuffer(2);

    radio.txbuf[0] = 0xE2;
    radio.txbuf[1] = 0x00;
    radio.sendBuffer(2);

    radio.txbuf[0] = 0x27;
    radio.txbuf[1] = 0x70;
    radio.sendBuffer(2);

    radio.txbuf[0] = 0x21;
    radio.txbuf[1] = 0x00;
    radio.sendBuffer(2);

    radio.txbuf[0] = 0x22;
    radio.txbuf[1] = 0x01;
    radio.sendBuffer(2);

    radio.txbuf[0] = 0x23;
    radio.txbuf[1] = 0x03;
    radio.sendBuffer(2);

    radio.txbuf[0] = 0x25;
    radio.txbuf[1] = 0x2D;
    radio.sendBuffer(2);

    radio.txbuf[0] = 0x24;
    radio.txbuf[1] = 0x00;
    radio.sendBuffer(2);

    radio.txbuf[0] = 0x31;
    radio.txbuf[1] = 0x09;
    radio.sendBuffer(2);

    radio.txbuf[0] = 0x26;
    radio.txbuf[1] = 0x07;
    radio.sendBuffer(2);

    radio.txbuf[0] = 0x50;
    radio.txbuf[1] = 0x73;
    radio.sendBuffer(2);

    radio.txbuf[0] = 0x3C;
    radio.txbuf[1] = 0x00;
    radio.sendBuffer(2);

    radio.txbuf[0] = 0x3D;
    radio.txbuf[1] = 0x00;
    radio.sendBuffer(2);

    radio.txbuf[0] = 0x31;
    radio.txbuf[1] = 0x09;
    radio.sendBuffer(2);

    radio.txbuf[0] = 0x1D;
    radio.txbuf[1] = 0x00;
    radio.sendBuffer(2);


}


void HCD::update(unsigned char *payload)
{
Serial.print("Sending, state: ");
Serial.print(state);
Serial.print("  Channel: ");
Serial.println(channel);
  unsigned char c=0;

  switch(state)
  {
  case HS_CONNECT:

    radio.offline();
    radio.txbuf[0] = 0x27;
    radio.txbuf[1] = 0x70;
    radio.sendBuffer(2); 
    radio.txbuf[0] = 0xE1;
    radio.txbuf[1] = 0x00;
    radio.sendBuffer(2); 
    radio.txbuf[0]=0x25;
    radio.txbuf[1]= channel; //0x2A;
    radio.sendBuffer(2);      //-Chan

    //radio.block(baseAddress);
    //radio.block(flushTX);

    radio.txbuf[0]=0xA0;
    radio.txbuf[1]=0x20;
    radio.txbuf[2]=0x14;
    radio.txbuf[3]=0x03;
    radio.txbuf[4]=0x25;
    radio.txbuf[5]=0x1F; //noteID[0];
    radio.txbuf[6]=0xC3; //noteID[1];
    radio.txbuf[7]=0x00; //noteID[2];
    radio.txbuf[8]=0xE2; //noteID[3];
    radio.txbuf[8]=0xAA; //noteID[3];
    radio.sendBuffer(9);      //-tx data
    //radio.block(PTX);
    radio.online();

    while(!c)
      c=radio.getStatus();
    radio.clrStatus();
     Serial.print("Status: " );
     Serial.println(c);
    if(c&0x10)  //MRT
    {
      state=HS_UNINITIALIZED;
      Serial.println("Uninitializing :( Connecting");
    }

    if(c&0x20)  //ACK
    {
      Serial.println("ACK Connecting");
      state=HS_CONNECTED;
    }
    break;

  case HS_CONNECTED:

    radio.offline();

    radio.txbuf[0]=0x25;
    radio.txbuf[1]=channel;
    radio.sendBuffer(2);      //-Chan


    radio.txbuf[0]=0x2a;
    radio.txbuf[1]=noteID[0];
    radio.txbuf[2]=noteID[1];
    radio.txbuf[3]=noteID[2];
    radio.txbuf[4]=noteID[3];
    radio.txbuf[5]=0xCC;
    radio.sendBuffer(6);      //-tx data

    radio.txbuf[0]=0x30;
    radio.txbuf[1]=noteID[0];
    radio.txbuf[2]=noteID[1];
    radio.txbuf[3]=noteID[2];
    radio.txbuf[4]=noteID[3];
    radio.txbuf[5]=0xAA;
    radio.sendBuffer(6);      //-tx data

    radio.online();

    radio.block(flushTX);

    radio.txbuf[0]=0xA0;
    radio.txbuf[1]=payload[0];
    radio.txbuf[2]=payload[1];
    radio.txbuf[3]=payload[2];
    radio.txbuf[4]=payload[3];
    radio.txbuf[5]=payload[4];
    radio.txbuf[6]=payload[5];
    radio.txbuf[7]=payload[6];
    radio.txbuf[8]=payload[7];
    radio.sendBuffer(9);      //-tx data

    radio.txbuf[0]=0x20;
    radio.txbuf[1]=0x7A;  //-TX
    radio.sendBuffer(2);

    while(!c)
      c=radio.getStatus();
    radio.clrStatus();


    if(c&0x10)  //MRT
    {
      Serial.println("MRT - connected");
    }

    if(c&0x20)  //ACK
    {
      Serial.println("ACK - connected");
    }

    break;

  }
}

我正在使用一个相当简单的 Arduino 草图来调用这些方法(这是上述项目中 INO 文件的修改版本):

#include <HCD.h>
HCD drone0;

unsigned char ID0[]={
  0x1F, 0xC3, 0x00, 0xCC};
unsigned char payload0[]={  0x0, 0x20, 0x14, 0x03, 0x25, 0x1F, 0xC3, 0x00 };
unsigned char payload1[]={
  0x00,0x70,0x70,0x1E,0x1E,0x00,0x10,0x7E};

void setup()
{
  Serial.begin(19200);
  Serial.println("ON");
  Serial.println("Connecting a");
  drone0.bind(ID0);
  drone0.setChannel(0x25);
}

unsigned long timer=0;

unsigned char chs[] = { 0x2A, 0x20, 0x34, 0x16, 0x3E, 0x0C, 0x48};
void loop()
{
  for (int i=0; i<128; i++)
  {
     drone0.setChannel(i);
     drone0.update(payload0);
     delay(10);
  }
  delay(2000);  
  drone0.setChannel(0x2); 
  drone0.update(payload1);
  delay(2000);
}

然而,四轴飞行器似乎轻轻地忽略了这个代码和它的许多变体。

如果有人在我的问题中遇到了这条线,我将不胜感激他/她可以提供的任何帮助。

1个回答

您的代码中有一些我不明白的项目:

  1. 在最初的“绑定”例程中,有命令 0x3F、0x3E、0x39,对应寄存器 1F、1E、19,如果我理解正确的话。这些未记录在 NRF24l01 数据表中(顺便说一句,您的链接不起作用)。

  2. 您使用正确的命令 0xA0 发送有效负载。但是,您总共发送了 9 个字节,包括命令。这是否意味着您发送的有效负载仅包含 8 个字节?在你的有效载荷发送命令之一中,你将 txbuf[8] 放入两次。也许你的意思是第二次 txbuf[9] 代替?

  3. 作为最后一个命令,您发送 0x20。如果我猜对了,这就是“写入配置”。这不应该早点出现吗?

否则,我对四轴飞行器一无所知(只是亚马逊想使用它们......)