Balap FPV pada simulator (kami membuat joystick USB dari remote control radio)

Musim dingin di garis lintang utara adalah waktu ketika pilot FPV memiliki waktu untuk istirahat dari balap dan kerusakan konstan, mengambil besi solder, dan membuat sesuatu yang berguna untuk hobinya.

Karena dingin terbang di luar, kami akan melatih keterampilan piloting pada simulator. Untuk melakukan ini, Anda perlu menghubungkan peralatan radio Anda ke komputer melalui adaptor khusus, yang mengubah sinyal PPM dari remote control ke sinyal USB-joystick yang dipahami komputer. Adaptor semacam itu, tentu saja, tidak biasa dan berharga satu sen di toko-toko Cina. Namun, pengiriman pesanan harus menunggu lama, dan apakah akan berfungsi seperti yang kami harapkan? Misalnya, saya punya yang ini:

Untuk beberapa alasan yang belum saya pahami, ia dengan tegas menolak untuk melakukan kalibrasi secara memadai di simulator FPV Freerider , meskipun itu bekerja dengan baik di Phoenix RC dan Aerofly RC 7. FPV Freerider cukup baik menyampaikan fisika acro-penerbangan pada copter racing, dan selain itu memiliki mode demo gratis.

Dipecahkan - kami membuat adaptor sendiri!

Sedikit peralatan:

Sebagian besar peralatan RC yang kurang lebih serius memiliki konektor tempat mereka mengeluarkan sinyal kontrol dalam format PPM (Pulse Position Modulation). Sinyal PPM adalah urutan pulsa pendek, interval di antaranya menentukan nilai kontrol dari masing-masing saluran peralatan radio.
Inti dari PPM dengan sempurna menyampaikan gambar:


Untuk memecahkan kode PPM, Anda perlu mengukur interval waktu secara akurat antara pulsa berurutan (tidak masalah antara tepi mana: depan atau belakang, karena durasi pulsa itu sendiri selalu sama).

Implementasi:

Menarik inspirasi dari sebuah artikel oleh AlexeyStn tentang pembuatan adaptor PPM-ke-USB berdasarkan STM32F3Discovery, tetapi hanya memiliki Arduino Pro Micro (Leonardo) dengan dukungan perangkat keras USB, mari mulai jalur sederhana ke adaptor kami.

Anda dapat menemukan beberapa proyek serupa di github, dan beberapa bahkan tidak memerlukan perangkat keras USB di controller. Namun, kebanyakan dari mereka harus selesai dengan file untuk mendapatkan sesuatu yang berfungsi. Proyek yang cocok adalah rc-leonardo-joy, yang mulai bekerja segera setelah mengisi sketsa, tetapi segera menunjukkan beberapa kelemahan: semua pembacaan joystick tidak terlalu stabil - penanda kursor pada panel kontrol menari sepanjang waktu di sekitar titik setel. Saya tidak bisa mengatakan bahwa ini secara signifikan mempengaruhi penanganan di simulator, tetapi kami ingin melatih peralatan yang baik!

Kita naik ke kode dan melihat: perhitungan lebar pulsa PPM dilakukan dengan memproses interupsi eksternal dan mengukur interval antara panggilan ke fungsi micros () :

void rxInt(void) {
  uint16_t now,diff;
  static uint16_t last = 0;
  static uint8_t chan = 0;

  now = micros();
  sei();
  diff = now - last;
  last = now;
  if(diff>3000) chan = 0;
  else {
    if(900<diff && diff<2200 && chan<RC_CHANS ) {
      rcValue[chan] = adjust(diff,chan);
    }
    chan++;
  }
}

Baca tentang fungsi micros () dalam dokumentasi Arduino:

Mengembalikan jumlah mikrodetik sejak papan Arduino mulai menjalankan program saat ini. Jumlah ini akan melimpah (kembali ke nol), setelah sekitar 70 menit. Pada papan Arduino 16 MHz (misalnya Duemilanove dan Nano), fungsi ini memiliki resolusi empat mikrodetik (yaitu nilai yang dikembalikan selalu kelipatan empat). Pada papan Arduino 8 MHz (mis. LilyPad), fungsi ini memiliki resolusi delapan mikrodetik.

