AIスピーカーをRaspberryPiで作ってみよう!準備編1

まず、下記を用意
1. RaspberryPi3(element14 製を使用しましたがRS製でもほぼ同じ)
2. MicroUSBケーブル(RaspberryPiとUSB ACアダプタを繋ぐ)
3. USB ACアダプタ(RaspberryPiへの5V電源供給)
4. USBキーボード
5. USBマウス
6. スピーカー(ダイソーの300円USBスピーカーを使用しました)
7. マイク(ウェブカメラのマイクを使用しました)
8. HDMIケーブル
9. モニタ(HDMIが使用できるもの)

RaspberryPi3へのOS Raspbianのインストール方法は、ネット上にたくさんあるため
割愛させていただきます。

それでは、上記用意したものをRaspberryPiにセットし、電源ON(MicroUSBに電気を流す)
無事モニタに下記デスクトップ画面が表示されたら起動完了

まず、今回はスピーカーとマイクの動作確認をして、録音テストまで行います。
【スピーカー】
スピーカーが認識されているかをaplay -lで確認
カード番号0、デバイス番号0にスピーカーが認識されています。

pi@raspberrypi:~ $ aplay -l							
**** List of PLAYBACK Hardware Devices ****							
card 0: ALSA [bcm2835 ALSA], device 0: bcm2835 ALSA [bcm2835 ALSA]							
Subdevices: 8/8							
Subdevice #0: subdevice #0							
Subdevice #1: subdevice #1							
Subdevice #2: subdevice #2							
Subdevice #3: subdevice #3							
Subdevice #4: subdevice #4							
Subdevice #5: subdevice #5							
Subdevice #6: subdevice #6							
Subdevice #7: subdevice #7							
card 0: ALSA [bcm2835 ALSA], device 1: bcm2835 ALSA [bcm2835 IEC95	8/HD	MI]					
Subdevices: 1/1							
Subdevice #0: subdevice #0

次に音声を出して、音声確認をしてみましょう。フロントセンターと聞こえればOKです。

pi@raspberrypi:~ $ aplay /usr/share/sounds/alsa/Front_Center.wav							
Playing WAVE '/usr/share/sounds/alsa/Front_Center.wav' : Signed 16	bit	Little	Endian,	Rate	48000	Hz,	Mono

【マイク】
マイクについては手持ちがなかったので、ウェブカメラに埋め込めれているマイクを流用します。
スピーカーが認識されているかをarecord -lで確認。
カード番号1、デバイス番号0にマイクが認識されています。

pi@raspberrypi:~ $ arecord -l							
**** List of CAPTURE Hardware Devices ****							
card 1: Camera [PC Camera], device 0: USB Audio [USB Audio]							
Subdevices: 1/1							
Subdevice #0: subdevice #0

ここで、音声を録音しようと

pi@raspberrypi:~ $ arecord test.wav							
arecord: main:788: audio open error: No such file or directory

としても、エラーになります。

【録音】下記のように録音(4秒)してみます

arecord -D plughw:(カード番号),(デバイス番号), -d (秒数) -f (サンプルフォーマット) (ファイル名)

pi@raspberrypi:~ $ arecord -D plughw:1,0 -d 4 -f cd test.wav
Recording WAVE 'test.wav' : Signed 16 bit Little Endian, Rate 44100 Hz, Stereo

ちなみにarecordのオプションの意味は下記、他にもオプションがあるので、-hでヘルプを読んでください
【arecordのオプション(一部)】
-l : 全てのサウンドカードとオーディオデバイスの番号を表示する
-D : 使用するPCMを指定する
-d : 指定の秒数後に終了する
-f : サンプルフォーマットを指定する(下記は環境によって変わります)
-f cd (16bit little endian, 44100, streo)
-f cdr (16bit big endian, 44100, streo)
-f dat (16bit little endian, 48000, streo)
-h : ヘルプを表示する

【マイクボリューム調節】マイクのボリュームを必要に応じて調節します

まずは現状のマイク(シンプルコントロール名 ‘Mic’ )の設定音量を確認。
$ amixer -c 1 sget Mic
※(-c でカード番号を指定)

