脳汁portal

アメリカ在住(だった)新米エンジニアがその日学んだIT知識を書き綴るブログ

焦電人感センサーSB612Aをラズベリーパイで使ってみた

以下の秋月で販売している焦電型赤外線センサーをラズベリーパイで使ってみました(¥600)
f:id:portaltan:20180516092309p:plain
akizukidenshi.com

仕様

  • 電源電圧:3.3V~12V(3.3VのLDOによりモジュール内部で安定化されています)
  • 最大検知距離:8m(気温等の環境条件によります)
  • 検知角度:120度
  • 検知出力保持時間:2秒~80分

ハードウェアサイ

SB612A側

画像のようにメスメスケーブルをさしていきます。
色はあわせなくていいですが、右から赤(VCC), 緑(信号出力). 黒(GND)です
f:id:portaltan:20180515182953j:plain

ラズベリーパイ

それぞれケーブルを以下のようにラズベリーパイに接続します

  • 赤:2番pin(5V)
  • 黒:6番pin(GND)
  • 緑:12番pin(GPIO 18)

f:id:portaltan:20180515183239j:plain
f:id:portaltan:20180515183307p:plain

この状態でラズパイの電源をいれるとSB612Aに5V電源が供給されます

ソフトウェアサイ

確認

まずはちゃんと動いているか確認をします

## GPIO設定
sudo echo 18 > /sys/class/gpio/export
sudo echo in > /sys/class/gpio/gpio18/direction

### 確認
## 検知していない時
cat /sys/class/gpio/gpio18/value
0

## 検知中
cat /sys/class/gpio/gpio18/value
1

LED連携

センサーが動体を検知すると31番ピン(GPIO6)にさしたLEDが光るようにします

#!/usr/bin/env python

import RPi.GPIO as GPIO

### setup
GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.IN) # GPIO 18 : human detect sensor
GPIO.setup(6, GPIO.OUT) # GPIO 6: LED

# initialize
if GPIO.input(18):
  GPIO.output(6, 1)
else:
  GPIO.output(6, 0)

while True:
  GPIO.wait_for_edge(18, GPIO.BOTH)
  if GPIO.input(18):
    print "detected!"
    GPIO.output(6, 1)
  else:
    GPIO.output(6, 0)

  time.sleep(1)

GPIO.cleanup()

GPIO.wait_for_edgeは電圧がLOWからHIGH、またはその逆を検知します
引数にはピン番号とGPIO.RAISING or GPIO.FALLINGを渡すことで電圧の動きをチェックします
両方取得したいときはGPIO.BOTHでとれます
単純にLoopで毎秒チェックとかにするよりは低負荷になります

その他設定

感度

SENSと書かれたつまみを右に回すほど感度が高くなります

検知出力保持時間

DELAYと書かれたつまみを左にまわすほど保持時間が長くなります
保持時間とは、一度動体を検知した際に何秒間検知状態のままにするかという設定です

Windows7でVagrant2.0を使ってVirtualBoxにUbuntu16.04の仮想環境をつくってteratermでアクセスする

環境

手順

1. VirtualBoxのダウンロード

Virtual Boxのインストール
http://www.virtualbox.org/
f:id:portaltan:20180302142838p:plain

Imageの配置場所の変更
f:id:portaltan:20180302155543p:plain

  • 自分はD:\VirtualBoxServersという名前のディレクトリにしました
2. Vagrantのダウンロードします

Vagrantのインストール
http://downloads.vagrantup.com/
f:id:portaltan:20180302142909p:plain

  • ちなみに私はCドライブ直下に作るのが嫌なのでC:\Program Files (x86)\HashiCorp\Vagrantにインストールしました

vagrantの確認

> vagrant -v
Vagrant 2.0.2

> vagrant -h
.
.
.

box(osのイメージ)の配置場所の指定

