2018年4月28日土曜日

DigisparkとArduino UNOでCapacitiveSensing(容量検知センサー)

Arduinoには、Capasitive Sensingというライブラリがあるんですね~
今までは、PIC内蔵の容量検知モジュールで遊んでおりました。

たぶんここが本家英語の「Arduino Capasitive Sensing Library」解説です。
そこにYouTubeリンクがあり、更にリンクをたどっていくと
YouTubeをUpされた方のサイトがあります。
見慣れない小さなTeensyというArduino、興味をそそりますが
ちょっと調べるとUS$ 10程もするのでポチるのは、パス。

同様の内容が、このGitHubにもあげられています。

ライブラリ解説の日本語訳がここにありました。
ブレッドボーダーズのサイトのようです。

上の参考サイトのスケッチを見ると
CapacitiveSensor.cppとCapacitiveSensor.hが必要なのです。
PC内を検索してみるとArduino v1.8.3のインストールフォルダ配下の
「...\libraries\Adafruit_CircuitPlayground\utility」

「CPlay_CapacitiveSensor.cpp」
「CPlay_CapacitiveSensor.h」
が見つかりましたが
どうやらこれは、
adafruit circuit playground」という「ATmega32u4」が乗った
円形基板のSensorと多色LED付の小さなAll-In-One Board用みたいです。

で、先の「Arduino Capasitive Sensing Library」から
「CapacitiveSensor04.zip」をダウンロードします。
「arduino-libraries-CapacitiveSensor-0.5.1-3-ga07209f.zip」 って名前ですね~
ちょっと前に戻って、さっきの下の
「This updated CapacitiveSensor version 05」の方をクリックすると
GitHubに飛びます。
[Tags]を見ると「0.5.1」が最新のようでね~
それぞれのCapacitiveSensor.cppの日付を見ると
・最初の...0.5.1-3:2016/02/20
・GitHubのMaster:2018/03/15
・GitHubの5.1.0版:2016/01/05

日本語訳のサイトにあるアドレス
「http://arduino.cc/playground/uploads/Main/CapSense04.zip」
からダウンロードすると「CapSense04.zip」のファイル名です。

どうやら日本語訳の時点からバージョンアップされているんですね~
いくつかコマンドも変わっています。
・「CapSense CapSense」⇒「CapacitiveSensor CapacitiveSensor」
・「long capSenseRaw」⇒「long capacitiveSensorRaw」
・「long capSense」⇒「long capacitiveSensor」

ということで一番新しいGitHubのここのMasterを使うことにします。
Clone or download]クリックして[Download ZIP]して
「CapacitiveSensor-master.zip」をDownloadします。

CapacitiveSensor-master.zipを解凍すると
「CapacitiveSensor-master」フォルダができるので
フォルダ名を「CapacitiveSensor」に変えて(変えなくてもいいけど)
C:\Users\[User名]\Documents\Arduino\libraries
に入れます。(Windows10 64bitです)
これでライブラリのインストール完了です。
Arduino IDE v.1.8.3を再起動します。
[ファイル]-[スケッチの例]から
▼にカーソルを置いて一番下まで行って
[CapacitiveSensor]に[CapacitiveSensorSketch]をクリックすると
先の英語のサイトと同じスケッチが立ち上がります。
まずは、Arduino UNOでやってみます。
スケッチ例は、タッチパッド3個なので1個用に変更します。
*****
#include <CapacitiveSensor.h>
/*
 * CapitiveSense Library Demo Sketch
 * Paul Badger 2008
 * Uses a high value resistor e.g. 10 megohm between send pin and receive pin
 * Resistor effects sensitivity, experiment with values, 50 kilohm - 50 megohm. Larger resistor values yield larger sensor values.
 * Receive pin is the sensor pin - try different amounts of foil/metal on this pin
 * Best results are obtained if sensor foil and wire is covered with an insulator such as paper or plastic sheet
 */
CapacitiveSensor   cs_4_2 = CapacitiveSensor(4,2);        // 10 megohm resistor between pins 4 & 2, pin 2 is sensor pin, add wire, foil

void setup()                    
{
   cs_4_2.set_CS_AutocaL_Millis(0xFFFFFFFF);     // turn off autocalibrate on channel 1 - just as an example
   Serial.begin(9600);
}

void loop()                    
{
    long start = millis();
    long total1 =  cs_4_2.capacitiveSensor(30);

    Serial.print(millis() - start);        // check on performance in milliseconds
    Serial.print("\t");                    // tab character for debug window spacing
    Serial.println(total1);                  // print sensor output 1

    delay(10);                             // arbitrary delay to limit data to serial port 
}
*****

