ラベル Arduino の投稿を表示しています。 すべての投稿を表示
ラベル Arduino の投稿を表示しています。 すべての投稿を表示

2017年6月23日金曜日

Arduino でバイト配列を文字列に変換する方法

概要

タイトルの通り
MQTT の PubSubClient.h を使う時にペイロードが byte* だったので文字列に変更したかった感じです

環境

  • macOS 10.12.5
  • Arduino IDE 1.6.12

コード

void callback(char* topic, byte* payload, unsigned int length) {
  payload[length] = '\0';
  String msg = String((char*) payload);
  Serial.println(msg);
  if (msg == "start") {
    // something ...
  } else if (msg == "stop") {
    // something ...
  }
}

ポイントはバイト配列の最後に終端文字を入れてること
こうしないとうまく文字列に変換できません

最後に

*byte を String に変換する方法を紹介しました
久しぶりに Arduino に触るとよくわかんないですね

参考サイト

2017年3月10日金曜日

Arduino でサーボモータの速度制御をしてみた

概要

Arduino でサーボモータの角度制御を速度制御を行ってみました

環境

  • Mac OS X 10.10.5
  • Arduino UNO
  • Arduino IDE 1.6.7
  • サーボモータ SG90

配線

arduino_servo_circuit.jpg

サーボモータから出ている線の

  • 茶色 -> Arduino GND
  • 赤色 -> Arduino 5v電源
  • オレンジ色 -> Arduino GPIO 8 番

という具合に配線します

VarSpeedServo ライブラリをインポート

これ を使います
リリースページから最新版の zip をダウンロードし解凍します

2016/02/02 時点での最新版は v1.1.3 でした
https://github.com/netlabtoolkit/VarSpeedServo/releases/download/v1.1.3/VarSpeedServo.zip

Arduino IDE を起動して

スケッチ -> ライブラリをインクルード -> .ZIP形式のライブラリをインストール

を選択してください
arduino_include_libs.png

ダウンロードした zip ライブラリを選択する画面になるので選択します
arduino_select_zip_libs.png

追加が完了すると「Library added to your libraries. Check “include library” menu」と IDE に表示されればライブラリのインポートは OK です

制御用スクリプト

サンプルコードは以下の通りです

#include <VarSpeedServo.h> 

VarSpeedServo servo;

int pin = 8;
int deg = 0;
int speed = 50; // 1 - 255

void setup() {
  servo.attach(pin);
  Serial.begin(9600);
} 

void move_servo(int deg) {
  servo.write(deg, speed, true);
  servo.detach();
}

int serialRead() {
  char c[4];
  for (int i = 0; i < 3; i++) {
    c[i] = Serial.read();
    if (c[i] == '\0') {
      break;
    }
  }
  return atoi(c);
}

void loop() {
  move_servo(deg);
  if (Serial.available() > 0) {
    delay(10);
    int input = serialRead();
    if ( input >= 0 && input <= 180 ) {
      Serial.println(input);
      servo.attach(pin);
      deg = input;
    }
  }
}

まず setup でサーボモータを制御するピンとシリアルモニタの初期化をします

loop でメイン処理に入ります
move_servo メソッドで引数に与えられた角度にサーボモータを動かします
その際に servo.write(deg, speed, true) を使うことで角度を動かします
2 つ目の引数にサーボモータを動かすスピードを指定することができます
1 から 255 までの範囲で指定することができ、1 が低速で 255 が高速になります
プログラム内の speed という変数で速度を調整できます
最後の true はサーボモータが指定された角度に動くまで次の処理を待ちます

loop 処理内で常にシリアルの入力を受け付けています
シリアルに角度を入力すると入力された角度にサーボモータが動きます

最後に

今回は以上です
Arduino ではサーボモータを制御する標準のライブラリに Servo.h があります
これを使っても角度を動かすことはできますが、速度の制御は自分で実装する必要があります
やるとしたら Servo.write で角度を 1 ずつ変えてその度 delay で休ませる時間を調整する感じになると思います

たぶん、VarSpeedServo を使うほうが断然楽だと思います

参考サイト

Arduino + ADXL345 で加速度センサを試してみた

概要

ADXL345 という加速度センサを Arduino の試してみました
ADXL345 は X, Y, Z 軸方向に対してどれくらい加速しているかを計測するための小型モジュールです

環境

ADXL345ライブラリ のインストール

http://wiki.androciti.com/download/SNS-1004/Adxl345.rar

からライブラリをダウンロードしてして解凍します
解凍してできた「Adxl345」を /path/to/Arduino/libraries/Adxl345 として配置します

インストールはこれで完了です

配線

Arduino と ADXL345 を配線しましょう
ADXL345 はピンヘッダがハンダづけされていないので、ハンダごてを使ってハンダしてください

配線の全体図は以下の通りです
arduino_with_adxl345_circuit.jpg

綺麗に写真が撮れたのでたぶん説明不要だと思いますが

  • Arduino Analog5 ピン -> ADXL345 SCL
  • Arduino Analog4 ピン -> ADXL345 SDA
  • Arduino 3.3V ピン -> ADXL345 VDD
  • Arduino GND ピン -> ADXL345 GND
  • ADXL345 GND -> ADXL345 SDO
  • ADXL345 VDD -> ADXL345 Vs

になります

スケッチ作成

配線できたらスケッチを作成しましょう
今回は ADXL345 ライブラリに付属しているサンプルをそのまま使います

#include <Wire.h>
#include <ADXL345.h>

ADXL345 adxl;

void setup(){
  Serial.begin(9600);
  adxl.powerOn();

  //set activity/ inactivity thresholds (0-255)
  adxl.setActivityThreshold(75); //62.5mg per increment
  adxl.setInactivityThreshold(75); //62.5mg per increment
  adxl.setTimeInactivity(10); // how many seconds of no activity is inactive?

  //look of activity movement on this axes - 1 == on; 0 == off 
  adxl.setActivityX(1);
  adxl.setActivityY(1);
  adxl.setActivityZ(1);

  //look of inactivity movement on this axes - 1 == on; 0 == off
  adxl.setInactivityX(1);
  adxl.setInactivityY(1);
  adxl.setInactivityZ(1);

  //look of tap movement on this axes - 1 == on; 0 == off
  adxl.setTapDetectionOnX(0);
  adxl.setTapDetectionOnY(0);
  adxl.setTapDetectionOnZ(1);

  //set values for what is a tap, and what is a double tap (0-255)
  adxl.setTapThreshold(50); //62.5mg per increment
  adxl.setTapDuration(15); //625μs per increment
  adxl.setDoubleTapLatency(80); //1.25ms per increment
  adxl.setDoubleTapWindow(200); //1.25ms per increment

  //set values for what is considered freefall (0-255)
  adxl.setFreeFallThreshold(7); //(5 - 9) recommended - 62.5mg per increment
  adxl.setFreeFallDuration(45); //(20 - 70) recommended - 5ms per increment

  //setting all interupts to take place on int pin 1
  //I had issues with int pin 2, was unable to reset it
  adxl.setInterruptMapping( ADXL345_INT_SINGLE_TAP_BIT,   ADXL345_INT1_PIN );
  adxl.setInterruptMapping( ADXL345_INT_DOUBLE_TAP_BIT,   ADXL345_INT1_PIN );
  adxl.setInterruptMapping( ADXL345_INT_FREE_FALL_BIT,    ADXL345_INT1_PIN );
  adxl.setInterruptMapping( ADXL345_INT_ACTIVITY_BIT,     ADXL345_INT1_PIN );
  adxl.setInterruptMapping( ADXL345_INT_INACTIVITY_BIT,   ADXL345_INT1_PIN );

  //register interupt actions - 1 == on; 0 == off  
  adxl.setInterrupt( ADXL345_INT_SINGLE_TAP_BIT, 1);
  adxl.setInterrupt( ADXL345_INT_DOUBLE_TAP_BIT, 1);
  adxl.setInterrupt( ADXL345_INT_FREE_FALL_BIT,  1);
  adxl.setInterrupt( ADXL345_INT_ACTIVITY_BIT,   1);
  adxl.setInterrupt( ADXL345_INT_INACTIVITY_BIT, 1);
}

