工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Manufacturing Technology >> 製造プロセス

DIYArduinoRC送信機

チュートリアルでは、DIYArduinoRC送信機を構築する方法を学びます。自分が作成するプロジェクトではワイヤレス制御が必要になることがよくあるので、ほとんどすべてに使用できるこの多機能無線コントローラーを作成しました。

次のビデオを見るか、以下のチュートリアルを読むことができます。

概要

これで、レシーバー側でわずかな調整を行うだけで、Arduinoプロジェクトをワイヤレスで制御できます。この送信機は、RC玩具、車、ドローンなどを制御するための商用RC送信機としても使用できます。そのためには、これらの商用RCデバイスを制御するための適切な信号を生成する単純なArduinoレシーバーが必要です。

このビデオでは、Arduinoロボットカーの制御、前のビデオからのArduino Antロボットの制御、ESCといくつかのサーボモーターを使用したブラシレスDCモーターの制御のいくつかの例を通じて、すべてがどのように機能するかを説明します。

このコントローラーの無線通信は、NRF24L01トランシーバーモジュールに基づいており、増幅アンテナと併用すると、オープンスペースで最大700メートルの安定した範囲を確保できます。 14チャンネルを備えており、そのうち6チャンネルはアナログ入力で8チャンネルはデジタル入力です。

2つのジョイスティック、2つのポテンショメータ、2つのトグルスイッチ、6つのボタンに加えて、加速度計とジャイロスコープで構成される内部測定ユニットがあり、コントローラを動かしたり傾けたりするだけで物事を制御するためにも使用できます。

ArduinoRC送信機の回路図

まず、回路図を見てみましょう。このRCコントローラーの頭脳は、約7.4ボルトを生成する2つのLiPoバッテリーを使用して電力を供給されるArduinoProMiniです。電圧を5Vに下げる電圧レギュレーターを備えたProMiniのRAWピンに直接接続できます。 Arduino Pro Miniには2つのバージョンがあることに注意してください。たとえば、私が持っているバージョンは5Vで動作し、もう1つは3.3Vで動作します。

一方、NRF24L01モジュールには3.3Vが厳密に必要であり、専用の電源から供給することをお勧めします。したがって、バッテリーに接続されている3.3V電圧レギュレーターを使用し、7.4Vを3.3Vに変換する必要があります。また、電圧をより安定させるために、モジュールのすぐ隣にデカップリングコンデンサを使用する必要があります。これにより、無線通信もより安定します。 NRF24L01モジュールはSPIプロトコルを使用してArduinoと通信し、MPU6050加速度計とジャイロモジュールはI2Cプロトコルを使用します。

このArduinoチュートリアルに必要なコンポーネントは、以下のリンクから入手できます。

  • NRF24L01トランシーバモジュール………..
  • NRF24L01 + PA+LNA……………………。
  • ポテンショメータ………………………………..
  • サーボモーター……………………………………
  • トグルスイッチ……………………………。…..
  • ジョイスティック…………………………………………..–このジョイスティックにはブレイクアウトボードが付属しているため、ジョイスティックをはんだ除去する必要があります
  • ブレイクアウトボードのないジョイスティック…………Ebay
  • Arduino ProMini……………………………..–このボードにはPCBV2またはV3バージョンが必要です
  • 私が使用したようなArduinoProMini…..– PCB V1
  • HT73333.3v電圧レギュレータ……………。地元の電気店から– PCB V1&PCB V2
  • AMS11173.3v電圧レギュレータ……………Amazon /バングード /AliExpress – PCB V3

PCBデザイン

私は実際にArduinoProMiniのすべてのアナログピンとデジタルピンを利用することになりました。だから今、私がジャンプワイヤーを使ってすべてを一緒に接続しようとすると、それはかなり混乱するでしょう。そのため、EasyEDAの無料オンライン回路設計ソフトウェアを使用してカスタムPCBを設計しました。

ここでは、コントローラーの人間工学を考慮し、すべてのコントロールが指の範囲内にある間、両手で簡単に保持できるように設計しました。後でPCBを何かに取り付けることができるように、エッジを丸くし、3mmの穴をいくつか追加しました。 Arduino Pro Miniをプログラミングするためのピンをコントローラーの上面に配置して、Arduinoを再プログラミングする場合に簡単にアクセスできるようにしました。ここで、ジョイスティックのボタンにArduinoのRXピンとTXピンを使用したこともわかります。ただし、スケッチをArduinoにアップロードしている間は、これら2つの線を何からも切り離す必要があります。したがって、2つのピンで中断され、簡単なジャンパーキャップを使用して簡単に接続できます。

注意: PCBをマッハするか、それに応じてPCBデザインを変更するための正しいArduinoProMiniバージョンがあることを確認してください。これは、Arduinoと電圧レギュレーターに応じた3つの異なるバージョンの比較写真です。