上のスケッチでは、
・Send Pin:Digital 4
・ReceivePin:Digital 2
なので
・2pin:1KΩ(静電気防御用、抵抗の先にタッチパッド)
・4pin ~ 2pin間:10MΩ
てっきりAnalog Pinを使うものと思っていたらDigital Pinなんですね~
その内、動作原理も調べてみたいです。
回路図もFritzingで。
スケッチを書き込むと...お~っ!動きました!
実態は、こんな状態。タッチパッドは、ただのアルミ箔です。
下に敷いているのは、PCからの影響があるかもしれないので、お菓子の缶の蓋。
動画で
PC画面は、シリアルモニタ  左:cs、右:csSumです。
RESET直後は、数値が2桁なのですが
一旦触ると、触っていない時の数値がぐんと上がって
300~500や1000以上にもなってしまい不安定です。
まあ、確実に触れた時は、10000~20000になるので
ON/OFFスイッチとしては、問題はないですが、ちょっと気に入らないですね~

そこで、これの出番です。
だいぶ前に作ったPCBスパイラルコイル、実は、コイルではなくて、
PIC用にと作っていたタッチパッドだったのですが、
PICで出番が来る前に、ArduinoのCapacitive Sensingを見つけたわけでして。
二重のコイル状になっていてGNDとSensing端子に繋いで
いい感じだったのですが
しばらくすると、振れていないのにこの数値
下の金属板をArduinoUNOのGNDに接続して、片方の手で金属板をつかんで、
もう一方の手でタッチパッドに触れるようにすると、
触れていない時の数値は低いまま安定しています。

ちなみ下の金属板をGNDと接続しただけでは、少し安定するようですが、
何度かやっていると、触れない時の値が増えていきます。

触れてない時は、浮遊容量だけで動作しているからだろうか?
パッドと並列に22pFのセラミックコンデンサ(右下)を入れてみます。
少~し安定した感じもするくらいであまり変わりませんね~
一旦、指を近づけると触ってない時の値が300~500に跳ね上がります。
Arduino UNOをRESETすると2桁に戻ります。

22pF⇒56pFにしてみます。
回路図は、これ
触っていない時の計測時間が30~31msecに伸びますが
お~いいですね~
触れたり離したりしても、触れない時の値は安定するようになりました。
Arduino IDEの環境設定で文字の大きさを36pointにしています。
動画で
前の下の金属板をGNDに接続して、片方の手で金属板をつかんで、
もう一方の手でタッチパッドに触れるようにする場合は、安定していて
しかも計測時間は、56pFを入れてない時と変わらず10以下なのです。
どうも何かの誘導ノイズも影響しているようです。
両面基板の裏をGND、表にタッチパッドというものを作ってもいいかもです。

次に、先の英語のサイトの下の方にある
Example code: Threshold のを少し変えてやってみます。
7_8 ⇒ 4_2 に変えます。(前の配線と同じにするため)
TriggerしたらArduino UNOの「L」のLEDをトグルで点灯させます。
マーティーなりの解釈で日本語コメントを入れました。
*****
#include <CapacitiveSensor.h>
CapacitiveSensor cs_4_2 = CapacitiveSensor(4,2);
     //2pin:センシング  2-4pin:10MΩ
unsigned long csSum;
int LED_State = LOW;

void setup() {
    Serial.begin(9600);
    pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
    CSread();
}