void loop(){

  //Boring accelerometer stuff   
  int x,y,z;  
  adxl.readAccel(&x, &y, &z); //read the accelerometer values and store them in variables  x,y,z

  // Output x,y,z values - Commented out
  //Serial.print(x);
  //Serial.print(y);
  //Serial.println(z);


  //Fun Stuff!    
  //read interrupts source and look for triggerd actions

  //getInterruptSource clears all triggered actions after returning value
  //so do not call again until you need to recheck for triggered actions
   byte interrupts = adxl.getInterruptSource();

  // freefall
  if(adxl.triggered(interrupts, ADXL345_FREE_FALL)){
    Serial.println("Free-fall detected.");           //自由落下を検出しました。
    //add code here to do when freefall is sensed
  } 

  //inactivity
  if(adxl.triggered(interrupts, ADXL345_INACTIVITY)){
    Serial.println("No motion detected.");          //動きを検出しなかった。
     //add code here to do when inactivity is sensed
  }

  //activity
  if(adxl.triggered(interrupts, ADXL345_ACTIVITY)){
    Serial.println("Motion detected.");                 //動きを検出しました。
     //add code here to do when activity is sensed
  }

  //double tap
  if(adxl.triggered(interrupts, ADXL345_DOUBLE_TAP)){
    Serial.println("Double tap detected.");           //ダブルタップを検出しました。
     //add code here to do when a 2X tap is sensed
  }

  //tap
  if(adxl.triggered(interrupts, ADXL345_SINGLE_TAP)){
    Serial.println("Single tap detected.");            //シングルタップを検出しました。
     //add code here to do when a tap is sensed
  }  
}

ファイル -> スケッチの例 -> Adxl345 -> ADXL345_Example

にあるものをそのまま使っています
不要なコメントは削除しています

あとはコンパイルして Arduino に書き込みましょう

動作確認

シリアルモニタを開いてスケッチを書き込みましょう
ブレッドボードを持ち上げて動かしてみると以下のような感じでシリアルモニタに表示されると思います
arduino_with_adxl345_serial.png

Single tap, Double tap はブレッドボードをコンコンと叩けば検出されます
Motion detected と No Motion detected はどの方向でもいいので動かしたり止めたりすれば簡単に出ると思います

一番出すのが難しいのが Free-fall detected. でした
ADXL345 のボード上に軸の方向が書いているのですが、 Y 軸方向に勢いよく加速すると発生させることができます
読んで字のごとく自由落下を検知しているかどうかなので、配線している Arduino とブレッドボードがある状態だと中々に難しいです

最後に

加速度センサを Arduino で試してみました
同じように角速度センサ(ジャイロセンサ)も試してみたいなと思っています

参考サイト

2017年3月9日木曜日

Arduino で JSON ライブラリを使ってみた

概要

調べればいろいろと情報は出てきますがメモがてら手順を記載しておきます

環境

  • Mac OS X 10.11.3
  • Arduino IDE 1.6.7

ライブラリのインストール

スケッチ -> ライブラリをインクルード -> ライブラリを管理

で「Arduinojson」と検索しインストールしましょう
以下のようにインストールされれば OK です
arduino_with_json_installation.png

スケッチ

簡単なスケッチを書いてみます

#include <ArduinoJson.h>

void setup() {
  Serial.begin(115200);
  StaticJsonBuffer<200> jsonBuffer;
  char buffer[256];
  JsonObject& root = jsonBuffer.createObject();
  root["name"] = "name";
  root["address"] = "address";
  root.printTo(buffer, sizeof(buffer));
  Serial.println(buffer);
}

void loop() {

}

実行するとこんな感じで一度だけ Json が出力されます
arduino_with_json_serial.png

include 文を忘れずに記載しましょう
StaticJsonBuffer から jsonBuffer.createObject() で JsonObject を取得し、あとは連想配列を扱う感じで値を追加していきます
文字列に変換した場合は printTo メソッドで用意した buffer に値を代入できます

今回は JsonObject から文字列という流れの変換でしたが、もちろん文字列から JsonObject の変換も可能です
またネストした JsonObject も扱うことができます

詳しくは参考サイトに記載した公式ドキュメントを確認してみてください

参考サイト

2017年3月8日水曜日

Arduino のアナログピンで複数のスイッチの情報を取得してみた

概要

Arduino には 6 ピンもアナログピンがあります
がたくさんのスイッチを使う場合、それぞれでアナログピンを使うとすぐになくなってしまいます
今回は複数のスイッチの情報を 1 つのアナログピンで受け取って、どのスイッチが押されたのか判断する回路を組んでみたいと思います

環境

  • Mac OS X 10.11.3
  • Arduino IDE 1.6.7

配線

全体の配線図は以下の通りです
arduino_single_analog_circuit.jpg

オレンジが Arduino のアナログ 0 ピンにつながっています
黄色と黒が GND につながっています
赤が Arduino の 3.3V です

あとは 470Ωの抵抗をスイッチの数分、直列につなぎます
今回非常に残念ながらタクトスイッチが 1 つしかないのでスイッチは横に移動しながらアナログピンの値を取得していきました
arduino_single_analog_circuit_hint.jpg
※こんなイメージです
取得したら矢印のほうにタクトスイッチを動かす

スケッチ

単純にアナログリードしてシリアルモニタに出力するスケッチにしました

void setup() {
  Serial.begin(9600);
}

void loop() {
  int a = analogRead(0);
  Serial.println(a);
  delay(500);
}

できたら Arduino に書き込んで動作確認してみましょう

動作結果

おそらく以下のようになったと思います
スイッチは図の右から 1 つ目として数えていきます

  • 押していない時 = 659
  • 1 つ目押した時 = 0
  • 2 つ目押した時 = 328 ≒ 659 * 1/2
  • 3 つ目押した時 = 438 ≒ 659 * 2/3
  • 4 つ目押した時 = 493 ≒ 659 * 3/4
  • 5 つ目押した時 = 526 ≒ 659 * 4/5
  • 6 つ目押した時 = 548 ≒ 659 * 5/6

いわゆる分圧回路というやつで直列に繋がれた抵抗の間の電圧を取っていくと抵抗分、電圧が下がるという仕組みを使っているんだと思います

今回の場合は同じ抵抗を使ったので電圧の下がり具合が二次関数的な値になりました
なので、このままスイッチを直列に繋げていくとアナログの値が 659 に非常に近くなり、どのスイッチを押したのかが値だけだと判断が難しくなります
おそらく、9個目のスイッチで 659 * 8/9 = 585、10 個目のスイッチで 659 * 9/10 =593 の値になると思われるので、電圧が安定しない回路 ( 電源リソースが電池やバッテリーのもの ) だとアナログの値にブレが出てしまうので 9 個目と 10 個目どちらなのかがわからなくなるという感じです