このPCBデザインのプロジェクトファイルへのリンクは次のとおりです。これらは3つの異なるバージョンを別々のタブで開くので、必要なものを選択できます。

そのため、設計が完了したら、PCBの製造に必要なガーバーファイルを生成しました。

ガーバーファイル:

次に、このビデオのスポンサーでもあるJLCPCBにPCBを注文しました。

ここでは、ガーバーファイルをドラッグアンドドロップするだけで、アップロードしたら、ガーバービューアでPCBを確認できます。すべて問題がなければ、先に進んでPCBに必要なプロパティを選択できます。今回はPCBの色を黒に選びました。これで、PCBをリーズナブルな価格で簡単に注文できるようになりました。 JLCPCBからの最初の注文の場合、わずか2ドルで最大10個のPCBを入手できることに注意してください。

そして、ここにあります。このPCBがこの黒い色でどのようになったかが本当に気に入っています。 PCBの品質は素晴らしく、すべてがデザインとまったく同じです。

PCBの組み立て

これで、PCBの組み立てに進むことができます。 ArduinoProMiniのピンヘッダーをはんだ付けすることから始めました。これを行う簡単で良い方法は、ブレッドボードに配置することです。そうすれば、はんだ付け中にしっかりと固定されます。

Pro Miniの側面にもピンがありますが、これらのピンの位置はメーカーによって異なる場合があることに注意してください。

私が持っている特定のモデルでは、各側に5つのピンが必要ですが、いくつかのトレースを実行するためにPCBの下部の領域を使用したため、1つのGNDピンは空のままにしておきます。 Arduino Pro MiniをPCBに直接はんだ付けし、ヘッダーのexecの長さをカットしました。そのすぐ隣には、MPU6050加速度計とジャイロスコープモジュールがあります。

次に、3.3V電圧レギュレーターの隣にコンデンサーを、NRF24L01モジュールの近くに別のコンデンサーをはんだ付けしました。このモジュールには3つの異なるバージョンがあり、ここではそれらのいずれかを使用できます。

Arduinoをプログラミングするためのピン、RXピンとTXピン、電源ピン、電源スイッチを続けました。

次に、ポテンショメータをPCBにはんだ付けするために、いくつかのピンヘッダーを使用してピンを延長する必要がありました。

ここで、以前にノブの長さをカットしたので、いくつかのキャップを適切に取り付けることができます。ただし、ポテンショメータは少し後でPCBにはんだ付けします。

次に、2つのトグルスイッチと2つのジョイスティックを所定の位置に挿入してはんだ付けしました。

最後に、残っているのは4つのプッシュボタンをはんだ付けすることです。ただし、適切な高さがないため、ピンヘッダーを使用してピンを少し伸ばしました。

これでPCBの準備ができたので、カバーの作成を続けることができます。 PCBの見た目が好きで、見やすくしたいので、カバーに透明なアクリルを使用することにしました。

ここに私は4mmの目盛りの透明なアクリルを持っています。これは現在保護フォイルがあり、青いように見えます。カバーのアイデアは、PCBの形状で2つのプレートを作成し、一方をPCBの上面に、もう一方を下面に固定することです。

そこで、PCBの形状に印を付け、金属製の手のこぎりを使用して、それに応じてアクリルをカットしました。

次に、シンプルなラスプを使用して、アクリルの形状を微調整しました。 2つのプレートは素晴らしく、PCBと完全に一致しています。

次に、コンポーネントが通過するための開口部を作成する必要がある場所にマークを付けました。 3mmのドリルを使用して、最初にプレートをPCBに固定するための4つの穴を開けました。これらの穴には、ボルトをプレートとフラッシュで配置できるように、カウンターシンクも作成しました。

トグルスイッチとポテンショメータの開口部には6mmのドリルを使用し、ジョイスティックの開口部には25mmのForstnerビットを使用しました。繰り返しになりますが、ラスプを使用して、すべての開口部を微調整しました。

カバーを組み立てる前に、電源のピンヘッダーを実際に逆さまにはんだ付けしたので、バッテリーが配置される裏側から届くようになっていることに注意してください。

これで、カバーの組み立てから始めることができます。アクリルから保護フォイルを剥がすことから始めましたが、アクリルがとてもきれいになったので、非常に満足のいくものでした。そこで、最初に2つのポテンショメータを天板に固定し、3mmの取り付けボルトを挿入し、11mmの距離リングを所定の位置に配置しました。

次に、いくつかのボルトを使用して、トッププレートとPCBを慎重にマージして固定しました。この時点で、ポテンショメータをPCBにはんだ付けしました。これは、以前はポテンショメータがどの高さに配置されるかが正確にわからなかったためです。