> SETX VAGRANT_HOME D:\Vagrant\.vagrant.d
> echo "%VAGRANT_HOME%"
  • デフォルトの配置場所は『(ユーザフォルダ)/.vagrant.d』
  • Dドライブに変更する理由は、今後色々な環境を作成していくので容量が大きいドライブでboxを管理しておきたいからです
  • 実際の保管場所は.vagrant.d以下のboxesディレクトリになります
3. PC再起動
4. 仮想環境を構築準備

ディレクトリの作成
今から構築するubuntu16.04用のディレクトリを作成します

### 仮想環境用のディレクトリを作成
> cd /d d:/Vagrant
> mkdir "servers/ubuntu1604_1"
> cd servers/ubuntu1604_1

boxを検索
VagrantCloudから欲しいパッケージを検索します

> vagrant init ubuntu/xenial64

Vagrantfileの編集

> notepad Vagrantfile
################################
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/xenial64"
  config.vm.network "private_network", ip: "192.168.33.10"
  config.ssh.insert_key = false
  config.vm.provider "virtualbox" do |vb|
    vb.name = "ubuntu1604_1"
  end
end
################################
5. 仮想環境を構築準備

Vagrant起動(boxダウンロード&サーバー作成)

> vagrant up #環境とかPCスペックによっては時間がかかります
6. 確認

Host OSから確認(via コマンドプロンプト)

### boxがちゃんとdownloadされているか確認
> vagrant box list
ubuntu/xenial64 (virtualbox, 20180228.1.0)

### ステータス確認
> vagrant status
Current machine states:

default runnning (virtualbox)
........

VMの管理画面でも以下のように仮想環境が作成されているのを確認できます
f:id:portaltan:20180302190604p:plain

Guest OSから確認(via teraterm)
teratermからVagrantfileで指定したprivate ipへsshでアクセスします
f:id:portaltan:20180302190650p:plain

ユーザ名はvagrant
秘密鍵は先ほど上書きせずにinsecure_keyを利用する設定をしたので、私と同じ環境で作った方は「D:\Vagrant\.vagrant.d\insecure_private_key」にあります
f:id:portaltan:20180302190818p:plain

あとはログインできることを確認します
f:id:portaltan:20180302191024p:plain

マウントされているかの確認
GuestOS

vagrant@ubuntu-xenial:/$ ls -la /vagrant/
total 72
drwxrwxrwx  1 vagrant vagrant     0 Mar  2 09:53 .
drwxr-xr-x 24 root    root     4096 Mar  2 09:59 ..
-rwxrwxrwx  1 vagrant vagrant 44317 Mar  2 09:57 ubuntu-xenial-16.04-cloudimg-console.log
drwxrwxrwx  1 vagrant vagrant     0 Mar  2 09:52 .vagrant
-rwxrwxrwx  1 vagrant vagrant   296 Mar  2 09:57 Vagrantfile

HostOS
f:id:portaltan:20180302191255p:plain
f:id:portaltan:20180302191355p:plain

以上で構築完了です

RasbperryPi3 のACT LEDをheartbeatにしてGPIO出力する

ラズベリーパイ3は基板上に電源ランプのLED(赤)とSDアクセスランプ(緑)の2つがありますが、ACT LEDはGPIOを介して外部LEDに機能をわりあてることができます

ACT LED(緑)を外部LEDにする

まずはrc.localとかで使いたい
github.com
GPIOのmodeをout(出力モード)にします
今回はGPIO8(pin24)を利用します

/usr/local/bin/gpio -g mode 8 out

次に/boot/config.txt上でACT LEDをGPIO上で利用する設定を追加します

# for ACT LED
dtoverlay=pi3-act-led,gpio=8

後は再起動すればラズパイ基板上の緑LEDは消えてGPIOの方へさしたLEDが点滅するようになります

LEDパターンをheartbeatにする

通常ACT LEDはSDへのアクセスで点滅しますが、これをheartbeatモードにすると一定間隔で点滅し続けるようになります
設定は簡単で、/boot/config.txtに更に1行追加するだけです