なので今回の方法だと 5, 6 個くらいのスイッチを目処に使ってもらうといい感じになると思います

最後に

紹介は以上です
マイコンボードによってはアナログピンが 1 つしかないのもあるので、知っておくとかなり便利な技だと思います

また以下の参考サイトに記載されていましたが、次のスイッチにつなぐときの抵抗の値を適切な値にすることで取得できる電圧の値を線形にすることができるみたいです
そうすることでブレなくアナログの値を取得できるようになるのでそれにもチャレンジしてみたいと思います

参考サイト

Arduino Pro mini を試してみた

概要

ATmega328p が動作する Arduio Pro mini を試してみました
サンプルのスケッチを書き込んで動作確認まで実施してみます

環境

とりあえず配線

とりあえず配線して電源を入れるところまでやってみます
Arduino Pro mini は購入した時点でヘッダピンのハンダ付けはされておりません
なので、付属の 12 ピンのヘッダピン x 2 とシリアル通信用の 6 ピンのヘッダピンをハンダ付けしてください

でシリアル用のピンに USB のシリアル変換アダプタを接続します
あとは PC と接続すれば電源が入ります
シリアル変換アダプタの電圧変換用のジャンパピンは 5V 側にしておきます
電源が入ると 10 ピン付近にあるボード実装上の緑色 LED が点滅します
try_arduino_pro_mini_circuit.jpg

サンプルスケッチを書き込んでみる

Arduino IDE の設定

まず Arduino Pro mini にスケッチを書き込むための設定を Arduino IDE にします
Arduino Pro mini の裏側にスペックが記載されているので確認します
try_arduino_pro_mini_back.jpg

5V, 20MHz までサポートしているのがわかります
この設定で Arduino IDE にも設定してあげます

設定する箇所は 2 つです

  • ツール -> マイコンボード -> Arduino Pro or Pro Mini
  • ツール -> プロセッサ -> ATmega328 (5V, 16MHz)

を選択しましょう
たぶん、最近のものであれば上記を設定しておけば問題ないです

スケッチの作成

サンプル用のスケッチを作成しましょう
とはいってもただの L チカスケッチです

int PIN = 12;

void setup() {
  pinMode(PIN, OUTPUT);
}

void loop() {
  digitalWrite(PIN, HIGH);
  delay(1000);
  digitalWrite(PIN, LOW);
  delay(1000);
}

書き込みと動作確認

書き込んで LED が点滅することを確認しましょう
try_arduino_pro_mini_circuit_led.jpg

最後に

Arduino Pro mini を初めて動作させてみました
まだ詳細には追っていないので何とも言えませんがスケッチはほぼ 100% Arduino UNO 互換で書けるのではないでしょうか

このブログで何度も紹介している ESP-WROOM-02 も Arduino 互換で Arduino Pro mini も当然のように互換だと思います
同一の Arduino スケッチで 3 つのマイコンを制御できるようになるので、どれを使ってもいいような感じですが、電力やスペースなどの用途に合わせてマイコンをチョイスできるようになったので、かなり良い武器を手に入れたと思います

参考サイト

Arduino Pro mini で 16チャネル・アナログマルチプレクサを試してみた

概要

Arduino Pro mini で 16チャネル・アナログマルチプレクサを試してみました
Arduino で試した記事はこちら
ESP-WROOM-02 で試した記事はこちら

環境

配線

配線の全体図は以下の通り
promini_with_mux_circuit.jpg

ほぼ Arduino のとき と同じです
S0 - S3 の信号を受信するデジタルピンを 9, 8, 7, 6 に変更しているだけです

スケッチ

こちらも Arduino ときと同様です
デジタルピンを 9, 8, 7, 6 に変更しているだけです

//Mux control pins
int s0 = 9;
int s1 = 8;
int s2 = 7;
int s3 = 6;
//Mux in "SIG" pin
int SIG_pin = 0;

int muxChannel[16][4] = {
  {0, 0, 0, 0}, //channel 0
  {1, 0, 0, 0}, //channel 1
  {0, 1, 0, 0}, //channel 2
  {1, 1, 0, 0}, //channel 3
  {0, 0, 1, 0}, //channel 4
  {1, 0, 1, 0}, //channel 5
  {0, 1, 1, 0}, //channel 6
  {1, 1, 1, 0}, //channel 7
  {0, 0, 0, 1}, //channel 8
  {1, 0, 0, 1}, //channel 9
  {0, 1, 0, 1}, //channel 10
  {1, 1, 0, 1}, //channel 11
  {0, 0, 1, 1}, //channel 12
  {1, 0, 1, 1}, //channel 13
  {0, 1, 1, 1}, //channel 14
  {1, 1, 1, 1} //channel 15
};

void setup() {
  pinMode(s0, OUTPUT);
  pinMode(s1, OUTPUT);
  pinMode(s2, OUTPUT);
  pinMode(s3, OUTPUT);

  digitalWrite(s0, LOW);
  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);

  Serial.begin(9600);
}

void loop() {
  int ch_count = 2;
  for (int i = 0; i < ch_count; i ++) {
    Serial.print("Value at channel ");
    Serial.print(i);
    Serial.print("is : ");
    Serial.println(readMux(i));
    delay(1000);
  }
}


int readMux(int channel) {
  int controlPin[] = {s0, s1, s2, s3};
  //loop through the 4 sig
  for (int i = 0; i < 4; i ++) {
    digitalWrite(controlPin[i], muxChannel[channel][i]);
  }
  //read the value at the SIG pin
  int val = analogRead(SIG_pin);
  //return the value
  return val;
}

動作確認

スケッチを書き込んでボーレート 9600 でシリアルモニタを開きましょう
promini_with_mux_serial.png

問題なく動作しました

最後に

Arduino Pro mini でも Mux が動作することを確認しました
センサモジュールや通信モジュールを Arduino -> WROOM -> Pro mini で動作確認する流れは、自分の中ではもはや定番になりつつあります

Arduino で 16チャネル・アナログマルチプレクサを使ってみた

概要

前回 MCP3204 を使ってアナログピンの拡張を行いました
今回は 16チャネルもあるアナログマルチプレクサというモジュールを使って 16 個のアナログピンまで拡張してみました

環境

配線

16 チャネル アナログマルチプレクサはヘッダピンは付属していましたが、ハンダ付けまではされていなかったので、16 ピン側と 8 ピン側のハンダ付けを行ってください
try_mux_done_handa.jpg

今回はブレッドボード上で配線している関係で 4 チャネルだけ使って値を読み込んでみます
もちろん同じように配線すれば 16 チャネル全部使うことができます
読み込む値はタクトスイッチの電圧を読み込みます

回路全体の様子は以下の通り
try_mux_circuit.jpg

ちょっと写真だとわかりづらい配線もあるのでざっと説明すると

  • Arduino 5V -> ブレッドボード [+]
  • Arduino GND -> ブレッドボード [-]
  • Arduino GND -> ブレッドボード [-]
  • Arduino A0 -> Mux SIG
  • Arduino 8ピン -> Mux S0
  • Arduino 9ピン -> Mux S1
  • Arduino 10ピン -> Mux S2
  • Arduino 11ピン -> Mux S3
  • Mux VCC -> ブレッドボード [+]
  • Mux GND -> ブレッドボード [-]
  • Mux EN -> ブレッドボード [-]