void CSread() {
    long cs = cs_4_2.capacitiveSensor(80);
      //a: Calibration時の読取値からの増分をサンプル数80でサンプリングした合計値
 if (cs > 200) {
      //b: csが200を超えるとSerialに数値を出力する
   csSum += cs;
      //csがb(200)を超えている間は、LOOPする毎にcsSumに加算していく
// Serial.println(cs);
    Serial.print(cs); 
    Serial.print("\t");
    Serial.println(csSum); 
     if (csSum >= 50000)
      //c: csがb(200)を超え続けて加算されたcsSumがc(50000)を超えるとTriggerと判定する
     {
        Serial.print("Trigger: ");    //Serialに"Trigger"文字を出力
        Serial.println(csSum);        //Triggerした時のcsSum値をSerialに出力

        if (LED_State == LOW){ // Current State LOW
          digitalWrite(LED_BUILTIN, HIGH);
          LED_State = HIGH;
        } else { // Current State HIGH
          digitalWrite(LED_BUILTIN, LOW);
          LED_State = LOW;
        }

          if (csSum > 0) { csSum = 0; } //Triggerしたら一旦csSumをClear(Reset)
            cs_4_2.reset_CS_AutoCal();    //読み取り停止してCalibration実行
     }
  } else {
    csSum = 0;
     //パッドから離れてcsがb(200)を下回るとcsSumをClear
     //又は、抵抗がなかったり、容量が大き過ぎて読み取りがTimeoutした場合
  }
}
*****
動画で
Sensing端子の抵抗の足に、指をギリギリまで近づけていくと(0.5~1mm)
200を超えれば左の数値(cs)が表示され、
右側のカウント値(csSum)が加算されていき
50000を超えるとトリガーがかかります。
途中で離れるとカウントされなくなり、csSumがClearされます。
一気に振れるとすぐに50000を超えてTriggerがかかります。
Arduino UNOの一番右のLEDがトグルでON/OFFしています。
なかなか面白いです。
PICの機能では、細かくで設定できなかったので、Arduinoの方が応用がよさげです。
んで、この前のワンボタン・スクリーンショット!を
Digispark(ATtiny85の小型Arduino)とタクトスイッチで作りましたが
人間というものは更に楽を求めるもので
ボタンを押すのではなくタッチだけでできるんじゃないかな~っと

まずは、Digisparkの使えるPINを探します。
Digistump CreatedのDigispark回路図は、このPDFです。
Capacitive Sensingに使えそうなのは、Board内に何もぶら下がっていない
PB0、PB2、PB5ですね。

・Send Pin:PB0
・ReceivePin:PB2
として
・2pin:1KΩ(耐静電気用、抵抗の先にタッチパッド)
・1KΩの先~GND間:56pF
・0pin ~ 2pin間:10MΩ
Digispark Board内には、PB1にLEDが付いているので
Arduino UNOのスケッチからの変更は、2つ
・4 ⇒ 0
・LED_BUILTIN ⇒ 1
ブレッドボード
回路図です。
Fritzingなかなか便利です。
*****
#include <CapacitiveSensor.h>
CapacitiveSensor cs_0_2 = CapacitiveSensor(0,2);
     //2pin:センシング  2-0pin:10MΩ
unsigned long csSum;
int LED_State = LOW;

void setup() {
    Serial.begin(9600);
// pinMode(LED_BUILTIN, OUTPUT);
    pinMode(1, OUTPUT);
}

void loop() {
    CSread();
}

void CSread() {
    long cs = cs_0_2.capacitiveSensor(80);
      //a: Calibration時の読取値からの増分をサンプル数80でサンプリングした合計値
 if (cs > 200) {
      //b: csが200を超えるとSerialに数値を出力する
   csSum += cs;
      //csがb(200)を超えている間は、LOOPする毎にcsSumに加算していく
// Serial.println(cs);
   Serial.print(cs); 
   Serial.print("\t");
   Serial.println(csSum); 
     if (csSum >= 50000)
      //c: csがb(200)を超え続けて加算されたcsSumがc(50000)を超えるとTriggerと判定する
     {
        Serial.print("Trigger: ");    //Serialに"Trigger"文字を出力
        Serial.println(csSum);        //Triggerした時のcsSum値をSerialに出力
        if (LED_State == LOW){ // Current State LOW
//       digitalWrite(LED_BUILTIN, HIGH);
          digitalWrite(1, HIGH);
          LED_State = HIGH;
        } else { // Current State HIGH
//       digitalWrite(LED_BUILTIN, LOW);
          digitalWrite(1, LOW);
          LED_State = LOW;
        }
          if (csSum > 0) { csSum = 0; } //Triggerしたら一旦csSumをClear(Reset)
            cs_0_2.reset_CS_AutoCal();    //読み取り停止してCalibration実行
     }
  } else {
    csSum = 0;
     //パッドから離れてcsがb(200)を下回るとcsSumをClear
     //又は、抵抗がなかったり、容量が大き過ぎて読み取りがTimeoutした場合
  }
}
*****

この前、Digispark用のボードマネージャー(開発環境パッケージ)を入れた、
Arduino IDE v1.8.3を起動してスケッチを書き込みます。
Digispark(ATtiny85)は、先に接続してはいけません。
[ツール]-[ボード]-[Digispark(Default - 16.5mhz)]を選択します。
[ツール]-[書込装置]-[Micronucleus]を選択します。
[ファイル]-[新規ファイル]して
上のスケッチを貼り付け、適当な名前で保存してから
[スケッチ]-[マイコンボードに書き込む]します。
コンパイルが終わり、下の欄に
Plug in device now...(will timeout in 60 seconds)」とでたら
Digispark(ATtiny85)をUSBに接続します。
「ボードへの書き込みが完了しました。」と
「Micronucleus done. Thank you!」の表示がでて
「ピポン、ピポン、ピポン」と3回ほど音が出ますが
無事、書き込み完了です。
シリアルモニタを起動しようとしたら、怒られました。
シリアルポートができていません。
デバイスマネージャーには、DigisparkのUSB認識エラーは、でていません。
あっ!
Digisparkは、専用のSerialライブラリを使う必要がありました。