pi@raspberrypi:~ $ amixer sget Mic -c 1							
Simple mixer control 'Mic',0							
Capabilities: cvolume cvolume-joined cswitch cswitch-joined							
Capture channels: Mono							
Limits: Capture 0 - 3							
Mono: Capture 0 [0%] [30.00dB] [on]

0%になっていたので、60%へと変更してみる

$ amixer -c 1 sset Mic 60%

pi@raspberrypi:~ $ amixer -c 1 sset Mic 60%							
Simple mixer control 'Mic',0							
Capabilities: cvolume cvolume-joined cswitch cswitch-joined							
Capture channels: Mono							
Limits: Capture 0 - 3							
Mono: Capture 0 [67%] [50.00dB] [on]

となり67%になりました。

60%指定したのに67%になった理由は、今回使用したウェブカメラのマイクが4段階しかコントロールできないもののため、0%⇒33%⇒67%⇒100%のレベルでしか設定できない事が理由。

繰り上げで設定されるので、もし70%と指定したら100%に指定されます。

このように、”-c” でマイクのカード番号を指定して、 ”sset”でボリュームを調整します

ちなみに同じようにスピーカーも設定が可能です

スピーカー(シンプルコントロール名 ‘PCM’、カード番号0 )の音量を確認
$ amixer -c 0 sget PCM

スピーカー(シンプルコントロール名 ‘PCM’ )の音量を 50% に設定する
$ amixer -c 0 sset PCM 50%

ただ、スピーカーは下記を使うとGUIでキーの上下操作で簡単に音量調整できます

alsamixer //Escで設定が保存され、元の画面に戻ります

 

【マイクの音をそのままスピーカーから出力する】

arecord | aplay
ではエラーとなるので、下記を入力すると、ハウリングがでますが録音ファイルを作成せずに
マイクの音がそのままスピーカーより出力されます

arecord -f cd -D plughw:1 | aplay -D hw:0
※Ctrl+Cで終了します。

ちなみにplugをつけないと、モノラル音声は再生できないというようなエラーが発生します。
なのでリサンプリングを行う”plug”をデバイスの前につけて解消しましょう

plugをつけると指定のフォーマット、ビットレートになるよう自動でリサンプリング処理を行ってくれます。
ただ、ハウリングはけっこうひどかったりします。

Raspberry Pi3へのSSH設定、固定IP設定方法

2018年2月22日に最新だったRaspbianのOSイメージ、

2017-11-29-raspbian-stretch

を使用。Raspberry Pi3はelement14 製を使用。

下記SSH

【SSH】

1. SSHを使えるようにする
設定画面でSSHを許可する

sudo raspi-config

「5. Interfacing Options」->「P2 SSH」->「Enable: YES」

2.SSHで接続してみる
まず、DHCPで割り当てられているRaspberry Pi3のIPアドレスを確認

hostname -I

これで、IP addressがわかるので、それと下記を使ってターミナル(Mac)からアクセス、WindowsはTeraTerm使用
IP address:192.168.11.xxx
初期ユーザー名: pi
初期パスワード: raspberry
接続が確認できたらOK

【固定IP設定】
サーバーとして利用する場合、IPアドレスは固定だったほうが便利なので固定IPを設定します
また、raspbian-stretchからは/etc/dhcpcd.confに記述するようになったようです。
なので、/etc/network/interfacesには書かなくてOK

固定IP 192.168.11.111をeth0(有線LAN)に設定してみます

nano /etc/dhcpcd.conf

