第九回 PCとの連携・シリアル通信応用

第九項 PCとの連携・シリアル通信の応用

電子工作創作表現(2019/6/21)

スライドPDF

先週の「シリアル通信」前回まで

  • PCから数字を1つ送る
     
  • Arduinoから来る数字を受信する
前回は、ArduinoのSerial.write関数を使って数字を送受信するというプログラムを解説しました。今回はその続きで、もう少し込み入った情報をやりとりする方法について解説していきます。

シンプルに数字を送るだけ

  • 複数のデータはどう区別する?
     
  • 255より大きい値を送るには?
シリアル通信は1バイトずつ数字を送ることができるので、0~255までの数字を送る事ができます。しかしそうなると、複数の値(アナログ入力の0番と1番や、傾きセンサのXYZ)を送ってもいつどのデータが来ているのか分かりませんし、値も255までしか送れないというのはかなり幅が狭いです。

基本的な文字をやり取りする「アスキーコード」

  • 簡単な文字を128種類におさめた「ASCII CODE」
     
  • 英数字記号などの簡単な「文字」が送れる
そこでもう少し複雑なやりとりをしようとすると、数字を文字として置き換えた「アスキーコード」の出番がやってきます。英数字記号とデータ用の特殊な文字で構成されていて、128種類に収められているので全てを1バイトの文字として使うことができます。「アスキーコード 一覧」などで検索すると、一覧が出てきます。

1バイトを1文字として扱う

  • 例:111:110:107:97:110 で「onkan」
     
  • 数字も文字として登録されていて「0」は48から始まる
     
  • 文字としてのデータが「アスキー」数字としてのデータが「バイナリ」
1バイトの数字がそのまま文字として扱われるので、例えば上記数字の並びをアスキーコード表に照らし合わせてみると「onkan」という文字になります。そして数字も文字として登録されていて、文字の「0」が48でそこから1ずつ増える形で対応しています。

こうなってくると少しややこしくて、数字のデータを送る時に文字として送るのか数字として送るのか、ルールを決める時に混乱が生じてしまいがちです。そこで文字としてのデータのことを「アスキー」、数字としてのそのままのデータを「バイナリ」と呼ぶのが慣例になっています。

アスキーデータのやり取り

  • 送るデータの自由度は上がる
     
  • ただしプログラムは煩雑になる
アスキーデータでやり取りをすると、情報の自由度が上がる一方でプログラムは煩雑になります。
しかしパソコンとの連携をする上でとても重要な方式なので、じっくり説明していこうと思います。

シリアルモニタはアスキーベース

  • ArduinoIDEの「シリアルモニタ」はアスキーベース
     
  • 受信したデータを出力して、送信もできる
アスキーベースでのシリアル通信を簡単に試す時には、ArduinoIDEのシリアルモニタが便利です。Arduinoから送られてきたデータをそのままウィンドウに表示(ダンプ)してくれるのと、テキストを入力すればそれをそのままArduinoに送信してくれるので、作りはじめにシリアル通信を試したい時や、何かバグが発生した時の検証などに便利なので活用しましょう。

Arduinoでデータを受信する

  • 文字を入れる変数「String」を使う
     
  • 「<on 2>」「<off 2>」というコマンドでLEDをスイッチする例
Arduinoで受信したシリアル信号を文字として扱うためには「String」という変数の型を使って、受け取った文字データをストックしていきます。
どんな文字で指示するかというのは、実現したい事に応じて考える必要があります。ここではデジタルピンのLEDをオンオフするために「on ピン番号」というコマンドを不等号で囲う形にします。

「>」を一つの命令の終わりと認識することで、複数バイトのデータを場合分けすることができるようになります。Stringには文字を抜き出したり、アスキーの数字をバイナリの数字に変換するなど色々な機能が搭載されているので、都度必要な機能を参照しながら使うのが良いでしょう。
https://www.arduino.cc/reference/en/language/variables/data-types/stringobject/

//====================以下Arduinoスケッチ===========================

// Arduinoのシリアルモニタから、デジタルピンを制御する
//  でHIGH、  でLOWにする

String recv; //文字列を保持する変数String

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

  //2~13までをすべて出力にする
  for (int i = 2;i <= 13;i++)
  {
      pinMode(i, OUTPUT);
  }
}

void loop()
{
  while (Serial.available())
  {
    //charは1文字だけを保持する変数
    char data = Serial.read();
    //読めるデータは1バイトずつなので、recvに追加していく
    recv += data;

    //データの最後に「>」を入れるルール
    if (data == '>')
    {
      //先頭3文字が「<on」かチェック
      if (recv.substring(0, 3) == "<on")
      {
          //5文字目以降の文字を抜き出してtrimedに入れる
          String trimed = recv.substring(4);

          //trimedで抜き出した文字としての数字をintに変換
          int pin = trimed.toInt();

          //指示されたピン番号をHIGHにする
          digitalWrite(pin, HIGH);
      }

      //先頭4文字が「/off」かチェック
      if (recv.substring(0, 4) == "<off")
      {
          //6文字目以降の文字を抜き出してtrimedに入れる
          String trimed = recv.substring(5);

          //trimedで抜き出した文字としての数字をintに変換
          int pin = trimed.toInt();

          //指示されたピン番号をLOWにする
          digitalWrite(pin, LOW);
      }

      //recvの中身を読み終えたので、リセットする
      recv = "";
    }
  }
}

Arduinoでデータを送信する

  • Serial.print() もしくは Serial.println()
     
  • 数字は自動的に変換してくれる
今度は逆に、Arduinoから文字データを送信するプログラムを書いてみます。Arduinoから1バイトのデータを送る時はSerial.write()という命令を使っていましたが、文字を送る際にはprint()もしくはprintln()という関数を使います。

3つのアナログ入力した値を出力しますが、この辺りは加速度センサを使った時にも使ったコードに近いですね。シリアル周りを重点的に解説していきます。

//====================以下Arduinoスケッチ===========================

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

void loop()
{
  Serial.print(analogRead(0));//アナログで読み取った値をシリアルでプリント
  Serial.print("\t");//3つの値をタブ文字で分割する

  Serial.print(analogRead(1));
  Serial.print("\t");

  Serial.print(analogRead(2));
  Serial.print("\n");
  //最後に改行文字'\n'を入れる
  //最後はSerial.println(analogRead(2));としてもOK。
  //printlnとすると最後の\nは勝手に追加してくれます
}

表記できない文字の表記

  • 「\(バックスラッシュ)」の後にアルファベットで、タブや改行などを表現
     
  • 「エスケープ文字」と言って特殊な文字を表記する時に使う
Serial.print("message")という感じで、文字を送る場合にはダブルクォーテーションで囲みます。ここではシリアルプロッタのフォーマットにならって3つの値をタブ文字で区切りました。0~1023までの値がプリントされています。

タブや改行のようにコード上では書けない記号を表記する場合、バックスラッシュを後ろに付けてエスケープ文字という形で表記する場合があります。

max/mspで受け取る

maxではbangを送ると受信したデータが流し込まれるので、prependオブジェクトでスタックした数字のデータを、改行のタイミング('\n'がバイナリの10)でitoaオブジェクトに流し込むことで文字のデータとして拾い上げています。

touchdesignerで受け取る

touchDesignerでは前回同様SerialDATを使い、Row/Callback Formatをone per lineに設定すると改行ごとにデータを区切ってくれます。

これを更に別々の数値として扱うにはsplitメソッドを使い、配列として分割した後にConstant ChOPなど使いやすいオブジェクトに入れるなどをします。

Processingで受け取る

  • Arduinoに近い書き方
Processingで受信する処理は、Arduinoがシリアルを受信する処理とかなり近く、Stringを連結していって改行のタイミングでブロックを処理してあげるという処理を施します。

import processing.serial.*;
int data[] = new int[3];
String recv;
Serial serial;

void setup()
{
  size(1023, 300);
  serial = new Serial(this, "COM3", 9600);
}

void draw()
{
  background(0);
  fill(255);
  rect(0,   0, data[0], 50);
  rect(0, 100, data[1], 50);
  rect(0, 200, data[2], 50);
}

void serialEvent(Serial s)
{
  char dat = char(serial.read());

  if (dat != '\n') recv += dat;
  if (dat == '\n') 
  {
    String[] list = split(recv, '\t');
    data[0] = int(list[0]);
    data[1] = int(list[1]);
    data[2] = int(list[2]);
    recv = "";
  }
}

第八項 PCとの連携・シリアル通信基礎

第八項 PCとの連携・シリアル通信基礎

電子工作創作表現(2019/6/14)

スライドPDF

パソコン<->Arduinoの通信

  • 色々なソフトと連携する
     
  • Processing, oF, Max/MSP, TouchDesigner...
Arduinoとパソコンの間で通信ができると、色々なソフトウェアと連携をとることができます。
今回はいくつかの通信手段を使って、パソコンと連携する方法を解説していきます。

USBシリアル通信

  • 1バイトずつデータを送る、シンプルな方法
     
  • 親戚にRS-232CやRS-485がいる
今までArduinoでデータをやり取りしていたUSBシリアル通信は、1対1の双方向通信をするための、シンプルでポピュラーな方法です。USBでシリアル通信をするのでUSBシリアルと言って、親戚のようなものにRS-232Cや、DMXのベースとなっているRS-485という規格のものがありますが、ここでやりとりするデータも基本的には同じ内容です。
プログラム上においてで複雑なルールは無く、1バイトずつデータをやりとりします。

「バイト」とは

  • 2進数の0と1を8個並べたものが「1バイト」
     
  • 0~255までの要素を表現できる
     
  • 16進数では0x00~0xFFのように2桁で表現できる
バイトとはコンピュータ上で扱う数字の単位で、0と1だけで数を表す「2進数」の数字8桁を1バイトとしています。
この1バイトで表せる数字は10進数の0~255までです。Arduinoでは2進数を0b00001111のように0bを付けて表現することもできます。
ちなみに16進数も0x5Aのように0xを頭に付けて記述できますが、16進数が使われるのは1バイトを表記するのに2桁で収まって見やすいという理由があります。

2/8/10/16進数の相互変換
https://hogehoge.tk/tool/number.html

バイトの列を送る

  • 0-255までの数字を1個ずつ送るのがシリアル通信
     
  • データの意味や区切りなど、自分でルール(仕様)を決めてやり取りする
この1まとまりの数字を1個ずつ送れるというのが、シリアル通信の基本的な機能です。
1バイトずつデータを送るので、この255までの数字にどういう意味を持たせるのかを決めながらやり取りしていく必要があります。

PCとの連携・基本編

  • Arduino側と、PCソフト側のプログラムでルール(仕様)を決めながら書く
     
  • max/msp oF Processing touchdesigner
シリアル通信では決まったデータのルールが特に無いため、やり取りの決め事をArduinoとソフトウェア側で決めながら実装していく必要があります。

基本的なArduinoでのシリアル通信の記述方法と、PCとの連携についていくつか具体的な方法を紹介していきます。

Arduinoシリアル送受信(基礎編)

  • 指定したピン番号のアナログ値を返すサンプル
まずは、とてもシンプルなArduinoのシリアル通信サンプルを用意します。これはPCから0~5までの数字を受け取って、その番号のアナログピンの値を返すというサンプルです。
アナログの値は0~1023まで取ることができますが、返す値は1バイトだけなので、0~255までしか送れません。大きい数字を送る方法は色々あるのですが、ここはひとまずアナログの値を255までに圧縮します。

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

void loop() {

  while (Serial.available())//データが来ているか確認
  {
    //1バイト分のデータを変数に入れる
    byte data = Serial.read();

    //アナログピンの番号の入力値を返す
    if (data < 6)
      Serial.write(analogRead(data) / 4); //1バイトでしか送れないので、4で割る
  }
}

max/mspとの連携

max_serial