Artinya, tidak hanya fungsinya yang tidak terlalu akurat dan selalu mengembalikan nilai yang merupakan kelipatan dari 4 Ξs, ia juga meluap setelah 70 menit, memberi kami beberapa nilai melengkung dari interval yang diukur. Tidak bagus Akan lebih baik menggunakan penghitung waktu dan interupsi untuk menangkap sinyal eksternal.

Kami melihat lebih jauh: sebagian besar data pada posisi joystick secara artifisial dibatasi hingga satu byte (0-255):
// Convert a value in the range 1000-2000 to 0-255
byte stickValue(int rcVal) {
  return map( constrain(rcVal - 1000, 0, 1000), 0, 1000, 0, 255);
}

Hmm, saya ingin lebih tepat. Tetapi untuk ini, Anda harus menulis ulang deskriptor HID dan memperbaiki semua tipe data terkait.

Tidak lebih cepat dikatakan daripada dilakukan!
Kami bercabang repositori, menulis ulang kode untuk menggunakan timer untuk menghitung interval PPM:
void initTimer(void) { 
	// Input Capture setup
	// ICNC1: =0 Disable Input Capture Noise Canceler to prevent delay in reading
	// ICES1: =1 for trigger on rising edge
	// CS11: =1 set prescaler to 1/8 system clock (F_CPU)
	TCCR1A = 0;
	TCCR1B = (0<<ICNC1) | (1<<ICES1) | (1<<CS11);
	TCCR1C = 0;

	// Interrupt setup
	// ICIE1: Input capture 
	TIFR1 = (1<<ICF1); // clear pending
	TIMSK1 = (1<<ICIE1); // and enable
}
...

ISR(TIMER1_CAPT_vect) {
	union twoBytes {
		uint16_t word;
		uint8_t  byte[2];
	} timeValue;

	uint16_t now, diff;
	static uint16_t last = 0;
	static uint8_t chan = 0;
	
	timeValue.byte[0] = ICR1L;    // grab captured timer value (low byte)
	timeValue.byte[1] = ICR1H;    // grab captured timer value (high byte)

	now = timeValue.word;
	diff = now - last;
	last = now;

	//all numbers are microseconds multiplied by TIMER_COUNT_DIVIDER (as prescaler is set to 1/8 of 16 MHz)
	if(diff > (NEWFRAME_PULSE_WIDTH * TIMER_COUNT_DIVIDER)) {
		chan = 0;  // new data frame detected, start again
	}
	else {
		if(diff > (MIN_PULSE_WIDTH * TIMER_COUNT_DIVIDER - THRESHOLD) 
			&& diff < (MAX_PULSE_WIDTH * TIMER_COUNT_DIVIDER + THRESHOLD) 
			&& chan < RC_CHANNELS_COUNT) 
		{
			rcValue[chan] = adjust(diff, chan); //store detected value
		}
		chan++; //no value detected within expected range, move to next channel
	}
}

Tambah interval deviasi stick ke 0-1000 dalam deskriptor HID:
	// Joystick
	0x05, 0x01,			// USAGE_PAGE (Generic Desktop)
	0x09, 0x04,			// USAGE (Joystick)
	0xa1, 0x01,			// COLLECTION (Application)
	0x85, JOYSTICK_REPORT_ID,	//   REPORT_ID (3)
	...
	0xA1, 0x00,		    //   COLLECTION (Physical)
	0x09, 0x30,		    //     USAGE (x)
	0x09, 0x31,		    //     USAGE (y)
	0x09, 0x33,		    //     USAGE (rx)
	0x09, 0x34,		    //     USAGE (ry)
	0x15, 0x00,		    //	   LOGICAL_MINIMUM (0)
	0x26, 0xE8, 0x03,	    //     LOGICAL_MAXIMUM (1000)
	0x75, 0x10,	  	    //	   REPORT_SIZE (16)
	0x95, 0x04,		    //     REPORT_COUNT (4)
	0x81, 0x02,		    //     INPUT (Data,Var,Abs)
	0xc0,			    //   END_COLLECTION

	0xc0				// END_COLLECTION