エディタはnano以外にviやvimなど慣れたものを使用してください。
dhcpcd.confの既に書かれているコードの該当箇所のコメント(#)外してIPアドレスを修正するだけ。

interface eth0
static ip_address=192.168.11.111/24 # IPアドレスとサブネットマスク(xxxに任意のIPを指定/24)
static routers=192.168.11.xxx # デフォルトゲートウェイ(自分が所属するネットワーク192.168.111のルータのIPアドレス、二重ルーターしている方は間違えないように)
static domain_name_servers=192.168.11.xxx 8.8.8.8 # DNSサーバ(ルータのIPアドレス、特別な事していない限り上記と同じ)

※”/24”という表記はサブネットマスクが255.255.255.0という意味
※domain_name_serversには複数のDNSサーバーが割り当てできるので、セカンダリにgoogleのPublicDNS 8.8.8.8を指定した

【参考】IPアドレスの後ろの /24 などの表記の意味
CIDR (Classless Inter-Domain Routing) というIPアドレスの表記で、
192.168.1.0/24
などのようにIPアドレスの最後に /24 というように表記する
意味は2進数で桁数32桁のIPアドレスの内、8桁(32-24)が割り当てられるということを表しています
11111111 11111111 11111111 00000000 ←/24
つまり255.255.255.0 のサブネットマスクという意味

ちなみに /25になると
255.255.255.128 のサブネットマスクという意味になる

【WiFiも固定IPにしたいとき】
デフォルトだとDHCPになっているwlan0を上記eth0と同じ方法で固定IPに設定ができます

interface wlan0 
static ip_address=192.168.11.111/24 
static routers=192.168.11.xxx
static domain_name_servers=192.168.11.xxx 8.8.8.8

各固定IP設定が終わったら再起動すれば反映されます

sudo shutdown -r now

再起動後に下記でまとめて確認できます。

ip addr

eth0、wlan0のinetに192.168.11.111と設定されていれば成功です。

5分でできる!BluetoothでArduino遠隔操作ラジコンカー製作 (DCモーター制御) スケッチコード付き

前回解説した
すぐにできる!Arduinoで赤外線ラジコンカー製作 (DCモーター制御) スケッチコード付き
Bluetooth版になります。
しかも、
①前回のキットにBluetoothモジュールを接続(四本のワイヤ接続するだけ!)
②本ページのコードをArduinoに上書きするだけ
なんと、5分もかかりません。

材料:
1. 前回使用キットそのまま
2. HC-06 (Bluetoothモジュール)×1 ※技適なしのモジュールになります。ご使用方法についてはご注意ください
3. ジャンパワイヤ×4

製作方法:
① 下記のように接続します。HC-06とArduinoのTX, RXを互いに逆に接続することに注意!

HC-06 Arduino UNO R3
 VCC  ⇒  5V
 GND  ⇒  GND
 TXD  ⇒  RX
 RXD  ⇒  TX

 

②下記スケッチコードをArduinoに書き込む(書き込む際は必ずHC-06を停止させてください、VCC抜くだけでOK)
何度もモーターの回転についてのコードがでてきますが、分かりやすくするためにわざと重複して書いてます。
分かる方はリファクタリングして短くまとめてください。

③PCもしくはスマホで操作
【PCの場合】:bluetoothペアリング後にArduino IDEのツール⇒シリアルポートでHC-06を選択
シリアルモニタを立ち上げて、そこに”test”と入力すると、”Hello, Wind Abaft”と返ってくれば成功です。
同じようにシリアルモニタに下記を打つとその対応のままラジコンが動作します。
f: 前進
r: 右折
l: 左折
b: 後進
R(大文字のR):右回転
L(大文字のL): 左回転
s: 停止

【スマホの場合】:HC-06はiPhoneに対応していないのでAndroidスマホでのみ操作が可能(頑張ればiPhoneもいけるかもしれない)
アプリArduino bluetooth controllerをgoogle Playからインストール(無料)
アプリの各ボタンに上記7種類の文字をあてはめるだけ!あとはペアリングするだけでコントロールが可能
例. →マークに”r”を当てはめる

#include <IRremote.h>
// Author Fumiyoshi.Yotsugi @ Wind Abaft Co.,Ltd.

char val;
int RECV_PIN = 12; //IR受信データピンを12に設定
int ledpin=13;

IRrecv irrecv(RECV_PIN);
decode_results results;

// モーターコントローラー(L298N)とArduino UNO R3の接続
// motor A
int enA = 5;
int in1 = 2;
int in2 = 4;
// motor B
int enB = 10;
int in3 = 7;
int in4 = 8;


void setup()

{
irrecv.enableIRIn();
Serial.begin(9600);
pinMode(ledpin,OUTPUT);

// モーターコントロールピンをoutputにセット
  pinMode(enA, OUTPUT);
  pinMode(enB, OUTPUT);
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(in3, OUTPUT);
  pinMode(in4, OUTPUT);
}

void loop() {
val=Serial.read();
performCommand();
if(val=='test')
{
digitalWrite(ledpin,HIGH);
delay(500);
digitalWrite(ledpin,LOW);
delay(500);
Serial.println("Hello, Wind Abaft!");
}

if (irrecv.decode(&results)) {
irrecv.resume();

if (results.value == 0x00FF629D){ // ↑ボタンを押すと前進

  // turn on motor A
  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);
  // スピードは 200に設定、 0~255の範囲で設定できるが100以下だとV不足で回らないこともある
  analogWrite(enA, 200);
  // turn on motor B
  digitalWrite(in3, HIGH);
  digitalWrite(in4, LOW);
  // スピードは 200に設定、 0~255の範囲で設定できるが100以下だとV不足で回らないこともある
  analogWrite(enB, 200);

}else if(results.value == 0x00FF22DD){ // ←ボタンを押すと左折する 

 // motor Aを前進させてmotor Bは止める
  // turn on motor A
  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);
  analogWrite(enA, 200);
  // turn on motor B
  digitalWrite(in3, LOW);
  digitalWrite(in4, LOW);
  analogWrite(enB, 200);
  
}else if(results.value == 0x00FF6897){ // ボタン1を押すと左回転 

 // motor Aは前進、motor Bは後進
  // turn on motor A
  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);
  analogWrite(enA, 200);
  // turn on motor B
  digitalWrite(in3, LOW);
  digitalWrite(in4, HIGH);
  analogWrite(enB, 200);
  
}else if(results.value == 0x00FFC23D){ // →ボタンを押して右折する 

// motor Aは止めてmotor Bは前進 
  // turn on motor A
  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);
  analogWrite(enA, 200);
  // turn on motor B
  digitalWrite(in3, HIGH);
  digitalWrite(in4, LOW);
  analogWrite(enB, 200);

}else if(results.value == 0x00FF9867){ // ボタン2を押すと右回転 

// motor A後進、motor B前進 
  // turn on motor A
  digitalWrite(in1, LOW);
  digitalWrite(in2, HIGH);
  analogWrite(enA, 200);
  // turn on motor B
  digitalWrite(in3, HIGH);
  digitalWrite(in4, LOW);
  analogWrite(enB, 200);

} else if(results.value == 0x00FFA857){ // ↓ボタン押すと後進(バック)

// motor A後進、motor B後進 
  // turn on motor A
  digitalWrite(in1, LOW);
  digitalWrite(in2, HIGH);
  analogWrite(enA, 200);
  // turn on motor B
  digitalWrite(in3, LOW);
  digitalWrite(in4, HIGH);
  analogWrite(enB, 200);

}else if(results.value == 0x00FF02FD){ // OKボタン押すと停止(ストップ) 

// motor A停止、motor B停止 
  // turn on motor A
  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);
  analogWrite(enA, 200);
  // turn on motor B
  digitalWrite(in3, LOW);
  digitalWrite(in4, LOW);
  analogWrite(enB, 200);

}
}
}