max/mspでシリアル通信をするときは、serialパッチを使います。1つ目の引数にポート名、2つ目には通信速度を記載します。ポート名はprintを送信すると右のアウトレットから出力されます。
数字をメッセージで送るとその数字が1バイトだけ送信されます。1バイトなので、255を超える数字を送ろうとするとオーバーフローが起きて、256で割った余りの数字になってしまいます。
ここではアナログ5番のデータが欲しいので5を一定間隔で送りました。

Arduinoからは返事が返ってきますが、返事はserialオブジェクトの中に格納されたままになっていて、bangを送る事でアウトレットから出力されます。

touchdesignerとの連携

  • serialDATを使う
     
  • TDはアスキーコードとして使うのがデフォルト(後述)
続いてTouchdesignerでの連携です。touchdesignerではSerialDATというオペレータを使って送受信をします。ポート名と通信速度を同じように設定して、データを出力するタイミングのRow/Callback FormatをOne par byte、Byte ColumnをONに設定します。byte ColumnをONにしたことで、1バイト分のデータが数字で表示されるようになります。使うデータは最新のものだけなので、Maximum Linesは1にしておきます。

execute DATからデータ送信

execute

毎フレームアナログ番号の5を送りたいので、Execute DATのFrame StartをONにし、onFrameStart内でserial1オペレータのsendByteメソッドを呼び出します。これで毎フレーム5が送られるので、アナログ入力値がserialDATに送られます。

CHOPで受け取る

DATの値をConstant CHOPに入れ込みます。直接DATから数字をもらってきても良いですが、これで使いやすくなりました。

グラフィックのパラメータにしてみる

noise top

これをNoise TOPのZパラメータに入れてみます。
データの範囲が0~255なので、これをexpressionで調整してnullに入れておいた値をNoise TOPのtzに入れます。アナログの値をぐりぐり動かすとNoiseの模様がリニアに変化していきます。

processingとの連携

  • processing.serialライブラリを使用
     
  • serialEventメソッドが呼び出される
続いてprocessingの場合です。processing.serialからライブラリをインポートして、Serialクラスを使います。writeメソッドで1バイト分のデータを送る事ができます。Processingではデータを受信するとserialEventが呼び出されるので、そこでデータを受信することができます。

import processing.serial.*;
int data = 0;

Serial serial;

void setup()
{
  serial = new Serial(this, "COM3", 9600);
}

void draw()
{
  background(0);
  serial.write(5);
  rect(width / 2, height / 2, 10 + data, 10 + data);
}

void serialEvent(Serial s)
{
  data = serial.read();
}

openFrameworksとの連携

  • C++なので、Arduino側と読み書きの構造は近い
     
  • 今日紹介した中で処理速度は最速
openFrameworksでは、ofSerialというクラスが用意されています。
C++ということもあって、書き方はArduinoとかなり近くなります。

//====header====
ofSerial serial;
int analog = 0;
//====header====

ofApp::setup()
{
  serial.listDevices();
  serial.setup("COM3", 9600);
}

ofApp::update()
{
  seiral.writeByte(5);
  while (serial.available())
  {
    analog = serial.readByte();
  }
}

ofApp::draw()
{
    ofDrawRectangle(ofGetWidth() / 2.0, ofGetHeight() / 2.0, 10 + analog, 10 + analog);
}

USBシリアルでの「決めごと」

  • 通信速度(9600/38400/115200bpsなど)
     
  • データ長・パリティビット・ストップビット
     
  • 8ビット長・パリティ無し・1ストップビット(SERIAL_8N1)がArduinoデフォルト
最後に、USBシリアルではいくつかルールがあってこれをArduino側とソフトウェア側でそろえなくてはいけません。通信速度はノイズ等でデータの取りこぼしがあるので早すぎない程度に高い数字を使いましょう。

データ長・パリティ・ストップビットについては通信のタイミングを決めるルールですが、基本的には8ビット・パリティ無し・1ストップビットが今スタンダードなようなので、特に意識する事はないと思います。メーカー製の装置等と通信する時に違った設定があることがあるので、なぜかちゃんと通信できないという時に思い出す程度で大丈夫です。各項目の意味については検索するとたくさん情報が出てきますが、これも自分で組み込みデバイスを設計しない限りあまり使うことはないかなと思います。

補足:通信速度

  • 9600だと60fpsの世界では1フレーム160バイト
     
  • 115200で1フレーム1920バイトなので無難?
自分の感覚としてはUSBシリアルなら9600未満は遅いかなという感じで、115200当たりが無難に思います。

映像的に考えると、9600bpsで1フレームに送れるデータ量は9600÷60=160バイトなのでちょっと遅いかも、115200bpsなら1フレーム1920バイトなので十分かなという感じです。

補足の補足:クロックとの組み合わせ

  • Arduinoのクロック数(UNOでは16MHz)によってエラーレートが変わる
     
  • 高いほどエラーが起きやすいという事でもない
その後、ツイッターで情報をいただいたのですが、実はクロック数と通信速度でデータを取りこぼしやすい組み合わせがあるということでした。
https://cache.amobbs.com/bbs_upload782111/files_22/ourdev_508497.html
ここによると16MHzでエラー率が低く、速度が速いのは76800bpsだそうです。115200だと3.7でやや高く、57600は少し遅いけど位相がずれていくのでエラー率が高くなっています。

https://ja-support.renesas.com/knowledgeBase/17794551
理論上は4.375%までが許容範囲ということなので、115200はギリギリですね…16MHzのArduinoでは76800くらいが丁度良さそうです。

ここまでがシリアル通信基本形

  • 生のバイナリ(数字)データでシンプルにやりとり
     
  • 複数種類のデータや大きい数字など複雑にしづらい
以上が、各ソフトウェアで扱える簡単なシリアル通信の方法です。単純なデータのやりとりはできますが、これではちょっと機能に物足りなさを感じます。
アナログのデータも欲しいけどデジタルの入出力もしたい、さらに複雑な処理をArduinoに指示したいとなるともう少し発展的な実装をする必要があるのですが、それはまた次回!

前期課題

  • デバイスを使った作品プランを提出
     
  • 「1種類のインプットと、それに対応した1種類のアウトプットを持つもの」
     
  • その組み合わせがどういう意味を持つか、どういう意味を持たせられるか考える
6月も半分を超えたので、ここで前期課題を出そうと思います。デバイスを使った作品プランを考えてみてください。後期は実際に作品を作ってもらいたいと考えているので、ここで少し作品についてや実現可能性についてディスカッションをできればと思っています。聴講生の提出も歓迎です。

どうしても作りたいものがある場合は、Arduinoかその他デバイスを使っていれば自由に考えてもらっても構いませんが、一応トライしてみてほしいテーマを「1種類のインプットと、それによって変化する1種類のアウトプットを持つもの」とします。

何かセンサーや入力を1種類と、それによって制御される出力を1種類決めて、その現象がどういう意味を持つか、どんな意味を持たせることができるか考えてみてください。

7/19に発表してもらいたいので、7/19のお昼12時を提出期限とします。また課題用のページを作りますが、Googleのドキュメントかスライド、PDFなどWebで共有できる形式をいくつか指定します。

第七項 通信とケーブル・はんだ付け

第七項 通信とケーブル・はんだづけ

電子工作創作表現(2019/6/7)

スライドPDF

今日使うもの

  • ジャンパワイヤ4本
     
  • MPU6050モジュール
     
  • はんだごて
     
  • はんだマット

今日の予定

  • 6軸センサを使ったセンシング&はんだづけ体験
     
  • 通信とケーブルについて

はんだづけ

  • 基板の銅等を使った接点(ランド)に電子部品を固定する
     
  • はんだを溶かしてくっつける。溶接ではなく「溶着」
今日はMPU6050という、傾きを検知するセンサーを使ってデモしようと思うのですが、せっかくなので部品のはんだ付けを皆さんに体験してもらおうと思います。
はんだづけとは、基板に電子部品を固定する方法の一つで、部品の金属接点と基板の接点の間にはんだという合金を溶かし入れて接着する方法です。溶接の一種とよく言われますが、溶接ではなく溶着ですので、溶接ほどの強度はありません。

はんだごてについて

  • 安くて温度が低いものは難しい
     
  • 自分用を買う時は「温度調節機能付き」がおススメ
はんだ付けは、熱したはんだごてではんだを溶かしながらつけていきます。溶かすはんだは種類によって融点が色々あり、あまり温度が低いとはんだ不良を起こすので自分用にこてが欲しくなった場合は温度調節機能付きのはんだごてがおススメです。白光やgootというメーカーのはんだごてがメジャーなので良いでしょう。

はんだの付け方

handaduke

  • 部品二つを温める(3~4秒)
     
  • はんだを押し当てて溶かし、流し込む
     
  • はんだごては1秒ほど、一息おいてからはなす
はんだの主な手順は上記のようなイメージです。部品の大きさや材質によって当然条件も変わってきますので、上手くなるためには数をこなしてみるのが一番だと思います。

良いはんだ、悪いはんだ

handa

  • つやつやした富士山型が良いはんだ
     
  • はんだを盛りすぎる、ランドに熱が伝わってないと「いもはんだ」になる
はんだ付けがきれいにできると、三角錐の形になります。接点側に伝える熱が不十分だと表面張力で丸っこい形になり、取れやすかったり電気が通じなかったりするので、そうなってしまった所は数秒はんだを当てるなどして直してあげましょう。
ただし、あまり長く基板や部品にこてを当てていると熱が伝わりすぎてランドが剥がれたり部品が熱で壊れたりしてしまうので、いい感じと思ったらすぐ離すようにしてください。念入りに当てすぎるのはNGです。

センサモジュールGY-521(MPU6050)を使う

センサモジュールにピンソケットをはんだ付けする

今回は傾きと、回転速度をとることができるセンサーGY-521(MPU6050)にピンソケットをはんだ付けしてみます。
傾きを取得する加速度センサと、回転角速度を取得するジャイロセンサが載ったセンサで、真ん中の黒くて四角いIC部分がTDK社製のMPU6050で、それをすぐ使えるようにしたモジュール基板の名前がGY-521となっています。

配線

wiring

はんだ付けができたら、以下の通りに配線していきます。アナログの4番5番ピンは、実はI2Cという通信方式のためのピンにもなる特殊なピンになっています。

スケッチの書き込み

  • という最初から入っているライブラリを使用
     
  • I2C(I Squared C)通信という通信方式を使って、センサーの情報を取得してくる
 #include <Wire.h>

 #define MPU6050_ADDR 0x68
 #define MPU6050_AX  0x3B
 #define MPU6050_AY  0x3D
 #define MPU6050_AZ  0x3F
 #define MPU6050_GX  0x43
 #define MPU6050_GY  0x45
 #define MPU6050_GZ  0x47
 #define MPU6050_POWER 0x6B

short int acc[3];
short int gyro[3];
short int temp;

void setup() 
{
  Serial.begin(115200);
  Serial.println("I2C Initialize.");

  //I2Cの初期化
  Wire.begin();
  Wire.beginTransmission(MPU6050_ADDR);

  //MPU6050の動作をスタート
  Wire.write(MPU6050_POWER);
  Wire.write(0);
  Wire.endTransmission();
}

void loop() 
{
  //約60fpsに抑える
  delay(12);

  //AXから連続する14バイトのデータをリクエスト
  Wire.beginTransmission(MPU6050_ADDR);
  Wire.write(MPU6050_AX);
  Wire.endTransmission();
  Wire.requestFrom(MPU6050_ADDR, 14);

  //データの取得開始、加速度センサの値を受信(2バイトで来るため、先頭8ビットを上位にシフトして合計)
  for (int i = 0;i < 3;i++) acc[i] = (Wire.read() << 8) | Wire.read();

  //温度センサを受信(今回は使わないが、順番に流れてくるので受信する)
  temp = (Wire.read() << 8) | Wire.read();

  //ジャイロセンサの値を受信
  for (int i = 0;i < 3;i++) gyro[i] = (Wire.read() << 8) | Wire.read();

  //受信結果をシリアルで表示。TAB('\t')で区切ると、色分けされたグラフとして表示される
  for (int i = 0;i < 3;i++) Serial.print(String(acc[i]) + '\t');
  for (int i = 0;i < 3;i++) Serial.print(String(gyro[i]) + '\t');
  Serial.println("");
}