# for ACT LED
dtparam=act_led_trigger=heartbeat
dtoverlay=pi3-act-led,gpio=8

注意

  • ラズベリーパイのモデルやkernelのversionによって方法が異なるようです
  • このデフォルトの基板上のLEDからGPIOへの切り替えは起動後に行われるので、起動してすぐとshutdownの最後の数秒は基板上のLEDへコントロールが戻ります

reference

ソフトウェアエンジニアがarduinoの割り込みタイマーライブラリを読んでみた

arduinoのタイマーを使って割り込み処理をするにはMsTimer2とflexitimer2があってそれらを読み込めば簡単に出来るのですが、中身を知らないのもあれだなーと思い今回ソースを呼んでUno用に簡略化してみた
MsTime2: https://github.com/PaulStoffregen/MsTimer2
flexitimer: https://github.com/wimleers/flexitimer2
MsTimer2はミリセカンド単位でタイマー指定できて、flexitimerはマイクロセカンドごとに指定できるらしい
(flexitimerの方はちゃんと読んでないのでもしかしたら厳密には違うかも)

Uno用に簡略化したソース

5V/16MHz駆動でarduino UNO(atmega328P)を利用する場合の割り込みタイマー処理

volatile unsigned long count; // overflowした回数
volatile char overflowing;  // overflow処理中かどうかのフラグ
volatile unsigned int tcnt2; // タイマーのオーバーフローのタイミング調整用変数
unsigned long msecs; // 何秒ごとに任意の処理を実行したいか
float prescaler; // 前置分周(F_CPUが1MHzから16MHzの場合は64.0が多い)


// 初期化や割り込みの許可等の設定
void setTimer2(){
  TIMSK2 &= ~(1<<TOIE2);
  TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
  TCCR2B &= ~(1<<WGM22);
  ASSR &= ~(1<<AS2);
  TIMSK2 &= ~(1<<OCIE2A);
  TCCR2B |= (1<<CS22);
  TCCR2B &= ~((1<<CS21) | (1<<CS20));
  prescaler = 64.0;
}

// timerのスタート
void startTimer(unsigned long ms){
  msecs = ms;
  tcnt2 = 256 - (int)((float)F_CPU * 0.001 / prescaler);  
  count = 0;
  overflowing = 0;
  TCNT2 = tcnt2;
  TIMSK2 |= (1<<TOIE2);
}

// timerのセットアップ
void setup() {
  setTimer2();
  startTimer(1000); // これで1000ミリセカンド単位のタイマーをスタート
}

// 割り込み検知
ISR(TIMER2_OVF_vect) {
  TCNT2 = tcnt2;
  overflow();
}

// 割り込み処理
void overflow(){
  count += 1;

  if (!overflowing && count >= msecs) {
    overflowing = 1;
    count = count - msecs;
    flash();
    overflowing = 0;
  }
}

// 任意のメソッド(1000ミリセカンド毎に実行したい処理)
void flash(){  
  static boolean output = HIGH;
  digitalWrite(13, output);
  output = !output;
}

set timer