次にバックプレートに2本のボルトでバッテリーホルダーを取り付けました。 4本の取り付けボルトを使用してバックプレートをPCBの裏側に固定し、カバーアセンブリを完成させました。

最後に、バッテリーラインを電源ピンに接続し、ポテンショメーターのノブを挿入して固定し、ジョイスティックのノブを挿入して、アンテナをNRF24l01モジュールに接続します。これで、DIYArduinoRC送信機がついに完成しました。

今残っているのは、Arduinoをプログラムすることです。 Pro Miniボードをプログラミングするには、コントローラーの上面にあるプログラミングヘッダーに接続できるUSB-シリアルUARTインターフェイスが必要です。

次に、Arduino IDEツールメニューで、ArduinoProまたはProMiniボードを選択し、適切なバージョンのプロセッサを選択し、ポートを選択して、「USBasp」へのプログラミング方法を選択する必要があります。

これで、コードをArduinoにアップロードできるようになりました。

DIYArduinoベースのRC送信機コード

送信機コードがどのように機能するかを説明しましょう。したがって、最初に、ワイヤレス通信用のSPIおよびRF24ライブラリと、加速度計モジュール用のI2Cライブラリを含める必要があります。次に、デジタル入力を定義する必要があります。以下のプログラムに必要ないくつかの変数は、無線オブジェクトと通信アドレスを定義します。

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Wire.h>


// Define the digital inputs
#define jB1 1  // Joystick button 1
#define jB2 0  // Joystick button 2
#define t1 7   // Toggle switch 1
#define t2 4   // Toggle switch 1
#define b1 8   // Button 1
#define b2 9   // Button 2
#define b3 2   // Button 3
#define b4 3   // Button 4

const int MPU = 0x68; // MPU6050 I2C address
float AccX, AccY, AccZ;
float GyroX, GyroY, GyroZ;
float accAngleX, accAngleY, gyroAngleX, gyroAngleY;
float angleX, angleY;
float AccErrorX, AccErrorY, GyroErrorX, GyroErrorY;
float elapsedTime, currentTime, previousTime;
int c = 0;


RF24 radio(5, 6);   // nRF24L01 (CE, CSN)
const byte address[6] = "00001"; // AddressCode language: Arduino (arduino)

次に、コントローラーの14個の入力値を格納する構造を定義する必要があります。この構造の最大サイズは32バイトになる可能性があります。これは、NRF24L01のバッファ制限、またはモジュールが一度に送信できるデータの量であるためです。

/ Max size of this struct is 32 bytes - NRF24L01 buffer limit
struct Data_Package {
  byte j1PotX;
  byte j1PotY;
  byte j1Button;
  byte j2PotX;
  byte j2PotY;
  byte j2Button;
  byte pot1;
  byte pot2;
  byte tSwitch1;
  byte tSwitch2;
  byte button1;
  byte button2;
  byte button3;
  byte button4;
};

Data_Package data; //Create a variable with the above structureCode language: Arduino (arduino)

セットアップセクションでは、MPU6050モジュールを初期化する必要があります。また、モジュールの正しい角度を計算するときに後で使用される値であるIMUエラーを計算することもできます。

void initialize_MPU6050() {
  Wire.begin();                      // Initialize comunication
  Wire.beginTransmission(MPU);       // Start communication with MPU6050 // MPU=0x68
  Wire.write(0x6B);                  // Talk to the register 6B
  Wire.write(0x00);                  // Make reset - place a 0 into the 6B register
  Wire.endTransmission(true);        //end the transmission
  // Configure Accelerometer
  Wire.beginTransmission(MPU);
  Wire.write(0x1C);                  //Talk to the ACCEL_CONFIG register
  Wire.write(0x10);                  //Set the register bits as 00010000 (+/- 8g full scale range)
  Wire.endTransmission(true);
  // Configure Gyro
  Wire.beginTransmission(MPU);
  Wire.write(0x1B);                   // Talk to the GYRO_CONFIG register (1B hex)
  Wire.write(0x10);                   // Set the register bits as 00010000 (1000dps full scale)
  Wire.endTransmission(true);
}Code language: Arduino (arduino)

MEMS加速度計とジャイロがどのように機能するかについて詳しくは、こちらをご覧ください。 MPU6050専用のチュートリアルが間もなく登場します。

次に、無線通信を初期化し、すべてのデジタル入力に対してArduino内部プルアップ抵抗をアクティブにし、すべての変数に初期デフォルト値を設定する必要があります。