※Mux は 16チャネル アナログマルチプレクサのことです
上記が Arduino と Mux の接続で、あとはタクトスイッチの電圧を各チャネルで取得する配線をします

  • GND -> 1KΩ -> ジャンパ -> ch0, ジャンパからスイッチの片側
  • 5V -> スイッチの片側

という感じで ch0 から ch3 の計 4 つのチャネルで電圧を読み込む配線をすれば OK です
ブレッドボードに余裕があればスイッチを 16 個並べて各チャネルに接続すれば 16 チャネル分使うことができます

スケッチ

スケッチも 4 チャネル分読み込む設定になっています
16 チャネル使う場合は ch_count 変数の値を 16 に変更してください

//Mux control pins
int s0 = 8;
int s1 = 9;
int s2 = 10;
int s3 = 11;
//Mux in "SIG" pin
int SIG_pin = 0;

int muxChannel[16][4] = {
  {0, 0, 0, 0}, //channel 0
  {1, 0, 0, 0}, //channel 1
  {0, 1, 0, 0}, //channel 2
  {1, 1, 0, 0}, //channel 3
  {0, 0, 1, 0}, //channel 4
  {1, 0, 1, 0}, //channel 5
  {0, 1, 1, 0}, //channel 6
  {1, 1, 1, 0}, //channel 7
  {0, 0, 0, 1}, //channel 8
  {1, 0, 0, 1}, //channel 9
  {0, 1, 0, 1}, //channel 10
  {1, 1, 0, 1}, //channel 11
  {0, 0, 1, 1}, //channel 12
  {1, 0, 1, 1}, //channel 13
  {0, 1, 1, 1}, //channel 14
  {1, 1, 1, 1} //channel 15
};

void setup() {
  pinMode(s0, OUTPUT);
  pinMode(s1, OUTPUT);
  pinMode(s2, OUTPUT);
  pinMode(s3, OUTPUT);

  digitalWrite(s0, LOW);
  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);

  Serial.begin(9600);
}

void loop() {
  int ch_count = 4;
  for (int i = 0; i < ch_count; i ++) {
    Serial.print("Value at channel ");
    Serial.print(i);
    Serial.print("is : ");
    Serial.println(readMux(i));
    delay(1000);
  }
}


int readMux(int channel) {
  int controlPin[] = {s0, s1, s2, s3};
  //loop through the 4 sig
  for (int i = 0; i < 4; i ++) {
    digitalWrite(controlPin[i], muxChannel[channel][i]);
  }
  //read the value at the SIG pin
  int val = analogRead(SIG_pin);
  //return the value
  return val;
}

ポイントは readMux 関数でここの引数に読み込むチャネルを与えるとチャネルに対応したビット列を muxChannel から取得します
そのビット列の情報を Mux 上の S0 から S3 に送ると必要なチャネルの値が Arduino A0 で取得できるという流れになります

動作確認

スケッチを記載した Arudino に書き込みましょう
ボーレートは 9600 にしてシリアルモニタを立ち上げます
結果は以下のようになると思います
try_mux_serial.png

スイッチを押したチャネルは 1023 で表示されスイッチを押していないチャネルは 0 になると思います
同時押しもできるので複数のスイッチを押した状態にすると対応した複数のチャネルが 1023 になるのが確認できると思います

最後に

かなり便利だと思いました
Arduino 側は電源と GND を除けば 5 ピンを消費するだけで 16 ピンのアナログ情報を取得できるようになるので 11 ピン分は得をしていることになります
アナログピンだけで言えば A0 を使っているだけなので、それが 16 ピン分取得できると思うとかなりお得感が伝わると思います

アナログマルチプレクサ自体も 300 円程度で購入できるので複数個持っていてもいいかもしれません
余談ですが、今回は安いという理由で海外から購入したので購入から到着までに 10 日ほどかかりました
海外からだから仕方ないとは思いますが、速攻手に入れたい場合はご注意ください

参考サイト

Arduino で MCP3204 を使って複数のセンサからデータを取得してみた

概要

MCP3204 は所謂、アナログデジタルコンバータでアナログの情報 (例えばセンサの情報) などを読み込むために使います
MCP3204 はアナログを読み込むチャネルが 4ch あり、12bit ( 0 - 4096 ) までの間でデータを取得することができます
今回は光センサと圧力センサの 2 つのアナログデータを MCP3204 1 つを使って読み込んでみたいと思います

環境

配線

まずは配線を紹介します
Arduino と MCP3204、光センサを接続します
arduino_with_mcp3204_circuit.jpg

ブレッドボード側だけアップにした配線も撮影しました
arduino_with_mcp3204_breadboard_circuit.jpg

配線の概要は以下の通り

  • MCP3204 DGND -> Arduino GND (黒ジャンパ)
  • MCP3204 AGN -> Arduino GND (黒ジャンパ)
  • MCP3204 CS chip select -> Arduino D10 (黄ジャンパ)
  • MCP3204 Din MOSI -> Arduino D11 (黄ジャンパ)
  • MCP3204 Dout MISO -> Arduino D12 (黄ジャンパ)
  • MCP3204 CLC clock -> Arduino D13 (黄ジャンパ)
  • MCP3204 Vref -> Arduino 5V reference voltage (that gives max adc reading) (赤ジャンパ)
  • MCP3204 Vdd -> Arduino 5V supply voltage, max 5.5V so Arduino 5V is fine (赤ジャンパ)

が MCP3204 と Arduino を接続するための配線です
MCP3204 のピンが何を示しているかは公式の回路図を見るとわかります

光センサは

  • 光センサ -> MCP3204 0ch
  • 光センサ -> Arduino 5V

に接続します

であとは FSR402 を MCP3204 の 2ch に接続します
10KΩの抵抗を挟んでから接続します、そうしないと FSR402 のアナログ値が安定しません、また GND に接続するのも忘れないでください
arduino_with_mcp3204_connected_fsr402.jpg

  • Arduino5V -> 10KΩ -> FSR402 (赤) -> MCP3204 2ch
  • Arduino GND -> FSR402 (青)

配線は以上です
写真だと複雑に見えますが組んでみるとそんなに複雑でもありません

スケッチ

MCP 3204 からデータを読み込むためのスケッチを紹介します

#include <SPI.h>

#define MCP3204_CS 10

void setup() {
  Serial.begin(9600);
  // Initializing SPI
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE1);
  SPI.setClockDivider(SPI_CLOCK_DIV8);

  delay(3000);
}
void loop() {
  int dt ;

  dt = ADC_analogRead(MCP3204_CS, 0);
  Serial.print("Analog CH0=");
  Serial.println(dt);
  dt = ADC_analogRead(MCP3204_CS, 2);
  Serial.print("Analog CH2=");
  Serial.println(dt);
  delay(1000);
}

int ADC_analogRead(int ss, int channel) {
  static char f;
  int d1 , d2;

  // Calling only once
  if (f != 1) {
    pinMode(ss, OUTPUT);
    digitalWrite(ss, HIGH);
    f = 1;
    delay(1);
  }
  // Reading a data from MCP3204
  digitalWrite(ss, LOW);
  d1 = SPI.transfer(0x06 | (channel >> 2));
  d1 = SPI.transfer(channel << 6);
  d2 = SPI.transfer(0x00);
  digitalWrite(ss, HIGH);

  return (d1 & 0x0F) * 256 + d2;
}

