Help us understand the problem. What is going on with this article?

タッチエンスのショッカクポット(POTU-001-1)を触ってみた。

More than 1 year has passed since last update.

はじめに

秋月電子でタッチエンス・ショッカクポット(POTU-001-1) が発売されたとの Tweet を見て、昔に秋葉原UDX 2F(アキバ・スクエア)の展示スペースで ShokacPot Miniのデモ をやっていたことを思い出し、気になって仕方がなかったので早速入手して触ってみた。

入手経路

今回は秋月電子でシリアル(UART)出力タイプの製品を入手。(※2019年3月21日現在)
Amazon と RT ROBOT SHOP は製品仕様が異なるので入手される場合は注意が必要。

仕様

タッチエンスのホームページを見るとアナログ出力、I2C出力、SPI出力(開発中)といくつかラインアップがあるが、シリアル(UART)出力のものは記載されていなかった。
秋月電子の商品ページのリンク先から。
取扱説明書

ショッカクポットは三次元方向の変位が検出できる柔軟触覚センサーで、重さを測るセンサーではない。(はじめ勘違いしていた。。)
スポンジの圧縮によりLED-フォトトランジスタ間の光量変化を利用して、スポンジの変位に応じた電圧変化が出力される。電圧変化をスポンジ変形量(変位量)に変換した上で出力する自動較正機能が搭載されているとのこと。

接続図

センサー基板はJST-SH/1.0の5ピンコネクタが採用されているため、他のホストデバイスへ接続しやすくするため付属ケーブルの片側を切断し、Groveコネクタへ変換した。(RSTを除いたVDD、GND、Rx、Tx)
今回はホストデバイスとしてNefryBTを使用した。
スクリーンショット 2019-03-25 10.03.31.png

シリアル通信

ボーレート[bps]: 57,600
データ[bit]: 8
ストップビット[bit]: 1
パリティ: なし
ホストデバイス(NefryBT)からデータ取得コマンド(0x6D)を送信する(①)と、センサーが測定を開始し、サンプリング時間(平均1.2ミリ秒)経過後にデータが出力される。(②)
10bitのAD変換値の上位2bitと下位8bitに分割されてデータが出力されるとのことだが、実測値で上位2bitに値がセットされることは無かったため、動作確認用のサンプルソースコードでは下位8bitだけ使用することにした。
スクリーンショット 2019-03-25 10.03.44.png

ソースコード

ソースコードはこちら
NefryBTに搭載されているESP32は複数のHardwareSerialをサポートしているため、SoftwareSerialは使用しない。
また、NefryBTにはTX,RXポートが存在するが、TX,RXポートにセンサーデバイスを接続したままだとプログラムの書き込みに失敗するので(プログラムを書き込みする時は抜いておき、書き込みが完了した後に接続すれば使用可能だが面倒なので)、D2(IO23)にRX、D3(IO19)にTXを割り当ててHardwareSerialを使用する。
取得したデータはNefryBTのディスプレイへ表示するのと合わせて、Arduino IDEのシリアルプロッタで表示するためシリアルモニターへ出力している。

NefryBT_TouchPod_02.ino
#include <Nefry.h>
#include <NefryDisplay.h>
#include <NefrySetting.h>

void setting(){
  Nefry.disableDisplayStatus();
}

NefrySetting nefrySetting(setting);

HardwareSerial Serial1(1);  // use HardwareSerial, do not use SoftwareSerial

byte cmd[1] = {0x6D};  // データ送信コマンド(0x6d)
unsigned char res[8];  // データ受信バッファ
bool flag = false;

void setup() {
  Nefry.setLed(0,0,0);
  NefryDisplay.clear();
  NefryDisplay.setFont(ArialMT_Plain_16);
  NefryDisplay.drawString(0, 0, "CH1: ");
  NefryDisplay.drawString(0, 16, "CH2: ");
  NefryDisplay.drawString(0, 32, "CH3: ");
  NefryDisplay.drawString(0, 48, "CH4: ");
  NefryDisplay.display();
  Serial.begin(115200);
  Serial1.begin(57600, SERIAL_8N1, 23, 19);  // (speed, type, RX:D2=23, TX:D3=19);
  delay(1000);
  Serial.println("start: ");
}