ちょっとUSBSerialをやってみましたが、泥沼にハマりそうなので
シリアルなしでやることにします。
Serialの所を全て削除します。
*****
#include <CapacitiveSensor.h>
CapacitiveSensor cs_0_2 = CapacitiveSensor(0,2);
     //2pin:センシング  2-0pin:10MΩ
unsigned long csSum;
int LED_State = LOW;

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

void loop() {
    CSread();
}

void CSread() {
    long cs = cs_0_2.capacitiveSensor(80);
      //a: Calibration時の読取値からの増分をサンプル数80でサンプリングした合計値
 if (cs > 200) {
      //b: csが200を超えるとSerialに数値を出力する
   csSum += cs;
      //csがb(200)を超えている間は、LOOPする毎にcsSumに加算していく
     if (csSum >= 50000)
      //c: csがb(200)を超え続けて加算されたcsSumがc(50000)を超えるとTriggerと判定する
     {
        if (LED_State == LOW){ // Current State LOW
          digitalWrite(1, HIGH);
          LED_State = HIGH;
        } else { // Current State HIGH
          digitalWrite(1, LOW);
          LED_State = LOW;
        }
          if (csSum > 0) { csSum = 0; } //Triggerしたら一旦csSumをClear(Reset)
            cs_0_2.reset_CS_AutoCal();    //読み取り停止してCalibration実行
     }
  } else {
    csSum = 0;
     //パッドから離れてcsがb(200)を下回るとcsSumをClear
     //又は、抵抗がなかったり、容量が大き過ぎて読み取りがTimeoutした場合
  }
}
*****
書き込み完了です。
一旦、Digisparkを取り外して
・2pin:1KΩ(耐静電気用、抵抗の先にタッチパッド)
・2pin~GND:56pF
・0pin ~ 2pin間:10MΩ
を配線して、USBに挿します。