void performCommand() {
if (Serial.available()) {
val = Serial.read();
}
if (val == 'f') { // 前進
  // turn on motor A
  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);
  analogWrite(enA, 200);
  // turn on motor B
  digitalWrite(in3, HIGH);
  digitalWrite(in4, LOW);
  analogWrite(enB, 200);
  Serial.println("Forward");
} else if (val == 'b') { // 後進
 digitalWrite(in1, LOW);
  digitalWrite(in2, HIGH);
  digitalWrite(in3, LOW);
  digitalWrite(in4, HIGH);
  analogWrite(enB, 200);
} else if (val == 'r') { // 右折
 digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);
  analogWrite(enA, 200);
  digitalWrite(in3, HIGH);
  digitalWrite(in4, LOW);
  analogWrite(enB, 200);
} else if (val == 'l') { // 左折
  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);
  analogWrite(enA, 200);
  digitalWrite(in3, LOW);
  digitalWrite(in4, LOW);
  analogWrite(enB, 200);
} else if (val == 's') { // 停止
  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);
  analogWrite(enA, 200);
  digitalWrite(in3, LOW);
  digitalWrite(in4, LOW);
  analogWrite(enB, 200);
}
 else if (val == 'R') { // 右回転
  digitalWrite(in1, LOW);
  digitalWrite(in2, HIGH);
  analogWrite(enA, 200);
  digitalWrite(in3, HIGH);
  digitalWrite(in4, LOW);
  analogWrite(enB, 200);
}
 else if (val == 'L') { // 左回転
  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);
  analogWrite(enA, 200);
  digitalWrite(in3, LOW);
  digitalWrite(in4, HIGH);
  analogWrite(enB, 200);
}
}