// Define the radio communication
  radio.begin();
  radio.openWritingPipe(address);
  radio.setAutoAck(false);
  radio.setDataRate(RF24_250KBPS);
  radio.setPALevel(RF24_PA_LOW);
  
  // Activate the Arduino internal pull-up resistors
  pinMode(jB1, INPUT_PULLUP);
  pinMode(jB2, INPUT_PULLUP);
  pinMode(t1, INPUT_PULLUP);
  pinMode(t2, INPUT_PULLUP);
  pinMode(b1, INPUT_PULLUP);
  pinMode(b2, INPUT_PULLUP);
  pinMode(b3, INPUT_PULLUP);
  pinMode(b4, INPUT_PULLUP);Code language: Arduino (arduino)

ループセクションでは、すべてのアナログ入力を読み取ることから始め、構造内の変数をバイトとしてすでに定義しているため、0から1023までの値を0から255までのバイト値にマップします。各入力は、構造体の特定のデータ変数に格納されます。

// Read all analog inputs and map them to one Byte value
  data.j1PotX = map(analogRead(A1), 0, 1023, 0, 255); // Convert the analog read value from 0 to 1023 into a BYTE value from 0 to 255
  data.j1PotY = map(analogRead(A0), 0, 1023, 0, 255);
  data.j2PotX = map(analogRead(A2), 0, 1023, 0, 255);
  data.j2PotY = map(analogRead(A3), 0, 1023, 0, 255);
  data.pot1 = map(analogRead(A7), 0, 1023, 0, 255);
  data.pot2 = map(analogRead(A6), 0, 1023, 0, 255);Code language: Arduino (arduino)

プルアップ抵抗を使用しているため、ボタンが押されたときのデジタルピンの読み取り値は0であることに注意してください。

// Read all digital inputs
  data.j1Button = digitalRead(jB1);
  data.j2Button = digitalRead(jB2);
  data.tSwitch2 = digitalRead(t2);
  data.button1 = digitalRead(b1);
  data.button2 = digitalRead(b2);
  data.button3 = digitalRead(b3);
  data.button4 = digitalRead(b4);Code language: Arduino (arduino)

したがって、radio.write()関数を使用して、14チャネルすべてから受信機に値を送信するだけです。

// Send the whole data from the structure to the receiver
  radio.write(&data, sizeof(Data_Package));Code language: Arduino (arduino)

トグルスイッチ1がオンになっている場合は、代わりに加速度計とジャイロのデータを制御に使用します。

if (digitalRead(t1) == 0) {
    read_IMU();    // Use MPU6050 instead of Joystick 1 for controling left, right, forward and backward movements
  }Code language: Arduino (arduino)

したがって、ジョイスティックの1 XおよびY値の代わりに、IMUから取得した角度値を使用します。これは、以前は-90〜 +90度の値から0〜255のバイト値に適切に変換していました。

// Map the angle values from -90deg to +90 deg into values from 0 to 255, like the values we are getting from the Joystick
  data.j1PotX = map(angleX, -90, +90, 255, 0);
  data.j1PotY = map(angleY, -90, +90, 0, 255);Code language: Arduino (arduino)

これが送信機のコードであり、最も重要なことは無線通信を定義し、データを受信機に送信することでした。

このDIYArduinoRCトランスミッターの完全なArduinoコードは次のとおりです。

/*
        DIY Arduino based RC Transmitter
  by Dejan Nedelkovski, www.HowToMechatronics.com
  Library: TMRh20/RF24, https://github.com/tmrh20/RF24/
*/

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Wire.h>


// Define the digital inputs
#define jB1 1  // Joystick button 1
#define jB2 0  // Joystick button 2
#define t1 7   // Toggle switch 1
#define t2 4   // Toggle switch 1
#define b1 8   // Button 1
#define b2 9   // Button 2
#define b3 2   // Button 3
#define b4 3   // Button 4

const int MPU = 0x68; // MPU6050 I2C address
float AccX, AccY, AccZ;
float GyroX, GyroY, GyroZ;
float accAngleX, accAngleY, gyroAngleX, gyroAngleY;
float angleX, angleY;
float AccErrorX, AccErrorY, GyroErrorX, GyroErrorY;
float elapsedTime, currentTime, previousTime;
int c = 0;


RF24 radio(5, 6);   // nRF24L01 (CE, CSN)
const byte address[6] = "00001"; // Address

// Max size of this struct is 32 bytes - NRF24L01 buffer limit
struct Data_Package {
  byte j1PotX;
  byte j1PotY;
  byte j1Button;
  byte j2PotX;
  byte j2PotY;
  byte j2Button;
  byte pot1;
  byte pot2;
  byte tSwitch1;
  byte tSwitch2;
  byte button1;
  byte button2;
  byte button3;
  byte button4;
};

Data_Package data; //Create a variable with the above structure

