#1.はじめに
市販のドローン(コントローラーで動かすタイプ)をハッキングするには,2通りの方法が考えられる。
(1) ドローン本体にマイコン等の制御基板をぶち込み、ドローンHWをパッキングする。
(2) 付属のコントローラをマイコンと接続し、コントローラHWをハッキングする。
(3) ドローン-コントローラ間の信号をハッキングし、ドローン-コントローラのSWをハッキングする。
ドローン本体にセンサを取り付けることは不可能なので,(2)の付属のコントローラーをハッキングするべきである。
#2.コントローラーのハッキング方法概要
ドローンのコントローラは、2つのジョイスティックを用いて機体の前後左右とYaw(ヨー),上下を制御する。マイコンによるデジタル信号制御を行い,「コントローラーのジョイスティックを倒す」と同じことをすることになる.
ジョイスティックとはXYの二次元軸に関して自由度を持った可変抵抗である。基本的に可変抵抗は3つの足を持った素子であり,左右の足の抵抗値は一定であるが,左-真ん中と真ん中-右の間の抵抗値が変化する抵抗である。ジョイスティックはX方向,Y方向に各々可変抵抗Rx,Ryが内蔵されており2軸を表現している。
・仮にスティックをX軸,y軸両方倒すと..
Rx,Ryは両方何かしらの抵抗変化を起こす
・スティックをX軸のみ倒す
Rxのみ変化する
・スティックをy軸のみ倒す
Ryのみ変化する
スティックを倒すことで抵抗値が変化するので,マイコンを用いた電気信号(デジタル信号)によって抵抗値を変化させることができれば,制御可能になる。
それを可能にするキー素子はディジタルポテンションメーターである。
#3.キー素子 DigitalPotentionMeter
ディジタルポテンショメータとは簡単に言うと電気的に調整できる可変抵抗のことです。様々なメーカーから製品が販売されているが,X9Cxxxシリーズを用いて今回は制御を行なう。実際にはxxxという型番は存在しなく以下の規則性の元同じようなディジタル処理を行なうことで抵抗値を変化することができる。
型番 | MAX抵抗値(Ω) |
---|---|
X9C102 | 102 = 10*10^2 = 1k |
X9C103 | 103 = 10*10^3 = 10kOhm |
X9C104 | 104 = 10*10^4 = 100kOhm |
X9C503 | 503 = 50*10^3 = 50kOhm |
このX9Cシリーズは3線(CS,UD,INC)でUp/Down端子(UD)を使って抵抗値を1ステップずつ上げたり下げたりして、目的の抵抗値に設定するものです。
そのため,規定の抵抗値に瞬時に変えることができず,**1ステップずつ抵抗値を変化させる必要がある。**ここで1ステップずつ変化させることができ,ポジション(抵抗)を0~100まで変化可能である。
それ故,X9C102であるとMAX抵抗値は1kΩであるので1ステップあたり以下の抵抗値分増減される。R1step = 1k * 1/100 = 10Ω
Vccに5V, または3.3Vを接続、VssはGNDに接続、後はU/D, INC, CSの3ピンを使って任意の位置にRw/Vwの位置を調整するだけです。
CSピンがLowになるとコマンド入力待ちなり、INCピンの立下りエッジでRw/Vw端子が移動します。この際U/DピンがHIGHだと大きい側へ、LOWだと小さい側へRw端子が移動します。最後にCSピンをHIGHに戻す際にINCピンがHIGHだとその時の設定値をメモリに書き込みます。
またポジションを0に設定しても約40Ωの抵抗が残ります。全体的に40Ωのオフセットが乗っているので実際の変化幅は40~9940Ω(X9C103の場合)になります。
#4.サンプルコード
###抵抗値変化確認(Arduino+Processing)
:sample1_a.ino
const float V_REF = 5.0; // Change if using different Vref
const int UD_PIN = 8; // Goes to X9C103P U/D pin - Up = HIGH, Down = LOW
const int INC_PIN = 9; // Goes to X9C103P INC pin - active falling edge
const int CS_PIN = 10; // Goes to X9C103P CS pin - active LOW
const int WIPER_PIN = A0; // Goes to X9C103P VW pin - Analog voltage output of pot
float voltage = 0;
//===============================================================================
// Initialization
//===============================================================================
void setup() {
Serial.begin(9600);
pinMode (CS_PIN, OUTPUT);
pinMode (UD_PIN, OUTPUT);
pinMode (INC_PIN, OUTPUT);
resetPot();
//PrintVoltage(); // Print X9C103P power up value
}
//===============================================================================
// Main
//===============================================================================
void loop() {
if (Serial.available()) DoSerial(); // Just loop looking for user input
}
//===============================================================================
// Subroutine to handle characters typed via Serial Monitor Window
//===============================================================================
void DoSerial()
{
char ch = toupper(Serial.read()); // Read the character we received
// and convert to upper case
switch (ch) {
case 'S': // Save settings
digitalWrite(CS_PIN, HIGH);
delay(50);
digitalWrite(CS_PIN, LOW);
//Serial.println("Setting Saved");
break;
case 'U': // Increment setting
Move_Wiper(UP);
//Serial.print("Incrementing Value");
PrintVoltage();
break;
case 'D': // Decrement setting
Move_Wiper(DOWN);
//Serial.print("Decrementing Value");
PrintVoltage();
break;
}
}
//===============================================================================
// Subroutine to read ADC and print to the Serial Monitor Window
//===============================================================================
void PrintVoltage()
{
int sampleADC = analogRead(WIPER_PIN); // Take reading on wiper pin
float volts = (sampleADC * V_REF) / 1023.0; // Convert to voltage
//Serial.print(" ADC = ");
Serial.write(sampleADC);
//Serial.print("tVoltage = ");
//Serial.println(volts, 3);
}
//===============================================================================
// Subroutine to move the wiper UP or DOWN
//===============================================================================
void Move_Wiper(int direction)
{
switch (direction) {
case UP:
digitalWrite(UD_PIN, HIGH); delayMicroseconds(5); // Set to increment
digitalWrite(INC_PIN, LOW); delayMicroseconds(5); // Pulse INC pin low
digitalWrite(INC_PIN, HIGH);
break;
case DOWN:
digitalWrite(UD_PIN, LOW); delayMicroseconds(5); // Set to decrement
digitalWrite(INC_PIN, LOW); delayMicroseconds(5); // Pulse INC pin low
digitalWrite(INC_PIN, HIGH);
break;
default:
break;
}
}
void resetPot (void)
{
digitalWrite(INC_PIN, HIGH);
digitalWrite(CS_PIN, LOW);
digitalWrite(UD_PIN, LOW);
for (char i = 0; i < 100; i++) ////lowest
{
digitalWrite(INC_PIN, HIGH); // sets the pin on
delayMicroseconds(100); // pauses for 50 microseconds
digitalWrite(INC_PIN, LOW); // sets the pin off
delayMicroseconds(100); // pauses for 50 microseconds
}
//////////////////////////move to center R 5k ohm -> 2.5k ohm
digitalWrite(UD_PIN, HIGH);
for (char i = 0; i < 49; i++) ////center
{
digitalWrite(INC_PIN, HIGH); // sets the pin on
delayMicroseconds(100); // pauses for 50 microseconds
digitalWrite(INC_PIN, LOW); // sets the pin off
delayMicroseconds(100); // pauses for 50 microseconds
}
digitalWrite(INC_PIN, HIGH);
digitalWrite(CS_PIN, HIGH);
delay(20);
}
:sample1_p.pde
import processing.serial.*;
Serial port;
int[] inbuf= new int[1];
void setup() {
port = new Serial( this, "COM7", 9600 );
}
void draw() {
}
void serialEvent(Serial port) {
// println( "available " + port.available() );
inbuf[0] = port.read();
println(inbuf[0]);
}
void keyPressed() {
if (key == CODED) { // コード化されているキーが押された
if (keyCode == RIGHT) {
port.write('U');
} else if (keyCode == LEFT) {
port.write('D');
}
if (keyCode == UP) {
port.write('A');
} else if (keyCode == DOWN) {
port.write('C');
}
}
}
おそらく,ProcessingとArduinoをシリアル通信で接続し,Processingからキーボードで入力したキー情報(aや1等,どのキーボードを押したのか?)をシリアル出力を行う。Arduino側は受け取ったキー情報に応じたコマンドを行なう。
例えば,キーボードの押したキーが
・Sなら,ポジションを保存。
・Uなら,ポジションを1ステップ増加
・Dなら,ポジションを1ステップ減少
UD,CS,INCの3線はArduinoのディジタルピンに接続。
RH/VHは5V,Rw/VwはAnalogPinに,RL/VLはGNDに接続する。一応,ポテンションメーターのRH/VHは5Vに直接繋げるのではなく,何かしらの抵抗と直列回路にするべきである。
AnalogPinに繋げたRw/Vwが抵抗変化するのでAnalogPinの入力電圧は変化する。