Portapackアプリケーション開発チュートリアル(7)nrf24l01復調

少し前にBluetooth Low Energyを行っているときにこのWebページを見ました

https://wiki.bitcraze.io/misc:hacks:hackrf

しかし、nrf24l01の復調に失敗しましたが、Bluetoothを正常に取得しました。

その後、新しく購入した小さな4軸を使用しましたが、復調に失敗したため、そのWebサイトで手順を正直に再現する予定です。

以前にcrazyflie製品(小さな4軸とcrazyradioモジュール)を購入したことがあったので、このcrazyradioモジュールが実験を繰り返すことがわかりました。

また、期間中にいくつかの優れたリソースを見ました。

https://www.bitcraze.io/2015/06/sniffing-crazyflies-radio-with-hackrf-blue/

これは同じウェブサイトの関連コンテンツでもありますが、より詳細です。

http://blog.cyberexplorer.me/2014/01/sniffing-and-decoding-nrf24l01-and.html

これは、nrf24l01とbtleのデコードプログラムの作者による記事です。この記事から、nrf24l01デコードプログラムの入力は2Mデータでなければならないことがわかりました。

次に、nrf24l01の送信機ハードウェアによって選択されたレートモードに従ってダウンサンプリングレートを決定します。nrf24l01で設定された速度が2Mの場合、ダウンサンプリングレートは1です。1Mの場合、ダウンサンプリングレートは2で、256Kの場合、ダウンサンプリングレートは8です。この値は自動的に判断することはできません。送信機に応じて事前に指定しておく必要があります。

また、実験中に穴も見つかりました。gnuradioフローグラフによるfifo出力は、各実験の前にクリアして再作成する必要があります。そうしないと、データが古くなります。デコードが正確かどうかを判断することは不可能です。

私の開発計画は4つのステップに分かれています。

1.実験のcrazyflie Webページで手順を繰り返し、crazyradioを使用して送信し、次にgnuradioフローグラフを使用してfm復調を実行し、fifoに出力してから、nrfデコードプログラムを使用してデコードします。

2. gnuradioのfm復調プログラムとnrf復号化プログラムを組み合わせて、単一のプログラムがcrazyradioによってコンピューター上で送信されたデータを復調できるようにします。

3.この独立したプログラムをportapackに移動して、crazyradioのデータを復調します。

4. portapackを使用して、小さな4軸のリモート制御コマンドを復調します。

これまでのところ、私の最初のステップは達成されています。

最初に、crazyflieライブラリをダウンロードして、Python言語で制御し、必要なデータを送信できるようにしました。

https://github.com/bitcraze/crazyradio-firmware

コンパイルしてインストールする必要はありませんが、いくつかの依存関係をインストールする必要があります

sudo apt install python-usb

次にlibに移動すると、crazyradio.pyが表示されます。これは、私たちが作成したPythonプログラムが呼び出すライブラリです。

次に、同じフォルダーに独自のpythonプログラムtry.pyを作成します。

from crazyradio import Crazyradio
import time
 
cr = Crazyradio()
cr.set_channel(26)
cr.set_data_rate(cr.DR_250KPS)
 
while True:
    cr.send_packet((0,1,2,3,4))
    time.sleep(0.1)

次に実行します

sudo python try.py

これで打ち上げが始まります。

次にフローグラフを描く

自分で描いたくない場合は、以下のフローチャートをダウンロードできますが、そのパラメータは私のものと同じではないので、パラメータを自分のものに変更する必要があります。

https://wiki.bitcraze.io/_media/misc:hacks:nrf24_demod.grc.zip

次に、私の以前の記事を参照して、NRF24-BTLE-Decoderプログラムをコンパイルできます。これは、前述のnrfデコードプログラムです。

完了後の実行シーケンスは次のとおりです。

sudo rm / tmp / fifo

mkfifo / tmp / fifo

次に、gnuradioフローグラフを実行します。

猫/ tmp / fifo | ./nrf24-btle-decoder -d 8
 

ターミナルでこの出力を見ることができます

ほとんどのデータパケットのアドレスは、私たちが送信したデータパケットであるE7E7E7E7E7であることがわかります。データは00 01 02 03 04であり、前のPythonプログラムで送信された0 1 2 3 4です。

干渉により、少数の不正なパケットが発生する場合があります。

これで最初のステップが完了しました。

ステップ2:

gnuradio復調とnrfデコードを組み合わせてみました

hackrf_nrf.cpp:

#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <pthread.h>
#include <libhackrf/hackrf.h>
#include <iostream>