void setup() {
  Serial.begin(9600);
  
  // Initialize interface to the MPU6050
  initialize_MPU6050();

  // Call this function if you need to get the IMU error values for your module
  //calculate_IMU_error();
  
  // Define the radio communication
  radio.begin();
  radio.openWritingPipe(address);
  radio.setAutoAck(false);
  radio.setDataRate(RF24_250KBPS);
  radio.setPALevel(RF24_PA_LOW);
  
  // Activate the Arduino internal pull-up resistors
  pinMode(jB1, INPUT_PULLUP);
  pinMode(jB2, INPUT_PULLUP);
  pinMode(t1, INPUT_PULLUP);
  pinMode(t2, INPUT_PULLUP);
  pinMode(b1, INPUT_PULLUP);
  pinMode(b2, INPUT_PULLUP);
  pinMode(b3, INPUT_PULLUP);
  pinMode(b4, INPUT_PULLUP);
  
  // Set initial default values
  data.j1PotX = 127; // Values from 0 to 255. When Joystick is in resting position, the value is in the middle, or 127. We actually map the pot value from 0 to 1023 to 0 to 255 because that's one BYTE value
  data.j1PotY = 127;
  data.j2PotX = 127;
  data.j2PotY = 127;
  data.j1Button = 1;
  data.j2Button = 1;
  data.pot1 = 1;
  data.pot2 = 1;
  data.tSwitch1 = 1;
  data.tSwitch2 = 1;
  data.button1 = 1;
  data.button2 = 1;
  data.button3 = 1;
  data.button4 = 1;
}
void loop() {
  // Read all analog inputs and map them to one Byte value
  data.j1PotX = map(analogRead(A1), 0, 1023, 0, 255); // Convert the analog read value from 0 to 1023 into a BYTE value from 0 to 255
  data.j1PotY = map(analogRead(A0), 0, 1023, 0, 255);
  data.j2PotX = map(analogRead(A2), 0, 1023, 0, 255);
  data.j2PotY = map(analogRead(A3), 0, 1023, 0, 255);
  data.pot1 = map(analogRead(A7), 0, 1023, 0, 255);
  data.pot2 = map(analogRead(A6), 0, 1023, 0, 255);
  // Read all digital inputs
  data.j1Button = digitalRead(jB1);
  data.j2Button = digitalRead(jB2);
  data.tSwitch2 = digitalRead(t2);
  data.button1 = digitalRead(b1);
  data.button2 = digitalRead(b2);
  data.button3 = digitalRead(b3);
  data.button4 = digitalRead(b4);
  // If toggle switch 1 is switched on
  if (digitalRead(t1) == 0) {
    read_IMU();    // Use MPU6050 instead of Joystick 1 for controling left, right, forward and backward movements
  }
  // Send the whole data from the structure to the receiver
  radio.write(&data, sizeof(Data_Package));
}

void initialize_MPU6050() {
  Wire.begin();                      // Initialize comunication
  Wire.beginTransmission(MPU);       // Start communication with MPU6050 // MPU=0x68
  Wire.write(0x6B);                  // Talk to the register 6B
  Wire.write(0x00);                  // Make reset - place a 0 into the 6B register
  Wire.endTransmission(true);        //end the transmission
  // Configure Accelerometer
  Wire.beginTransmission(MPU);
  Wire.write(0x1C);                  //Talk to the ACCEL_CONFIG register
  Wire.write(0x10);                  //Set the register bits as 00010000 (+/- 8g full scale range)
  Wire.endTransmission(true);
  // Configure Gyro
  Wire.beginTransmission(MPU);
  Wire.write(0x1B);                   // Talk to the GYRO_CONFIG register (1B hex)
  Wire.write(0x10);                   // Set the register bits as 00010000 (1000dps full scale)
  Wire.endTransmission(true);
}

