Hatena::ブログ(Diary)

uncertain world

2017-06-19

アクリルケースに触ったことをセンシングするシステムを開発

| 21:01 | アクリルケースに触ったことをセンシングするシステムを開発を含むブックマーク アクリルケースに触ったことをセンシングするシステムを開発のブックマークコメント

D

またしてもですが、どこで使われるのかはわかりませんが、

アクリルケースへ触ったことを検知するシステムを作ってみました。

 

こちらのセンシング方法では、

ざっくりですが、触ってる指の本数を検知したり、

ケースの中に水を入れておけば、水に触れたことも検知することが可能です。

 

一本指だと、シンプルな音で、

複数で触るとフレーズができたりすると、メロディラインを作って楽しめたりできそうな気がしなくもないです。

 

基盤技術は、Disney Researchの研究で発表された、

Toucheの概念を応用しています。

https://www.disneyresearch.com/project/touche-touch-and-gesture-sensing-for-the-real-world/

2017-05-23

RedBearLab BLE Nanoで色々ためす

| 10:17 | RedBearLab BLE Nanoで色々ためすを含むブックマーク RedBearLab BLE Nanoで色々ためすのブックマークコメント

f:id:rin1024:20170523101654j:image

みんな裏側からのピンアサイン書いてて混乱したので、

表からみた図を用意してみたよ。


あとで色々メモ。


f:id:rin1024:20170523101901j:image

2WDを操縦するときの回路図

モータードライバ(TA7291P)を2つ積んで、

出力制御はBLE Nanoのデジタルピン x 2、PWMピン x 1をそれぞれのドライバにつなぐ。

電源は単3 x 4本の6Vで動かす。

モーターはマブチとかの一般的なDCモーターを想定。

制御はRedBearLabが出しているBLE ControllerでピンのH/Lを制御すれば動く。

超シンプル。

2016-12-18

3ピンのDYP-ME007TXをArduino UNOで使う

| 20:23 | 3ピンのDYP-ME007TXをArduino UNOで使うを含むブックマーク 3ピンのDYP-ME007TXをArduino UNOで使うのブックマークコメント

以前購入したこのセンサ、OUTってかいてるからアナログの値出力してると思ったら、

どうやらシリアルで動いていた様子…ハマった。


下記のコードで動作確認。

OUTピンをD6にさせばいいみたい。

#include <SoftwareSerial.h>

// TX_PIN is not used by the sensor, since that the it only transmits!
#define PING_RX_PIN 6
#define PING_TX_PIN 7

SoftwareSerial mySerial(PING_RX_PIN, PING_TX_PIN);

long inches = 0, mili = 0;
byte mybuffer[4] = {0};
byte bitpos = 0;

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


void loop() {
  bitpos = 0;
  while (mySerial.available()) {
    // the first byte is ALWAYS 0xFF and I'm not using the checksum (last byte)
    // if your print the mySerial.read() data as HEX until it is not available, you will get several measures for the distance (FF-XX-XX-XX-FF-YY-YY-YY-FF-...). I think that is some kind of internal buffer, so I'm only considering the first 4 bytes in the sequence (which I hope that are the most recent! :D )
    if (bitpos < 4) {
      mybuffer[bitpos++] = mySerial.read();
    } else break;
  }
  mySerial.flush(); // discard older values in the next read

  mili = mybuffer[1] << 8 | mybuffer[2]; // 0x-- : 0xb3b2 : 0xb1b0 : 0x--
  inches = 0.0393700787 * mili;
  Serial.print("PING: ");
  Serial.print(inches);
  Serial.print("in, ");
  Serial.print(mili);
  Serial.println("mili");

  delay(100);
}

微調整する部分は、

たまにマイナスの値がくるのでそれを無視するのと、

インチとmiliでしか値が出てないのでcmに変換が必要。


f:id:rin1024:20161219135830j:image:medium