おっ!タッチセンサー動きました!!!
が、
そのまま放置していたら
手は、最低でも10cmは離れているのにLEDが点灯することがあります。
csSumに加算を始める閾値を上げます。
*****
 if (cs > 1000) {
      //b: csが1000を超えるとSerialに数値を出力する
*****
触ってから反応するまでのディレイが長めなので
*****
     if (csSum >= 20000)
*****
いい感じになりました!

スクリーンショットのスケッチ(青文字)を合体しました。
Triggerがかかったら一瞬、内蔵LEDも光らせることににました。
*****
#include <CapacitiveSensor.h>
#include <DigiKeyboard.h>
#define KEY_PRINT_SCREEN 0x46
CapacitiveSensor cs_0_2 = CapacitiveSensor(0,2);
     //2pin:センシング  2-0pin:10MΩ
unsigned long csSum;
int LED_State = LOW;

void setup() {
    pinMode(1, OUTPUT);
    digitalWrite(1, LOW);
}

void loop() {
    CSread();
}

void CSread() {
    long cs = cs_0_2.capacitiveSensor(80);
      //a: Calibration時の読取値からの増分をサンプル数80でサンプリングした合計値
 if (cs > 1000) {
      //b: csが1000を超えるとSerialに数値を出力する
   csSum += cs;
      //csがb(1000)を超えている間は、LOOPする毎にcsSumに加算していく
     if (csSum >= 20000)
      //c: csがb(1000)を超え続けて加算されたcsSumがc(20000)を超えるとTriggerと判定する
        {
         digitalWrite(1, HIGH);
         DigiKeyboard.update();
         DigiKeyboard.sendKeyStroke(KEY_PRINT_SCREEN, MOD_GUI_LEFT);
         DigiKeyboard.delay(50); 
         digitalWrite(1, LOW);
          if (csSum > 0) { csSum = 0; } //Triggerしたら一旦csSumをClear(Reset)
            cs_0_2.reset_CS_AutoCal();    //読み取り停止してCalibration実行
        }
        } else {
           csSum = 0;
     //パッドから離れてcsがb(1000)を下回るとcsSumをClear
     //又は、抵抗がなかったり、容量が大き過ぎて読み取りがTimeoutした場合
  }
  DigiKeyboard.delay(10);
}
*****
まず、コンパイルだけすると。
このスケッチで77%です。
USBのBootloaderがなかなか認識してくれない時もあり不安定です。
書き込みエラーになるとArduino IDEを再起動しないといけないし
USBポートを変えたり、何度もしつこく挿し直して
やっと書き込みできました。
書き込み時は、全てのUSBを外しておくのがいいようです。
それでもダメな時はありますが。
実体配線は、この状態です。
できました~!
成功です。
こりゃー良さそうです。
抵抗の先にチョンと触れるとスクリーンショットできます!
静止画ではわからないので、動画を
でも途中から固まっちゃいましたね~  LED付いたままで反応していません。
リード線が長いのがいけないのかなあ~
実は、この前、Digisparkが面白かったので
この元祖タイプの直挿Digispark Cloneもポチっておりました。
最安値 US$ 1.25のここから買ったのですが
今見ると、売り切れですね~
こちらは、まだ売っているようです。価格上昇中なのかなあ?
いつもよりかなり早くて丁度いいタイミングで届きました。
3つも買ってしまっております。
早速チェックすると
既にLチカが入っていました。確認がしやすいので親切ですね~
ATtiny85と78M05(この前のは、78L05でした)
早速、メスのピンヘッダーをハンダ付けして
抵抗2本とセラミックコンデンサをつけました。
赤矢印の抵抗の先っぽを丸めた所がタッチパッド代わりです。
抵抗の先っぽをタッチパッド代りにしたので回路図を少し変えました。
静電気が心配なので1KΩ⇒10KΩにしています。
マーティーPCに取り付けた状態。
他のUSBを全部外して何度か挿さないとなかなか認識してくれませんが
配線を短くしたら動作は安定するようになりました!
差込がやや甘いので強く振れるとUSB給電が一瞬切れてUSB認識が外れます。
一旦USB認識されると
このように便利は便利です。
スクリーンショットの保存フォルダにどんどん溜まっていきます。
動画で
USBの認識さえ問題なければ完璧なのですが、ちょっと悪すぎます。
一度認識してくれればSLEEPから復帰しても大丈夫です。
ただ、復帰時には必ず、自動で一発ショットされます。まあ仕方ないでしょう。

タッチ式はいいですね~
しばらくこの状態で使うことにします。

6 件のコメント:

てる さんのコメント...

arduinoを使ったスライドセンサーを作りたいと考えています。原理や詳しいプログラミングの説明や詳しく書いているサイトがありましたら教えていただきたいです。
よろしくお願いします。

マーティーの工房日誌 さんのコメント...

スライドバー式のタッチセンサーは、やったことないです。
この手のものは、英語サイトが進んでいますので
私だったら、"arduino capacitive sensing slide"辺りで検索して、そこから自分に合ったものを参考に紐解いていって試行錯誤していくと思います。
色々工夫したセンサー形状がでてくので、面白そうですね。
答えになっておらずm(_ _)m

kiki さんのコメント...

とても分かりやすく、また実用的な内容で勉強になります。
これからもどんどんバージョンアップ楽しみです。
タッチセンサのONOFFで、Bluetooth経由で何かを遠隔で制御できたら面白いですね。

マーティーの工房日誌 さんのコメント...

kikiさん、見ていただきありがとうございます。
実は、その後、USB口の不足で使っておりません(-_-;)
Bluetoothモジュールも眠ったままです(-_-;)
ここに載ってるATtiny85の単品チップは、とても面白いです。

kiki さんのコメント...

同じく静電容量センサでのタッチセンサを作成中です。
悩みは、長時間駆動させていると、値が徐々に上昇してきて、
数時間後には、閾値を超えて勝手にLEDがONOFFしてしまいます。
定期的にリセットできるプログラムがあれば教えてください。

マーティーの工房日誌 さんのコメント...

もうすっかり忘れてますね~(-_-;)

1.
C1 22pFの時に似たような症状がでてるので、
C1 56pFを大きく、R2 10MΩを小さく してみるのも手かと思います。

2.
読み返すと、最後の方に、次の記述があります。
この「cs > 1000」を変更してみてはいかがでしょうか?

~~~~~
そのまま放置していたら
手は、最低でも10cmは離れているのにLEDが点灯することがあります。
csSumに加算を始める閾値を上げます。
*****
if (cs > 1000) {
//b: csが1000を超えるとSerialに数値を出力する
*****
~~~~~

3.
数十msec毎にcsSumの変化量をチェックして、緩やかな増加だったら
csSumをClearするルーチンを追加するのが確実だと思います。