落胆がらくた街

Dr.Rootはサポート終了製品です。

Nucleoでタッチセンサを自作した

タッチセンサの仕組みは
建築発明工作ゼミ2008: Arduino タッチセンサ
を参照。これをMbed環境でやりたい…という話。その際に出た問題を覚書。

1.青bedでやったらダメだった
このタッチセンサはMbedで言うDigitalInを使う。出力ピンと入力ピンを2MΩくらいの抵抗で繋ぎ、出力をHighにしてから入力がHighになるまでの時間を計測するわけだ。
ところが青bed及びLPC1114はDigitalInの入力閾値電圧が微妙に高く(Analogでいう0.75くらいだったと記憶しているから2.5Vくらい?)これだけ大きい抵抗を通すといつまで経ってもDigitalInはHighにならない。一応AnalogInを使えば解決するのだが、同時に6ピンしかタッチセンサに出来ないのは余りに寂しい。
そこでNucleo F401REを使ったところ一発で上手くいった。同じARMのCPUだろうにここらへんの仕様が違うんやなぁ。

2.値がめっちゃふらつく
こんな感じの回路で
f:id:suzumodoki:20160907182247j:plain

こんな感じのソースを実行すると

#include "mbed.h"

#define NUM 3

DigitalIn in[]= {D14,D15,D12};
DigitalOut dout(D7);


int ret_us(int pin)
{
    Timer t;
    dout=0;
    while(in[pin]==1);
    t.reset();
    wait_us(10);
    t.start();
    dout=1;
    while(in[pin]==0);
    return t.read_us();
}

int main()
{

    while(1){
        printf("%d,%d,%d\r\n",ret_us(0),ret_us(1),ret_us(2));
        wait(0.2);
    }
}

こんな感じの結果が得られる。

10,10,10
10,10,10
9,10,10
10,11,11
11,11,9
10,11,9
10,10,9
9,10,11
10,11,8
9,177,10
18,2,12
19,2,11
9,149,12
12,2,15
18,2,12
12,29,12
13,2,14
16,2,13
18,2,8


赤字の部分が真ん中のピンを触った時の挙動だ。これを見ると、
1.タッチされた時、応答速度は早くなるか、極端に遅くなる
2.自分以外の誰かがタッチされていても応答は若干ふらつく。具体的には若干遅くなる。

という事がわかる。触られた時に応答速度が遅くなるという予想に反した結果だが、何度やってもこうなる。
ちなみに2つ以上を同時にタッチしてもこの法則に基づくようだ。

この2つのルールをうまい具合に判定しないといけない。

最終的なソースコードは以下。

#include "mbed.h"

#define NUM 3

DigitalIn in[]= {D14,D15,D12};
int num[NUM]= {0};
DigitalOut dout(D7);
DigitalOut led(LED1);

int ret_us(int pin)
{
    Timer t;
    dout=0;
    while(in[pin]==1);
    t.reset();
    wait_us(10);
    t.start();
    dout=1;
    while(in[pin]==0);
    return t.read_us();
}

int main()
{
    led=1;

    //初回でレンジ出す
    int range[NUM],buf;
    for(int i=0; i<NUM; i++) {
        range[i]=ret_us(i);
        for(int j=0; j<50; j++) {
            buf=ret_us(i);
            if(range[i]>buf) range[i]=buf;
        }
    }
    
    int fil[NUM]= {0};
    int cnt=0;
    const int loop=10;
    const int border=5;
    while(1) {
        memset(fil,0,sizeof(int)*NUM);
        for(int k=0; k<loop; k++) {
            for(int i=0; i<NUM; i++) {
                cnt=0;
                for(int j=0; j<5; j++) {
                    if(range[i]>ret_us(i)) {
                        cnt++;
                    }
                }
                if(cnt>=2)fil[i]++;
            }
        }
        for(int i=0; i<NUM; i++){
            if(fil[i]>border)printf("1:");
            else printf("0:");
        }
        printf("\r");
    }
}

ようは複数回判定する事で、時間解像度を犠牲に判定の精度を上げるわけだ。
この方法でも「中途半端に触ってる時」なんかは判定がふらつくが、その場合用途に応じて判定回数を増やしたりすればいい。
ちなみにこれ、出力ピンが共通だからこんな事になってしまっているが、ケチらず出力ピンと入力ピンを一対一で用意してやればもう少し判定は楽になる。
…が、それでも「複数回判定して例えば分散を見る」みたいにした方がいいのは変わらない。


RH6010?久々に棚から出したら死んでたよ。