#include <stdint.h>
#include <time.h>
#include <sys/time.h>
#include <stdbool.h>
#include <inttypes.h>

#define MAXIMUM_BUF_LENGTH		(16 * 16384)


/* Global variables */
int32_t g_threshold = 0; // Quantization threshold
int g_srate = 8; 
uint8_t channel_number = 38;

int skipSamples = 1000;

/* Ring Buffer */
#define RB_SIZE 1000
int rb_head=-1;
int16_t *rb_buf;

using namespace std;
static volatile bool do_exit = false;

hackrf_device *device;
uint32_t freq;
uint32_t hardware_sample_rate;
uint16_t buf16[MAXIMUM_BUF_LENGTH];

int16_t buffer[MAXIMUM_BUF_LENGTH];
int lp_len;
int rate_in;
int16_t result_demod[MAXIMUM_BUF_LENGTH];
int result_demod_len;
int pre_r, pre_j;

void sigint_callback_handler(int signum) 
{
    cout << "Caught signal" << endl;
    do_exit = true;
}

void multiply(int ar, int aj, int br, int bj, int *cr, int *cj)
{
	*cr = ar*br - aj*bj;
	*cj = aj*br + ar*bj;
}

int polar_discriminant(int ar, int aj, int br, int bj)
{
    int cr, cj;
    double angle;
    multiply(ar, aj, br, -bj, &cr, &cj);
    angle = atan2((double)cj, (double)cr);
    return (int)(angle / 3.14159 * (1<<14));
}