すいません、それぞれの細かい処理は SPI.h のリファレンスを読んでください
ポイントは ADC_analogRead メソッドでここの引数にチャネルを与えることでアナログ値を取得することができます
Arduino の 10 ピン (SS) を LOW にしている間 MCP3204 から値を取得することができます
その間に指定のビットからデータを読み込むことで値が取得できるみたいです ( 曖昧ですいません )

とりあえずこれで動作確認してみましょう

動作確認

スケッチを Arduino に書き込んでシリアルモニタを起動しましょう
以下のように表示されると思います
enter image description here

ch0 と ch2 の情報が連続で表示されると思います
光センサを手で覆って暗くすると ch0 の値が小さくなります
圧力センサを手で押すと ch2 の値が小さくなります

今回は ch0 と ch2 を使っていますが、ch1 と ch3 を使っても全然問題ないです
また、ch1 と ch3 を追加したい場合は loop メソッド内に ADC_analogRead(MCP3204_CS, 1);, ADC_analogRead(MCP3204_CS, 3); あたりを追記すれば動作すると思います

最後に

なぜこれをやったかというとアナログピンの消費を抑えたかったからです
光センサやFSR402 等の圧力センサを使うと、その値を取得するためにアナログピンを 1 つ消費します
そうなると複数のセンサを使う回路だと、すぐにアナログピンが尽きてしまい複数の Arduino を購入するなんてことになってしまいます

そんなときに MCP3204 や MCP 3208 があるとデジタルピン 4 ピンを消費する代わりに複数のアナログデータを取得することができます
ちょっとした Arduino 等のマイコンボードを使う時の技ですが、覚えておくとかなり重宝すると思います

で、更に今後やろうと思っているのが 16チャネル持っているアナログマルチプレクサを使って 16 チャネルからデータを読み込んでみたいと思っています
おそらく同じようなやり方でできると思ったので予行演習として今回は手元にあった MCP3204 を使って複数のアナログリードを実施した感じです

参考サイト

2017年2月15日水曜日

Arduino と HC-SR04 の情報を BLESerial2 で送信してみた

概要

前回 Arduino で超音波センサ (HC-SR04) を使ってみました
今回は HC-SR04 で測定した距離情報を BLESerial2 を使って Bluetooth で送信してみました

環境

  • Arduino Uno
  • Arduino IDE 1.6.7
  • 超音波センサ HC-SR04
  • 温度センサ
  • BLESerial2

配線

配線は以下の通りです
arduino_with_hcsr04_with_bleserial_circuit.jpg

全体は前回の配線とほぼ同じです
追加で BLESerial2 を乗せれば OK です
電源は 3.3v から取得しましょう
BLESerial2 の TX と Arduino TX (1ピン) を接続すれば OK です

スケッチ

スケッチは以下の通りです
Serial.write で BLESerial2 に距離情報を書き込むだけで OK です

int duration = 0;
double distance = 0;
int trigger = 2;
int echo = 3;

void setup() {
  Serial.begin(9600);
  pinMode(trigger, OUTPUT);
  pinMode(echo, INPUT);
}

void loop() {
  int ans, temp, tv;
  ans = analogRead(0);
  tv = map(ans, 0, 1023, 0, 5000);
  temp = map(tv, 300, 1600, -30, 100);
  digitalWrite(trigger, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigger, LOW);
  duration = pulseIn(echo, HIGH, 5000);
  if (duration > 0) {
    distance = duration / 2;
    float sonic = 331.5 + 0.6 * temp;
    distance = distance * sonic * 100 / 1000 / 1000;
    Serial.write(int(distance));
  }
  delay(500);
}

動作確認

iPhone と接続して動作確認してみました
使用したアプリは LightBlue になります
arduino_with_hcsr04_with_bleserial_result.png

こんな感じで Notify の Characteristic に距離情報がどんどん送られてくると思います

最後に

超音波センサの情報を Bluetooth に乗せて送信してみました
次回は ESP-WROOM-02 を使って Wifi で送信してみたいと思います

2017年2月14日火曜日

avrdude: no programmer has been specified on the command line or the config file

概要

Arduino Pro mini にスケッチを書き込もうとしたら急にタイトルのエラーが発生しスケッチがうまく書き込めなくなりました

avrdude: no programmer has been specified on the command line or the config file
         Specify a programmer using the -c option and try again

対処できたので方法を紹介します

環境

  • Arduino IDE 1.6.7
  • Mac OS X 10.11.5
  • Arduino Pro mini (5V 16MHz)

対処方法

Arduino IDE を 1.6.9 にアップデートしました (2016/06/15 時点で最新)

https://www.arduino.cc/en/Main/Donate

から Zip ファイル (arduino-1.6.9-macosx.zip) をダウンロードし展開します
その中に入っている「Arduino.app」をアプリケーション配下にコピーします
既存の Arduino.app がある場合は上書きしちゃって OK です

で再度 Arduino IDE を開いてスケッチを書き込んだらうまくいきました

参考サイト

2017年2月13日月曜日

サインスマートのリレーモジュールを Arduino で使って LED を制御してみた

概要

リレーモジュールという電気信号で制御するスイッチを使って LED を制御してみました

環境

配線

まず今回の配線の全体図は以下の通りです
try_relay_module_with_arduino_circuit.jpg

Arduino は Mac に USB で接続してスケッチを書き込めるようにしてください
リレーモジュールを制御する Arduino のピンは 2 番ピンを使っています

詳細

ちょっと配線について詳しく説明します

まず、Arduino -> リレーモジュールの配線は以下になります

  • Arduino 2 ピン -> リレーモジュール IN1
  • Arduino GND -> リレーモジュール GND
  • Arduino 5v -> リレーモジュール VCC
  • Arduino 5v -> リレーモジュール JD-VCC

がリレーモジュールとの配線になります
Arduino の 5v ピンは 1 つしかないのでブレッドボードに一度 5v を繋いでそこから 2 線分の 5v を確保しています

次に、リレーモジュール -> LED の接続です

  • Arduino 3.3v -> リレーモジュール NO1 ( -> リレーモジュール COM1 )
  • リレーモジュール COM1 -> 抵抗 10kΩ -> 青色 LED アノード -> 青色 LED カソード -> Arduino GND

という感じです

リレーモジュールは電源が ON になると NO1 と COM1 が接続されます
ちょっと文で説明するとわかりづらいですが、リレーモジュールの NO1 と COM1 がちょうどスイッチの動きになるように接続しています

リレーモジュールはあくまでもスイッチとしての動作しかしないので LED を点灯させるための電源は Arduino 3.3v から供給しています
( もちろん別の電源から確保しても問題ありません )

スケッチ

デジタルピン 2 番を制御する簡単なスケッチを用意しました

void setup() {
  pinMode(2, OUTPUT);
}

void loop() {
  digitalWrite(2, HIGH);
  delay(2000);
  digitalWrite(2, LOW);
  delay(2000);
}

配線したら書き込んでみましょう

動作確認

動作として 2 秒おきに青色 LED が点灯 -> 点滅を繰り返せば OK です
Arduino に電源が入り、リレーモジュールにも電気が通い始めるとわかりますが、「カチッ、カチッ」とリレーモジュールが音を出していると思います

これがリレーモジュールのスイッチの挙動になります
スイッチが ON になっているときにはリレーモジュール上の LED も赤く点灯します

最後に

いかがでしたでしょうか
自分がリレーモジュールを触った感じだとリレーモジュールの役割は