モニタ/プロッタで確認

  • シリアルモニタでは、タブ区切りの数字として表示される
     
  • シリアルプロッタに展開すると、色分けされたグラフとして見える

graph

プログラムが無事アップロードされたら、シリアルモニタでデータを確認します。
USBからそれぞれの値がタブ区切りで送信されるのが確認できると思います。

タブ区切りで見ることで簡単な時系列の値の変化を読み取りやすいというのもありますが、こうして書いておくとシリアルプロッタの画面で見た時に色別で表示されるのでとても分かりやすくなります。

通信とケーブル

  • データをやり取りする方法
このようにハードウェアを扱っていくと、Arduino<->PC間やArduino<->モジュール基板間のように、2つの機器の間で情報をやり取りするということがよくあります。今回はUSBケーブルとジャンパーピンを使って通信しましたが、これもやりとりする情報の内容や、やりとりする2つの機器の距離など条件によって使うべき通信方式・ケーブルやコネクタの選択肢がいろいろと変わってきます。

このあたりは展示や実験装置を作る上でかなり重要なトピックなのですが、電子工作関連の情報の中では少ない印象があったので、このあたりまとめつつ解説していこうと思います。

通信する時に決めること

  • どんな伝え方をするか (プロトコル/Protocol)
  • どんな端子を使うか (コネクタ/Connector)
      
  • どんな線材を使うか (ケーブル/cable)
まず何らかの機器同士でやりとりする時に何を決める必要があるかという点ですが、大きく3つ「プロトコル」「コネクタ」「ケーブル」に分類することができます。

伝え方「プロトコル」

  • Arduinoとパソコン:RS-232C・USBシリアル・TCP・UDP…
     
  • Arduinoとモジュール基板(基板同士):SPI・I2C・UART
一つ目の伝え方「プロトコル」は、誰と誰が通信するか、どんな内容をどんな速度でやりとりするかによって選択肢が決まってきます。お互いがソフトウェアで対応するプロトコルを使う必要があり、今日Arduinoとモジュール間でやりとりしたのはI2Cという規格です。モジュール基板はI2CかSPIに対応していることが多いです。

つなぎ方「コネクタ」

mixer

  • 必要なピンの数
     
  • 誤挿入の防止
     
  • 抜き差し頻度・環境に求められる耐久性
まず一つ目のコネクタは、デバイスの出入口にあたる部分です。PCだとUSB端子や有線LANポートがあったり、オーディオだとXLR端子やフォン端子、フォンにも3.5Φや6.3Φといった大きさ違いの物もあると思います。

先ほどジャンパーピンでセンサーとArduinoを接続したように、極端な話電気的に繋がってさえいれば通信はできます。しかし、頻繁に抜いたり差したりする必要が出てくると、3本も4本も毎回場所を確認しながら抜き差しするのは面倒です。そこでこういったコネクタを使うと、抜き差しの作業を効率化できる上、間違ったピンにつないでデバイスを壊したりするという事故も防止することができます。

伸ばし方「ケーブル」

  • 伝送距離が延びる程、ノイズの影響を受けやすい
     
  • ツイストペアやシールドはノイズ対策になる
  • 数が増えてくると、美観的なところも気になってくる

cables

ある程度伸ばす距離が伸びてくると、ケーブルにも気を使ったほうがよくなってきます。
これはノイズの影響を受けやすくなってくるからで、センチメートル単位であれば電子工作用の導線で事足りますが、長くなってくると信号の種類に応じて、シールドされているケーブルを選ぶ必要が出てきたりします。

簡単なケーブル作りの例

  • JST XHコネクタ
     
  • 入手性が良く、メス端子は基板に直接取り付けられる
最後に、よく使うケーブル作りの例を紹介します。
以前モーターを制御する仕事でユニットを作った際に作ったケーブルの例です。

コネクタは基板用のコネクタというのが色々ありますが、JSTというメーカーのXHコネクタを使いました。アマゾンや秋月で購入できるので入手性がよく、ユニバーサル基板にも直接はんだで取り付けられるのでよく使っています。お気に入りのコネクタをストックしておくと便利です。

ケーブル

  • ミスミで購入(個人で買うならモノタロウやオヤイデ)
  • AWG22の2芯・3芯を使用
ケーブルは柔らかくて取り回しの良い、PVCで被覆されたロボットケーブルを使っています。銅線の太さでよく使われるのがAWGという規格ですが、XHコネクタであればAWG22がちょうどよい太さなので、AWG22の2芯・3芯ケーブルを使っています。

私の場合事業者が使えるミスミという販売サイトを使っているのですが、学生の皆さんはモノタロウや実店舗のあるオヤイデ電気を使うのが良いでしょう。

圧着して、ケーブルを作る

  • 圧着工具で、端子とケーブルをつなぐ
     
  • ケーブルははんだ付けでは作らない
コネクタとケーブルをバラバラで買ったら、この二つを必要な長さでつないでコネクタ付きのケーブルにします。
端子の金具で、中の銅線と被覆をしっかり掴むように変形させて合体させます。引っ張ったら抜けてしまいそうにも感じますが、この手のコネクタは接続部分に力がかかるので、はんだ付け等でつけてしまうと金属疲労を起こしてすぐ切れてしまうので、しっかり力を入れて圧着した方が丈夫になります。

メス端子(レセプタクル)は、基板にはんだ付け

XHコネクタはピンの間隔が2.54mm(0.1インチ)ピッチになっているので、ユニバーサル基板にもそのままはんだ付けしてしまうことができます。はんだ付けすればあとは差し込めばカチッとしっかりロックされるので、ジャンパーピンなどを使うよりも安心感のある結線が可能になりました。

課題と今後の講義のためのアンケート

基礎的な知識の紹介をしてきたので、徐々に具体的な実例などをやっていこうと思っていますが、シラバスの内容をどのくらいの割合でやるか、課題どうするかなどをちょっとアンケートを元に計画を練っていきたいのでGoogleフォームのアンケートにお答えいただけると助かります。聴講の人も是非!

第六項 Arduino開発基礎(ライブラリとモジュール)

第六項 Arduino開発基礎(ライブラリとモジュール)

電子工作創作表現(2019/5/31)

スライドPDF

これまで紹介したのは「基本機能」

  • 小規模で、シンプルな構造のセンサーやアクチュエータなら扱うことができる
     
  • もう少し込み入ったことをするには「ライブラリ」や「モジュール基板」が有効
今回はArduinoでより複雑な機能を扱うための「ライブラリ」について紹介していきます。
これまで紹介したプログラム構文やリファレンスで紹介していたものは、Arduinoの基本的な機能を使うための情報でした。

これらの基本機能だけでも小規模でシンプルな構造のセンサーやアクチュエータを扱うことはできます。
もう少し込み入ったことも出来ないわけではありませんが、そのためには必要な知識が更にどっと増える事になりますので、まずはライブラリやモジュールとよばれる部品を使う事をおススメします。

モジュールとは

modules

  • 目的に沿った部品を組み合わせて一つの基板にまとめたもの
     
  • コストはかかるが、電源管理やノイズ対策のようなところを気にしなくて済む
モジュールというのは、実現したい目的に合わせてあらかじめ基本的な部品が一つの基板にまとまった物です。大半が小さい基板の上にICやセンサー部品と、抵抗やトランジスタ、コンデンサといった部品をギュッと一つにまとめた形をとっています。

例えばモーターを動かしたいとなった時、一から回路を設計しようとするとノイズ対策や逆起電力対策というものが必要になってくるのですが、そういったある程度ややこしくて本筋とはあまり関係ない部分を全部ひとまとまりにやってくれているのがモジュールです。そういう意味では、Arduinoもモジュールの一種と呼べます。

モジュールの例

  • モータードライバ
     
  • 6軸センサモジュール
     
  • Arduinoシールド

motorShield

定番としてはモータードライバやセンサモジュールがあります。入力装置であるをモジュールにしたものはセンサモジュールという事が多いですが、アクチュエータを動かすためのモジュールは「ドライバ」と言う事が多いです。なのでアクチュエータを使うためのモジュールが欲しくなった場合は「モータードライバ」「LEDドライバ」などと検索すると良いでしょう。

そしてArduinoに関しては、ピンに上から差し込めるタイプのモジュールが色々開発されており、これらは「シールド」と呼ばれることもあります。写真はモータードライバのシールドです。
 

モジュール選び

  • 同じ機能でもいろいろな仕様のモジュールがたくさんある
     
  • Webページや、周囲で使ってる人がいるか
     
  • ノウハウが手に入りそうな物を狙って買うべし
そんなモジュールですが、実に様々なモジュールがあります。同じモータードライバだけでもたくさんあり、その使い方も様々です。
シンプルなセンサーと違いデータシートというものは無く簡単な説明書があるだけだったりします。(載っているチップのメーカーからデータシートを手に入れてね!というスタンスも)

「このモジュールを買ったんですが動かなくて…」という相談をされる事があったりするのですが、見たこと無いモジュールですぐには問題が特定できなかったり答えられないことがあったりします。

何かモジュールを買ってみる時にはできるだけメジャーそうなもの、Arduinoで使ったWebの記事を見つけたり、回りで使ってそうな人に相談するなどして、ノウハウがゲットできそうなモジュールを買うようにしてみてください。

ライブラリとは

  • 基本以外の機能を実現する
     
  • 「ライブラリ」はコーディングで共通のワード
     
  • モジュールを利用するための専用ライブラリも
そして今日もう一つ紹介するのが「ライブラリ」です。ライブラリというのはモジュールのプログラム版のようなイメージで、ArduinoIDEで使える機能を増やせる追加のプログラムです。

一般的にプログラミング言語で用意されている機能というのは基本的なものだけで、必要に応じてこのライブラリを使って拡張するという考え方で設計されています。

Arduinoの開発についても同じで、外部との通信や複雑な制御をひとまとめにしたり、先のモジュールを開発したメーカーが、モジュールをコントロールするためのライブラリを自分達で作って提供していたりもします。

ライブラリマネージャを使う

libMan

ArduinoIDEではライブラリマネージャから主要なライブラリを追加することができます。
スケッチ>ライブラリをインクルード>ライブラリを管理 もしくはCtrl(⌘)+Shift+Iでライブラリマネージャを開きます。

検索・インストール

install

このライブラリマネージャは、個人でもGithubというところで申請をして登録してもらうことができるので、メーカーから個人まで様々なライブラリが検索できるようになっています。

右上のテキストボックスで検索をします。今回はNeoPixelというライブラリをインストールしてみます。「neopixel」と検索するといくつかのライブラリに絞り込まれるので、「Adafruit NeoPixel by Adafruit」をマウスオーバーして「インストール」ボタンを押します。これでライブラリのインストールは完了です。

ライブラリのサンプル

libEx

インストールが完了すると、スケッチ例の項目にインストールしたライブラリのサンプルが追加されます。「More info」でソースコードが公開されているページにジャンプしてドキュメントを読む事も可能です。二つを合わせて読むとそのライブラリについて必要な情報が得られます。

複数のLEDを簡単に制御できる「NeoPixel」

neopix

  • Adafruitが開発しているLEDモジュール
     
  • 電源・信号線・GNDの3本線だけで複数のLEDを制御できる
NeoPixelはAdafruitという会社が作っているLEDモジュールのシリーズ名で、テープ状や板状のモジュールとして売っています。国内でもスイッチサイエンス等で取り扱いがあり、手っ取り早くLEDをたくさん光らせたい時には大変便利なモジュールになっています。電圧やノイズ等環境によっても変化しますが、数十粒単位で光らせることが可能です。