【追記】
006Pの9V角型電池1個でArduinoとBluetooth(HC-06)に電源供給していると
電流不足からか、たまに不安定になることもあったので、アルカリ電池4本以上の電源を繋いだところ安定しました。
長い時間遊ぶ場合はアルカリ電池4本以上の電源(電池ボックス)に繋ぐことをお勧めします。

すぐにできる!Arduinoで赤外線ラジコンカー製作 (DCモーター制御) スケッチコード付き

Arduino UNO互換機を使って、DCモーターを赤外線で制御してラジコンを作成します。

材料
1. Arduino 2輪駆動 三輪スマートカー車体キット(Yahoo!ショッピングAmazon
2. Arduino(互換品) UNO R3
3. モータードライバー L298N
4. 赤外線受信モジュール(CHQ1838, 5V, 周波数:37.9KHz)
5. IRワイヤレスリモコン
6. アルカリ電池(単三×4、9V型角型電池×1)
7. 9V型角型電池用ホルダー×1、DCプラグ端子台×1
8. UNO R3ボード固定用ネジ×1・ナット×2、L298Nモジュール固定用ネジ×2・ナット×4、IR受信モジュール固定用ネジ×1・ナット×2、9V型角型電池用ホルダー固定用ネジ×2、ナット×2

上記全部セットはこちら(Yahoo!ショッピングAmazon)で買えます

写真のように組立をしていきます。
①下段車体にモーター2個と車輪3個を取り付ける
②下段シャーシにL298Nモータードライバーを取り付ける
③モーター2個とL298NのMOTORA、MOTORBとを繋ぐ(要マイナスドライバー)
④上段シャーシにArduino UNOと単三用電池ボックス、9V角型電池用ボックスを取り付ける
⑤単三電池ボックスのプラスマイナス導線をL298NのGNDとVMSに繋ぐ

 

⑥Arduino UNOとL298Nモータードライバーを下記のように接続する
※上段と下段のシャーシはまだネジで接続して固定しない(最後に行う)
※Arduinoへの接続ピン番号は適当に選んで繋げただけなので、自由に変更してOKです。
それに合わせてスケッチ内の該当ピンナンバーを変更するだけで動きます。

L298NとArduinoのピン接続は下記
ENA ⇒ 5
IN1 ⇒ 2
IN2 ⇒ 4
IN3 ⇒ 8
IN4 ⇒ 7
ENB ⇒ 10

⑦IRレシーバーモジュールとArduinoを下記のようにピン接続する
S ⇒ 12
+ ⇒ 5V
GND ⇒ GND

⑧Arduinoに下記スケッチを書込む⇒リモコン操作で動作確認できたら、上段と下段のシャーシをネジで固定するのをお勧め(配線間違いで何度もネジを外したりするのを避ける為)⇒終了
【詳細】
IRワイヤレスリモコンの7つのボタンを前、後、左、右、停止、右回転、左回転に使用します。
また、使用する7つのボタンを下記のように解析したので、そのHEXコードをスケッチ内で使用します。
※リモコン毎に赤外線コード割り当てが違うので、動かない場合にはご使用のリモコンの赤外線コードを解析して、スケッチ内の該当箇所を変更してください
↑(前): 0x00FF629D
↓(後): 0x00FFA857
→(右): 0x00FFC23D
←(左): 0x00FF22DD
OK(停止): 0x00FF02FD
1(左回転): 0x00FF6897
2(右回転): 0x00FF9867

下記がUNO R3用のスケッチコード

#include <IRremote.h>
// Author Fumiyoshi.Yotsugi @ Wind Abaft Co.,Ltd.

int RECV_PIN = 12; //IR受信データピンを12に設定

IRrecv irrecv(RECV_PIN);
decode_results results;

// モーターコントローラー(L298N)とArduino UNO R3の接続
// motor A
int enA = 5;
int in1 = 2;
int in2 = 4;
// motor B
int enB = 10;
int in3 = 7;
int in4 = 8;


void setup()

{
irrecv.enableIRIn();

// モーターコントロールピンをoutputにセット
  pinMode(enA, OUTPUT);
  pinMode(enB, OUTPUT);
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(in3, OUTPUT);
  pinMode(in4, OUTPUT);
}

void loop() {

if (irrecv.decode(&results)) {
irrecv.resume();

if (results.value == 0x00FF629D){ // ↑ボタンを押すと前進

  // turn on motor A
  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);
  // スピードは 200に設定、 0~255の範囲で設定できるが100以下だとV不足で回らないこともある
  analogWrite(enA, 200);
  // turn on motor B
  digitalWrite(in3, HIGH);
  digitalWrite(in4, LOW);
  // スピードは 200に設定、 0~255の範囲で設定できるが100以下だとV不足で回らないこともある
  analogWrite(enB, 200);

}else if(results.value == 0x00FF22DD){ // ←ボタンを押すと左折する 

 // motor Aを前進させてmotor Bは止める
  // turn on motor A
  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);
  analogWrite(enA, 200);
  // turn on motor B
  digitalWrite(in3, LOW);
  digitalWrite(in4, LOW);
  analogWrite(enB, 200);
  
}else if(results.value == 0x00FF6897){ // ボタン1を押すと左回転 

 // motor Aは前進、motor Bは後進
  // turn on motor A
  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);
  analogWrite(enA, 200);
  // turn on motor B
  digitalWrite(in3, LOW);
  digitalWrite(in4, HIGH);
  analogWrite(enB, 200);
  
}else if(results.value == 0x00FFC23D){ // →ボタンを押して右折する 

// motor Aは止めてmotor Bは前進 
  // turn on motor A
  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);
  analogWrite(enA, 200);
  // turn on motor B
  digitalWrite(in3, HIGH);
  digitalWrite(in4, LOW);
  analogWrite(enB, 200);

}else if(results.value == 0x00FF9867){ // ボタン2を押すと右回転 

// motor A後進、motor B前進 
  // turn on motor A
  digitalWrite(in1, LOW);
  digitalWrite(in2, HIGH);
  analogWrite(enA, 200);
  // turn on motor B
  digitalWrite(in3, HIGH);
  digitalWrite(in4, LOW);
  analogWrite(enB, 200);

} else if(results.value == 0x00FFA857){ // ↓ボタン押すと後進(バック)

// motor A後進、motor B後進 
  // turn on motor A
  digitalWrite(in1, LOW);
  digitalWrite(in2, HIGH);
  analogWrite(enA, 200);
  // turn on motor B
  digitalWrite(in3, LOW);
  digitalWrite(in4, HIGH);
  analogWrite(enB, 200);

}else if(results.value == 0x00FF02FD){ // OKボタン押すと停止(ストップ) 

// motor A停止、motor B停止 
  // turn on motor A
  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);
  analogWrite(enA, 200);
  // turn on motor B
  digitalWrite(in3, LOW);
  digitalWrite(in4, LOW);
  analogWrite(enB, 200);

}

}

}