void calculate_IMU_error() {
  // We can call this funtion in the setup section to calculate the accelerometer and gury data error. From here we will get the error values used in the above equations printed on the Serial Monitor.
  // Note that we should place the IMU flat in order to get the proper values, so that we then can the correct values
  // Read accelerometer values 200 times
  while (c < 200) {
    Wire.beginTransmission(MPU);
    Wire.write(0x3B);
    Wire.endTransmission(false);
    Wire.requestFrom(MPU, 6, true);
    AccX = (Wire.read() << 8 | Wire.read()) / 4096.0 ;
    AccY = (Wire.read() << 8 | Wire.read()) / 4096.0 ;
    AccZ = (Wire.read() << 8 | Wire.read()) / 4096.0 ;
    // Sum all readings
    AccErrorX = AccErrorX + ((atan((AccY) / sqrt(pow((AccX), 2) + pow((AccZ), 2))) * 180 / PI));
    AccErrorY = AccErrorY + ((atan(-1 * (AccX) / sqrt(pow((AccY), 2) + pow((AccZ), 2))) * 180 / PI));
    c++;
  }
  //Divide the sum by 200 to get the error value
  AccErrorX = AccErrorX / 200;
  AccErrorY = AccErrorY / 200;
  c = 0;
  // Read gyro values 200 times
  while (c < 200) {
    Wire.beginTransmission(MPU);
    Wire.write(0x43);
    Wire.endTransmission(false);
    Wire.requestFrom(MPU, 4, true);
    GyroX = Wire.read() << 8 | Wire.read();
    GyroY = Wire.read() << 8 | Wire.read();
    // Sum all readings
    GyroErrorX = GyroErrorX + (GyroX / 32.8);
    GyroErrorY = GyroErrorY + (GyroY / 32.8);
    c++;
  }
  //Divide the sum by 200 to get the error value
  GyroErrorX = GyroErrorX / 200;
  GyroErrorY = GyroErrorY / 200;
  // Print the error values on the Serial Monitor
  Serial.print("AccErrorX: ");
  Serial.println(AccErrorX);
  Serial.print("AccErrorY: ");
  Serial.println(AccErrorY);
  Serial.print("GyroErrorX: ");
  Serial.println(GyroErrorX);
  Serial.print("GyroErrorY: ");
  Serial.println(GyroErrorY);
}

void read_IMU() {
  // === Read acceleromter data === //
  Wire.beginTransmission(MPU);
  Wire.write(0x3B); // Start with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU, 6, true); // Read 6 registers total, each axis value is stored in 2 registers
  //For a range of +-8g, we need to divide the raw values by 4096, according to the datasheet
  AccX = (Wire.read() << 8 | Wire.read()) / 4096.0; // X-axis value
  AccY = (Wire.read() << 8 | Wire.read()) / 4096.0; // Y-axis value
  AccZ = (Wire.read() << 8 | Wire.read()) / 4096.0; // Z-axis value

  // Calculating angle values using
  accAngleX = (atan(AccY / sqrt(pow(AccX, 2) + pow(AccZ, 2))) * 180 / PI) + 1.15; // AccErrorX ~(-1.15) See the calculate_IMU_error()custom function for more details
  accAngleY = (atan(-1 * AccX / sqrt(pow(AccY, 2) + pow(AccZ, 2))) * 180 / PI) - 0.52; // AccErrorX ~(0.5)

  // === Read gyro data === //
  previousTime = currentTime;        // Previous time is stored before the actual time read
  currentTime = millis();            // Current time actual time read
  elapsedTime = (currentTime - previousTime) / 1000;   // Divide by 1000 to get seconds
  Wire.beginTransmission(MPU);
  Wire.write(0x43); // Gyro data first register address 0x43
  Wire.endTransmission(false);
  Wire.requestFrom(MPU, 4, true); // Read 4 registers total, each axis value is stored in 2 registers
  GyroX = (Wire.read() << 8 | Wire.read()) / 32.8; // For a 1000dps range we have to divide first the raw value by 32.8, according to the datasheet
  GyroY = (Wire.read() << 8 | Wire.read()) / 32.8;
  GyroX = GyroX + 1.85; //// GyroErrorX ~(-1.85)
  GyroY = GyroY - 0.15; // GyroErrorY ~(0.15)
  // Currently the raw values are in degrees per seconds, deg/s, so we need to multiply by sendonds (s) to get the angle in degrees
  gyroAngleX = GyroX * elapsedTime;
  gyroAngleY = GyroY * elapsedTime;

  // Complementary filter - combine acceleromter and gyro angle values
  angleX = 0.98 * (angleX + gyroAngleX) + 0.02 * accAngleX;
  angleY = 0.98 * (angleY + gyroAngleY) + 0.02 * accAngleY;
  // Map the angle values from -90deg to +90 deg into values from 0 to 255, like the values we are getting from the Joystick
  data.j1PotX = map(angleX, -90, +90, 255, 0);
  data.j1PotY = map(angleY, -90, +90, 0, 255);
}Code language: Arduino (arduino)
受信者コード

次に、このデータを受信する方法を見てみましょう。これがArduinoとNRF24L01レシーバーの簡単な回路図です。もちろん、他のArduinoボードを使用することもできます。

これが簡単な受信機コードです。データを受信して​​シリアルモニターに印刷するだけで、通信が正しく機能していることがわかります。ここでも、RF24ライブラリを含め、送信機コードと同じ方法でオブジェクトと構造を定義する必要があります。無線通信を定義する際のセットアップセクションでは、送信機と同じ設定を使用し、radio.startListening()関数を使用してモジュールを受信機として設定する必要があります。