TIMSK2 &= ~(1<
  • TIMSK2: タイマ/カウンタ2割り込み許可レジスタ(Timer/Counter 2 Interruput Mask Register)
  • TOIE2: タイマ/カウンタ2溢れ割り込み許可(Timer/Counter 2 Overflow Interrupt Enable)
  • OCIE2A: タイマ/カウンタ比較A割り込み許可(TImer/Counter2 output Compare Match A Interrupt Enable)

f:id:portaltan:20180125120321p:plain

TCCR2A &= ~*1
  • TCCR2A: タイマ/カウンタ制御レジスタA(Timer/Counter 2 Control Register A)
  • WGM21,20: 波形生成種別(Waveform Generation Mode)

f:id:portaltan:20180125114814p:plain

TCCR2B &= ~(1<*2;
  • TCCR2B: タイマ/カウンタ制御レジスタB(Timer/Counter 2 Control Register B)
  • WGM22: 波形生成種別 (Waveform Generation Mode bit 2)
  • CS22,21,20: クロック選択(Clock Select)

f:id:portaltan:20180125114933p:plain

ASSR &= ~(1<
  • ASSR: タイマ/カウンタ2非同期状態レジスタ(TImer/Counter 2 Asynchronous Status Register)
  • AS2: タイマ/カウンタ2非同期動作許可(Asynchronous Timer/Counter2)

f:id:portaltan:20180125115102p:plain

prescaler = 64.0;
  • 前置分周(次の項目で説明)

startTimer

tcnt2 = 256 - (int)((float)F_CPU * 0.001 / prescaler)

指定したミリセカンドぴったりで処理が実行されるようにするための調整値を求めている
F_CPUが16MHzだとして計算を一つ一つ説明

説明①

  • F_CPU(16,000,000Hz) * 0.001 = 16,000(Hz)
    • まずは秒単位ではなくミリセカンド単位で扱うために1/1000している
    • 16MHzなので1秒で16,000,000カウント、1ミリセカンドで16,000カウントされることとなる
    • これだと8bit(256)のカウント内に収まらないため、1ミリセカンド分もカウントできない(カウントできる時間間隔が短すぎる)
    • そこでCPU側で1Hzごとにカウントアップするのではなく、何Hzかごとにまとめて1カウントとするようにしている(この値をプリスケーラといい、チップや駆動電圧によって異なる)
  • 16,000(Hz) / prescaler(64.0) = 250(count)
    • atmega328Pで16MHzの場合prescalerの値は64.0
    • prescalerなしだと1msecで16,000Hz(16,000カウント)だったが、prescaler処理をいれると64Hzに1回しかカウントしなくなるので、1msecで250カウントとなる
    • これで8bit(256)カウント内でおさまるようになった
    • しかし、8bit(256) timerはカウント250回ではなく256回でオーバーフローするため、 毎回6カウントずつずれてしまう。これの調整を以下で行う
  • 256 - 250 = 6
    • ようは6からカウントを開始すれば250カウント経過で256になり、ちょうど1msecでオーバーフローする
    • そのためカウントの開始地点(初期カウント数)をここで求めている
    • 実際にISRで割り込んだ後も毎回カウントの初期値に6をセットしている


説明②(上記と同じ説明を順番を変えて考えただけ)

  • 16,000,000Hz / prescaler(64.0) = 250,000
    • 通常16MHz(16,000,000Hz)なので16,000,000カウントで1秒
    • arduinoにのっているtimerは8bit(256)か16bit(65536)なのでさすがにカウントが速すぎて使いにくい
    • そこでCPU側で毎Hzごとにカウントアップするのではなく、何Hzかごとに1カウントアップするようにしている(この値をプリスケーラといい、チップや駆動電圧によって異なる)
    • atmega328Pの場合は通常64.0
    • これによって実際の16,000,000Hz(16,000,000カウント)毎ではなく、250,000カウント毎に1秒という計算になる
  • 250,000 * 0.001 = 250
    • しかしまだ8bit(256)タイマーでも16bit(65536)タイマーでも値が足らずに1秒間もカウントできない(その前にオーバーフローしてしまう)
    • しかしそもそもマイコンの世界のタイマーで最小単位が秒単位というのは逆に長すぎるので、ミリセカンド単位で管理できるようになればよいので、1/1000している
    • 1秒では250,000カウントだったが、1msecでは250カウントなので、8bitカウンタ(256)でもカウントできるようになった
  • 256 - 250 = 6
    • しかし、8bit(256) timerはカウント250回ではなく256回でオーバーフローするため、 毎回6カウントずつずれてしまう。これの調整を以下で行う
    • ようは6からカウントを開始すれば250カウントで256になり、ちょうど1msecでオーバーフローする
    • そのためカウントの開始地点(初期カウント数)をここで求めている
    • 実際にISRで割り込んだ後も毎回カウントの初期値に6をセットしている
TCNT2 = tcnt2(6)
  • TCNT2: Timer/Counter 2 Counter Value Register

f:id:portaltan:20180125153553p:plain
上記のとおりカウントの値を書き換えて、初期値を0ではなく6にしている

TIMER2_OVF_vect

ISR(TIMER2_OVF_vect) {
  TCNT2 = tcnt2;
  overflow();
}
  • ISR: interrupt service routine
  • TIMER2_OVR_vect: タイマ2のオーバーフロー割り込み
  • 割り込みを検知する処理
  • 上記の設定の結果、1msec毎にtimer2がオーバーフローし、それを検知してこの処理が実行される
  • オーバーフローする毎にカウントが0に戻るので、初期値(6)を毎回代入している

void overflow

void overflow(){
  count += 1;

  if (!overflowing && count >= msecs) {
    overflowing = 1;
    count = count - msecs; // subtract ms to catch missed overflows. set to 0 if you don't want this.

    flash();
    overflowing = 0;
  }
}
  • 1msecごとに実行されてcountを1ずつincrementしていく
    • (このように平行した処理内で値が変わる可能性のある変数は宣言時にvolatile属性をつけておく必要がある)
  • 1msec毎にカウントして、指定のmsec回数を越えたら実際に実行したい処理(このコードではflash();)を実行する
  • 上記の処理中はoverflowingフラグをあげることで、処理が1ミリセカンド以上かかったとしても二重で処理が実行されるのを防ぐことができる
  • しかしこの間もcountのincrementは続いているので、実行する処理が数ミリセカンドかかったとしてもその分次回の処理がずれていくということはない
    • ただし指定したミリセカンド秒数を越える処理遅延が発生する場合は対策が必要(1000msecごとに行いたい処理があるのに、その処理自体が1000msec以上かかる場合など)

*1:1<

*2:1<

HTC Viveでテレポート機能を実装する方法

HTC Viveでコントローラーを利用したテレポートの方法です
こんなのです
f:id:portaltan:20180115183249p:plain

ライブラリとしてgithubで公開されている以下のライブラリを利用させていただきます
github.com

環境

HTC ViveをUnityで開発するにはSteamVR PluginというPluginを利用することになりますが、Unity5.x系とは相性が悪くコントローラーが表示されなかったり一部機能がうまく動かなかったりするので、そういう場合は素直にUnity2017を利用するとすんなり動くことが多いです
(この記事はところどころ5.6.3で書いていますが)
https://www.assetstore.unity3d.com/jp/#!/content/32647

ライブラリimport

import Vive-Teleporter library

テレポート用のライブラリをimportします
githubからそのままダウンロードしてUnityにimportします
https://github.com/Flafla2/Vive-Teleporter

importすると設定を最適なものにするかどうか聞かれるダイアログが表示されるので、問題なければAcceptを選択します
f:id:portaltan:20180115175129p:plain

今回は上記のライブラリにSteamVR Pluginも入っているため、追加でSteamVR Pluginをimportする必要はありません

テレポート機能の作成

地面の作成

まずは移動するための地面を作ります
Groundという名前でCubeを作成し、地面っぽく引き伸ばします

  • position: 0, -0.5, 0
  • Scale: 10, 1, 10
  • (Staticにチェック)
  • (LightProbeをOff)
  • (Lightmap Staticにチェック)

f:id:portaltan:20180115175344p:plain

Windows > Navigationを選び、Groundを選択します

  • Objectタブ
    • Navigate Staticにチェックをチェック
    • Generate OffMeshLinksのチェックを外す
  • bakeタブ
    • bakeをクリックして実行

bakeがうまくいくと以下のようにcubeの上面に水色のエリアが表示されます
f:id:portaltan:20180115175932p:plain

NavMeshの作成

NavMesh prefabをヒエラルキーD&Dします
InspectorのVive Nav Mesh(Script)の項目でUpdate Navmesh Dataをクリックして実行します
そうすると以下のようなマス目と移動の境界線にエフェクトが表示されます
f:id:portaltan:20180115181947p:plain

Pointerの作成

pointer prefabをヒエラルキーD&Dします

  • NavMeshに上記で作成したNavmeshをアタッチ
Cameraの設定

まずは不要なMain Cameraを削除して、Camera Rig prefabをヒエラルキーD&Dします
f:id:portaltan:20180115182310p:plain
次にInspectorから各項目を設定していきます
Camera Rig本体

  • Steam VR_Play Area(script)を削除
  • (Mesh Filter)を削除
  • Mesh Rendererを削除

Camera(eye)

  • Vive Teleporterスクリプトをadd component
    • (Border ReferererとTeleport Viveの項目が追加されます)
  • Teleport Vive
    • pointerに上記で作ったpointerをアタッチ
    • Origin TransformにCameraRig自体をアタッチ
    • Head TransformにCamera(head)自体をアタッチ
    • Navmesh Animatorに上記で作ったNavMeshをアタッチ
    • Fade Materialはライブラリに入っているFadeBlackを選択
    • Controllersのsizeを2に変更
      • Element0にController(left)をアタッチ
      • Element1にController(right)をアタッチ
  • Border renderer
    • Border MaterialでRoom Area Borderを選択

f:id:portaltan:20180115183027p:plain

以上で設定は完了です

確認

デバッグを起動すると以下のようにタッチパッド長押しでテレポートできるようになります
f:id:portaltan:20180115183249p:plain

おまけ

侵入禁止エリアの設定

Cube等のcolliderの設定されている障害物を作成し、Groundに接地させる(めりこませてもよい)
f:id:portaltan:20180115183920p:plain
Inspectorタブでstaticにし、Navigationタブでbakeします
すると以下のようにCubeのまわりだけの水色のスペースが除外されます
f:id:portaltan:20180115184104p:plain
次に忘れずにNavmeshからUpdate Navmesh Dataをクリックします
f:id:portaltan:20180115184221p:plain

この状態でデモを実行するとCubeのまわりだけテレポートできないようになります
f:id:portaltan:20180115184359p:plain

arduinoを最小構成で自作する(atmega328/8MHz/3.3V/内部クロック)

arduinoはいまや様々な種類が出ていて、かつ安価に購入できるので、IoTなどの分野でも幅広く利用されています
しかしarduinoを利用したシステムなどを量産する際に、更に小型化・省コストを狙う際にはarduinoのチップ(atmega328)を利用してarduino自体を自分の必要な構成で自作することが可能です

今回は以下の最小構成で自作します

  • 8MHz(既製品は16MHz)
  • 3.3V駆動(既製品は入力電圧:7V-12V, 駆動電圧:5V)
  • atmega328(既製品についているマイコンチップ)
  • 内部クロックを利用(既製品は外部クリスタルを利用)

必要なもの

  • atmega328
  • Arduino Uno(初期設定/FW書き込み用)
  • ジャンパーケーブル(初期設定/FW書き込み用)
  • ブレッドボード(初期設定/FW書き込み/確認用)
  • LED(確認用)

手順

1. ライブラリやIDEのダウンロード

以下のリンクのMinimal Circuitの項目にあるBreadboard-1-x-x.zipをダウンロードして解凍し、arduinoのhardwareフォルダに配置します
Arduino - ArduinoToBreadboard

  • 私の環境では”C:\Program Files (x86)\Arduino\hardware”にありました
  • ダウンロードするライブラリのversionですが、自分が使っているArduino IDEに対応したものをダウンロードします
    • 私は1.7.11を利用していますが、1.7用がなかったのでBreadboard-1-6-x.zipを使って問題なく動作しました
2. arduino ISPの書き込み

Arduino UNOへISPスケッチを書き込みます
サンプルにデフォルトで入っているので、Open > ArduinoISPを選択してそのままUploadします
f:id:portaltan:20180104125541p:plain

3. arduinoとatmega328の接続

以下の画像の通りarduinoとatmegaを接続します
f:id:portaltan:20180104125614p:plain

4. ブートローダー書き込み

atmegaを利用する際に、何も書き込まれていない素のままのTipを購入した際は一番最初にbootloaderを書き込まなければいけません
書き込み済みのものを購入した場合はスキップしてOKですが、16MHz用のブートローダーが書き込まれている場合は上書きしなければならず、その場合には外部発振子(水晶やセラロック)が必要になります。今回は割愛します

手順1でライブラリをarduinoのhardwareフォルダに配置している場合、boardの項目にAtmega328という項目が追加されているのでそれを選択します
f:id:portaltan:20180104130058p:plain

次にTools > Programmerの項目からArduino as ISPを選択します
(AVR ISPでもArduino ISPでもなくArduino as ISPです)

そうしたらTools > Burn Bootloaderを選択すればブートローダーの書き込みが行われます

5. スケッチ書き込み

ブートローダーは一度書き込めばよいので、不要なケーブルを抜き以下のようにスケッチ書き込み用の構成にします
f:id:portaltan:20180104130451p:plain
この際にArduino UnoについているAtmegaを外さないといけないのですが、これがとても固くて全作業の中で一番大変でした

あとはarduinoから通常のように書き込みをすればブレッドボード上のatmega328へ書き込まれます
試しにblinkを書き込んで動作確認をしてみました
f:id:portaltan:20180104131538j:plain

6. arduinoを外して確認

最後にスケッチ書き込み用のarduinoを外してちゃんと動作するか確認します
外部電源として3.3Vを供給しています
f:id:portaltan:20180104132535j:plain

外部発振子を利用する場合

  • BoardでArduino Pro or Pro Miniを選択
  • ProcessorでAtmeta328(3.3V, 8MHz)を選択
  • 1番ピン10kΩでプルアップ

f:id:portaltan:20180117160831p:plainf:id:portaltan:20180117160836p:plain

Raspberry PiとArduinoをGPIOでシリアル接続する場合は電圧に注意(3.3V/5V)

Raspberry PiArduinoをシリアル接続する際は単純につなぐとそれぞれ電圧が違うので壊れてしまう可能性がある(主にラズパイの方が)

入出力電圧

Raspberry PI

  • 入力電圧
    • 0~0.8V : LOW(OFF)として判断
    • 0.8~1.3V : 不定(不安定でどっちになるかわからない)
    • 1.3~3.3V: HIGH(ON)として判断
  • 出力電圧
    • ON : 3.3V出力
    • Off : GND(出力)

Arduino

  • 入力電圧
    • 0~2.5V : LOW(OFF)として判断
    • 2.5~5.0V: HIGH(ON)として判断
  • 出力電圧
    • ON : 5.0V出力
    • Off : 0V

接続時の問題

RaspberryPi(TX) => Arduino(RX)
ラズベリーパイの出力電圧は3.3Vですが、Arduinoは入力電圧として2.5~5.0Vに対応しているのでそのまま送ってしまって問題ありません

Arduino(TX) => RaspberryPi(RX)
問題なのはこちらです
ラズベリーパイの入力電圧は上記の通り0V~3.3Vですが、arduinoの出力電圧は5Vでこの範囲を超えてしまっています
このまま何もせず接続すると過電圧で最悪ラズパイが壊れてしまいます

解決方法

電圧を下げる

具体的に電圧を下げる方法はいくつもありますが、抵抗分割するのがブレッドボード上などでは一番てっとり早いです
f:id:portaltan:20171226134538p:plainf:id:portaltan:20171226134752p:plain
分圧回路 - Wikipedia