※2WD3輪車体の場合、モーターを付けていない白の後輪車輪が動いてしまい、前進や後進時に曲がって進んでしまいます。4WD4輪車体の場合には、それが解消されますので、気になる場合には4WD4輪車体をご利用ください

【完成写真】


ロボットスクール様や塾で教材として使用したい方向けに、本資材のご提供やカスタマイズ、出張講義も可能です!

是非お問い合わせください!

Raspberry Pi3で写真を撮ってみよう

写真のようにカメラインターフェイスの白いフックを引き上げてそこに
カメラモジュールを差し込み、白いフックを引き下げ固定します。

このモジュールは中心のカメラレンズの上の四角いコネクタがあるほうが上になります。

とりあえず、写真がとれるか試してみましょう

sudo raspistill -o picture.jpg

エラーがでて撮影できなかった場合、
1. RaspberryPi側でカメラがOFFになっている
2. 接触不良
3. カメラモジュールとの相性問題
4. カメラモジュールの故障(LEDが付いているモジュールの場合、LED点灯していて、認識もされているがデータが送られてきませんというような表示が出たときには故障の可能性があります)

まず、Raspberry PiのカメラをONにします。

sudo raspi-config

ここで
5. Interfacing Options をEnter
⇒P1 Camera にEnter
⇒Enabled? にYES にEnter
これでカメラインターフェイスが使用できるようになったので、再度さきほどのコマンドを試してください。

