読者です 読者をやめる 読者になる 読者になる

ブログ

クソブログ

esp32のBLE scanでRSSIを表示する

esp32のBLE scanでRSSIが取得できるか?

現時点で "esp32 ble scan RSSI" でweb検索すると、上手くいかないとか、変な値が取得できるといった情報ばかりが見つかる。そこで、本当にできないのか試してみたら上手くいったのでメモ。

開発環境の準備

まずesp-idfの開発環境を揃える。esp-idfはWindowsよりLinuxで開発したほうが色々と捗るので、WindowsVirtualboxdebian linuxを動作させ、その中でesp-idfの開発環境をセットアップした。特にハマる点もないので詳細な手順は省略。検索すればすぐ見つかる。

次に、ソースを見る際に grep -r しまくっても良いが、IDEの方がなにかと便利なので、eclipseからesp-idfを扱えるようにセットアップした。ついでにeclipseからbuild→flashまでできるようにした。これも簡単なので詳細な手順は省略。

一点だけハマる可能性があるのは、Virtualboxにesp32開発ボードのUSB-Serialのインターフェイスをアタッチする所で、何かの拍子に乱暴に切断してしまった後だと再アタッチが失敗することがある。そんな場合は、windowsのデバイスマネージャの「ポート(COMとLPT)」にあるCOMポートを削除してから開発ボードを接続して再アタッチするとうまくいく。これに気づくまではいちいちwindows自体を再起動させていた。

BLE scanできるサンプルソース

esp-idf/examples/bluetooth/gatt_client/

がそれ。昔はexample 15_gatt_clientと呼ばれていたもののようだ。