Di sepanjang jalan, ubah uint8_t menjadi uint16_t di mana pun nilai deviasi stick ditransmisikan.
Kami menghapus kode tambahan, menambahkan selusin #define dan kami mendapatkan sketsa yang bagus, diasah agar berfungsi sebagai adaptor PPM-USB.

Hasilnya tersedia di github: github.com/voroshkov/Leonardo-USB-RC-Adapter

Pengaturan Sketsa:

Masuk akal untuk menghapus definisi untuk futaba jika Anda memiliki perangkat keras lain:
#define FUTABA

dan, jika perlu, sesuaikan nilai mikrodetik dalam parameter jika peralatan Anda menghasilkan timing lain:
#define STICK_HALFWAY 500
#define STICK_CENTER 1500
#define THRESHOLD 100


Kompilasi:

Untuk mengkompilasi dan mengunggah sketsa, Anda perlu mengganti perpustakaan USB di lingkungan Arduino itu sendiri, setelah membuat cadangan.
Untuk melakukan ini, kita masuk ke usus Arduino di sepanjang jalan ... \ Arduino \ hardware \ arduino \ cores \ arduino \ , cadangan usbapi.h dan hid.cpp , dan kemudian menimpanya dengan file yang sama dari folder ArduinoLibs dari repositori. Selanjutnya, buka sketsa, hubungkan Arduino Leonardo dan isi.

Koneksi:

Semuanya sangat sederhana: di satu sisi kami memasukkan USB, di sisi lain, kami menyolder dua kabel (pada Digital Pin 4 dan ground) dan menempelkannya masing-masing ke PPM dan ground pemancar. Ternyata entah bagaimana seperti ini:

Pada Windows 7, perangkat ini dikenali sebagai komposit (keyboard, mouse, joystick) dengan nama Arduino Leonardo.

Disebutkan secara khusus layak konektor di peralatan. Di suatu tempat itu adalah jack audio biasa, dan di suatu tempat (seperti di Futaba 7C saya) adalah sesuatu yang lebih rumit:


Untuk pemasangan berbagai konektor "pria", saya telah lama berhasil menggunakan lem panas. Untuk melakukan ini, kami meletakkan kertas atau polietilen pada "ibu", menembus media ini dengan pin sehingga mereka menempel ke konektor di sisi lain, dan kemudian secara bertahap menuangkan lem di antara pin, secara bersamaan membentuknya dengan jari-jari basah. Kabel, tentu saja, harus disolder terlebih dahulu agar tidak melelehkan perekat yang disembuhkan saat disolder. Ternyata tidak selalu estetis, tetapi sangat fungsional:

(Di sini, di konektor, 4 pin diperlukan untuk penentuan posisi yang jelas, hanya ada dua pekerja.)

Itu saja. Kami mengunduh simulator, menghubungkan peralatan dan melatih keterampilan pilot sambil minum teh panas di depan perapian di malam musim dingin yang gelap.

PS

Bagaimana jika tidak ada Arduino Leonardo, tetapi ada Dewan Pengembangan Minimum pada STM32F103C8T6?

Jangan khawatir, sepanjang jalan. Untuk Anda, juga untuk pengembangan saya sendiri, saya porting proyek Alexey Stankevich yang telah disebutkan .
Sumber dan binari yang dikompilasi untuk diunggah ke pengontrol ini dapat ditemukan di sini: github.com/voroshkov/STM32-RC-USB-Adapter .

Saya akan menjawab semua pertanyaan dengan senang hati di komentar.

Selamat menikmati penerbangan!

Source: https://habr.com/ru/post/id388811/


All Articles