本来の販売元はTindieで出てるこれっぽい。

https://www.tindie.com/products/upgradeindustries/serial-ultrasonic-distance-sensor/

Serial Ultrasonic Distance Sensor (DYP-ME007TX)

Description
This is a fully digital, serial output ultrasonic sensor that uses typical RS-232/UART output signaling. Only one wire required!

This module constantly pumps out readings at 10 Hz which makes it incredibly easy to operate.

Package Contents

1DYP-ME007TX Serial Ultrasonic Sensor
Specifications

Interface: RS-232 / UART (constant output)
Serial Format: 9600 Baud No Parity 8 bits per byte 1 Stop Bit (output)
Range: up to 4m
Accuracy: 1mm
Sound Frequency: 40 kHz
Output Rate: 10 Hz
Response Envelope: &lt; 30 deg
Supply voltage: 5V
Supply current: 15mA typical
Serial output format

The output from this sensor comes in packets of 4-bytes:

Data[0] = 0xFF: Packet Header
Data[1]= 0x0-0xFF: Data Most Significant Byte (MSB)
Data[2]= 0x0-0xFF: Data Least Significant Byte (LSB)
Data[3]= 0x0-0xFF: Data Checksum: = (0XFF + MSB + LSB) & 0xFF
Data is in MILLIMETERS
16 bit value in mm = Data[1] >> 8 | Data[2]

ちなみに、MegaでやるとなぜかSoftwareSerialでDigital Pinを使おうとするとうごかなくて、

A8とかのピンだったら動く様子。ナジェナンディスカ…。


もう一点追記、

SoftwareSerialを複数やる場合、一度に複数ポートをよめないみたいで、

myPort.listen()で切り替える必要がある。

更に、listenして直後はデータ読めないので、ちょっとまってあげる必要がある。

めどい。。。

もろもろ加味したコードが下記。

#include<SoftwareSerial.h>

long showTimer;

#define NUM_SENSORS 7
#define MAX_RANGE 5000

SoftwareSerial mySerial[NUM_SENSORS] = {
  SoftwareSerial(A8,5),
  SoftwareSerial(A9,6),
  SoftwareSerial(A10,7),
  SoftwareSerial(A11,8),
  SoftwareSerial(A12,9),
  SoftwareSerial(A13,10),
  SoftwareSerial(A14,11),
};

int currentSensorIndex = 0;
long millimeters[NUM_SENSORS];
long waitTimer;

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

  for (int i=0;i<NUM_SENSORS;i++) {
    mySerial[i].begin(9600);
    millimeters[i] = 0;
  }
}

void loop() {
  if (currentSensorIndex < NUM_SENSORS) {
    if (waitTimer == 0) {
      mySerial[currentSensorIndex].listen();
      waitTimer = millis();
    }
    else if (millis() - waitTimer > 100) {
      readSerial(&mySerial[currentSensorIndex], currentSensorIndex);
      waitTimer = 0;
      currentSensorIndex++;
    }
  }
  else {
    currentSensorIndex = 0;
  }

  if (millis() - showTimer > 100) {
    for (int i=0;i<NUM_SENSORS;i++) {
      Serial.print(millimeters[i]);
      Serial.print("\t");
    }
    Serial.println();

    showTimer = millis();
  }
}

void readSerial(SoftwareSerial *s, int idx) {
  if (s->available() > 3) {
    byte myByte = s->read();
    byte myBuffer[2] = {0};
    if (myByte == 0xFF) // Start-Byte erkennen
    {
      myBuffer[0] = s->read(); // HighByte einlesen
      myBuffer[1] = s->read(); // LowByte einlesen
      s->flush();              // Checksumme und ggf. weitere aufgelaufene Messungen verwerfen
    }

    long mm = myBuffer[0] << 8 | myBuffer[1]; // HighByte und LowByte verodern
    if (mm > 0 && mm < MAX_RANGE) {
      millimeters[idx] = mm;
    }
  }
}