int rx_callback(hackrf_transfer* transfer)
{
    for (int i = 0; i < transfer->valid_length; i++) 
    {
        double sample =  (int8_t)(transfer->buffer[i]) + 1;
        buf16[i] = (int16_t)sample;    //s->buf16[i] = (int16_t)buf[i] - 127; s->buf16[i] -127~128 uint16_t, unsigned for negative?
    }

    memcpy(buffer, buf16, 2*transfer->valid_length);
    lp_len = transfer->valid_length;

    //fm demod //rate = rate_in =  2M  
    int i, pcm;
    pcm = polar_discriminant(buffer[0], buffer[1], pre_r, pre_j);
    result_demod[0] = (int16_t)pcm;
    for (i = 2; i < (lp_len-1); i += 2)
    {
        pcm = polar_discriminant(buffer[i], buffer[i+1], buffer[i-2], buffer[i-1]);
        result_demod[i/2] = (int16_t)pcm;
    }
    pre_r = buffer[lp_len - 2];
    pre_j = buffer[lp_len - 1];
    result_demod_len = lp_len/2;

    int i4;
    for (i4 = 0; i4 < result_demod_len; i4 += 1)
    {
        int16_t cursamp = (int16_t) (result_demod[i4]);
rb_head++;
		rb_head=(rb_head)%RB_SIZE;
		rb_buf[(rb_head)%RB_SIZE]=(int)cursamp;
		skipSamples = skipSamples - 1;

		if (skipSamples<1)
		{	
			int32_t threshold_tmp=0;
			for (int c=0;c<8*g_srate;c++)
			{
				threshold_tmp = threshold_tmp + (int32_t)rb_buf[(rb_head+c)%RB_SIZE];
			}

			g_threshold = (int32_t)threshold_tmp/(8*g_srate);

			int transitions=0;
			if (rb_buf[(rb_head + 9*g_srate)%RB_SIZE] > g_threshold)
			{
				for (int c=0;c<8;c++)
				{
					if (rb_buf[(rb_head + c*g_srate)%RB_SIZE] > rb_buf[(rb_head + (c+1)*g_srate)%RB_SIZE])
						transitions = transitions + 1;
				}
			}
			else 
			{
				for (int c=0;c<8;c++)
				{
					if (rb_buf[(rb_head + c*g_srate)%RB_SIZE] < rb_buf[(rb_head + (c+1)*g_srate)%RB_SIZE])
						transitions = transitions + 1;
				}
			}
			bool packet_detected=false;
			if (transitions==4 && abs(g_threshold)<15500)
			{
				int packet_length = 0;
				uint8_t tmp_buf[10];
				uint8_t packet_data[500];
				uint8_t packet_packed[50];
				uint16_t pcf;
				uint32_t packet_crc;
				uint32_t calced_crc;
				uint64_t packet_addr_l;

				/* extract address */
				packet_addr_l=0;

				for (int t=0;t<5;t++)
				{
					bool current_bit;
					uint8_t byte=0;
					for (int c=0;c<8;c++) 
					{
						if (rb_buf[(rb_head+(1*8+t*8+c)*g_srate)%RB_SIZE] > g_threshold)
							current_bit = true;
						else
							current_bit = false;
						byte |= current_bit << (7-c);
					}
					tmp_buf[t]=byte;
				}

				for (int t=0;t<5;t++) packet_addr_l|=((uint64_t)tmp_buf[t])<<(4-t)*8;

				/* extract pcf */
				for (int t=0;t<2;t++)
				{
					bool current_bit;
					uint8_t byte=0;
					for (int c=0;c<8;c++) 
					{
						if (rb_buf[(rb_head+(6*8+t*8+c)*g_srate)%RB_SIZE] > g_threshold)
							current_bit = true;
						else
							current_bit = false;
						byte |= current_bit << (7-c);
					}
					tmp_buf[t]=byte;
				}

				pcf = tmp_buf[0]<<8 | tmp_buf[1];
				pcf >>=7;

				/* extract packet length, avoid excessive length packets */
				if(packet_length == 0)
					packet_length=(int)pcf>>3;
				if (packet_length>32) 
					packet_detected = false;

				/* extract data */
				for (int t=0;t<packet_length;t++)
				{
					bool current_bit;
					uint8_t byte=0;
					for (int c=0;c<8;c++) 
					{
						if (rb_buf[(rb_head+(6*8+9+t*8+c)*g_srate)%RB_SIZE] > g_threshold)
							current_bit = true;
						else
							current_bit = false;
						byte |= current_bit << (7-c);
					}
					packet_data[t]=byte;
				}

				/* Prepare packed bit stream for CRC calculation */
				uint64_t packet_header=packet_addr_l;
				packet_header<<=9;
				packet_header|=pcf;
				for (int c=0;c<7;c++){
					packet_packed[c]=(packet_header>>((6-c)*8))&0xFF;
				}

				for (int c=0;c<packet_length;c++){
					packet_packed[c+7]=packet_data[c];
				}

				/* calculate packet crc */
				const uint8_t* data = packet_packed; 
				size_t data_len =  7+packet_length;
				bool bit;
				uint8_t cc;
				uint_fast16_t crc=0x3C18;
				while (data_len--) {
				cc = *data++;
				for (uint8_t i = 0x80; i > 0; i >>= 1) 
				{
					bit = crc & 0x8000;
					if (cc & i) 
					{
						bit = !bit;
					}
					crc <<= 1;
					if (bit) 
					{
						crc ^= 0x1021;
					}
				}
					crc &= 0xffff;
				}
				calced_crc = (uint16_t)(crc & 0xffff);

				/* extract crc */
				for (int t=0;t<2;t++)
				{
					bool current_bit;
					uint8_t byte=0;
					for (int c=0;c<8;c++) 
					{
						if (rb_buf[(rb_head+((6+packet_length)*8+9+t*8+c)*g_srate)%RB_SIZE] > g_threshold)
							current_bit = true;
						else
							current_bit = false;
						byte |= current_bit << (7-c);
					}
					tmp_buf[t]=byte;
				}
				packet_crc = tmp_buf[0]<<8 | tmp_buf[1];

				/* NRF24L01+ packet found, dump information */
				if (packet_crc==calced_crc)
				{
					printf("NRF24, Threshold:%"PRId32", Address: 0x%08"PRIX64" ",g_threshold,packet_addr_l);
					printf("length:%d, pid:%d, no_ack:%d, CRC:0x%04X data:",packet_length,(pcf&0b110)>>1,pcf&0b1,packet_crc);
					for (int c=0;c<packet_length;c++) printf("%02X ",packet_data[c]);
					printf("\n");
					packet_detected = true;
				} 
				else
					packet_detected = false;
			}
			if (packet_detected) 
			{
				skipSamples=20;
			}
		}

    }   
    return 0;
}