このプロジェクトをeclispeにインポートして色々と探ってみると、rssiはesp_gap_ble_api.hで定義されているesp_ble_gap_cb_param_tという共用体にintとして入っており、gattc_demo.cのesp_gap_cbというコールバック関数の中でアクセスできることがわかる。よって、この関数の中で

    case ESP_GAP_BLE_SCAN_RESULT_EVT: {
        esp_ble_gap_cb_param_t *scan_result = (esp_ble_gap_cb_param_t *)param;
        switch (scan_result->scan_rst.search_evt) {
        case ESP_GAP_SEARCH_INQ_RES_EVT:
            for (int i = 0; i < 6; i++) {
                ESP_LOGI(GATTC_TAG, "%x:", scan_result->scan_rst.bda[i]);
            }
            ESP_LOGI(GATTC_TAG, "\n");
            adv_name = esp_ble_resolve_adv_data(scan_result->scan_rst.ble_adv,
                                                ESP_BLE_AD_TYPE_NAME_CMPL, &adv_name_len);
            ESP_LOGI(GATTC_TAG, "Searched Device Name Len %d\n", adv_name_len);

            ESP_LOGI(GATTC_TAG, "RSSI: %d\n", scan_result->scan_rst.rssi);  //これを追加。以下省略。

とRSSIを出力するようにしてみた。

簡単なテスト

使ったesp32デバイスはdoitの開発ボードと、秋月でも買えるespressifの開発ボードで、両方とも同じ動作をした。
変更したプログラムをビルドしてesp32にflashして、適当なシリアルモニタ(LinuxのCuteComが使いやすかった)で出力を見てみると、BLEタグ(スマートフォンで代用。BLE Peripheral Simulatorを使用。)がesp32の数十cm程度の近くにあるときは

\0x1b[0;32mI (9350) GATTC_DEMO: RSSI: -64

程度で、数メートル離すと

\0x1b[0;32mI (7260) GATTC_DEMO: RSSI: -85

程度となったので、正常な値を取得できているようだ。ただ、当然だがesp32の向きが変わると値が大きく変動するので、色々と工夫してタグの接近・離脱を判断する必要はある。

まとめ

安価な据え置き型ble scanner(wifiへのゲートウェイ)としての利用可能性が薄ぼんやりと見えた。その用途では、これまではRaspberry PiやEdisonなどを使うしかなかったが、esp32で代用できれば色々と可能性が広がる。

Beaglebone Green WirelessでEnOceanゲートウェイ(の基本部分)を用意する

BBGWでnode.jsのEnOceanモジュールを使ってゲートウェイを動作させてみたら極めて高品質で使いやすかったのでメモ。Raspberry Piでも同様に動作した。

EnOceanとは

バッテリーなしで動作するセンサ機器と受信機、データフォーマットの総称。現時点で実用的と言える数少ないIoTデバイスの一つ。

EnOceanの利点

電池交換の必要がない。

太陽電池で動作するもの、スイッチの押す力で発電して動作するものが代表的である。プロトタイピングやPOCの段階ではデバイスの電池交換は問題にならないが、実用フェーズに入ると電池交換は人的・物的コストを生み続ける悪魔になる。電池交換作業でデバイスを破壊するような事故も頻発する。

送受信の信頼性が高い。

送受信の信頼性を高めるために、一度にパケットを3つ送信するようになっている。電波状況は色々と変化するが、経験上、受信機との距離が10メートル以内ならデータの取りこぼしはほぼ無い。928MHz帯の電磁波を利用するため、障害物を回りこんで届く。

データフォーマットがよく整理されている。

様々なセンサ機器のデータフォーマットが規定されており、更に機器の登録などのコマンド体系も整備されている。

EnOceanの欠点

バイスが高価。

電池交換の人的・物的コストがゼロなので、デバイス自体の高価さは長期運用を考えるとあまり問題にはならないが、単純に他のデバイスと較べてしまうと高価。

あまり流通していない。

10 高いからあまり売れない。

20 あまり売れないから高い。

30 GOTO 10

まともなゲートウェイソフトウェアがない(ように見える)。

EnOcean Linkという名のEnOcean公式のゲートウェイソフトウェアライブラリがあるが、C++で書かれているのでコンパイルして動作させるまでが大変面倒である。最近ではrubypythonで簡易的なテレグラムパーサを自作してセンサデータを抽出するような使い方が増えてきたようだが、EnOceanの良く整備された機能群を利用できていない。

今回、node.jsで書かれた大変優れたフル機能のゲートウェイソフトウェアライブラリがBBGWやR-Pi上で動作することが検証できたので、まともなゲートウェイソフトウェアが無い問題は私の勝手な幻想だったと言って良い。

日本国内では1ホップまでのリピータしか使えない。

これはあまり問題にならない。2ホップ以上必要ならゲートウェイを増やすべき。

今回使ったハードウェア

Beaglebone Green Wireless

シングルボードコンピュータ

SeeedStudio BeagleBone Green Wireless

他にも、node.jsが動作する機器なら多分なんでもOK。

USB400J

EnOeanのUSBドングル型受信機。これは割りと安い。

www.switch-science.com

ところで某Wi-S○Nの受信機ってなんであんなに高いの?買って試す気が起こらないので誰かくれ。

STM431J

温度センサ。これも割りと安いが、ケースがない。ケースだけを某所で買うと4000円くらいする。うーん・・・。タカチのケースを加工した方が良いだろう。個人利用なら紙や布でケースを作ってしまうのが手軽で良い。

www.switch-science.com

ESM210R

プッシュスイッチ。物理世界からの様々なイベント入力に使える。

EnOcean ロッカースイッチ・シングル ESM210R - スイッチサイエンス

売り切れですかそうですか。

node.jsのEnOceanモジュール

今回の主役。node.jsのEnOceanモジュールは幾つかあるが、BBGWやR-Piでも動作したフル機能のモジュールは

node-enocean-utils

だった。作者は日本の方のようだ。素晴らしいモジュールをありがとうございます。

最初に見つかるnode-enoceanというモジュールはコンパイルに失敗して動作しなかった。

導入準備

今回使うモジュールはnode.jsの4.4以上でのみ動作するので、それより古い環境ではnode.js自体の更新が必要である。今回用いたBBGWでは、OSイメージとして

https://debian.beagleboard.org/images/bone-debian-8.6-seeed-iot-armhf-2016-11-06-4gb.img.xz

を使ったが、これのnode.jsが白亜紀の0.12系だったので更新が必要であった。

sudo apt-get purge bb-node-red-installer nodejs

sudo apt-get update

sudo apt-get install -y curl locales ntpdate avahi-utils python build-essential

curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -

sudo apt-get install -y nodejs

hash -r

これでBBGW上でnode.jsの6系が使えるようになった。

$ node -v
v6.10.1
$ npm -v
3.8.2

bonescriptもここで再インストールすればちゃんと動く。

導入

動作検証用に適当にディレクトリを掘ってモジュールをローカルインストールする。

mkdir enocean_exp

cd enocean_exp

npm install node-enocean-utils

基本的な動作テスト

まずは、全てのテレグラムを出力する単純なコードを書いてみる。'data-unknown'イベントを捕まえて、テレグラムのmessage部分をコンソールに出力する。

simple1.js

var enocean = require('node-enocean-utils');

// Start to monitor telegrams incoming from the Enocean devices
enocean.startMonitor({'path': '/dev/ttyUSB0', 'rate': 57600});

// Set an event listener for 'data-unknown' events
enocean.on('data-unknown', (telegram) => {
var message = telegram['message'];
console.log(message);
});

 これを動作させて

node simple1.js

ロッカースイッチを押して離すと

{ packet_type: 10,
packet_type_desc: 'RADIO_ERP2 (ERP2 protocol radio telegram)',
device:
{ id: '0000002C8674',
eep: '',
name: '',
manufacturer: '',
learned: false },
oid: '00 2C 86 74',
crc: true,
eep: '',
known: false,
rorg: '',
rorg_desc: '',
func: '',
func_desc: '',
type: '',
type_desc: '',
data_dl_buffer: <Buffer 84>,
dbm: -50,
dbm_desc: '-50 dBm' }
{ packet_type: 10,
packet_type_desc: 'RADIO_ERP2 (ERP2 protocol radio telegram)',
device:
{ id: '0000002C8674',
eep: '',
name: '',
manufacturer: '',
learned: false },
oid: '00 2C 86 74',
crc: true,
eep: '',
known: false,
rorg: '',
rorg_desc: '',
func: '',
func_desc: '',
type: '',
type_desc: '',
data_dl_buffer: <Buffer 00>,
dbm: -52,
dbm_desc: '-52 dBm' }

パケット2つぶんが基本的なデコードを経て出力された。eepの指定を行っていないので、ON/OFFのデータはdata_dl_buffer部分に数値として現れている。

今回のロッカースイッチは2ボタンのタイプで、EEPとしてF6-02-04を指定するとテレグラムの完全な解釈ができる。このEEPタイプはnode.jsモジュール内で定義されているのでそのまま利用できる。

バイスIDが 00 2C 86 74 のロッカースイッチを、EEP: F6-02-04としてteach(登録)して、data-knownイベントで解釈済みのデータを出力する機能を追加すると以下のようになる。

simple2.js

var enocean = require('node-enocean-utils');

//// Teach the information of Enocean devices
enocean.teach({
'id' : '00 00 00 2C 86 74',
'eep' : 'F6-02-04',
'name': 'Rocker Switch, 2 Rocker'
});

// Start to monitor telegrams incoming from the Enocean devices
enocean.startMonitor({'path': '/dev/ttyUSB0', 'rate': 57600});

// Set an event listener for 'data-known' events
enocean.on('data-known', (telegram) => {
var message = telegram['message'];
console.log(message['device']['id'] + ': ' + message['device']['name'] + ': ' + message['desc']);
});

これを動作させて、ロッカースイッチを左右(上下?)押して離すと以下のように完全に意味までデコードされた情報が出力される。

$ node simple2.js
0000002C8674: Rocker Switch, 2 Rocker: B0 pressed
0000002C8674: Rocker Switch, 2 Rocker: released
0000002C8674: Rocker Switch, 2 Rocker: BI pressed
0000002C8674: Rocker Switch, 2 Rocker: released

ボタン0が押されて離され、ボタンIが押されて離されたことが記録された。releaseはどちらのボタンからのものかは区別できないようだ。DolphinViewで見てもそうなので、デバイスから出る信号そのものが同じと考えられる。

温度センサも全く同様に、teachでEEPを登録してデータを解釈できた。

ここまで理解できれば、モジュールのドキュメントを読み進める知識が整ったので

node-enocean-utils

を参照して機能の全貌を理解できる。

M2Xへのアップロードも普通にできたが省略。

次は

これをNode-Redから使えるようにして管理や運用を容易にして実用性を高める。teach-inテレグラムの扱いとteachメソッドの呼び出しといったデバイスの登録処理、クラウドへのデータ送信などはNode-Redのノードとして構成すれば、コツメカワウソちゃんでも扱えるようになるはずである。

まとめ

これでシングルボードコンピュータ上でEnOceanのフル機能のまともなゲートウェイをやっと作れる見通しが立った。

ESP32の開発ボード(DOIT ESP32 Development Board)をArduino IDEで使ってみる

2016年末に買って使い方がわからず放置してあったESP32の開発ボードを、ふと思い立って触ってみたらプログラムのアップロードから動作検証までいけたのでメモ。

ESP32開発ボード

github.com

このボードをAliExpressで買った。人類の天敵であるTELECの認証マークが付いているので日本国内で使用しても殺害される危険は少ない。

http://esp32.net/

を見ると、すでに膨大な種類の開発ボードが出回っているが、日本製の良いものはまだ無いようだ。

開発環境準備

Windows上で行う。基本的には解説ページ

github.com

に従えばOK。私はgit clientとしてSourceTreeを使ったが、解説ページに書いてあるようにgitの純正?クライアントを使っても同じだろう。

解説ページに書いてない部分としては、Arduino IDE上でボードを選ぶときは

f:id:XX-Prime:20170312194916p:plain

のようにESP32 Dev ModuleでOK。

もう一つ、プログラムをアップロードするときにBOOTボタンを押しっぱなしにしておく必要がある。ボードの初期リビジョンのバグみたいだが、これはこれでうっかりアップロードを防げるので良い仕組みのような気もする。

BOOTボタンを押さずにアップロードしようとすると

esptool.py v2.0-dev
Connecting...

A fatal error occurred: Failed to connect to ESP32: Timed out waiting for packet header
A fatal error occurred: Failed to connect to ESP32: Timed out waiting for packet header

というエラーがでる。ここまで来た人はあとはBOOTボタンを押しっぱなしにするだけなので成功したも同然である。ちなみに私がBOOTボタン押下の必要性に気づくまで試行錯誤や検索を繰り返して数時間を浪費したことは恥ずかしくて書けない。

追記:macarduino IDEではBOOTボタン押下の必要がなかった。

サンプルプログラムを試す

Arduino IDE

ファイル→スケッチ例→Simple BLE→SimpleBleDevice

をアップロードしてみる。BOOTボタンを押すたびに、アドバタイズする文字列(の数値部分)が変わるというもので、デバッグ出力をシリアルモニタで確認できる。シリアルモニタは115200bpsで開く。

このプログラムを動作させた状態でスマートフォンでBLEスキャンをすると

f:id:XX-Prime:20170312200801p:plain

のように、BLE32 at: XX という名でアドバタイズされているのを確認できる。BOOTボタンを押すとXXの部分が増えていく。これでESP32の開発環境からデバイスまで一通りが正常に機能していることを確認できる。ちなみにみんな大好きBlinkプログラムは(そのままでは)エラーが出て動作しないので泣かないように。Blinkは

int ledPin = 2;

と定義してこのピンをON/OFFするようにするとボード上の青いLEDが点滅する。

どっかに配線図ないのかな?

→どうやらこれっぽい:https://www.dropbox.com/s/jefwxxtufgwg0ex/esp32_Schematic%20Prints.pdf?dl=0 

まとめ

ESP32開発ボードを買って使い方がわからずに放置してる人は再挑戦してみてはいかがだろうか。

 

BMP085とNode-REDでM2Xに気圧データを送る

Node-REDで簡単にI2C接続の気圧センサの取得値をM2Xにアップロードできるだろうとやってみたら、初心者が踏むであろう地雷を余すこと無く踏んでいって手こずったのでメモ。

ハードウェア準備

今回はホストマシンにBeaglebone Blackを、OSに

BeagleBoard.org - latest-images

の Jessie IoT (non-GUI) for BeagleBone via microSD card を選んだ。このイメージは最初からBeaglebone用のNode-REDが動作しているので便利である。BBGでもBBGWでもBBBWでもBBBlueでも同様に動作するはずである。

センサはサインスマート(SainSmart)BMP085 気圧センサーモジュール を使った。選択に積極的な理由は無い。そのへんに転がってたから。

BMP085の配線はI2Cなので

BeagleBoard.org - demo_bmp085

の通りだが、残念ながら新しいOSイメージでは /sys/bus/i2c/drivers/bmp085/ がもはや存在しないのでこのbonescriptデモは動作しない。bme280あたりで動くデモにそろそろ作り直したほうが良いと思う。bonescriptのデモは他にも色々と古くなってて残念な感じである。

bmp085のnode.jsモジュールをインストール

一応、全部をnode.jsで行ってみようと思ったので、読み取りライブラリもnode.jsのを用いた。

www.npmjs.com

の通り、npmでモジュールをインストールする。今回はNode-REDで使いたいので

$ sudo npm -g install bmp085

とグローバルインストールOK。/usr/local/lib/node_modules/bmp085/にモジュールがインストールされる。

気圧と気温を読み取れるかテストする際には、

var BMP085 = require('bmp085'),
barometer = new BMP085({
  'device': '/dev/i2c-2'
});
barometer.read(function (data) {
  console.log("Temperature:", data.temperature);
  console.log("Pressure:", data.pressure);
});

と、I2Cバスの場所として/dev/i2c-2を明示的に指定しないと失敗する(地雷1)。

M2XのNode-REDモジュールをインストール

www.npmjs.com

$ sudo npm -g install node-red-m2x

OK

$ sudo systemctl restart node-red.service

でnode-redを再起動してからNode-REDのwebページを開き、storageカテゴリにM2Xノードが現れていればインストール成功。

f:id:XX-Prime:20170214204619p:plain

M2X準備

M2Xのwebページにログインして、デバイス一つと、その配下にストリーム2つ(気圧用と温度用)を作っておく。

Node-REDフロー構成

一分に一回、気圧と温度データを取得してM2Xにアップロードするフローを構成した。

f:id:XX-Prime:20170214205921p:plain

やることは単純なので直線的でわかりやすいフローである。

測定開始タイマー

injectノードを1分のインターバルでリピート構成した。出力ペイロードは使わないのでデフォルトのタイムスタンプのままにしてある。

f:id:XX-Prime:20170214210659p:plain

気圧測定(BMP085)

問題はここ。functionノードでbmp085モジュールを呼び出して使う部分である。色々あったが動作する状態になったのが以下の図。

f:id:XX-Prime:20170222222823p:plain

topic_idにM2XのDEVICE IDを、sub_topic_idにストリーム名を指定する。

まず、素朴にfunctionノード内でrequireによるbmp085モジュールのロードを試みると

function : (error)
ReferenceError: require is not defined

などと怒られて動かない(地雷2)。

ちょっと調べると、Node-REDで外部モジュールを使う方法が分かった。requireはsettings.jsの中のfunctionGlobalContextに書け、というのが正解である。と言われてもBBB上のnode-redのsettings.jsがどこにあるかがわからんので、/var/logあたりにnode-redの起動ログがあるはずと予想して

root@bbb0001:/var/log# grep -r 'node-red' * | grep 'settings.js'

で探してみたら

daemon.log:Feb 11 11:52:30 bbb0001 Node-RED[2814]: 11 Feb 11:52:30 - [info] Settings file  : /root/.node-red/settings.js

と、あっさり見つかった。このファイルの中を見てみると、

functionGlobalContext: {
// os:require('os'),
// octalbonescript:require('octalbonescript'),
// jfive:require("johnny-five"),
// j5board:require("johnny-five").Board({repl:false})
},

と、外部モジュールのrequire方法がコメントとして例示されている。ありがたい。よって、ここに

bmp085:require("bmp085")

を追加した。functionノード内ではrequireではなく

var BMP085 = global.get('bmp085');

のようにしてグローバルコンテクストの中からロードするとrequireと同様にモジュールを使うことができる。

次に、取得したセンサ値をmsgのペイロードに詰めてreturnで次のノードに送ろうとしたが何も送られなかった(地雷3)。

この問題の原因は、bmp085モジュールのセンサ値取得が非同期で行われるためである。センサの取得値はモジュールのコールバック関数の中でしか触れなく、普通にreturnしてしまうと値の取得が行われない状態でfunctionノードが終了してしまう。node.jsで毎回この手の地雷を踏んでる気がするがいい加減覚えたらどうだ俺。

Node-RED日本ユーザ会 : Functions Nodeの書き方 日本語訳にいくつか誤りがあるので原文を参照したほうが良いかもしれない。いま修正案を作成中。→修正案が受理されてサイトに反映された(2017/02/27)。

の 非同期メッセージ送信 の所に、そのものずばりの答えが書いてあった。node.sendを使えば非同期で呼ばれる関数の中からメッセージを後続のノードに送ることができる。メッセージを複数返せるというのが嬉しい所で、今回は気圧と温度を別のメッセージとして送りたかったので正に2回node.sendを実行している。actionとしてsetStreamValue以外の何かを指定すれば一回で複数ストリームへのputが行えるかもしれないが、もう調べる気力が残ってない。

2017/02/20 追記

functionノード内で、毎回newによるbarometerオブジェクト生成を行っていたが、

Feb 17 09:24:42 bbb0001 Node-RED[11054]: (node) warning: possible EventEmitter memory leak detected. 11 exit listeners added. Use emitter.setMaxListeners() to increase limit.

というエラーがsyslogに出るので、コンテキストを利用して最初の一回だけnewするようにした所、当該エラーが消えた。これも地雷だな(地雷3.5)。Node-REDのノードは実行中に消えずに生き続けるということか。

M2Xへアップロード

M2XノードでAPIキーを指定する。ここは間違いようがない。

f:id:XX-Prime:20170214215216p:plain

Feedの鉛筆ボタンをクリックして

f:id:XX-Prime:20170214215357p:plain

API keyにM2XのデバイスAPI keyを入力してUpdateをクリックする。

確認用出力

このノードは特に要らないが、putされているオブジェクトを見るためにdebugノードを置いている。

出力例

f:id:XX-Prime:20170214215633p:plain

こんな感じで記録されていたら成功。台風の目が近くを通り過ぎると、尖点を持つかなり面白いグラフが得られる。

M2Xは、webサイトに埋め込むためのグラフも自動的に作ってくれるので、自動生成されたimgタグを埋め込むことで以下のように簡単にリアルタイムグラフを表示できる。

二軸までの同時表示が可能。timezoneの指定が出来ないのが残念な所で、UTCのみである。

Node-RED自動起動

デフォルトではnode-redサービスは自動起動しない。webブラウザで1880番ポートにアクセスするとxinetd的な何らかの仕組みでnode-redサービスが立ち上がるようだが、自動起動していると勘違いすると痛い目に会う(地雷4)。

$ sudo systemctl enable node-red.service

自動起動するようにしておかないとリブート後にデータアップロードが途切れて号泣する。

まとめ

Node-REDは大変扱いやすいけど、非同期で動作する外部モジュールを使う時にはここで書いたような地雷を踏まないようにしてね。

Nexus 6P 早期シャットダウン問題(と対処法)

寒いと落ちるNexus 6P

バッテリーの残りが20~30%あるのに、突然Nexus6Pがシャットダウンするという問題が世界中で起こっている。私のも昨年の12月半ばあたりからその症状が出始めて、今では残り60%でも寒いとシャットダウンするという鬼畜仕様になっている。

世界中の叫び

https://code.google.com/p/android/issues/detail?id=227849

大まかにまとめると、寒い場所で落ちやすい、電力消費の大きいときに落ちやすい、優先度smallってフザケンナさっさと直せ、という感じでみんな怒ってる。特に、車で事故って写真撮ったり電話したりしてるときに落ちて困った、という報告はかなり気の毒である。死者がでたらどうすんだゴルァという書き込みもある。

今日は40%くらいまでは持った。本当に、ありがとうございます。

f:id:XX-Prime:20170124220307p:plain

一旦冷えてからスリープ解除すると強制シャットダウンというお馴染みの流れ。寒いと動かなくなるのは爬虫類だけで十分である。

Nexusヘルプセンターに連絡

support.google.com

Nexusヘルプセンターの右上に お問い合わせ というリンクがあり、(昼間だけ)電話での連絡を依頼することができる。これを依頼して症状を説明した所、交換対応という結果になった。保証はすでに切れているが、特別に対応してもらえた。一年後にまた爬虫類状態になる可能性は極めて高いが、このまま使い続けるよりはマシである。

まとめ

同じ問題に苦しんでるかたは連絡を依頼してみてはどうだろうか。向こうから自発的に連絡してくるほどgoogleのサポートは優しくないようだ。

ジャンパケーブルオスメス問題

なんか作るときにジャンパケーブルが必要になって

  • オスーメスのケーブルが欲しいのにオスーオスしかない
  • オスーオスのケーブルが欲しいのにメスーメスしかない
  • メスが欲しいのにまわりにオスしかいない

などの問題が生じて発狂することがよくあるが、少なくともケーブルの問題を解決するそこそこうまい方法はある。

ケーブルはメスーメスしか買わない

オスーオス、オスーメス、メスーメスの三種類のジャンパケーブルがあるが、メスーメスだけあれば十分である。

バラ売りされているジャンパケーブルは地味に高価なので、無用なケーブルを用意するのは馬鹿げている。

さらに、

digitalparts.net

のようなリボン状のメスーメスケーブルを買えば比較的安く大量の本数を入手できる。割いて使うこともできるので、I2C用に4本だけまとめて切り離して使う、などバラ売りのケーブルより便利である。

オス化

akizukidenshi.com

のような両端が長いピンヘッダを用意しておく。これも1つずつ割いて使えるので、オスが必要な方に挿せばオスになる。メスからオスが生まれるのは生物界と同じである。

まとめ

オスのジャンパケーブルって要らなくね?

Rの代入演算子 <- をtypoして恐ろしいことが起こった

問題

Rで

x <- c(1, 2, 3)

は、xという変数に右辺のベクトルをアサインする式だが、この <- という演算子

y <-- c(1, 2, 3)

と打ち間違えると何が起こるか分かるだろうか?そんな演算子ねーよボケ、とエラーを吐いて停止するだろうと人間なら期待するが、R処理系は世にも恐ろしいことをやってのける。

答え

上の式のアサイン(?)は何の警告もなく完了し、yの値を出力すると

> y
[1] -1 -2 -3

と、各要素を-1倍した反対向きのベクトルがアサインされる。もう少し分かりやすく言うと、パリティ反転されたベクトルがアサインされる。同一文字を2回間違って入力することはたまにあるが、アサイン演算子のマイナス記号を2回入力したのを気づかないまま解析を進めると、この世ではあり得ない結果がどんどん出てきてデバッグに時間を盗られて夜中の2時56分にこのような下らない記事を書く羽目に陥る。

まとめ

この鬼畜仕様は何か意味なり歴史があるのだろうか?

追記

z <--- c(1, 2, 3)

> z
[1] 1 2 3

と、もう一回パリティ反転されてもとに戻ったw

w <-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- c(1, 2, 3)

パリティはどうなるだろうねえ。