【カメラの接続確認】

$ vcgencmd get_camera
supported=1 detected=1 //これが出れば接続OK

 

動画をh.264で撮影してみます。

raspivid -o video.h264

オプションで下記のように設定可能
-t : 撮影時間
-w : 解像度の幅
-h : 解像度の縦

raspivid -o video.h264 -t 5000 -w 640 -h 480

omxplayerというソフトをインストールして、さきほどのh.264形式の動画を再生してみましょう
インストール後にそのままomxplayer video.h264 で再生できます

sudo apt-get -y install omxplayer
omxplayer video.h264

 

オプショナル型のアンラップについて Swift4

オプショナル型=変数にnilの代入を許すデータ型
宣言方法:変数のデータ型の最後に”?”か”!”をつける

var name: String?
var age: Int!

※オプショナル型の変数は宣言をしただけで初期化をしなかった場合、nilが入っている

暗黙的アンラップ型”!” =使用する際に自動でアンラップされる
オプショナル型の宣言には”?”か”!”を用いますが、”!”を用いて宣言したオプショナル型(暗黙的アンラップ型)は下記のように使用する際に自動でアンラップされます。

"?"で宣言したオプショナル型の場合、非オプショナル型とは計算できない
var x: Int  = 5 // 非オプショナル型
var y: Int? = 10 // "?"で宣言したオプショナル型
x + y
# => エラー

"!"で宣言したオプショナル型の場合、自動でアンラップされるため非オプショナル型と計算できる
var x: Int  = 5 // 非オプショナル型
var y: Int! = 10 // "!"で宣言したオプショナル型(暗黙的アンラップ型)
x + y
# => 15

暗黙的アンラップ型は、

最初はnilで宣言⇒使用時には絶対に値が入っている(nilではない)

という使い方の際に使用します。
そのため、使用するときに変数の値がnilのときにはエラーとなりますので要注意です。

 

アンラップ=オプショナル型から値を取りだす

アンラップの方法は下記3通り

1. Forced Unwrapping (強制的アンラップ)
オプショナル型を強制的にアンラップする方法で、
オプショナル型の後ろに”!”をつける

2. Optional Binding (オプショナルバインディング)
オプショナル型の変数に値が入ってる⇒アンラップ⇒処理{}を実行
オプショナル型の変数に値がない(=nil)⇒処理{}を行わない、もしくはelse{}の処理を実行

var test: String? // オプショナル型

if let testUnwrapped = test {
println(testUnwrapped)
}
else {
println("テストはありません")
}

if let 変数2 = 変数1{} はSwiftでよく使われるnilチェックの方法
if let hogehoge = hogehogeValue {
//nilでない場合実行される処理
}

※他にもあるエラーハンドリング
if let 変数2 = try? 変数1 {}
try?はエラーが発生するとnilを返すオプショナル型変数、この組み合わせでエラーにならないようにしています

3. Optional Chaining(オプショナルチェイニング)
オプショナル型の変数に続けてプロパティを取得したり、メソッドを呼び出す場合に使用する、戻り値はオプショナル型になる
戻り値がオプショナル型となるため、オプショナル型の変数の中身がnilの可能性があってもプロパティを取得したり、メソッドを呼び出せる。

使用方法:オプショナル型の変数のあとに”?”をつける
オプショナル型の変数?.プロパティ
オプショナル型の変数?.メソッド()

【例1】

var animal1: Animal? = Animal()
var animal2: Animal?

// nilでないためプロパティが取得できる
animal1?.type
// => "Optional(ねこ)"

// nilでないためメソッドを呼び出せる
animal2?.call()
// => "Optional(わんわん)"
var animal1: Animal? = Animal()
var animal2: Animal?

// animal1がnilの場合、nilが返る
animal1?.type
// => nil

// animal2がnilの場合、nilが返る
animal2?.call()
// => nil

【例2】

var x: String?
Var y = x?.uppercased()
// => nil

 

メソッドのラベル 名前付き引数 Swift4

ラベル:名前付き引数