https://sekailab.com/wp/2017/01/20/neopixel-like-rgbleds/

#includeでライブラリを読み込む

  • #include <xxx.h>でライブラリをスケッチと接続する
先ほどライブラリをインストールしましたが、これはArduinoIDEにインストールされただけなので、自分のスケッチでライブラリを使う宣言をしなくてはいけません。

スケッチでライブラリを使いたい時には"#include<xxx.h>"という記述を最初に書きます。これによってライブラリのプログラムをスケッチが接続されて、自分のスケッチの中で使えるようになります。カッコの中に入るファイル名はライブラリによって違ってくるので、サンプルやドキュメントを参考にします。

ソースコード:
https://www.tinkercad.com/things/hbvNF04It4l

ライブラリで使う機能は”クラス”になっていることが多い

  • 変数のような形でインスタンスが定義される。
     
  • インスタンス名.関数名()という形式をとる
pixels.showという新しい記述方法が出てきました。これはC++の「オブジェクト指向」に基づく書き方になります。
Adafruit_NeoPixelの部分は”クラス”と定義されますが、ライブラリはこのようなクラスの形式を持つものが多く、変数のような形で使うクラスを宣言した後、クラス.(ドット)関数名という書き方でクラスが持っている機能を使うことができます。

基本的にはサンプルを参照しながら使う事になりますし、Arduinoをやるためにオブジェクト指向を学ぶというのは少しハードルが高くもあるので、ここでは省略します(もう少し進んでからやるかも)

演習

06-exerciseを改良する形で作ってみてください。
 

  • 梅:光が移動するたびに赤・緑・赤・緑…と変化する
     
  • 竹:赤・緑・青の三色が並んで動く
     
  • 松:光が往復して光り、跳ね返るところで色が変わる
     
    https://www.tinkercad.com/things/hbvNF04It4l

梅:光が移動するたびに赤・緑・赤・緑…と変化する

ヒント:counterの値が偶数か奇数かを、前回やったIf文で判定することで実現できます。

#include <Adafruit_NeoPixel.h>

#define PIN        6 // On Trinket or Gemma, suggest changing this to 1
#define NUMPIXELS  8 // Popular NeoPixel ring size

Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

int counter = 0;

void setup()
{
  pinMode(PIN, OUTPUT);
  pixels.begin();
}

void loop()
{
  counter++;

  pixels.clear();

  if (counter % 2 == 0)
  {
      pixels.setPixelColor(counter % NUMPIXELS, pixels.Color(255, 0, 0));
  }
  else {
      pixels.setPixelColor(counter % NUMPIXELS, pixels.Color(0, 255, 0));    
  }
  pixels.show();

  delay(500);
}

竹:赤・緑・青の三色が並んで動く

ヒント:setPixelColor命令を増やせば、同時に光らせるLEDを増やせます。counterの数字を工夫してみましょう。

#include <Adafruit_NeoPixel.h>

#define PIN        6 // On Trinket or Gemma, suggest changing this to 1
#define NUMPIXELS  8 // Popular NeoPixel ring size

Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

int counter = 0;

void setup()
{
  pinMode(PIN, OUTPUT);
  pixels.begin();
}

void loop()
{
  counter++;

  pixels.clear();
  //counter - 1 / conter - 2としてあげることで1個ずつずれる
  pixels.setPixelColor(counter % NUMPIXELS, pixels.Color(255, 0, 0));
  pixels.setPixelColor((counter - 1) % NUMPIXELS, pixels.Color(0, 255, 0));
  pixels.setPixelColor((counter - 2) % NUMPIXELS, pixels.Color(0, 0, 255));

  pixels.show();

  delay(500);
}

松:光が往復して光り、跳ね返るところで色が変わる

ヒント:行き8個、帰り8個で16個周期という考え方で、行きかえりの動きを定義してあげることで実現できます。

#include <Adafruit_NeoPixel.h>

#define PIN        6 // On Trinket or Gemma, suggest changing this to 1
#define NUMPIXELS  8 // Popular NeoPixel ring size

Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

int counter = 0;
int hue = 0;

void setup()
{
  pinMode(PIN, OUTPUT);
  pixels.begin();
}

void loop()
{
  counter++;

  pixels.clear();

  if (counter % 16 < 8) //16個周期初めの8個
  {
    pixels.setPixelColor(counter % NUMPIXELS, pixels.ColorHSV(hue, 255, 255));
  }
  else //後半8個は戻るので、7からカウンタの余りを引いた数で定義する
  {

      pixels.setPixelColor(7 - (counter % NUMPIXELS), pixels.ColorHSV(hue, 255, 255));
  }

  if (counter % 8 == 0) 
  {
    //ランダムで色相を変更
    hue = random(0, 65536);
  }

  pixels.show();

  delay(200);
}

第五項 Arduino開発基礎(if構文・ループ構文)

第五項 Arduino開発基礎(if構文・ループ構文)

電子工作創作表現(2019/5/24)

スライドPDF

今日の内容

  • if / for構文
     
  • 配列変数

プログラムの基本は「上から下」

  • 前回までやったルール「上から下」と「ジャンプ」
     
  • 決まり切った動作しかできない
     
  • 複雑な動作を実現するための「制御構造」(control structure)
前回まで、Arduinoのプログラムは基本的に上から下に動き、setup()関数は1度、loop()関数は繰り返し行われるという話をしました。
ですが、これだけだと決まりきった動作をさせることしかできません。もう少し複雑な動作を実現するための「制御構造」というのがいくつか用意されており、それを紹介していきたいと思います。

代表的な制御構造

  • if構文(If statement)
     
  • for構文
  • while構文
代表的な制御構造を解説していきます。「XX構文」という言い方をします。Arduinoのリファレンスページにもありますが、これらはArduino開発のベースになっているC/C++で定義されている構文になります。

if構文

  • 特定の条件を満たした時だけ動作する
     
  • もしも...だったら~をする
まず一つ目はif構文です。これは特定の条件を満たしたときにだけ実行したい処理を定義するための構文です。
書き方は
if (条件式) {
  /* 条件を満たしたときの処理 */
}
という書き方をします。かっこで囲まれた条件式を満たす時だけ、この中に書いた処理が実行されるので、条件が満たされない場合は処理がスキップされます。

条件式 (conditional expression)

  • 等号・不等号(== < >)で値を検証する
     
  • 等しい(==) 以下・以上(>= <=) 等しくない(!=) など、少し書き方が特殊
     
  • 結果はtrue(真)かfalse(偽)
条件式は、特定の変数や値が等しいか等しくないか、大きいか小さいかで定義します。イコールは等号が二つ、以上・以下は>=, <=など、ここでも数学とは少し違う書き方をします。

条件の書き方

if (digitalRead(13) == HIGH) //13番ピンがHIGH
 
if (analogRead(0) < 300) //アナログ0番が300「未満」
 
if (analogRead(0) <= 300) //アナログ0番が300「以下」
 
if (Serial.read() != 'a') //シリアル通信で来た文字がa以外

具体的には、このような書き方をします。Arduinoの場合はピンから入力した値を比較したり、シリアル通信で文字のやりとりを検証したりすることに使うことが多いくあります。

条件を満たさない時は「else」も使う

  • 条件を満たさなかった時に実行する処理
そしてこのif文には後ろにelseという構文を追加することができます。これは逆に「条件を満たさなかった場合」の処理を記述するブロックで「もし~ならこう、そうでなければこう」という場合分けを書く際便利な書き方です。

if (条件式){
  条件を満たした時の処理
}else{
  条件を満たさなかった時の処理
}

if文を使った例

  • if文を使うと複雑な動作も条件付けで実現できる
     
  • 0.5秒周期と、0.3秒周期で点滅するLEDを同時に制御するには?
if文を使うとどういったことができるようになるか。単純に考えると「インタラクティブな要素が作れる」というのが素直な結論ですが、それだけではなく色々な表現の幅が生まれます。
例えば0.5秒ごとに点滅するLEDをBlinkのサンプルに沿って作るとdelay関数を使いますが、ここへ0.3秒ごとに点滅するLEDも付けたいとなるとどうなるでしょうか。もう1個Arduinoを用意すればできますが、それは無駄なのでIf文を組み合わせてこんな感じに実現することができます。

void loop()
{
  if (millis() % 1000 < 500) digitalWrite(10, HIGH);
  else digitalWrite(10, LOW);

  if (millis() % 600 < 300) digitalWrite(9, HIGH);
  else digitalWrite(9, LOW);
}

for構文

  • 命令を少しずつ変えながら繰り返したい時に便利な構文
     
  • 繰り返す回数や条件を指定することができる
二つ目はfor構文です。これは繰り返しをするための構文です。loop()関数は電源が入っている限り繰り返されるようになっていますが、このfor構文は有限回繰り返したい時に便利な構文です。
for (int i = 0;i < 10;i++)
{
  /* 繰り返す処理 */
}
for文は初期化・繰り返し条件・ループ処理の3つをセミコロンで区切ってカッコの中に定義します。上の例ではiという変数を用意して、iが10未満の間繰り返すという条件になっています。ループの終わりまで到達すると「i++」が呼ばれてiの値が1増えます。

for文の書き方

for (初期化; 繰り返す条件式; カウント式)
 
for (int i = 0; i < 回数; i++) で覚えておくのが便利

カッコの中を日本語で書くとこのようになります。初期値を0以外にしたりカウントを++ではなく--にしたり、5ずつ追加するなど色々な応用が効きますが、はじめのうちはシンプルに特定の回数繰り返すものとして、int iから始まる書き方を覚えておくのが良いでしょう。i, j, K などを使うのが通例になっていますが、変数の名前は基本的に自由です。

初期値を工夫した用法

初期値を工夫して、変数iを有効活用する
 
for (int i = 9;i < 12;i++)
{
analogWrite(i, millis() % 255);
}

変数はループのカウンタとして使いますが、初期値や条件を工夫することで中の処理に活用することができます。
ただの繰り返しではなく、連続して変化する処理を複数行いたい時にはこのような書き方が便利です。

配列変数(array variables)

  • for文と組み合わせてよく使う「配列変数」
     
  • 複数の値を格納することが可能
そしてこのfor構文とセットで覚えたい「配列変数」を紹介します。
配列変数は同じ種類の変数をいくつも扱う時に便利なもので、変数名とインデックスの2つの要素があります。

変数の定義

  • float value; //通常の変数は一つの値を保持する
     
  • float arrValue[5]; //10個の数値を持てる配列変数
     
  • float arrValue[] = {10, 12, 15, 31, 35}; //こういう書き方も
通常の変数は宣言(変数を用意)するときに変数の種類と名前を定義しますが、配列変数の場合名前の後ろに[10](角括弧、bracket)という形で作りたい変数の数を記述します。最初に入れておきたい数が決まっている時は、3つ目のような書き方も可能です。

便利な「添え字」

  • 0から始まって、連続する
     
  • 角括弧の中の添え字は数字なので、変数などを使って呼び出せる
この角括弧の中の数字は「添え字」や「インデックス」という呼び方をして、変数XXの何番目の数かということを表しています。
少し注意したいのは、添え字は0から始まるということです。なので、arrValue[5]と定義した場合添え字に指定できる数は0~4までということになります。

使い方

  • 複数の数値をひとまとまりとして扱う
     
  • 配列の添え字とForループを組み合わせて使う
どういう使い方が便利なのかというのを実践を交えて解説していきます。
複数の数値をひとまとまりとして扱うときには便利です。例えばフルカラーLEDは赤・青・緑の三色を組み合わせて色を表現しますが、こういうものをコントロールするときは赤用の変数、青用の変数…と別々に用意するよりも、色用の配列変数として定義するのが効率的です。