int main(int argc, char **argv)
{
    signal(SIGINT, &sigint_callback_handler);
    int result;
    rb_buf = (int16_t *)malloc(RB_SIZE*2);
    freq = 2426e6;
    rate_in = 2000000;

    hardware_sample_rate = (uint32_t)(rate_in);

    result = hackrf_init();

    if( result != HACKRF_SUCCESS ) 
    {
        cout << "hackrf_init() failed" << endl;
        return EXIT_FAILURE;
    }

    result = hackrf_open(&device);
    if( result != HACKRF_SUCCESS ) 
    {
        cout << "hackrf_open() failed" << endl;
        return EXIT_FAILURE;
    }

    result = hackrf_set_lna_gain(device, 14);
    if( result != HACKRF_SUCCESS ) 
    {
        cout << "hackrf_set_lna_gain() failed" << endl;
        return EXIT_FAILURE;
    }

    result = hackrf_set_vga_gain(device, 20);
    if( result != HACKRF_SUCCESS ) 
    {
        cout << "hackrf_set_vga_gain() failed" << endl;
        return EXIT_FAILURE;
    }
		
    /* Set the frequency */
    result = hackrf_set_freq(device, freq);
    if( result != HACKRF_SUCCESS ) 
    {
        cout << "hackrf_set_freq() failed" << endl;
        return EXIT_FAILURE;
    }

    /* Set the sample rate */
    result = hackrf_set_sample_rate(device, hardware_sample_rate);
    if( result != HACKRF_SUCCESS ) 
    {
        cout << "hackrf_set_sample_rate() failed" << endl;
        return EXIT_FAILURE;
    }

    result = hackrf_set_baseband_filter_bandwidth(device, hardware_sample_rate);
    if( result != HACKRF_SUCCESS )
    {
        cout << "hackrf_baseband_filter_bandwidth_set() failed" << endl;
        return EXIT_FAILURE;
    }
        

    fprintf(stderr, "Output at %u Hz.\n", rate_in);
    usleep(100000);
	
    result = hackrf_start_rx(device, rx_callback, NULL); 

    while ((hackrf_is_streaming(device) == HACKRF_TRUE) && (do_exit == false)) 
    {
        usleep(100000);
    }

    if (do_exit)
    {
        fprintf(stderr, "\nUser cancel, exiting...\n");
    }
    else 
    {
        fprintf(stderr, "\nLibrary error, exiting...\n");
    }

    result = hackrf_close(device);
    if(result != HACKRF_SUCCESS)
    {
        cout << "hackrf_close() failed" << endl;
    } 
    else 
    {
        cout << "hackrf_close() done" << endl;
    }

    hackrf_exit();
    cout << "hackrf_exit() done" << endl;
  
    return 0;
}
g++ hackrf_nrf.cpp -o hackrf_nrf -lhackrf -pthread
./hackrf_nrf 

 ゲインが高すぎてはいけないこと忘れないでくださいそうでなければそれは受け取られません

3番目のステップ:

マージされたコードをポートパックに追加し、ブトルを模倣しました。2MPS信号を復調するために、8MHzを4倍から2MHzにダウンサンプリングする必要がありましたが、機能しないことがわかりました。4MHzから4倍にしかダウンサンプリングできないため、理論的には1MPSと250KPSを復調できますが、実際には1MPSでも機能しないため、現時点では250KPSしか復調できません。

私のcrazyradioによって送信されたデータパケットは、赤い丸でデコードされます。

後で、実際の小さな4軸リモコンを復調する場合があります。

コードがgithubにアップロードされ、変更された部分はbtleに似ています。主に4つのファイルui_nrf_rx.cpp ui_nrf_rx.hpp proc_nrfrx.cpp proc_nrfrx.hppです。

4番目のステップ:

crazyflie-clients-pythonをダウンロードしてインストールすると、小さな航空機の地上局がインストールされます。crazyradioを使用してcrazyflieと双方向で通信したり、データ転送情報を確認したりできます。ジョイスティックがあれば、航空機を制御することもできます。

git clone https://github.com/bitcraze/crazyflie-clients-python.git 

#如果pip3命令安装这个包的时候,提示internal之类的错误,要运行下面两行
wget https://bootstrap.pypa.io/get-pip.py  --no-check-certificate
sudo python3 get-pip.py

#然后再次用pip3安装
pip3 install -e . --user

#装完就能运行了,记得加sudo,否则无法访问crazyradio
sudo ./cfclient

さらに、この地上局がnrf24l01を呼び出してデータを送信する方法を深く研究したい場合は、調べることをお勧めします

https://github.com/bitcraze/crazyflie-lib-python

ここのコードはcflibを生成し、crazyflie-clients-pythonがインストールされると、コンパイルされたバージョンが自動的にインストールされます。したがって、このcrazyflie-lib-pythonはコードを監視するためだけのものであり、インストールを繰り返さないでください。このパッケージを自分でコンパイルしてインストールする場合は、crazyflie-clients-pythonをインストールする前に行う必要があります。手順も異なります。

ビデオ:https : //www.bilibili.com/video/BV1vT4y1G7S7

ここではゲームのジョイスティックを見つけられなかったので、今日示したのはデジタルデータ送信のみです。コントロールでは、USBジョイスティックの代わりにIphoneを使用してBluetooth経由で携帯電話に接続します。

おすすめ

転載: blog.csdn.net/shukebeta008/article/details/105478579