void loop() {
  Serial1.write(cmd,1);
  while(Serial1.available()>0)
  {
    Serial1.readBytes(res, 8);
    flag=true;
  }
  if(flag)
  {
    flag=false;
    unsigned int P01H = (unsigned int) res[0];  // CH1 AD変換値 上位2bit/10bit (使用しない)
    unsigned int P01L = (unsigned int) res[1];  // CH1 AD変換値 下位8bit/10bit (使用する)
    unsigned int P04H = (unsigned int) res[2];  // CH4 AD変換値 上位2bit/10bit (使用しない)
    unsigned int P04L = (unsigned int) res[3];  // CH4 AD変換値 下位8bit/10bit (使用する)
    unsigned int P02H = (unsigned int) res[4];  // CH2 AD変換値 上位2bit/10bit (使用しない)
    unsigned int P02L = (unsigned int) res[5];  // CH2 AD変換値 下位8bit/10bit (使用する)
    unsigned int P03H = (unsigned int) res[6];  // CH3 AD変換値 上位2bit/10bit (使用しない)
    unsigned int P03L = (unsigned int) res[7];  // CH3 AD変換値 下位8bit/10bit (使用する)

    Serial.print(P01L);
    Serial.print(",");
    Serial.print(P02L);
    Serial.print(",");
    Serial.print(P03L);
    Serial.print(",");
    Serial.print(P04L);
    Serial.println("");

    char buf[10];
    NefryDisplay.clear();
    NefryDisplay.setFont(ArialMT_Plain_16);
    NefryDisplay.drawString(0, 0, "CH1: ");
    sprintf(buf, "%d", P01L);
    NefryDisplay.drawString(50, 0, buf);
    NefryDisplay.drawString(0, 16, "CH2: ");
    sprintf(buf, "%d", P02L);
    NefryDisplay.drawString(50, 16, buf);
    NefryDisplay.drawString(0, 32, "CH3: ");
    sprintf(buf, "%d", P03L);
    NefryDisplay.drawString(50, 32, buf);
    NefryDisplay.drawString(0, 48, "CH4: ");
    sprintf(buf, "%d", P04L);
    NefryDisplay.drawString(50, 48, buf);
    NefryDisplay.display();
  }
  delay(100);
}

NeoPixel WS2812Bと連動

取得したデータの値に連動してネオピク(NeoPixel WS2812B)をLチカしてみる。
取得したデータはそれぞれCH1→R(赤)、CH2→G(緑)、CH3→B(青)に割り当てる。(CH4は使用しない。)
ネオピクの配線(DIN)はNefryBTのD4(GPIO18)に接続する。
スクリーンショット 2019-03-25 10.16.22.png

ソースコードはこちら

NefryBT_TouchPod_03.ino
#include <Nefry.h>
#include <NefryDisplay.h>
#include <NefrySetting.h>
#include <FastLED.h>

void setting(){
  Nefry.disableWifi();
  Nefry.disableDisplayStatus();
}

NefrySetting nefrySetting(setting);

HardwareSerial Serial1(1);  // use HardwareSerial, do not use SoftwareSerial

// LED Strip
const int numLeds = 256;  // Change if your setup has more or less LED's
#define DATA_PIN 18  //The data pin that the WS2812 strips are connected to. NefryBT D2=GPIO23, D4=GPIO18
CRGB leds[numLeds];

byte cmd[1] = {0x6D};  // データ送信コマンド(0x6d)
unsigned char res[8];  // データ受信バッファ
bool flag = false;

void setup() {
  Nefry.setLed(0,0,0);
  NefryDisplay.clear();
  NefryDisplay.setFont(ArialMT_Plain_16);
  NefryDisplay.drawString(0, 0, "CH1: ");
  NefryDisplay.drawString(0, 16, "CH2: ");
  NefryDisplay.drawString(0, 32, "CH3: ");
  NefryDisplay.drawString(0, 48, "CH4: ");
  NefryDisplay.display();

  Serial.begin(115200);

  Serial1.begin(57600, SERIAL_8N1, 23, 19);  // (speed, type, RX:D2=23, TX:D3=19);

  FastLED.addLeds<WS2812, DATA_PIN, GRB>(leds, numLeds);
//  FastLED.setBrightness(10);
//  for (int i = 0; i < numLeds; i++) {
//    leds[i] = CRGB(1,1,1);
//  }
//  FastLED.show();

  delay(1000);

  Serial.println("start: ");
}