int led_pin[] = {9, 10, 11};
int led_color[3];

void setup()
{
  for (int i = 0;i < 3;i++) pinMode(led_pin[i], OUTPUT);
}

void loop()
{
  delay(12);
  for (int i = 0;i < 3;i++)
  {
      led_color[i] = (sin(millis() / ((i+2) * 100.0)) + 1) * 128.0;
      analogWrite(led_pin[i], led_color[i]);
  }
}

演習

  • 回路:https://www.tinkercad.com/things/5l5dPsFDRzz
     
  • 梅:ダイヤルを途中まで上げると赤が光り、さらに上げるとオレンジが光る
     
  • 竹:ダイヤルを上げていくと順番に光っていく(数が多いのでFor文を使おう)
     
  • 松:ボタンを押したときに、LEDが順番にフラッシュする

梅の回答

ヒント:赤のLEDと橙のLEDをそれぞれIF文でコントロールしましょう。
analogRead(0)で値が取れるので、数値を使って光り方を変えていきます。

void setup()
{
  for (int i = 2;i <= 9;i++)
  {
    pinMode(i, OUTPUT);
  }
}

void loop()
{
  delay(12);

  //赤色が点灯する
  if (analogRead(0) > 300) {
    digitalWrite(2, HIGH);
  }
  else{
    digitalWrite(2, LOW);
  }

  //橙色が点灯する
  if (analogRead(0) > 1000) {
    digitalWrite(3, HIGH);
  }
  else{
    digitalWrite(3, LOW);
  }
}

竹の回答

ヒント:基本的な方向性は梅と一緒ですが、8個別々に記述していくと大変です。
できるっちゃできますが、For構文を使うとよりきれいに書くことができます。

void setup()
{
  for (int i = 2;i <= 9;i++)
  {
    pinMode(i, OUTPUT);
  }
}

void loop()
{
  delay(12);
  for (int i = 2;i <= 9;i++)
  {
    //光る境目の値(スレッショルド)をiを使って定義する
    if (analogRead(0) > i * 100) {
      digitalWrite(i, HIGH);
    }
    else{
      digitalWrite(i, LOW);
    }
  }
}

松の回答

ヒント:光るタイミングがスイッチに依存していて、かつそれぞれ独立しているので、LEDの状態を持っておくための変数を配列で持っておくと作りやすくなります。

int led_stat[8];

void setup()
{
  for (int i = 2;i <= 9;i++)
  {
    pinMode(i, OUTPUT);
  }

  pinMode(10, INPUT_PULLUP);
}

void loop()
{
  delay(12);

  //ボタンが押された時
  if (digitalRead(10) == LOW)
  {
    for (int i = 0;i < 8;i++)
      led_stat[i] = 0;
  }

  for (int i = 0;i < 8;i++)
  {
    //led_statは常にカウントし続ける
    led_stat[i]++;

    //led_statの値が特定の範囲になった時、LEDを光らせる
    if ((led_stat[i] > (i + 1) * 4) && (led_stat[i] < (i + 1) * 10))
    {
      digitalWrite(i + 2, HIGH);
    }
    else
    {
      digitalWrite(i + 2, LOW);
    }
  }
}

第四項 Arduino開発基礎

第四項 Arduino開発基礎

電子工作創作表現(2019/5/17)

スライドPDF

Messengerグループを作ります

比嘉さんの講義と同様に連絡用グループ作りました

https://m.me/join/AbZhVqUurvKr9_8u

休講のお知らせなど講義の連絡用に、FacebookのMessengerグループを作りました。
以下のURLから参加できますので、申請をお願いします。
Facebookアカウントを持っていない人でも、Messengerだけのアカウントを作ることができるので、アプリをダウンロードしてみてください。

今日の内容

  • Arduinoプログラミング
     
  • TinkerCADで開発のシミュレーション

TinkerCADで開発

  • 色々試したい時配線が大変
     
  • 簡単な部品を使ったシミュレーションができる
Arduinoの現物に色々配線をしていこうとするとそっちに時間が取られたり、回路に問題があるのかプログラムに問題があるのか分かりづらい事が多いです。
なので、ここから先Arduinoの開発に関する演習はこのTinkerCADを使ってやっていこうと思うので、ユーザー登録をしてみてください。

Arduino IDEができること

  • Arduioファミリ用のプログラムを生成する
     
  • シリアルモニタ/プロッタなどデバッグ機能
     
  • ライブラリ(特別な機能を搭載するためのプログラム)の管理
前々回から触っているArduinoIDEについて少しおさらいです。
ArduinoIDEはArduinoの開発に関わる色々な機能をひとつにまとめたソフトで、プログラムの作成と書き込みをしたり、シリアルモニタやプロッタで情報を見たりする機能がついています。
加えて、特殊な機能を使えるようになる「ライブラリ」と呼ばれるものの管理ができたりもします。

開発手順のイメージ

1.Arduino IDEでコーディング
 
2.コードをコンパイルしてバイナリに変換
 
3.変換したバイナリをArduinoマイコンに転送

開発のイメージはこんな感じで、私たちが英語に近い文章で書いたプログラムをArduinoのマイコンが理解できるデータに変換(コンパイル)し、USBを経由して転送しています。

開発言語について

  • ArduinoはC++という言語をベースにしている
     
  • 基本的な拡張子は.inoだが、.cppや.hも使える
コーディングの際記述する文のルールをまとめて「プログラミング言語」と呼びます。今は非常に多くの言語が存在していますが、ArduinoはC++という言語をベースに作られています。そして保存したファイルを「スケッチ」と呼び(この辺りはProcessingの系譜を継いでいます)拡張子は.inoを使いますが、C++がベースになっていて.cppや.hも使うことができます。

補足:C++ベースとは?

  • .inoはArduino IDEで変換されたあと、avr-g++に通される
     
  • .cpp/.cで記述されたものはavrのコンパイラに直接流し込まれる
C++ベースとはどういうことなのかという点ですが、コンパイル段階で色々なことをしています。.inoスケッチはArduinoIDEで改変されてからAVRコンパイラへと流され、main関数を含むmain.cppは別で用意されているものが一緒にコンパイルされます。
.cpp/.cで定義されたファイルはダイレクトにAVRコンパイラへ通されるので、Arduinoの改変をされたくない場合はこの拡張子を使うということになります。
参考:https://garretlab.web.fc2.com/arduino/introduction/compile_process/index.html

前回のプログラムをおさらい

code

https://www.tinkercad.com/things/4danaaOlAin
ではどのようなルールに基づいてプログラムを書いて行ったら良いのか、前回書いたコードを元にとっかかりとなる基本的な構造を説明していきます。

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

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

setupとloop

  • Processingから来ている基本構造
     
  • 1回のsetupと、半永久的に繰り返されるloop
プログラムというのは、下に向かって順番にコードが解釈・実行されていくものですが、プログラムの内容によってはその読んでいくラインがあちこちにジャンプします。

Arduinoにおいては、setupとloopという二つの「関数」と呼ばれるまとまりがベースとなっています。
setupは起動して一番初めに一度だけ処理される関数で、ピンの設定のような初めに決めておきたい事を書いていくブロックで、すぐ下の大かっこ{}で囲まれた部分がsetupの中身ということになります。

同様にloopの中も大かっこで囲まれた部分ですが、ここに書かれたことは一番下まで実行されるとまた先頭に戻って、電源が落とされない限り半永久的に実行され続けます。このsetupとloopの中にプログラムを書いていくのがArduinoの基本で、これはProcessingやOpenFrameworksのようなメディアアート系の開発環境によくある構造です。古くはProcessingの前身であるDesign by numbersから来ています。

関数と変数

  • 小さなプログラムのまとまりが「関数」
     
  • 関数名(引数){ 内容 }というフォーマットで定義される
setup・loopの事を関数と呼びますが、この中に記述する最も基本的な要素が「関数」と「変数」です。
前回出たdigitalWriteやdelayも関数の一つで、Arduinoが実現できる命令が色々な関数として定義されています。

関数の情報は「リファレンス」を見る

つまりArduinoで何かやろうとすると、どんな関数があるかを知らなくてはならないわけですが、公式のWebなどに細かな情報がまとめられています。こういったプログラミング言語などに定義された機能をまとめた情報のことをよく「リファレンス」と言います。
Arduinoの場合は公式で出されている英語と日本語のリファレンスがありますが、日本語は随時翻訳しているようでまだ情報が歯抜けになっているので(2019/05/17現在)英語のリファレンスを読むか、非公式のリファレンスなどを見るのが良いでしょう。

前回までに使った関数

pinMode(pin, mode)

digitalWrite(pin, value)

delay(ms)

実際に、前回までに使った関数をリファレンスで見てみましょう。

変数

  • 関数と同様に重要な「変数」
     
  • 中に数値や文字を保存しておいて、色々な計算ができる
関数と同じくらい重要な要素に変数があります。変数はデータを入れておく箱のようなイメージです。
入力したデータを一時的に保存しておくことができるので、複雑な計算や複数の項目に同じパラメータを使いたい時などに有用です。

数学と少し違う「演算子」

" + - * / "という数学の記法とは少し異なる演算子を用いる
 

四則演算のほかにも%(余剰) ^(累乗)やビット演算子のような特殊な演算子も

プログラムに使うのは基本的に半角英数字なので、×や÷のような記号が無く、通常の四則演算しとは少し異なる記号を使って計算を表現します。Arduinoで用いる演算子はC++に準拠していて、余りや累乗のような演算子も使うことができます。

また補足ですが、パソコンと違ってメモリや処理速度に限りがあるため、大きなプログラムになるとデータの節約が必要になります。そういった際には2進数で保持されている数字を直接操作する「ビット演算」が役に立つので、より高度な制御をやりたいと思っている人は覚えておくと良いでしょう。

演習

梅:LEDが赤・緑・青と1秒ずつ順番に点灯していって、同時に消えるのを繰り返す

竹:電位差計のメモリを操作すると、点滅する速度が変化

松:全消灯~全点灯までの8通りの組み合わせを、int型の変数pattern1つで表現する

最後に、簡単な演習を用意したので梅から順にチャレンジしてみてください。

演習の正解例と解説

以下演習の正解例と解説です。あくまで正解例であり、書いてある要件を実現する方法はほかにも色々な書き方があると思います。

梅編

お題:LEDが赤・緑・青と1秒ずつ順番に点灯していって、同時に消えるのを繰り返す

delayで時間を区切りながら、digitalWriteで光らせたいところ、消したいところを記述していきます。
最後は同時に消えてほしいので、delayを挟まず三つのdigitalWriteを続けて書けばほぼ(人には知覚できない速度で)同時に消灯されます。
void setup()
{
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT); 
}

void loop()
{
  delay(1000);
  digitalWrite(9, HIGH);

  delay(1000);
  digitalWrite(10, HIGH);

  delay(1000);
  digitalWrite(11, HIGH);

  delay(1000);
  digitalWrite(9, LOW);
  digitalWrite(10, LOW);
  digitalWrite(11, LOW);
}

竹編

お題:電位差計のメモリを操作すると、点滅する速度が変化

delayの値に変数を使ってみます。
analogRead(0) + 100という値を入れることで、点滅する感覚が100ミリ秒~1123ミリ秒の間で推移します。

秒数指定が中途半端で気持ち悪いと思ったら、map関数を組み合わせると簡単に範囲を変えることができます。リファレンスで調べてみましょう。
int interval;

void setup()
{
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT); 
}

void loop()
{
  interval = analogRead(0) + 100;

  delay(interval);

  digitalWrite(9, HIGH);
  digitalWrite(10, HIGH);
  digitalWrite(11, HIGH);

  delay(interval);
  digitalWrite(9, LOW);
  digitalWrite(10, LOW);
  digitalWrite(11, LOW);
}

松編

お題:全消灯~全点灯までの8通りの組み合わせを、int型の変数pattern1つで表現する

