焦電人感センサーSB612Aをラズベリーパイで使ってみた
以下の秋月で販売している焦電型赤外線センサーをラズベリーパイで使ってみました(¥600)
akizukidenshi.com
仕様
- 電源電圧:3.3V~12V(3.3VのLDOによりモジュール内部で安定化されています)
- 最大検知距離:8m(気温等の環境条件によります)
- 検知角度:120度
- 検知出力保持時間:2秒~80分
ハードウェアサイド
SB612A側
画像のようにメスメスケーブルをさしていきます。
色はあわせなくていいですが、右から赤(VCC), 緑(信号出力). 黒(GND)です
ソフトウェアサイド
確認
まずはちゃんと動いているか確認をします
## 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でアクセスする
環境
- Windows7(64btit)
- VirtualBox 5.2.6
- Ubuntu 14.04
- Vagrant 2.0.2
手順
1. VirtualBoxのダウンロード
Virtual Boxのインストール
http://www.virtualbox.org/
Imageの配置場所の変更
- 自分はD:\VirtualBoxServersという名前のディレクトリにしました
2. Vagrantのダウンロードします
Vagrantのインストール
http://downloads.vagrantup.com/
vagrantの確認
> vagrant -v Vagrant 2.0.2 > vagrant -h . . .
box(osのイメージ)の配置場所の指定
> SETX VAGRANT_HOME D:\Vagrant\.vagrant.d > echo "%VAGRANT_HOME%"
3. PC再起動
4. 仮想環境を構築準備
ディレクトリの作成
今から構築するubuntu16.04用のディレクトリを作成します
### 仮想環境用のディレクトリを作成 > cd /d d:/Vagrant > mkdir "servers/ubuntu1604_1" > cd servers/ubuntu1604_1
boxを検索
VagrantCloudから欲しいパッケージを検索します
- app.vagrantup.com
- 今回はVagrant box ubuntu/xenial64 - Vagrant Cloudを利用します
- VagrantCloudにあるboxであれば前もってboxをインストールしなくても、init時に指定するだけで初回起動時にboxもまとめてダウンロードしてくれます
> 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 ################################
6. 確認
Host OSから確認(via コマンドプロンプト)
### boxがちゃんとdownloadされているか確認 > vagrant box list ubuntu/xenial64 (virtualbox, 20180228.1.0) ### ステータス確認 > vagrant status Current machine states: default runnning (virtualbox) ........
VMの管理画面でも以下のように仮想環境が作成されているのを確認できます
Guest OSから確認(via teraterm)
teratermからVagrantfileで指定したprivate ipへsshでアクセスします
ユーザ名はvagrant
秘密鍵は先ほど上書きせずにinsecure_keyを利用する設定をしたので、私と同じ環境で作った方は「D:\Vagrant\.vagrant.d\insecure_private_key」にあります
あとはログインできることを確認します
マウントされているかの確認
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
以上で構築完了です
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
注意
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)
TCCR2A &= ~*1
- TCCR2A: タイマ/カウンタ制御レジスタA(Timer/Counter 2 Control Register A)
- WGM21,20: 波形生成種別(Waveform Generation Mode)
TCCR2B &= ~(1<*2;
- TCCR2B: タイマ/カウンタ制御レジスタB(Timer/Counter 2 Control Register B)
- WGM22: 波形生成種別 (Waveform Generation Mode bit 2)
- CS22,21,20: クロック選択(Clock Select)
ASSR &= ~(1<
- ASSR: タイマ/カウンタ2非同期状態レジスタ(TImer/Counter 2 Asynchronous Status Register)
- AS2: タイマ/カウンタ2非同期動作許可(Asynchronous Timer/Counter2)
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)
- 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
- 256 - 250 = 6
- しかし、8bit(256) timerはカウント250回ではなく256回でオーバーフローするため、 毎回6カウントずつずれてしまう。これの調整を以下で行う
- ようは6からカウントを開始すれば250カウントで256になり、ちょうど1msecでオーバーフローする
- そのためカウントの開始地点(初期カウント数)をここで求めている
- 実際にISRで割り込んだ後も毎回カウントの初期値に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以上かかる場合など)
reference
https://avr.jp/user/DS/PDF/mega328P.pdf
&= (AND) : http://www.musashinodenpa.com/arduino/ref/index.php?f=0&pos=978
<< bit shift: http://www.musashinodenpa.com/arduino/ref/index.php?f=0&pos=784
~(NOT): http://www.musashinodenpa.com/arduino/ref/index.php?f=0&pos=767
volatile: http://www.musashinodenpa.com/arduino/ref/index.php?f=0&pos=1780
HTC Viveでテレポート機能を実装する方法
HTC Viveでコントローラーを利用したテレポートの方法です
こんなのです
ライブラリとして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を選択します
今回は上記のライブラリにSteamVR Pluginも入っているため、追加でSteamVR Pluginをimportする必要はありません
テレポート機能の作成
地面の作成
まずは移動するための地面を作ります
Groundという名前でCubeを作成し、地面っぽく引き伸ばします
- position: 0, -0.5, 0
- Scale: 10, 1, 10
- (Staticにチェック)
- (LightProbeをOff)
- (Lightmap Staticにチェック)
Windows > Navigationを選び、Groundを選択します
- Objectタブ
- Navigate Staticにチェックをチェック
- Generate OffMeshLinksのチェックを外す
- bakeタブ
- bakeをクリックして実行
bakeがうまくいくと以下のようにcubeの上面に水色のエリアが表示されます
NavMeshの作成
NavMesh prefabをヒエラルキーにD&Dします
InspectorのVive Nav Mesh(Script)の項目でUpdate Navmesh Dataをクリックして実行します
そうすると以下のようなマス目と移動の境界線にエフェクトが表示されます
Cameraの設定
まずは不要なMain Cameraを削除して、Camera Rig prefabをヒエラルキーにD&Dします
次にInspectorから各項目を設定していきます
Camera Rig本体
- Steam VR_Play Area(script)を削除
- (Mesh Filter)を削除
- Mesh Rendererを削除
Camera(eye)
- Vive Teleporterスクリプトをadd component
- (Border ReferererとTeleport Viveの項目が追加されます)
- Teleport Vive
- Border renderer
- Border MaterialでRoom Area Borderを選択
以上で設定は完了です
おまけ
侵入禁止エリアの設定
Cube等のcolliderの設定されている障害物を作成し、Groundに接地させる(めりこませてもよい)
Inspectorタブでstaticにし、Navigationタブでbakeします
すると以下のようにCubeのまわりだけの水色のスペースが除外されます
次に忘れずにNavmeshからUpdate Navmesh Dataをクリックします
この状態でデモを実行するとCubeのまわりだけテレポートできないようになります
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
2. arduino ISPの書き込み
Arduino UNOへISPスケッチを書き込みます
サンプルにデフォルトで入っているので、Open > ArduinoISPを選択してそのままUploadします
4. ブートローダー書き込み
atmegaを利用する際に、何も書き込まれていない素のままのTipを購入した際は一番最初にbootloaderを書き込まなければいけません
書き込み済みのものを購入した場合はスキップしてOKですが、16MHz用のブートローダーが書き込まれている場合は上書きしなければならず、その場合には外部発振子(水晶やセラロック)が必要になります。今回は割愛します
手順1でライブラリをarduinoのhardwareフォルダに配置している場合、boardの項目にAtmega328という項目が追加されているのでそれを選択します
次にTools > Programmerの項目からArduino as ISPを選択します
(AVR ISPでもArduino ISPでもなくArduino as ISPです)
そうしたらTools > Burn Bootloaderを選択すればブートローダーの書き込みが行われます
reference
Raspberry PiとArduinoをGPIOでシリアル接続する場合は電圧に注意(3.3V/5V)
Raspberry PiとArduinoをシリアル接続する際は単純につなぐとそれぞれ電圧が違うので壊れてしまう可能性がある(主にラズパイの方が)
入出力電圧
- 入力電圧
- 0~0.8V : LOW(OFF)として判断
- 0.8~1.3V : 不定(不安定でどっちになるかわからない)
- 1.3~3.3V: HIGH(ON)として判断
- 出力電圧
- ON : 3.3V出力
- Off : GND(出力)
- 入力電圧
- 0~2.5V : LOW(OFF)として判断
- 2.5~5.0V: HIGH(ON)として判断
- 出力電圧
- ON : 5.0V出力
- Off : 0V