void loop() {
  Serial1.write(cmd,1);
  while(Serial1.available()>0)
  {
    Serial1.readBytes(res, 8);
    flag=true;
  }
  if(flag)
  {
    flag=false;
    unsigned int P01H = (unsigned int) res[0];  // CH1 AD変換値 上位2bit/10bit (使用しない)
    unsigned int P01L = (unsigned int) res[1];  // CH1 AD変換値 下位8bit/10bit (使用する)
    unsigned int P04H = (unsigned int) res[2];  // CH4 AD変換値 上位2bit/10bit (使用しない)
    unsigned int P04L = (unsigned int) res[3];  // CH4 AD変換値 下位8bit/10bit (使用する)
    unsigned int P02H = (unsigned int) res[4];  // CH2 AD変換値 上位2bit/10bit (使用しない)
    unsigned int P02L = (unsigned int) res[5];  // CH2 AD変換値 下位8bit/10bit (使用する)
    unsigned int P03H = (unsigned int) res[6];  // CH3 AD変換値 上位2bit/10bit (使用しない)
    unsigned int P03L = (unsigned int) res[7];  // CH3 AD変換値 下位8bit/10bit (使用する)

    Serial.print(P01L);
    Serial.print(",");
    Serial.print(P02L);
    Serial.print(",");
    Serial.print(P03L);
    Serial.print(",");
    Serial.print(P04L);
    Serial.println("");

    char buf[10];
    NefryDisplay.clear();
    NefryDisplay.setFont(ArialMT_Plain_16);
    NefryDisplay.drawString(0, 0, "CH1: ");
    sprintf(buf, "%d", P01L);
    NefryDisplay.drawString(50, 0, buf);
    NefryDisplay.drawString(0, 16, "CH2: ");
    sprintf(buf, "%d", P02L);
    NefryDisplay.drawString(50, 16, buf);
    NefryDisplay.drawString(0, 32, "CH3: ");
    sprintf(buf, "%d", P03L);
    NefryDisplay.drawString(50, 32, buf);
    NefryDisplay.drawString(0, 48, "CH4: ");
    sprintf(buf, "%d", P04L);
    NefryDisplay.drawString(50, 48, buf);
    NefryDisplay.display();

    unsigned int r,g,b;
    if (P01L > 10) {r = P01L;} else {r = 1;}
    if (P02L > 10) {g = P02L;} else {g = 1;}
    if (P03L > 10) {b = P03L;} else {b = 1;}
    for (int i = 0; i < numLeds; i++) {
      leds[i] = CRGB(r,g,b);
    }
    FastLED.show();

  }
  delay(100);
}

obnizで動作確認

スクリーンショット 2019-03-25 15.15.27.png

ソースコードはこちら

ShoKacPot.html
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script src="https://obniz.io/js/jquery-3.2.1.min.js"></script>
  <script src="https://unpkg.com/obniz@2.0.1/obniz.js" crossorigin="anonymous"></script>
</head>
<body>

<div id="obniz-debug"></div>
<h1>obniz instant html</h1>
<button id="on">ON</button>
<button id="off">OFF</button>
<div id="print"></div>

<script>
var obniz = new Obniz("OBNIZ_ID_HERE");
obniz.onconnect = async function () {

  obniz.display.clear();

  obniz.io11.output(false); // GND
  obniz.io10.output(true);  // VDD(5V)

  var led = obniz.wired("WS2812B", {gnd:2, vcc: 1, din: 0});
  var colors = [];
  var r = [];
  var g = [];
  var b = [];
  var s_flag = [];

  for (var i=0; i<85; i++) {
    colors[i]=([0, 0, 0]);
  }
  led.rgbs(colors);

  obniz.switch.onchange = function(state) {
    $('#print').text(state);
    obniz.display.clear();
    obniz.display.print(state);
  }  

  $('#on').click(async function () {
    obniz.display.clear();
    obniz.display.print("ON");
    s_flag = 0;
    obniz.uart0.start({tx: 8, rx: 9, baud:57600});
    while(1){
      obniz.uart0.send(0x6D);
      obniz.uart0.onreceive = function(data, text) {
        console.log(data[1] + "," + data[3] + "," + data[5] + "," + data[7]);
        for (var i=0; i<80; i++) {
          if (data[1] > 10) {r = data[1];} else {r = 1;}
          if (data[3] > 10) {g = data[3];} else {g = 1;}
          if (data[5] > 10) {b = data[5];} else {b = 1;}
          colors[i]=([r, g, b]);
        }
      }
      led.rgbs(colors);
      await obniz.wait(100);
      if (s_flag) break;
    }
  });

  $('#off').click(async function () {
    obniz.display.clear();
    obniz.display.print("OFF");
    for (var i=0; i<80; i++) {
      colors[i]=([0, 0, 0]);
    }
    led.rgbs(colors);
    s_flag = 1;
    await obniz.wait(100);
    obniz.uart0.end();
  });
}