複数のフラグを1バイトの変数にまとめておく手法は、マイコンなどPCを使わないデバイスではよく使われる手法です。ここでは3つのLEDの状態をint型変数の最後3ビットからそれぞれ取得することで、0~8までの数字をLED点灯パターンの組み合わせとして使っています。
int pattern = 0;

void setup()
{
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT); 
}

void loop()
{
  delay(1000);
  pattern = pattern + 1;

  digitalWrite(9, pattern & 0x1);
  digitalWrite(10, pattern & 0x2);
  digitalWrite(11, pattern & 0x4);
}

第三項 アクチュエータの基本

第三項 アクチュエータの基本

電子工作創作表現(2019/5/9)

スライドPDF

評価について

  • 前期・後期で1度ずつ提出の課題
     
  • 出席も参考程度にとります
初回の時にふわっとしか話せておらず、前回質問されたので改めて書いておきます。
成績については前期と後期で1回ずつ簡単な課題を出そうと思っています。
課題メインですが、出席も一応取ります。

今日の内容

  • LEDを使って、Arduinoからのデジタル/アナログ(PWM)出力
     
  • ピエゾスピーカーで簡単な発音
     
  • 各部品について解説

アクチュエータ=出力部品について

  • センサーは現実で起きていることを「数値」に置き換える装置
     
  • アクチュエータはその逆で、数値を何らかのエネルギーとして出することができる
前回のセンサーに続き、今回はアクチュエータをいくつか触ってみようと思います。
センサーは起きている事を数値=電気信号に置き換える装置であるということは前回話しましたが、アクチュエータはその逆で、電気エネルギーを別のエネルギーに変換するための装置です。

アクチュエータの例

  • LED
  • スピーカー
  • モーター
代表的なものとしてはLED・スピーカー・モーターなどです。
LEDやスピーカーは小さいものならArduinoから簡単な制御ができるので、今日はこの2つを実際に触ってみますが、その前に先週の復習も兼ねてArduinoについてもう少し詳しく解説していこうと思います。

Arduinoの「ピン」

Arduino

  • アナログ入力ピン
  • デジタルピン
  • 電源・GNDなどその他システムピン
前回も使ったArduinoの黒いソケット部分ですが、穴のひとつひとつを「ピン」と呼びます。中には金属のバネが入っていて、これが回路を通じてArduinoのマイコンと電気的に繋がっています。

ピンにも種類があるのですが、大きくアナログ入力ピン・デジタルピン・その他のピンに分けて説明します。

アナログ入力ピン

Arduino

  • UNOではA0~A5までの6本
  • 0~5Vまでの電圧を0~1023まで
まず前回使ったアナログピンですが、これはUNOの場合A0からA5までの6本のピンがあって、同時に使うことができます。

0~5Vまでの電圧を0~1023までの1024段階で計測することができます。

補足

  • 電圧の高さは、基準電圧によって決まる。デフォルトでは5V
     
  • AREFピンとanalogReference関数でより低電圧で細かい入力も可能
ちなみに補足すると、5Vというのはデフォルトの値なのでここは変更することが可能です。(5V以上には設定できない)
AREFピンに基準となる電圧を加えて、analogReference関数で設定を変更することで例えば0~1Vの範囲を1023段階で刻むなど、より細かいパラメータを見ることができるようにもなります。

デジタルピン

Arduino

  • デジタルピンは「入力」「出力」両方できる
     
  • 入出力とも0(=0V)か1(=5V)の二種類しか区別することができない
     
  • なんちゃってアナログ出力「PWM」が使えるピンがいくつかある
そして今日使うのが、13本あるデジタルピンです。アナログピンは入力だけなのですが、デジタルピンは入力と出力を切り替えて使うことができます。
 
このデジタルピンは0か1の2種類の状態にしかなれません。出力はArduinoの場合、0Vか5Vを出す事ができ、入力の場合は、2.5V周辺を境目に、それより高いか低いかで0か1の数値を取ることができます。

なので微妙な変化を取ることは難しいですが、スイッチを使う時なんかは6個しかないアナログ入力ピンを使わずにデジタル入力ピンを使えば良いわけです。

そしてこのデジタルピンには番号にチルダ(~)が付いているものもあります。これらのピンには「PWM」という技があって、コレを使うと「アナログ出力っぽい」ことができるのですが、それについては後述します。

その他のピン

Arduino

  • 外部の部品に電源を供給したい時に便利なVIN/GNDピン
     
  • RESET・AREF・IOREF
     
  • TXD・RXDはなるべく使わないようにするのがオススメ
最初のうち主に使うピンはデジタルピンとアナログピン、そしてPOWERと書かれている電源ラインのピンになってくると思います。
VIN/5V/3V3はそれぞれ所定の電圧が出ているピンです。5Vはそのまま5V、3V3は3.3Vの事で、VINは電源のプラスに直結していますが、USBを使っている限りはここからも5Vが出ています。

RESETピンはArduinoのプログラムを最初からやり直すためのピンで、自動で再起動させたい時などに使います。AREFは先ほど補足したピンで、IOREFはデジタル入力の基本電圧5Vが流れているだけなので、殆ど使う事はないでしょう。

あとは0番・1番ピンを見るとTXD・RXDと書かれたピンがあります。これはデータ通信用のピンでUSB側とも繋がっています。ここを埋めてしまうとプログラムを書き込めない場合があったりするので、使うピンが少ないうちは使わない方が何かと便利です。

補足

  • ArduinoUNOはUSBじゃなくてもACアダプタから5~12Vの電源でも動作可能
     
  • VCCが電源電圧、5V3Vはレギュレータに繋がっている
VINについてもう少し詳しく説明すると、ArduinoにはUSB以外に外部のACアダプタを接続するポートがついていて、こっちの電源で動作できるようにもなっています。電源からきた電圧は一度レギュレータと呼ばれる部品によって5Vまで落とされてArduinoのCPU部分に供給されるようになっています。

こちらは推奨最大12Vまで突っ込めるようになっており、高い電圧で動くモーターのような部品を1つの電源で動かしたい時などはこっちを使うと便利です。その場合5Vピンからは5V、VINピンからは12Vが出てくるということになります。

LEDを点灯してみる

Arduinoの画像

結線&書き込み

それではLEDを点灯させてみようと思います。
図のように結線をしたら、以下のコードを記述して前回同様Arduinoにアップロードしていきます。
1秒ごとにLEDが点滅したら成功です。

digitalWriteというのが、デジタル出力をするための「関数」と呼ばれるものです。
Arduinoのプログラムについては次回じっくりやっていこうと思っていますが、ここではdigitalWriteの後のカッコに命令の詳細を書いていて、「9番ピンをデジタル出力のHIGH/LOWにする」という意味を持っています。HIGHの時には9番ピンの電圧が5Vに、LOWの時は0Vに変化します。

その次のdelayというのはディレイ=遅延という意味で、指定した数値のミリ秒分何もせずにプログラムを停止させます。ここでは1000ミリ秒な1秒止まってはHIGH、1秒止まってはLOWという具合に切り替えることで、LEDの点滅を繰り返しています。

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

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

PWM出力をしてみる

デジタルピンからPWM出力を試す

点滅だけでは少し味気ないので、先ほど少し触れたPWMを使ってもう少し気の利いた表現をしてみましょう。今のスケッチは後で使いたいので、好きな名前で保存しておいてください。

保存したら新しいスケッチを立ち上げて、今度は以下のようなコードを書きます。少しかっこの数が多いので注意しながら書いてみてください。

正しくコーディングできると、LEDがふわふわと点滅します。

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

void loop()
{
    analogWrite(9, (sin(millis() / 300.0) + 1) * 128);
}

PWM出力は仮想のアナログ出力

  • Pulse Width Modulation(パルス幅変調)
     
  • デジタルのHIGHとLOWを高速に切り替えて、間を表現している
     
  • 漫画のトーンに近いイメージ
digitalWriteの時は消えてるか点いているかハッキリしてましたが、今度のプログラムではanalogWriteという関数を使いました。これは0~255の数字を指定すると、0~5Vの中間の電圧を指定できるものです。ここでは、Arduinoのプログラムが実行されてからの時間millis()関数と、三角関数であるサイン関数を使って0~255の間を上下するようなプログラムを書いています。

これはPWM(パルス幅変調)という方式で、デジタルのHIGHとLOWを目に見えないスピードで高速に切り替えながら、その割合を変化させることで中間の電圧がかかっているように振る舞うというものです。iPhoneのハイスピードカメラで見ると、チラつきが見えたりします。

漫画のスクリーントーンを想像してもらうと分かりやすいと思います。漫画雑誌の印刷は通常白か黒の2色だけで印刷しているのですが、黒をものすごく細かくまばらに点在させることで見せかけのグレーを表現しています。それと同じで、HIGH=5Vにしている時間をまばらにすることで「見せかけの低電圧」を作っているということです。

PWMはケース次第で使えない

 

  • 綺麗な「アナログ出力」はコストが上がる
     
  • PWMではないアナログ出力はDACと呼ばれる
そのため、LEDなどで諧調のある表現をする分には問題ないのですが、スピーカーやモーターなど一部の部品についてはこのPWMでは都合の悪い場合が出てきます。なので厳密な原理はまだそこまで理解しなくても大丈夫ですが、あくまで「それっぽいアナログ出力」として認識しておいた方が良いでしょう。

補足:何故こんな回りくどいやり方をするかというと、基本的にデジタルの世界であるマイコンでアナログ電圧を出力するというのは地味に部品数が多くなって、コストがかさむ傾向があります。ケース次第で使えないといいつつ、大抵のことはPWMで十分対応ができるので、アナログ出力はデジタルピンでPWMしてくださいよ、ということになってるんですね。

ちなみにPWMではなく純粋なアナログ電圧を出力する方法はDAC(Digital-Analog-Convert)と呼ばれます。DAWをやってたりすると聞く言葉かもしれません。電子工作ではこのDAC専用のICをArduinoと通信させて扱うというような事ができるので、それもいずれ解説していこうと思います。

圧電スピーカー

Speaker

同様にスピーカーも試してみます

同じように、スピーカーも試してみましょう。先ほどと同じように9番ピンとGNDに、圧電スピーカーを接続します。スピーカーの場合抵抗は必要ありません。

LEDの時に保存したプログラムを再利用しますが、delayの値2か所を1000から1に変更します。とても簡単な方法ですが、圧電スピーカーから矩形波が出てきます。delayの値を変えると周波数が変わるので、音程が変わってきます。

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

void loop()
{
    digitalWrite(9, HIGH);
    delay(1);
    digitalWrite(9, LOW);
    delay(1);
}

部品解説

  • カーボン抵抗
  • 圧電素子
     
  • LED
前回説明を省略してしまったカーボン抵抗とLED、圧電素子について説明しようと思います。

抵抗について

  • 地味だけどよく使う「抵抗器」 一般的なのは「カーボン抵抗」
     
  • 原則、部品には抵抗を付ける。流れる量は「オームの法則」で決まる
     
  • I = V / R  (電流=電圧÷抵抗)
電子部品の多くは、単体では殆ど抵抗が無い(0ではない)ように作られています。回路に流れる電流は電圧(V) / 抵抗値(Ω)で決まるので、そのまま電源やICに直結すると大量の電流が流れてしまいます。

条件によって流したい電流は変わってくるので、その都度必要な電流を流すための抵抗値を差し込んであげる必要があります。

直結について

direct

  • LEDを直結した図もたまにあるが、よくは無い
     
  • GNDに向かう線は、原則一度は抵抗があるようにする
まれにArduinoにLEDを直接差してる図や写真があったりしますが、あまりよろしくありません。

最近のLEDが多少電流を多く流しても壊れにくくなったというのと、オームの法則とは別にArduinoのデジタル出力からは20mAしか流せないという条件からこういうことが出来てしまうのですが、LEDとArduino両方の寿命を縮めることになります。