メソッドの呼び出し側で、引数をよりわかりやすくするためにラベルを使います。

例えば、引数名が”ct” だったとして、意味するものが国だったとしたら、ラベルに”country”をつけるとメソッドの呼び出し側でコード書く際に分かりやすい、という感じです。

// 総重量:数量×重さ
func calcSum(quantity qt: Int, weight wt: Int) -> Int {
    return qt * wt //メソッド内では引数名を使う
}

//メソッドを呼び出す際は第一引数にquantity、第二引数にweightとして呼び出す
calcSum(quantity: 20, weight: 100)

引数の前に”_”(アンダースコア)を付けてラベルを省略する場合もある

String(describing: Subject) について Swift4

Swift3 ⇒ Swift4 で同じプログラムでもprint()にオプショナル型を放り込むと下記エラーが出るようになったみたい、swift3では自動解釈してくれていたような。。←未確認

expression implicitly coerced from ‘string ‘ to any

これはアンラップすればだいたいが解決する

アンラップはデータ型の最後に「!」をつける ⇒  (String!)

 

次にStringのinit(describing instance: Subject)について

string interpolation produces a debug description for an optional value

これはStringのイニシャライザについてのエラー

String(describing:)と書き直せば解消する。ちなみに意味は
String(describing:)にインスタンスを渡すことで、そのインスタンスの情報を文字列で取得することができる
というもの。

これもprint文にオプショナル型で入れてしまった際によくでるエラー

監視カメラ用DVRの設定方法 時刻編

監視カメラや防犯カメラは時間の設定が重要です、なんせ証拠に利用するものなので

正確な時間が記録できていたほうがもちろん良い。しかもこれを自動で行いたい。

これを弊社で販売している下記DVRを例に挙げて説明すると

【顔検出・侵入者検知機能】付きDVR 防犯カメラレコーダー

型番:4chdvr4in1-fd

インターネット経由で定期的に時刻を取得し、DVRに反映するという方法をとります。

※メインメニュー⇒ネットワーク⇒NetApply⇒NTP

ここで、NTPサーバーの設定を行います。他メーカーさんのDVRでも設定項目はほぼ同じです。

NTPサーバーはプロバイダ等多くの企業が公開しています。

今回はNTPサーバー大御所のNICT(独立行政法人情報通信研究機構)のサーバーを例に設定してみます。

HostIP: ntp.nict.jp

Port: 123

更新間隔:60分(適当でOKです)

はい、これだけで終了です。

あとは、タイムゾーンが

GMT +09:00

になっている事を確認すればOKです。

もし、なっていなければGMT +09:00にしてください。

これだけの設定で、後はDVRが自動的に正確な時間を取得し、正確な時間を刻んでくれます。

華強北のお店たち @深圳

世界最大の電気街である中国シンセンにある華強北

行ったことある!という方も多いかと思います。

写真にあるように小さなブースが大量に並び、各商店がそこで商売をしています。

なので、日本の電気街とはかなり違います。

ビル毎に商材のテーマがかなり大ざっぱですが決められており、

同じテーマに合う商材を持つ商店が同じビルに集い、かつそのフロア毎に

またジャンル(or 商売形態)で大雑把にわかれて入居しています。

なので、LEDビルやICチップビル、修理用部品ビル、スマホアクセサリービルなどなどという感じで別れています。

ビルの中の階層分けは全部ということはないですが、下層階は一般小売向け商店、上層階は卸業者が多い傾向にあります。

なので、下層階のお店のほうが規模が小さく、1個単位で基本は買えます(1個は嫌がられますが)

上層階は卸業者が増え、店面積も広く店構えも1階とは違いしっかりしてきます。

また、特定の商材を大量に置いている店が多くなります。

ただ、ここでも1個から買える店がありますので、がんばって話しかければ売ってくれます。

中華系のビジネス全般的にあることですが、他店の商品を置いて、商品数を多く見せる「見せ商品(他店の商材)」

が必ずあるため、安く買いたければその店の独自品はどれかを見極め、それだけを買うようにすれば

安く買い物はできるでしょう。

ただし、昔よりよくなってきましたが、華強北はいまだに不良品を売りさばくマーケットでもあるため

大量に買う際には、よく確認する事をお勧めします。