/*
    DIY Arduino based RC Transmitter Project
              == Receiver Code ==

  by Dejan Nedelkovski, www.HowToMechatronics.com
  Library: TMRh20/RF24, https://github.com/tmrh20/RF24/
*/
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
RF24 radio(10, 9);   // nRF24L01 (CE, CSN)
const byte address[6] = "00001";

unsigned long lastReceiveTime = 0;
unsigned long currentTime = 0;

// Max size of this struct is 32 bytes - NRF24L01 buffer limit
struct Data_Package {
  byte j1PotX;
  byte j1PotY;
  byte j1Button;
  byte j2PotX;
  byte j2PotY;
  byte j2Button;
  byte pot1;
  byte pot2;
  byte tSwitch1;
  byte tSwitch2;
  byte button1;
  byte button2;
  byte button3;
  byte button4;
};

Data_Package data; //Create a variable with the above structure

void setup() {
  Serial.begin(9600);
  radio.begin();
  radio.openReadingPipe(0, address);
  radio.setAutoAck(false);
  radio.setDataRate(RF24_250KBPS);
  radio.setPALevel(RF24_PA_LOW);
  radio.startListening(); //  Set the module as receiver
  resetData();
}
void loop() {
  // Check whether there is data to be received
  if (radio.available()) {
    radio.read(&data, sizeof(Data_Package)); // Read the whole data and store it into the 'data' structure
    lastReceiveTime = millis(); // At this moment we have received the data
  }
  // Check whether we keep receving data, or we have a connection between the two modules
  currentTime = millis();
  if ( currentTime - lastReceiveTime > 1000 ) { // If current time is more then 1 second since we have recived the last data, that means we have lost connection
    resetData(); // If connection is lost, reset the data. It prevents unwanted behavior, for example if a drone has a throttle up and we lose connection, it can keep flying unless we reset the values
  }
  // Print the data in the Serial Monitor
  Serial.print("j1PotX: ");
  Serial.print(data.j1PotX);
  Serial.print("; j1PotY: ");
  Serial.print(data.j1PotY);
  Serial.print("; button1: ");
  Serial.print(data.button1);
  Serial.print("; j2PotX: ");
  Serial.println(data.j2PotX); 
}

void resetData() {
  // Reset the values when there is no radio connection - Set initial default values
  data.j1PotX = 127;
  data.j1PotY = 127;
  data.j2PotX = 127;
  data.j2PotY = 127;
  data.j1Button = 1;
  data.j2Button = 1;
  data.pot1 = 1;
  data.pot2 = 1;
  data.tSwitch1 = 1;
  data.tSwitch2 = 1;
  data.button1 = 1;
  data.button2 = 1;
  data.button3 = 1;
  data.button4 = 1;
}Code language: Arduino (arduino)

available()関数を使用したメインループでは、着信データがあるかどうかを確認します。 trueの場合、データを読み取り、構造体の変数に格納するだけです。これで、シリアルモニターにデータを印刷して、送信が正しく機能するかどうかを確認できます。また、millis()関数とifステートメントを使用して、データを受信し続けるかどうかを確認します。または、1秒を超える期間データを受信しない場合は、変数をデフォルト値にリセットします。これを使用して、不要な動作を防止します。たとえば、ドローンのスロットルが上がっていて接続が失われた場合、値をリセットしない限り、ドローンが飛び去り続ける可能性があります。

以上です。これで、Arduinoプロジェクトのデータを受信するこの方法を実装できます。たとえば、以前のビデオの1つからArduinoロボットカーを制御するためのコードです。

このプロジェクトのアップデートとして、Arduinoベースの専用RCレシーバーを作成しました。繰り返しになりますが、これはArduino Proミニボードに基づいており、コンパクトなPCB上に配置されたすぐに使用できるサーボとESC接続がいくつかあります。

RC送信機を使用したArduinoロボットカーのワイヤレス制御

Arduinoコード:

ここでは、前に説明したように、ライブラリ、構造、および無線通信を定義する必要があります。次に、メインループで、受信データを読み取り、必要なデータを使用する必要があります。この場合、車の運転にはジョイスティック1の値を使用します。

ArduinoAntロボット/ArduinoRC送信機を使用したヘキサポッド制御

Arduinoコード:

まったく同じ方法で、前のビデオからArduino Ant Robotを作成し、このArduinoRC送信機を使用してワイヤレスで制御できるようにしました。データを読み取るだけで、それに応じて、前進、左、右、噛む、攻撃などの適切な機能を実行できます。

RC送信機を使用したESCおよびサーボ制御

最後に、この送信機を商用RCデバイスの制御にどのように使用できるかを見てみましょう。