2016-02-18

FadaCandyことはじめ(Mac OS X Yosemiteにて)

23:46 | FadaCandyことはじめ(Mac OS X Yosemiteにて)を含むブックマーク FadaCandyことはじめ(Mac OS X Yosemiteにて)のブックマークコメント

f:id:rin1024:20120207132506j:image:medium

ふつう、USBをさしたらlsコマンドで一覧に出てくるものだと思うし、

ましてやUSBをさしたらジャックの隣のLEDは点灯するもんだと思ってたのだけど、

いずれも反応せず動かない!?って焦ったんだけど、

ちゃんと手順をふんでインストールすると、無事動作を確認できた。

ジャックの隣のLEDは疎通ができてるって意味のLEDだった様子。


手順、メモ。

git clone git://github.com/scanlime/fadecandy
cd fadecandy/server
make submodules
make
sudo mv fcserver /usr/local/bin
fcserver

これをやってから、ブラウザで「http://localhost:7890/」を開いてFadeCandyが接続されてると一覧に出てくる。


チュートリアルはちゃんと読みましょう、ということで。

参考: https://learn.adafruit.com/1500-neopixel-led-curtain-with-raspberry-pi-fadecandy/fadecandy-server-setup


D

動作テスト

2016-01-03

Facebookを1日1時間しかみれないようにしてみた

| 01:22 | Facebookを1日1時間しかみれないようにしてみたを含むブックマーク Facebookを1日1時間しかみれないようにしてみたのブックマークコメント

年明けのリハビリにChromeのExtension書いてみた。

内容は、タイトルの通り「Facebookを1日1時間以上見れないようにする」もの。


ExtensionをDLする

ここにあります → http://sorauta.net/files/fbFilter.crx


△もむろにGoogle Chromeをひらき、アドレスバーに「chrome://extensions」とうちこむ。

f:id:rin1024:20160104011720j:image:w360

こんなページが出てくるはず


DLしたExtensionをDrag & Dropする

f:id:rin1024:20160104011835j:image:w360

ファイル名は「fbFilter.crx」です。

Dropすると、上記のようなアラートがでるので、Add Extensionをおす


インストールされたか確認するために、おもむろにfacebookをひらいてみる

f:id:rin1024:20160104012115j:image:w360

SSのとおり、残り時間が表示されていればインストール完了です!

おめでとうございます。



経過秒数後どうなるかって?

それは、やってみてのおたのしみということで(特にそんな大したことしてない)




ソースは下記。


manifest.json

{
  "name": "Internet filter",
  "version": "0.1",
  "manifest_version": 2,
  "description": "This Extension is intended to limit the viewing time of Facebook.",
  "icons": {
      "48": "icon128.jpg",
      "128": "icon128.jpg"
  },
  "content_scripts": [{
    "matches": ["https://www.facebook.com/*"],
    "js": ["script.js"]
  }]
}


script.js

var STOP_THRESHOLD = 3600; // 1日あたり、この秒数以上Facebookをみていたら閲覧制限がかかる
var TIMER_INTERVAL = 1000; // loop関数を実行する周期、ミリ秒で表記

var watchTimer;
var fbClosed = false;
var isViewer = false;

/**
 * 初期処理を行う関数
 *  ページをひらくとまずこの関数が実行されます
 */