</script>
</body>
</html>

2台のobnizと連動

スクリーンショット 2019-03-25 15.16.05.png

ソースコードはこちら

ShoKacPot2.html
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="https://obniz.io/js/jquery-3.2.1.min.js"></script>
    <script src="https://unpkg.com/obniz@2.0.1/obniz.js" crossorigin="anonymous"></script>
  </head>
  <body>

    <div id="obniz-debug"></div>
    <h1>obniz instant html</h1>
    <button id="on">ON</button>
    <button id="off">OFF</button>
    <div id="print"></div>

    <script>
      var obniz = new Obniz("OBNIZ_ID_HERE");
      var obniz1 = new Obniz("OBNIZ_ID1_HERE");

      obniz1.onconnect = async function () {
        obniz1.display.clear();
        var led1 = obniz1.wired("WS2812B", {gnd:2, vcc: 1, din: 0});
        var colors = [];
        var r = [];
        var g = [];
        var b = [];
        var s_flag = [];
        for (var i=0; i<85; i++) {
          colors[i]=([1, 1, 1]);
        }
        led1.rgbs(colors);
        obniz1.switch.onchange = async function(state) {
          $('#print').text(state);
          //          obniz1.display.clear();
          obniz1.display.print(state);
        }  


        obniz.onconnect = async function () {

          obniz.display.clear();

          obniz.io11.output(false); // GND
          obniz.io10.output(true);  // VDD(5V)

          var led = obniz.wired("WS2812B", {gnd:2, vcc: 1, din: 0});
          var colors = [];
          var r = [];
          var g = [];
          var b = [];
          var s_flag = [];

          for (var i=0; i<85; i++) {
            colors[i]=([0, 0, 0]);
          }
          led.rgbs(colors);

          obniz.switch.onchange = async function(state) {
            $('#print').text(state);
            //          obniz.display.clear();
            obniz.display.print(state);
          }  

          $('#on').click(async function () {
            obniz.display.clear();
            obniz.display.print("ON");
            obniz1.display.clear();
            obniz1.display.print("ON");
            s_flag = 0;
            obniz.uart0.start({tx: 8, rx: 9, baud:57600});
            while(1){
              obniz.uart0.send(0x6D);
              obniz.uart0.onreceive = function(data, text) {
                console.log(data[1] + "," + data[3] + "," + data[5] + "," + data[7]);
                for (var i=0; i<80; i++) {
                  if (data[1] > 10) {r = data[1];} else {r = 1;}
                  if (data[3] > 10) {g = data[3];} else {g = 1;}
                  if (data[5] > 10) {b = data[5];} else {b = 1;}
                  colors[i]=([r, g, b]);
                }
              }
              led.rgbs(colors);
              led1.rgbs(colors);
              await obniz.wait(100);
              if (s_flag) break;
            }
          });

          $('#off').click(async function () {
            obniz.display.clear();
            obniz.display.print("OFF");
            obniz1.display.clear();
            obniz1.display.print("OFF");

            for (var i=0; i<80; i++) {
              colors[i]=([0, 0, 0]);
            }
            led.rgbs(colors);
            led1.rgbs(colors);
            s_flag = 1;
            await obniz.wait(100);
            obniz.uart0.end();
          });
        }
      }
    </script>
  </body>
</html>

動作確認

ディスプレイ(NefryBTのOLED)表示

シリアルプロッタ(Arduino IDE)表示

NeoPixel(WS2812B)でLチカ

obnizで動作確認

まとめ

検出点が4箇所あるため、触る場所によって変位量が変わることが確認できました。また、感度(押し込む力に比例して数値が0〜120の間で変化する)や反応速度は良好でした。
良き"ショッカク"ライフを!

iotlt
IoT縛りの勉強会です。 毎月イベントを実施しているので是非遊びに来てください! 登壇者を中心にQiitaでも情報発信していきます。 https://iotlt.connpass.com
https://iotlt.connpass.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away