GNDに向かっていく線をたどった時には原則として抵抗が存在しているように回路を組みましょう。(例外として抵抗内蔵型のLEDというのもあって、直接差して大丈夫なものもあります)

圧電(ピエゾ)素子

  • 電圧をかけると形が変化する薄い膜状の素材(水晶など)が使われる
     
  • この素材が、スピーカーのコーンに当たる役割を持っている
続いてスピーカーとして使った圧電素子について。これは電圧をかけると形が変化する膜状の素材が使われていて、それがコーンの代わりになって音を出すことができます。

そのためあまり繊細な表現はできませんが、簡単な電子音を鳴らすブザーなどによく使われています。

ピエゾは電流が流れない

  • 電圧で押し込むようなイメージ
     
  • コンデンサなど「電流が流れない」部品も一定数存在する
     
  • 一般的なスピーカーはこの限りではない
先ほど回路には原則抵抗を入れるという話をしましたが、ピエゾには抵抗を入れませんでした。
これは何故かというと、ピエゾの線には電流が流れず、電圧が加わるだけで形が変化するためです。

このように電流が流れない部品も一部あって、コンデンサなどが代表的な例ですが、そういう時には特に抵抗が必要ない場合が多いです。入れても動きます。

ただし気を付けたいのが一般的なコーンの入っているスピーカーは全く違う原理で動くためこの限りではないので、電流のコントロールは必須です。

LEDについて

  • Light Emitting Diode(発光ダイオード)の略
     
  • 電流の入り口「アノード」と、出口「カソード」がある
     
  • 電球と違い流れる方向は一方向
LEDは今や電子部品に限らず照明としても超定番の素子です。白熱電球や蛍光灯よりも少ない電流でより明るい光を出す事ができて、発熱も少ないので寿命も長いためです。

元々「ダイオード」という電気を一方向だけに流すための部品があったのですが、その性質を応用して発明されたので「Light Emitting Diode=LED」という名前がついています。

ダイオードなので電源側を接続する「アノード」と、GND側に接続する「カソード」があります。今日使った砲弾型のLEDの場合は大抵片方の線が長くなっていて、長い方がアノードというのが定番になっています。

補足:足の長さで分かるようになっているので、配線の都合で切ってしまったりすると分からなくなることが多くありますが、そういう時は中の金属部分を見ると分かることがあります。素子の小さい方がアノード側になっていることが多いので、大量に切って使ったりする時は参考にすると良いでしょう。

LEDの種類

  • 色や形で非常に多くのバリエーションがある
     
  • 大量に制御したい時にはNeoPixelことWS2812が便利
今日使ったのは単色の青色LEDでしたが、当然色々なLEDがありますし、1個の樹脂に3色のLEDが封入されたフルカラーLEDというのも存在します。

1個あたりの値段が100円しないものも多くあるので、色々買って試すだけでも楽しいと思います。

LEDをたくさん使ってコントロールしたい時に便利なWS2812、通称NeoPixelと呼ばれるLEDがあるのでそれの制御についても解説しようと思います。

次回予告

  • Arduino IDEのコーディングについて
     
  • TinkerCADを使ってやってみます
次回ですが、ArduinoIDEのコーディングについてやっていきたいと思います。
ソフトウェアが中心になるので、TinkerCADを使ってみようと思います。TinkerCADを使うにはアカウントの作成が必要なので、前もって登録しておいてもらえると助かります!

第二項 Arduinoとセンサー入力の基本

第二項 Arduinoとセンサー入力の基本

電子工作創作表現(2019/4/25)

スライドPDF

Arduinoに触る

http://sheep-me.me/media/IMG_1635.jpg

  • 電子部品を手軽に扱えるようにするツール
     
  • もっとも基本的なのがArduino UNO(左側)
     
  • たくさんの種類がある
今日から実際に電子部品に触っていこうと思いますが、そのために必用なツールArduinoについて紹介します。ワンボードマイコンと呼ばれる電子基板のことで、電子部品でやれる基本的なことは大概これにプログラムを書き込むことですぐ実現できるようになっています。

Arduino UNOと呼ばれるものが一番ベーシックなタイプです。よく似たものにLeonardというものがありますが、最初のうちはUNOを使う事をおすすめします。

込み入った話しをすると、UNOが使うATmega328PではなくATmega32u4というチップを使っていて、これはUSBホストとして振る舞えるのでマウスやキーボードとして動作させたり、UARTというシリアル通信ポートがUSB以外にも付いていたりとちょっとだけ違います。込み入ったことをやり始めるとハマったりすることがあるので、まずはUNOで練習するのが良いでしょう。

他にもたくさんの種類があります。メインストリームのUNOはこの前にいくつもバージョンアップを重ねていて、生産終了したものではDuemilanoveやDiecimilaという物があります。もともとイタリアで産まれたプロジェクトなので、イタリア語がよく使われています。

他のArduino - Arduino nano/micro

Arduino nano

小型のArduino。小さい空間に使ったり、ウェアラブルデバイスにも便利

用途別のラインとして開発されているものもあり、Arduino nanoはUNOを小型化したタイプ、Arduino microはLeonardを小型化したタイプとして位置づけられています。小さなデバイスやウェアラブル用途に向いています。

他のArduino - Arduino mega

Arudino mega

大型で入出力が多いArduino MEGA

他にはArduino megaという、電気を入出力するチャンネルがたくさん付いたバージョンもあります。作品によってはArduino UNO/Leonardで実現しにくい事もあるので、こういったシーンに応じて使い分けができるというのも頭の片隅に置いておくと良いと思います。

Arduino IDE の基本画面

http://sheep-me.me/media/01-ide.png

ArduinoIDEを起動すると、このような画面が出てきます。IDEとは統合開発環境(Integrated Development Environment)のことで、ようはこのソフトの事を指します。ソフトを指して「Arduino」と言ったりすることもありますし、それで通じる事もありますが、ここでは基本的に本体をArduino、PC上で動くソフトの事をArduino IDEと表記します。

Arduinoはここにスケッチと呼ばれるプログラムを書いていって、最終的にUSB経由で書き込む事で目的の動作を実現します。一度書き込んだプログラムは基本的にはArduinoの中に残ったままになるので、ArduinoIDEを閉じてもArduinoの中でプログラムは動作し続けますし、USBを差し直せばまた最初からプログラムが動作します。

サンプルのプログラムBlink

http://sheep-me.me/media/01-blink.png

試しに、プログラムをArduinoに書き込んでみましょう。メニューのファイル>スケッチ例>01.Basics>Blinkを選択すると、新しいウィンドウが開き、プログラムのサンプルが読み込まれます。このスケッチ例には、色々なプログラムのサンプルが登録されているので、コードが読めるようになると、Arduinoにどんな機能が備わっているか、特定の機能を実現する時にどんなコーディングをすれば良いか、知ることができます。

プログラムを書き込む

プログラムを書き込む

読み込んだコードを実際にArduinoに書き込みます。ツール>シリアルポートを選んで、書き込むデバイスを選択します。シリアルポートというのはPCが外のデバイスとやりとりする出入り口のようなもので、英語だと「港」という意味です。PC本体が陸地だとすると、データがやりとりされる港のようなものなので意味を覚えておくと理解しやすいかもしれません。

シリアルポートの中に(Arduino/Genuino Uno)という表記があれば、それを選択します。表記が出ない場合は、Arduinoを抜くと消えるポートが出てくるので、それがArduinoのポートだということが認識できます。Macの場合ttyとcuから始まる物があるかもしれませんが、どちらを選択しても構いません。

それとその上の「ボード」も確認します。どのタイプのArduinoに書き込むかという事を明記する必要があります。

書き込み&実行

書き込み・実行

設定ができたら、矢印マークの書き込みボタンを押すと書き込みがされます。しばらく下の領域に文字がつらつらと流れた後、日本語だと「ボードへの書き込みが完了しました。」と表示されます。こうなると書き込み成功です。

”Lチカ”

Lチカ

正しく書き込まれていると、基板の上の方にあるLEDが1秒おきに点滅します。これでArduinoにプログラムを書き込む手はずは整ったので、実際に電子部品を扱ってみようと思います。

センサー(入力)とは

現実で起きている出来事を、プログラム上の「数値」に置き換える

まず最初は「センサー」を扱おうと思っています。センサーと言う言葉はわりとどの言語圏の方も馴染みあると思うのですが、電子回路においては、現実に起きていることをプログラムの中の数値に直して扱うという考え方です。

明るさセンサーを読み取る

フォトトランジスタNJL7302L-F5

秋月電子で1個50円

フォトセンサ