var setup = function() {
  console.log('setup fbTiler');

  // ブラウザ上に保存されていたデータを読みだす
  var storedTimestamp = Number(localStorage.getItem("storedTimestamp"));
  // もしブラウザ上にデータが保存されていなかった場合、初期化する
  if (storedTimestamp == null) {
    console.log("initialize local storage");

    var cDate = new Date();
    storedTimestamp = Math.floor(cDate.getTime() / 1000);
    saveToStorage(storedTimestamp, 0);
  }

  // loop関数を定期的に実行するようにセット
  watchTimer = setInterval(loop, TIMER_INTERVAL);

  // 残り時間をFacebook上に表示するようにする
  var mPattern = location.href.match("/messages/([0-9a-z\.\_\-]+)");
  if ((location.pathname == "/" || (mPattern.length > 0 && mPattern[1].length > 0)) &&
      document.title && document.title.length > 0) {
    var element = document.createElement('div');
    element.id = "timeLimitView";
    element.innerHTML = "&nbsp;";
    element.style.position = 'fixed';
    element.style.bottom = '5px';
    element.style.left = '5px';
    document.body.appendChild(element);

    isViewer = true;
  }
}

/**
 * 定期的に実行される関数
 *  閲覧時間の確認、表示制限の処理などを行う
 */
var loop = function() {
  // タイムスタンプ(long型)を、処理しやすいように連想配列に整形する
  var cDate = new Date();
  var cHash = getDateHash(Math.floor(cDate.getTime() / 1000));
  var storedTimestamp = Number(localStorage.getItem("storedTimestamp"));
  var sHash = getDateHash(storedTimestamp);

  // 日付が更新されたか確認
  var keys = ['Y', 'M', 'D'];
  var isDifferentDate = false;
  for (var i in keys) {
    if (cHash[keys[i]] != sHash[keys[i]]) {
      isDifferentDate = true;
      break;
    }
  }

  // 日付が更新されていた場合、閲覧秒数のカウントをリセット
  if (isDifferentDate == true) {
    cTimestamp = Math.floor(cDate.getTime() / 1000);
    console.log("update stored data", cTimestamp);
    saveToStorage(cTimestamp, 0);
  }
  // 経過時間をチェックする
  else {
    var storedViewSec = Number(localStorage.getItem("storedViewSec"));

    // 閲覧時間が、本日の制限時間を超えていた場合、表示をブロック
    if (storedViewSec > STOP_THRESHOLD) {
      //console.log("shut down facebook");
      document.body.innerHTML = '<center><img src="http://serif.hatelabo.jp/images/cache/2b0a04a1636b501e0ad202e672039491b05690d9/f9d7755e1c8f7abead4c76b1a4c5e2225aba1080.gif" style="margin:10px auto;text-align:center;" /></center>';
      fbClosed = true;
    }
    // 残り時間を更新
    else {
      if (isViewer == true) {
        document.getElementById('timeLimitView').innerHTML = (STOP_THRESHOLD - storedViewSec) + " sec";
      }
      //console.log("only " + (STOP_THRESHOLD - storedViewSec) + " second, you can enjoy facebook");
      saveToStorage(storedTimestamp, storedViewSec + (TIMER_INTERVAL / 1000));

      // TODO: test here
      //if (fbClosed == true) {
      //  location.reload();
      //}
    }
  }
}

/**
 * タイムスタンプを処理しやすいように連想配列に変換する
 */
var getDateHash = function(timestamp) {
  var d = new Date(timestamp * 1000);

  var hash = {
    Y  : d.getFullYear(), // year
    M  : d.getMonth() + 1, // month
    D  : d.getDate(), // date
    h  : d.getHours(), // hour
    m  : d.getMinutes(), // min
    s  : d.getSeconds(), // sec
    t  : Math.floor( d.getTime() / 1000 ), // unix time
  };

  for (var k in hash) {
    if (k != 'Y' && k != 't') {
      hash[k] = ('0' + hash[k]).slice(-2);
    }
  }

  return hash;
}

/**
 * ブラウザ上に現在の閲覧時間などを保存する
 */
var saveToStorage = function(st, sv) {
  localStorage.setItem("storedTimestamp", st); // unix time
  localStorage.setItem("storedViewSec", sv); // sec
}

///////////////////////////////////
// 初期化する関数を実行
setup();


gitにもあげたので、なにか更新があればこちらのリポジトリでやってきます

https://github.com/rin1024/Internet-filter-on-Chrome