スイッチのない回路を電気信号のスイッチで制御できるようにする

なのかなと思います
( たぶん専門的な人からすると「全然ちげーよ」と言われそうですが、、、)

結局スイッチなので、例えば市販の物理スイッチをリレーモジュールに置き換えることで Arduino などからプログラムで制御できるようになるのがメリットなのかなと思います
言葉の通り「リレー」なので 2 つの電気回路をつなぐためのモジュールという感じだと思います

参考サイト

2017年1月31日火曜日

Arduino で DC モータを制御してみる

概要

Arduino で DC モータを制御してみました
作成した回路とスケッチを紹介します

環境

  • Arduino Uno
  • Arduino IDE 1.6.9
  • トランジスタ 2N5088 x 1
  • 一般用整流ダイオード 1N4007 x 1
  • 抵抗 1kΩ x 1

とりあえず DC モータを回す

スイッチを押すとモータが回る回路です
arduino_with_dcmotor_circuit1.jpg

電池とスイッチとジャンパケーブルだけです
これを Arduino から制御できるようにします

電源を Arduino から取る回路

電源を電池 2 本から Arduino に変更した回路です
arduino_with_dcmotor_circuit2.jpg

電源を変更しただけなのでこれでもモータは回ります

デジタルピンで制御する回路 (誤)

2 番ピンを使って制御してみます
まずはバカ正直に回路を組んでみます
arduino_with_dcmotor_circuit3.jpg

スケッチは以下の通りです

void setup() {
  pinMode(2, OUTPUT);
}

void loop() {
  digitalWrite(2, HIGH);
  delay(2000);
  digitalWrite(2, LOW);
  delay(2000);
}

これだとモータが回らないのがわかると思います
電圧は足りているのですが、電流が足りていないためモータが回りません
これにトランジスタを加えることでモータを制御してみます

デジタルピンで制御する回路 (正)

トランジスタ+ダイオードを使った回路は以下の通りです
arduino_with_dcmotor_circuit4.jpg

トランジスタの配線部分だけ拡大しました
arduino_with_dcmotor_circuit5.jpg

スケッチは前述のとおり 2 ピンを制御するスケッチを使っています
これで正しく動作すると 2 秒おきにモータが起動/停止を繰り返します

ポイントはトランジスタとダイオードの配線です

  • エミッタ (写真一番左) は GND に接続します
  • ベース (写真真ん中) は Arduino 2 ピンの信号を 1kΩ の抵抗を挟んで接続します
  • コレクタからジャンパケーブルを出してモータと整流ダイオードを並列に接続します

整流ダイオードはプラスとマイナスの区別があるのでプラス側に Arduino の 3.3v を接続します
トランジスタはものによってエミッタ、ベース、コレクタのピンの順番が異なるので適宜電気特性のシートなどを見ながら確認してください

また、今回モータ用の電源は Arduino の 3.3v から取得していますが電池から取得しても問題ありません

最後に

Arduino で DC モータを制御してみました
今回のポイントはトランジスタとダイオードでしたがそれぞれの働きは

  • トランジスタ・・・電流を増幅させる
  • ダイオード・・・電流の流れを一方向にする

ですが、実際に回路を組んでみると更に動きを理解することができました

あとは電圧の増幅 (昇圧) とかもやってみたいと思っています

参考サイト

Arduino で赤外線信号を学習してエアコンを制御してみた

概要

Arduino + 赤外線受信モジュールを使ってリモコンの赤外線信号を学習しました
そして、その信号を赤外線 LED を使って送信することでエアコンを制御してみました
今回学習したリモコンは Panasonic の A75C3639 という型番になります

環境

対象のリモコン

信号を学習するリモコンは以下の通りです
とりあえず今回は冷房をつけたいので冷房ボタンを学習します
try_arduino_infrared_remocon.jpg

配線

  • Arduino と赤外線受信モジュール
  • Arduino と赤外線 LED
  • Arduino とタクトスイッチ

を配線します
タクトスイッチを押した時に赤外線を送信するようにします
try_arduino_infrared_circuit1.jpg

ブレッドボード側のアップです
try_arduino_infrared_circuit2.jpg

赤外線受信モジュールは 5V, GND, 2 番ピンを使っています
あとで説明しますが、赤外線受信モジュールは必ず 2 番ピンを使ってください
赤外線 LED は GND, 3 番ピンを使っています
これもあとで説明しますが、赤外線の送信は必ず 3 番ピンを使ってください
タクトスイッチはプルダウンで接続し 3V, GND, 7 番ピンを使っています

IRremote のインストール

Arduino IDE で赤外線を操作することができるライブラリをインストールします

スケッチ -> ライブラリをインクルード -> ライブラリを管理 -> IRremote と検索

するとライブラリが見るかるので選択してインストールしてください
try_arduino_infrared_install_lib.png

リモコンの信号を学習する

では、まずリモコンの赤外線信号を学習します
スケッチは以下の通りです

#define maxLen 800

volatile  unsigned int irBuffer[maxLen];
volatile unsigned int x = 0;

void setup() {
  Serial.begin(115200);
  attachInterrupt(0, rxIR_Interrupt_Handler, CHANGE);
}

void loop() {
  Serial.println(F("Press the button on the remote now - once only"));
  delay(5000);
  if (x) {
    Serial.println();
    Serial.print(F("Raw: ("));
    Serial.print((x - 1));
    Serial.print(F(") "));
    detachInterrupt(0);
    for (int i = 1; i < x; i++) {
      // if (!(i & 0x1)) Serial.print(F("-"));
      Serial.print(irBuffer[i] - irBuffer[i - 1]);
      Serial.print(F(", "));
    }
    x = 0;
    Serial.println();
    Serial.println();
    attachInterrupt(0, rxIR_Interrupt_Handler, CHANGE);
  }

}

void rxIR_Interrupt_Handler() {
  if (x > maxLen) return;
  irBuffer[x++] = micros();
}

これを Arduino に書き込んで赤外線受信モジュールにリモコンを向けてボタンを押すと信号の情報がシリアルモニタに表示されます
try_arduino_infrared_receive_ir.png

事前の配線で受信モジュールは 2 番ピンを使うようにしましたが上記のコードは暗黙で 2 番ピンを使うことになっています
( コード上でピン番号を指定している部分がないと思います )

送信時にこの情報を使用するのでメモしておいてください

ちょっとここで詳細に説明したいのですが、実はリモコンの学習はインストールした IRremote ライブラリを使ってもできます
ですが、101 個以上の信号を送信するリモコンを IRremote で学習することができません
https://github.com/z3t0/Arduino-IRremote/issues/137

IRremoteInt.h というファイル内で RAWBUF という変数を管理しており、これが受信できる信号の個数の MAX 値なのですが、この値をデフォルトの 101 から変更してもうまくそれ以上の信号が受信できないのです

なので、別途赤外線の信号を学習するスケッチを作成して、そこで学習できた信号の情報を使うことにしました

学習した信号を送信する

信号を学習できたら送信してみましょう
送信用のスケッチは以下の通りです

#include <IRremote.h>

int ON = 7;
int khz = 38;
IRsend irsend;

void setup() {
  pinMode(ON, INPUT);
  Serial.begin(9600);
}