通常、これらのデバイスでは、サーボまたはブラシレスモーターを制御する必要があります。したがって、送信機からデータを受信した後、サーボを制御するには、Arduinoサーボライブラリを使用し、0〜180度の値を使用します。 ESCを使用してブラシレスモーターを制御する場合も、サーボライブラリを使用してESCの制御に使用される50HzPWM信号を生成できます。デューティサイクルを1000から2000マイクロ秒まで変化させることにより、モーターのRPMをゼロから最大まで制御します。ただし、次のチュートリアルでは、ESCを使用したブラシレスモーターの制御について詳しく説明します。

実際には、標準のRC受信機システムをこのNRF24L012.4GHzシステムにバインドすることはできないことに注意してください。代わりに、ArduinoとNRF24L01モジュールで構成される独自のレシーバーを変更または作成する必要があります。そこから、RCデバイスを制御するための適切なPWMまたはPPM信号を生成できます。

/*
    DIY Arduino based RC Transmitter Project
   == Receiver Code - ESC and Servo Control ==

  by Dejan Nedelkovski, www.HowToMechatronics.com
  Library: TMRh20/RF24, https://github.com/tmrh20/RF24/
*/
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Servo.h>

RF24 radio(10, 9);   // nRF24L01 (CE, CSN)
const byte address[6] = "00001";

unsigned long lastReceiveTime = 0;
unsigned long currentTime = 0;

Servo esc;  // create servo object to control the ESC
Servo servo1;
Servo servo2;
int escValue, servo1Value, servo2Value;

// Max size of this struct is 32 bytes - NRF24L01 buffer limit
struct Data_Package {
  byte j1PotX;
  byte j1PotY;
  byte j1Button;
  byte j2PotX;
  byte j2PotY;
  byte j2Button;
  byte pot1;
  byte pot2;
  byte tSwitch1;
  byte tSwitch2;
  byte button1;
  byte button2;
  byte button3;
  byte button4;
};

Data_Package data; //Create a variable with the above structure

void setup() {
  Serial.begin(9600);
  radio.begin();
  radio.openReadingPipe(0, address);
  radio.setAutoAck(false);
  radio.setDataRate(RF24_250KBPS);
  radio.setPALevel(RF24_PA_LOW);
  radio.startListening(); //  Set the module as receiver
  resetData();
  esc.attach(9);
  servo1.attach(3);
  servo2.attach(4);
}
void loop() {
  // Check whether we keep receving data, or we have a connection between the two modules
  currentTime = millis();
  if ( currentTime - lastReceiveTime > 1000 ) { // If current time is more then 1 second since we have recived the last data, that means we have lost connection
    resetData(); // If connection is lost, reset the data. It prevents unwanted behavior, for example if a drone jas a throttle up, if we lose connection it can keep flying away if we dont reset the function
  }
  // Check whether there is data to be received
  if (radio.available()) {
    radio.read(&data, sizeof(Data_Package)); // Read the whole data and store it into the 'data' structure
    lastReceiveTime = millis(); // At this moment we have received the data
  }
  // Controlling servos
  servo1Value = map(data.j2PotX, 0, 255, 0, 180);
  servo2Value = map(data.j2PotY, 0, 255, 0, 180);
  servo1.write(servo1Value);
  servo2.write(servo2Value);
  // Controlling brushless motor with ESC
  escValue = map(data.pot1, 0, 255, 1000, 2000); // Map the receiving value form 0 to 255 to 0 1000 to 2000, values used for controlling ESCs
  esc.writeMicroseconds(escValue); // Send the PWM control singal to the ESC
}

void resetData() {
  // Reset the values when there is no radio connection - Set initial default values
  data.j1PotX = 127;
  data.j1PotY = 127;
  data.j2PotX = 127;
  data.j2PotY = 127;
  data.j1Button = 1;
  data.j2Button = 1;
  data.pot1 = 1;
  data.pot2 = 1;
  data.tSwitch1 = 1;
  data.tSwitch2 = 1;
  data.button1 = 1;
  data.button2 = 1;
  data.button3 = 1;
  data.button4 = 1;
}Code language: Arduino (arduino)

So that’s it.このビデオを楽しんで、何か新しいことを学んだことを願っています。以下のコメントセクションで質問をして、Arduinoプロジェクトコレクションを確認してください。


製造プロセス

  1. カズー
  2. DIY LUMAZOID Arduino Music Visualiser
  3. 自宅でDIY宿題ライティングマシンを作る
  4. Arduinoとスマートフォンを使用したDIY電圧計
  5. Arduino + ESPウェザーボックス
  6. DIYバーチャルリアリティスケートボード
  7. DIY ArduinoRADIONICSトリートメントマシン
  8. DIY2Dモーションレーシングシミュレーター
  9. RFIDを使ったDIYのアイデア
  10. DIY3軸CNCVMC
  11. DIY Arduino + GY-906赤外線温度計