実際に明るさセンサーNJL7302L-F5(http://akizukidenshi.com/catalog/g/gI-08700/)を使って、センシングまでの流れを追ってみます。ちなみに光センサにはフォトトランジスタの他にCdsセルというのもありますが、こちらは硫化カドミウムという有害な物質を含んでいるので最近はあまり使われなくなっているようです。

ブレッドボードに配線

circuit

ブレッドボードにセンサーを差し込み、Arduinoと接続していきます。(TinkerCadの都合上光センサが白いです)ブレッドボードは隣り合って並ぶ穴が電気的に中で繋がっている板になっていて、部品を差し込んでいくだけで回路が作れる便利グッズです。

フォトとランジスタには極性があるので注意してください。赤い線とつなぐのは、少しだけ足が長いコレクタ(=電気を集めるのでCollect)、緑の線とつなぐのは短い方のエミッタ(=電気を放射する、発するのでemit)です。

プログラムを入力

接続が終わったら、このようにコーディングします。A0ピンに送られてくる電気の電圧を計測して、USBから数値を出力するプログラムです。

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

void loop() {
  Serial.println(analogRead(0));
  delay(12);
}

シリアルモニタ

monitor

プログラムの書き込みができたら、ツール>シリアルモニタか、画面右上の虫眼鏡マークをクリックして、シリアルモニタを開きます。シリアルモニタはUSB経由でデータをやりとりするためのもので、Arduinoのプログラムから送信されたデータを表示してくれます。

通信速度を先程コードで書いた数値と同じ115200に設定すると、数値がたくさん流れてきます。この状態でフォトトランジスタに手をかざして、数値が変化すれば成功です!

シリアルプロッタ

値の確認に便利なシリアルプロッタ
 

シリアルモニタと同時には起動できないが、シリアル通信で流れてきたデータをグラフにしてくれる

plotter

そしてもう一つ便利なシリアルプロッタという機能があります。これも一度シリアルモニタを閉じてからツール>シリアルプロッタと押すと出てきて、先程の数字を自動的にグラフで表示してくれます。

数値の変化を直感的に読み取ることができるというのと、センサーの微調整や複数の値を比較する時に重宝します。

アナログの値を図る回路

アナログ入力をする時の基本形

circuit

Arduinoで値が取れたところで、回路に戻りましょう。
ワイヤーで3本の線をつなぎましたが、線が2本ある部品の場合、多くがこのような形で配線をします。一方を電源(プラス)、もう一方を抵抗を介した状態でグラウンド(マイナス)に接続し、部品と抵抗の間から線を伸ばしてそこの電圧を図るという形です。

構造が単純なセンサーの多くがこのような電源・グラウンド・Voutの3線式の形を取っているので、この図を頭の隅に置いておくと今後色々と便利になると思います。

抵抗が変化するタイプのセンサー

  • 光量・温度等センシングする条件によって抵抗値が変わる
     
  • 「分圧回路」を作ってあげてセンサーで読み取る
光センサのように線が2本出ているタイプというのは、前の画像の回路のような分圧回路を作ってあげることで、Arduino等のマイコンで値の変化を読み取ることができるようになります。

フォトトランジスタはトランジスタの構造を持っているので少し特殊ですが、他多くのセンサーは、条件によって抵抗値が変わる仕様になっています。

モジュールになっている3線式のセンサー

  • Vcc・Vo・GNDがあらかじめパッケージされて出ているので、接続が楽
     
  • 電圧ではなくデータを送信する場合もあるので注意(センサー応用編で解説します)
また、この回路があらかじめ組まれている親切なタイプのセンサーも販売されています。
例:
 磁気センサー(http://akizukidenshi.com/catalog/g/gI-11029/)
 距離センサー(http://akizukidenshi.com/catalog/g/gI-02551/)

このように必要な機能がある程度組み込まれたものを「センサモジュール」とか「パッケージ」とか言ったりするのですが、このパッケージの中に先ほどのような回路が組み込まれているので、Arduinoから利用する時は出ている3本線をつなぐだけでセンサーの値を取ることができます。

ただし、同じ3線式でも電圧の上下ではなくデジタルの信号を送信してくるタイプもあるので、自分でセンサーを買って試してみる時にはデータシートをよく読んで確認してください。そのようなタイプのセンサーの使い方は、また後の講義で解説します。

データシート

  • 部品の使い方など細かい情報は「データシート」を読むと分かる
データシートという言葉が出てきましたが、これは部品に関する情報がまとまった、いわゆる「取扱説明書」のようなものです。例えば先ほどの光センサは、秋月電子通商のWebサイトで確認することができます。(http://akizukidenshi.com/download/ds/jrc/NJL7302L-F5.pdf)

「XXセンサ Arduno 使い方」などで検索すると、たいていの物は丁寧な解説ページが出てきたりもするんですが、そういう方たちはじゃあどこで情報を得ているかというと、部品メーカーが制作しているこのデータシートが基準になります。

白黒で専門用語だらけですし、モノによっては全て英語だったりするのですが、このデータシートをしっかり読めるようになると自分の目的に合った部品を選定できるようになるので、色々なパーツを試してみたい人は頑張って読めるようにしておくと良いと思います。

電子部品屋さんについて

  • 電子部品と言えば秋葉原だが、最近は通販も充実
     
  • アマゾンにも色々売っているが、データシートのような情報は部品屋さんが充実
自分でも部品を色々買いたいとなったら、電子部品屋さんで購入するのがおすすめです。秋葉原はすっかりアニメカルチャーの街になってしまいましたが、それでも昔ながらの電子部品屋さんがたくさん残っています。

秋月電子のようにメジャーな電子部品屋さんだとだと、実店舗と通販を両方やっています。こういう所で買っておくと、普段は通販を使いつつ急に必要だったりした時に買いに走れるというメリットもあります。

アマゾンも最近は色々な部品が売られたりしているのですが、製品の情報が薄かったり怪しかったりするので、単純な部品以外は少し注意して購入するのが良いでしょう。

店舗情報

秋月電子通商

千石電商

マルツパーツ

スイッチサイエンス

第一項 電気と安全

第一項 電気と安全

電子工作創作表現(2019/04/19)

第一項では、実際に電子部品に触る前に
電気と安全についての基本的な概念を確認していきます。

電気の基礎知識

「電気の正確な知識」ではなく「便利な概念」を習得する

まず電気について。小中校と理科や物理で、さらに生活の中でなんとなく概念は分かってると思いますが、ここではもう少しだけ掘り下げて「物理的に正しい電気の正確な知識」ではなく「電気を道具として扱う上で便利な概念や考え方」という視点で、少し噛み砕いた言い方でポイントを抑えながら電気というものについて説明して行こうと思います。

電気とは?

電気力・電気伝導など、種々の電気現象のもととなるもの。多く、電荷・電流または電気エネルギーをいう。(大辞林 第三版)

→電気というものがあるわけではなく、"電子"が流れている現象周辺の事を指す

電気とは何ぞやと辞書を引いてみると、このように書いてあります。何でこんな書き方かというと、電気という物体そのものは存在していないわけで、実際は電子と呼ばれる素粒子の一種が流れる事によって起きる現象やその状態の事を広く「電気」と呼んでいるわけです。

しかし電子工作で電気を使う立場としては、あまりここの正確さは重要ではないので、軽く触れるだけにしておきます。

電気の使い方

力としての電気と、情報としての電気がある

電気を「使い方」という視点で見た時に、力としての電気と、情報としての電気というふうに大きく2つに分けることができます。

力としての電気

電気のエネルギーを他の有用なエネルギーに変換する

→光らせる・温める・動かすetc...

→規模が大きくなると、強い電気が必要

力としての電気というのは、電気エネルギーを変換して光らせたり、温めたり、動かしたり何か他のエネルギーにするという使い方です。
例:電灯・ヒーターの電熱線・モーター

情報としての電気

流す電気のパターンに意味をもたせるもの

→基本的には弱い電気を流す

情報としての電気というのは、電子部品同士や機械同士の間で、情報をやりとりするための電気です。電気信号とも言います。
身近な例ではオーディオケーブルや映像ケーブルに流れる電気がそれにあたります。
ここで使われる電気は、基本的に弱い電気を使っている事が多いです。

電気の強さ

電気の強さ電力(Watt)=電圧(Volt) X 電流(Ampere)

強い電気、弱い電気という言葉が出てきましたが、電気の強さは電力とも言い、数字で表されます。
単位はワットで、電圧と電流をかけたものが電力になります。
この電圧・電流というのはこれからよく使うものなので、言葉と違いをよく覚えておいてください。

電圧

電気を流そうとする強さ。単位はボルト

3.3/5/9/12/24Vなど、良く使われる電源電圧は決まっている

電圧というのは電気を流そうとする強さのことで、何か回路を作る時には、何ボルトの電圧を流すか決める必要があります。大体よく使われる電圧はいくつかの数字に決まっていて、USB機器に流れている電圧は5Vで動くのでArduinoも5Vで動作する設計になっています。

電流

回路に流れる電子の量。

→ざっくりと言うと「回路が消費する電気の量」

電流は、回路に流れる電子の量を表します。これだけだとナンノコッチャですが、電子回路を作るシーンにおいては、まず電圧の方が決まっているので、この電流というのが「その回路が消費する電気の量」と思っておくと大まかな感覚としては間違いないです。

例えば日本の家庭用電源は契約によって20Aとか30Aとかだったりしますが、電圧は全国で100V統一です。つまり20Aなら20Ax100V=2000Wまで使えるということになるので、同時に使う家電の総量がここに収まるよう計算すれば、ブレーカーによる停電を防ぐことができます。日常使う家電なんかは数十ワットで収まりますが、電子レンジなんかは1台で1000w使ったりするので、レンジでブレーカーが落ちる理由がよく分かると思います。

まとめ

  • 電気の使い方には「力として」と「情報として」の使い方がある
  • 電力(電気の強さW) = 電圧(電気を流す力V) x 電流(消費する電気A)

安全の基礎知識

続いては安全についてです。電子工作も、理工学系ではなくこういった芸術系の大学で教えるくらい間口が広く扱いやすい存在になったわけですが、その分安全面には一層注意を払わなくてはなと考えています。

作品制作と発表における危険

  • 作る時の危険
  • 見せる時の危険
作る時の危険と、見せる時の危険についてそれぞれ気をつける必要があります。

作る時の危険

  • 道具を正しく使う(1メートルは一命取る)
  • 電子工作で起こる危険は後述
作る時に気をつける事の基本は「正しく道具を使う」と同義です。
特に慣れている道具ほど気をつけなくてはいけません。「1メートルは一命取る」という安全標語があるように、大丈夫そうに見えてしまう状況が一番危険です。

見せる時の危険

  • 日々使う電化製品は、ものすごく厳しい安全基準をクリアしている
  • 自分が大丈夫でも、年齢・性別・文化などで安全性は変わる
私達が日常使っている電気製品には数多くの安全基準が課されています。普段何の苦労もなく使えているので、つい自分で作るデバイスを他の人が使ったり体験するようなシーンについては、そういった危険性を見落としがちです。

また、自分が体験して安全だったとしても、他の人にとっては危険ということもあります。強くて早い光の点滅がだめな人(子供は特にNG)や、暗い空間で心臓の鼓動のような音を聞くのが苦手な人もいます。

最近では2眼式のVRゴーグルを7~10歳以下の子供に体験させると眼球や視野の発達に影響を及ぼすのではないかという事が議論されています。(Oculusは13歳、Nintendo labo VRは7歳からなど)目新しいデバイスや、まだ多くの人が体験していないような装置にはそういった未知の危険性が潜んでいることもありますので、しっかりとリサーチをするなどより注意が必要です。

電子工作で起こりうる危険

  • 発熱
  • 発火
  • 感電
ここまで一般的な展示やパフォーマンスにおける安全性についてでしたが、電子工作で起こりうる危険について少し掘り下げてみようと思います。

発熱

  • 全ての部品は発熱する
  • 熱が溜まると、部品の溶融や発火につながる
  • ヒートシンクや空冷で「冷やす」
まず発熱ですが、ほんのり温かくなる程度や、触っただけでは分からないレベルも含めると基本的にほぼ全ての電子部品は大なり小なり発熱をしています。
導体には流れてくる電流を抑える抵抗という性質があるのですが、この抵抗によって熱が生じます。(摩擦熱のようなイメージ)

発生した熱は空気に触れたりすることで放熱されますが、放熱より発熱する量の方が多い時、温度が上がり続けて素子が壊れたり、周りのものを溶かしたり焦がしたり、最悪の場合燃やしてしまいます。

追々詳しく説明しますが、基本はファンやヒートシンクで「冷やす」ということと、そもそも発熱するのがおかしい場合は回路や使っている部品を検証し直すなどの対策が必要になります。

発火

  • 発熱及び放電+可燃性物質
  • 燃えやすい物は、とにかく離す
続いて発火です。これは発熱で可燃性の高い物質が熱せられる事で火が出る、というのが一番わかりやすいパターンです。電気が流れているもののそばに燃えやすい物をとにかく置かないというのが大原則です。

東京デザインウィークで投光器から出火して5歳の男の子が亡くなるという痛ましい事故がありました。あれも照明自体は通常使用で出る発熱量ですが、そこに燃えやすいおがくず状の木材が密着されていた事が原因の一つです。また、可燃性のあるガスうや液体については熱が出ていなくとも静電気やショートによる放電で発火することもありますうので、熱源が確認できていなくとも、電気回路のそばにはとにかく可燃性物質を置かない、やむをえない場合は相応の安全策を取り、舞台や展示会場の責任者に通達するなど対策を徹底するようにしてください。

感電

  • 電流量によって感じ方が変わる
  • 電源を入れたまま回路を付け替えたりしない
  • ケーブルやケースなどは必ず「絶縁」する
  • 作業によっては「電気工事士」の資格が必要なこともあるので注意
最後は感電です。これは可能性としては低い部類ですが、注意するに越したことはありません。要するに人体に電気が流れ込むことで神経が刺激されるわけですが、人間の筋肉も微弱な電気信号によって動いているので、強い電流が流れた場合心停止などもおきます。

プラスとマイナスに同時に触れれば回路が出来上がるので当然電気が流れますが、プラスだけを触っていても、地面や金属などに触れて電気の逃げ道があった場合は電気が流れる可能性は十分あります。

対策としては、回路をつないだり外したりする時は必ず電源を切るようにしてください。思うように動かなくて焦っている時などついやってしまいがちですが、危険です。

この講義では扱う予定は無いですが、100V電源など配線する時は特に気をつけてください。場合によっては「電気工事士」の資格が必要な事があります。

まとめ

  • 作る時の危険と見せる時の危険、それぞれ検証を重ねて準備を進める
  • 電子工作では特に「発熱・発火・感電」に気をつける。

安全についてさらに詳しく

舞台技術の共通基礎

山岡潤一さん - 安全な作品を作るには:体験型作品展示の安全管理チェックリスト

入門テキスト 安全学

なぜ13歳未満の子供は、Oculus Riftを使用してはいけないのか?医学的な見地からの警鐘