void loop() {
  if (digitalRead(ON) == HIGH) {
    Serial.println("ON");
    unsigned int irSignal[440] = {3584, 1664, 532, 352, 524, 1228, 528, 388, 492, 392, 496, 384, 492, 388, 492, 392, 488, 396, 492, 388, 492, 388, 492, 388, 492, 392, 492, 388, 492, 1224, 528, 392, 492, 392, 492, 388, 492, 388, 492, 388, 492, 364, 520, 388, 492, 1228, 524, 1228, 528, 1232, 528, 388, 492, 388, 488, 1228, 532, 360, 524, 388, 488, 360, 524, 388, 492, 360, 524, 388, 492, 388, 496, 388, 488, 360, 524, 360, 524, 388, 492, 388, 412, 472, 492, 388, 492, 388, 492, 360, 520, 364, 520, 392, 492, 388, 488, 360, 524, 392, 492, 392, 488, 388, 496, 388, 416, 468, 412, 468, 412, 436, 524, 388, 492, 392, 492, 388, 488, 1232, 528, 1228, 524, 392, 492, 392, 412, 468, 488, 360, 520, 388, 492, 9956, 3584, 1660, 528, 392, 412, 1304, 528, 388, 492, 360, 524, 360, 520, 392, 492, 356, 444, 440, 520, 392, 488, 360, 524, 388, 416, 440, 520, 388, 492, 1228, 524, 392, 492, 392, 492, 388, 488, 396, 412, 468, 412, 472, 488, 392, 488, 1228, 524, 1228, 528, 1232, 528, 388, 492, 388, 488, 1232, 524, 364, 520, 392, 416, 464, 492, 388, 416, 468, 492, 392, 488, 360, 520, 360, 520, 364, 520, 360, 524, 388, 492, 388, 416, 468, 416, 1304, 448, 468, 488, 392, 488, 396, 488, 1228, 452, 1304, 448, 436, 448, 472, 412, 468, 412, 464, 492, 1228, 528, 360, 520, 1228, 452, 1304, 448, 468, 492, 360, 520, 392, 488, 396, 412, 468, 412, 472, 488, 356, 448, 468, 488, 392, 488, 1240, 524, 388, 416, 1304, 452, 464, 488, 364, 520, 360, 448, 464, 416, 1304, 524, 364, 448, 468, 412, 468, 488, 388, 492, 364, 520, 392, 412, 468, 412, 468, 416, 468, 488, 364, 444, 436, 444, 468, 488, 396, 412, 468, 412, 468, 488, 360, 448, 436, 448, 464, 412, 1304, 452, 1304, 528, 360, 524, 388, 416, 468, 412, 468, 412, 440, 444, 468, 412, 468, 416, 432, 448, 472, 412, 464, 488, 1228, 452, 1304, 452, 472, 412, 468, 412, 468, 488, 392, 412, 472, 412, 468, 488, 364, 444, 464, 416, 472, 412, 468, 412, 468, 412, 468, 412, 472, 416, 468, 412, 432, 448, 468, 412, 440, 444, 468, 412, 468, 412, 468, 412, 472, 416, 464, 416, 468, 412, 464, 416, 1308, 524, 396, 412, 464, 416, 468, 412, 472, 416, 468, 412, 468, 412, 468, 412, 472, 416, 464, 416, 1304, 448, 1304, 524, 400, 416, 432, 448, 464, 416, 468, 412, 472, 412, 1308, 448, 468, 412, 468, 412, 1308, 452, 1304, 452, 468, 412, 468, 412, 468, 412};
    irsend.sendRaw(irSignal, sizeof(irSignal) / sizeof(irSignal[0]), khz);
  }
  delay(500);
}

学習した信号情報をそのまま配列に格納すれば OK です
今回はこの配列の情報がリモコンの冷房ボタンの信号になります
なので、別のボタンを送信したい場合はここの配列の情報をそのまま書き換えてください

今回はタクトスイッチが HIGH になったときに赤外線の信号を送信するようにしています
赤外線情報を送信するときはインストールした IRremote を使用しています
で、配線時に赤外線 LED を 3 番ピンに接続しましたが、IRremote の sendRaw は勝手に 3 番ピンを使っています
なので、3 番ピンに接続しておかないと IRremote で信号がうまく送信できないということになってしまいます

動作確認

赤外線 LED をエアコンに向けてスイッチを押してみましょう
ちゃんと信号が学習できていれば、エアコンが反応するはずです
ちなみに今回紹介した信号の配列で送信してみたところ、ちゃんとエアコンが冷房ボタンと認識し冷房が付きました
なので、これで Arduino からエアコンをつけれるようになりました

最後に

紹介は以上です

やはり一番ハマったのは信号を学習する部分でした
初めはずっと IRremote の学習するスケッチを使っていたのですが、どうも信号が 101 個以上増えなく、エアコンもその情報だと反応しませんでした
おかしいなと思い、いろいろ調べたところ送信する赤外線の信号が 101 個以上長いケースがあるということがわかり、別途信号を学習するスケッチを作るということになりました

ただ、この方法はおそらくどのリモコンにも応用可能だと思います
学習用のスケッチで学習したデータを配列に突っ込んで、そのデータをそのまま送信しているだけなので、同じことを別のリモコンでやれば良いだけです

IRremote の関数とかを見ると Sony や NEC などメーカごとに用意された関数があるのですが、これはライブラリ内部ですでにリモコンの情報を持っているため、少しでも対応していないリモコンだと動かなくなります

そんな場合でも今回の方法を知っていれば簡単に対応できるようになる、と思います

あと、停止の信号を学習するのと ESPr 対応ができれば家の外からでもエアコンを制御できるようにできそうです
それもできたら紹介したいと思います

参考サイト

2017年1月27日金曜日

Arduino で超音波センサ (HC-SR04) を使ってみた

概要

Arduino で超音波センサ (HC-SR04) を使ってみました
HC-SR04 は送信用と受信用のセンサがついており、送信した信号を受信側で受信するまでの時間を測定することができます
音波の速さは音速 (約 340.29 m / s) なのでこれと測定時間を掛け合わせることで距離を測定することができます

環境

  • Arduino Uno
  • Arduino IDE 1.6.7
  • 超音波センサ HC-SR04
  • 温度センサ

今回は温度センサがあったので使っています
温度センサを使って温度を考慮することでより正確な距離を算出することができます
温度変化は音速の値に影響します

配線

実際に配線した写真は以下の通りです
arduino_with_hcsr04_circuit.jpg

やや複雑な配線だったので fritzing を使って配線図も作成しました
arduino_with_hcsr04_circuit_fritzing.png

特に迷うところはないと思います
HC-SR04 はデジタルピン 2, 3 番を使います
温度センサはアナログピン 0 番を使います
電源は 5v から供給してください

スケッチ

スケッチ全体はは以下の通りです

int duration = 0; // 受信した時間
double distance = 0; // 距離
int trigger = 2;
int echo = 3;

void setup() {
  Serial.begin(9600);
  pinMode(trigger, OUTPUT);
  pinMode(echo, INPUT);
}

void loop() {
  int ans, temp, tv;
  ans = analogRead(0);
  tv = map(ans, 0, 1023, 0, 5000); //センサ値 -> 電圧
  temp = map(tv, 300, 1600, -30, 100); //電圧 -> 温度 (-30 から 100 度まで)

  Serial.print("temp:");
  Serial.print(temp);
  Serial.print("c");

  // 音波を出力して pulseIn で受信する
  digitalWrite(trigger, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigger, LOW);
  duration = pulseIn(echo, HIGH, 5000);

  if (duration > 0) {
    distance = duration / 2;
    // 温度から音速を計測 (単位は m/s)
    float sonic = 331.5 + 0.6 * temp;
    Serial.print("\tsonic:");
    Serial.print(sonic);
    Serial.print("m/sec");
    // 音速を cm 単位のマイクロ秒に変換
    // 100 掛けることで cm に変換
    // 1000 割ることで ms に変換
    // 再度 1000 割ることで us に変換
    distance = distance * sonic * 100 / 1000 / 1000;
    Serial.print("\tdistance:");
    Serial.print(distance);
    Serial.print("cm");
  }
  Serial.println("");
  delay(500);
}

ポイントはアナログピンから取得した値を電圧 -> 温度と変換している部分と digitalWrite, pulseIn を使って音波の送受信をしている部分かなと思います
あとは最終的に cm 単位で出力するので単位を変換してあげています

動作確認

スケッチを書き込んでシリアルモニタを起動してみましょう
以下のように表示されると思います
arduino_with_hcsr04_result.png

ちなみに計測できた距離の最大は 75cm くらいが限界でした
60cm を超えたあたりから距離の計測精度も落ちてきました (実際 70 cm 距離があるが測定できた値は 66cm くらいの精度)
温度センサを使わないバージョンでも計測してみましたが、それよりかは温度センサを使ったほうが精度は良かったです

Tips

  • distance の値が 0 になってしまう

理由はわからないのですが、distance が 0 になってしまう現象が発生しました
音速を cm 単位のマイクロ秒に修正すると 0.034cm/us ( = sonic * 100 / 1000000) になるのですが、これを時間 (duration) と掛け合わせるところでなぜか 0 になってしまいました
何度か試しているとちゃんと表示されるようになったのだが、うまく表示されない場合は一旦変数に格納してから音速を掛け合わせるようにすると直るかもしれません
もしくは 0.034 を直接掛けあわせても直ると思います

  • map 関数について
    map は値をある範囲に変換してくれるメソッドです
    例えばソースコード中の

tv = map(ans, 0, 1023, 0, 5000)

であれば入力が 0 から 1023 の範囲でそれを 0 から 5000 の範囲に変換して tv に格納するということをやっています

参考サイト

Arduino で温度センサを使ってみた

概要

Arduino で温度センサを使ってみました

環境

配線

arduino_temp_sensor_circuit.jpg

Arduino の 3.3v を AREF ピンに接続する必要があります
センサは写真の左から 5.5v, A0, GND に接続しています

センサの 5.5v, GND にセラミックコンデンサを挟んでいます
その方が値が安定するみたいです

スケッチ

アナログ値から温度を求めるスケッチは以下の通りです

const int voutPin = 0;

void setup() {
  Serial.begin(9600);
  analogReference(EXTERNAL);
}

void loop() {
  int reading = analogRead(voutPin);
  // Analog -> mV
  float voltage = ((long)reading * 3300) / 1024;
  Serial.print(voltage);
  Serial.print(" mV, ");

  // mV -> 摂氏
  float tempC = (voltage - 500) / 10;
  Serial.print(tempC);
  Serial.println(" degress C, ");

  delay(1000);
}

AREF に 3.3v を接続し analogReference(EXTERNAL); しているので基準電圧は 3.3v (3300) になります
1024 は分解能です、取得したアナログ値を 1024 までの範囲に変換する必要があります

そのあとで 500 を引いています
これは 0 度のときに 500mV になるため引いています
10 で割っているのは 1 度あたりの電圧が 10mV になっているためです

動作確認

スケッチを書き込んでシリアルモニタで確認してください

arduino_temp_sensor_ret.png

最後に

Arduino で MCP9700 の温度センサを使ってみました
精度が ±4 度あるらしいのであしからず

この後は ESP-WROOM-02 でも使ってみたいと想います

参考サイト

2017年1月1日日曜日

Arduino で 5v ソレノイドを制御してみた

概要

秋月で 450 円で売っていたソレノイドを Arduino で制御してみました

環境

  • Arduino UNO
  • Arduino IDE 1.6.9
  • ソレノイド
  • トランジスタ 2N5088 x 1
  • 抵抗 47 Ω x 1
  • 整流ダイオード x 1

配線

全体の写真
arduino_with_solenoid_circuit1.jpg

回路の部分をアップにした写真
arduino_with_solenoid_circuit2.jpg

ソレノイドは LOW <-> HIGH を切り替えた時に逆起電流が発生するので回路および Arduino を保護する目的で整流ダイオードを並列に接続しています

スケッチ

int tr = 2;

void setup() {
  pinMode(tr, OUTPUT);
}

void loop() {
  digitalWrite(tr, HIGH);
  delay(1000);
  digitalWrite(tr, LOW);
  delay(60000);
}

2 番ピンの LOW <-> HIGH を繰り返しているだけです
なぜこんなに delay を入れているかは以下で記載します

ポイント

まずこのソレノイドは 5v という小さな電圧で動作するのですが、電流が 1.1A も必要になります
Arduino のピンはだいたい 20mA くらいなので全く足りません

そこでトランジスタを使い電流を増幅させます
ベース (真ん中) に 47Ω の抵抗を挟んで Arduino の 2 番ピンを接続します
そしてエミッタ (左) に Arduino のGND を接続し、コミッタ (右) をソレノイドの GND 側に接続します
これで 2 番ピンの出力電流を増幅させることができます

で抵抗の値がなぜ 47Ω なのかというと手元にあるのが、それしかないからという理由もありますが、いろいろな抵抗で試した結果 47Ω の抵抗しかソレノイドが動作しなかったからです
はじめは 7.5KΩ というかなり大きい抵抗を使っていたのですが、それだとベースに流れるベース電流の量がかなり小さくなってしまいソレノイドがうんともすんとも言いませんでした
で、手元にある抵抗を使って抵抗の値をどんどん小さくしていった (7.5KΩ -> 5KΩ -> 3KΩ -> 1KΩ -> 470Ω -> 220Ω -> 47Ω) のですが、それで動作したので 47Ω の抵抗だけでした

ただ、問題が発生しました
47Ω の抵抗を使えばソレノイドは動くのですが、トランジスタがとんでもなく熱くなります
(おそらくベースから流れる電流が大きすぎるせいでトランジスタに負荷がかかり発熱していると思われる)
で、スケッチのほうで制御しようと基本は 2 番ピンの状態を LOW にすることでベースにかかる負荷を最小限にしています
なので LOW の状態で delay を 60 秒もかけているわけです

おそらくこの方法はあまりよくないと思われます
本来ならもう少し抵抗の値を大きくして、トランジスタにかかる負荷を軽減し電流増幅率の高いトランジスタに変えてあげるのが良いと思います
トランジスタにはダーリントン式と呼ばれるトランジスタを複数つなげて更に電流を増幅する方式があります
自分でダーリントン接続回路を組まなくてもダーリントン式のトランジスタというのがあるのでそれに変えてあげるといいかなと思います

動作確認

PC に Arudino を接続してスケッチを書き込んでみましょう
ソレノイドが 60 秒おきに「カチッ」と動作すると思います

最後に

Arduino でソレノイドを制御してみました
前に DC モータも制御したのですが、そのときもトランジスタを使って電流増幅させました
アクチュエータ系の制御はトランジスタ必須と言ってもいいかもしれません

あとはどれか他のデバイス (Pro mini, WROOM, RPi, zero) でも試してみたいかなと思っています

参考サイト