歩きながら考えたこと

ボーッとする時間、何も考えない時間、の重要性。不安があるとき、悩みがあるとき、解決策を考えようとして新しい情報をインプットすることで考えを整理しようとしてきたが、なにもインプットしないことも必要ではないか。脳を完全に休ませる時間を確保する。意識的に何も考えないことも思考の整理になる。脳にはもともとそういう機能が備わっている。理想は完全にオフラインにすることだが、現代ではなかなか難しそう。小学生の頃は暇だな、という感覚があったが、最近は全く感じないのはなぜだろう。情報が多すぎるからではないか。日記が続かない理由はなにか。書くこと自体に苦手意識はない。自分の一日に、記録するほどの価値がないと感じてしまう。自分が好きなことや、自分のために今取り組んでいることについて記録するならまだわかるが、自分が好きでもない仕事のことを、わざわざ書きたいとは思わない。過去を振り返ること自体もあまり好きではない。卒業アルバムを見たいというユーミン的感情が全くわかない。回復思考の特性で、常に今の自分の欠点と、今の環境の不完全な点にばかり注目してしまう。常に次の問題に目が言ってしまう。これをどう帰るのが望ましいのか。日記には次にやりたいことだけを書くのがいいのか。今日気づいたポジティブなことだけを書いたほうがいいのか。もともと自分は何がやりたかったんだろうという原点を書いて読み返すほうがいいのか。自分がもともと、問題に意識が向いてしまう特性があるなら、それを補正するには、他人のいいところを見つけたこと、世界の素晴らしいものを見つけたとき、自分がこれからやりたいことを思いついたとき、それらを記録しておく、というのが良さそう。反省点などはわざわざ書いて言語化しなくても無意識のうちに考えてしまうので、むりにもう一度書いて苦しい思いをもう一度する必要はないと思う。行きたい旅行先を見つけたらそれを書く。これから調べたいこと、勉強してみたい分野、キーワードを思いついたらそれを書く。なぜそれを思いついたのか、きっかけも合わせて書いておく。自分の幸せにとって親密な関係の友人が絶対に必要なのだが、それを今は満たせていないと感じる。なぜそれができないのか、単に技術的な問題なのか。小学生の時に紙飛行機ブームを作ったことを思い出した。体力的、精神的な余裕があって初めて、文化的な活動をしようと思える。この3年くらいで疲れてしまったのかもしれない。自分で言うのも何だが、この部署に来てから、なんだかんだいろいろなことを学んだし、手を抜くことなく、決していい環境ではない中で、主体的に勉強して、問題を解決してきた、我ながらよく頑張ってきたのではないだろうか。自分が苦手だと思っている対人関係も、おそらく他人から見たら、そこまで苦手なようには見えないと思う。なんだかんだいって必要だから工夫しつつこなしてしまえるし、なんとかしてきたと思う。舞台の電子チケットのQRコードを端末にかざすときに、ものすごい手が震えてしまったことを思い出した。論理的に考えれば、全く不安に思ったり緊張したりする必要のない場面なのに、頭ではわかっていても、急激に不安が顔を出す。上司に話しにくいことや複雑なことを話すとき、客に電話を掛ける時、完全台本を用意してから話す。そうするとうまくいく。そういないと不安で話始められない。じゃあそれでなにか問題が起きたのかといえば、結果的に問題が起きたことは一度もない。ただ不安や変な緊張が出てしまう。あるいは、次も不安に襲われるのではないかという不安から、積極的な決断やアクションができないことがある。自分にとって有益な、楽しいことをしたいと思っても、そこに本来は考えなくて良い不安のような悪いイメージが湧いてしまい、それが次のアクションの妨げになってしまう。べつに友だちを誘って旅行に行けばいいのに何故かそれができない。いや、それは感情に負けているのかもしれない、論理的に考えて問題ないのだから、最後まで論理的にやり通さなければ行けないのかもしれない。そこで、やっぱり不安だから、と最後に感情に流されてしまっているところが、だめなところなのかもしれない。こうやってダラ長方式でなるべく全部吐き出すことで、これ以上何も考えたいことはない、という状態にして、マインドレス状態を実現する。自分ってそもそもなにを求めてたんだっけ。美味しいご飯を食べて、ゆっくりお風呂に入って、温かい布団で眠る、にんげんっていいなの世界観。これ以上何を望むことがあるのか。父が作った野菜を母が料理して食う。これを父母がいなくなってもできる状態を目標にしようかな。

内省とフィードバックと伝えること

とにかく自分の考えていることを吐き出す、あるときに考えたことと同じ問題設定で1ヶ月空けて再び考えてみる。自分を客観視することは大事だが自分一人で自分を客観視するには限界もある。でも自分のことを理解してもらえていないと感じる人からフィードバック(ダメ出し)をもらってもうまく受け止められない。わがままだとは思うがそのへんうまくやっていく必要がある。

自分から積極的に自分の考えを信頼できる他人に言ってみて、どう思うか意見を求めるということをやる必要ある。友人の時間を奪うことになるから、相手にとってもある程度有意義な、楽しいとか、ためになる、という話題である必要もあると思う。基本的に人は他人のことはどうでもいいと思うだろうから。

なんとなく、自分のことをわかってほしいが、どうせ相手は自分のことには興味がないだろうからこの話をするのはやめておこう、という心理が俺はよく働くのかもしれない。相手が興味がないかもしれない話をするときは、ある程度、相手が面白いと感じるように構成を練ったり、役に立つ知識を盛り込んだり、といったサービスをしなければいけない、というプレッシャーを感じる。

すくなくとも、この情報は相手にとって価値があるかないか、重要であるかないか、を判断する能力は高いと思う。だから無駄なことは言わない、必要なことは相手にわかりやすいように伝える、ということはうまくできる。

ただ、そもそも、この世界は、価値のあるなし、重要性のあるなしですべてが決まっているわけでもない。意味のないこと、些末なことをただ言う、ということもコミュニケーションだ、というのはまあ理解できる。ただ、実践できない。

ただ素直に思っていることを言う、ということの難しさよ。
ただ思ったことをポッと言う、ということをおれはうまくできない。

言ってしまって、言うべきではなかったと後悔したことがあるからかもしれない。実際には対して相手は気にしていないことがほとんどなのだけれど。

intのデータ長は何バイトか

前の記事(いつのまにかIRremoteESP8266の仕様が変わってる? - てらもろす)の問題でしばし頭を抱えることになった原因の一つが、int型は2バイト(16ビット)だと思い込んでいたこと。

私の環境の場合(というかesp-wroom-02の場合?)、int型は4バイトだった。

手元のC言語のテキストには「本書ではintは16ビットと想定する(ただし処理系によって異なる)」みたいに書いてある。
手元のArduinoのテキストには「int:2バイト:16ビット符号付き整数値。-32,768から32767の整数値を格納。ただし、処理系によっては32ビット符号付き整数値。」と書いてある。

そんなわけで、int型は2バイト(16ビット)だと無意識のうちに思い込んでいた。それゆえ、なぜ「unsigned intからuint16_tへのconversionがダメ」みたいなエラーが表示されるんだろう、と思っていた。

試してみた。実際に書き込んでシリアルモニタで見る。

    Serial.print("int:");
    Serial.println(sizeof(int));
    Serial.print("unsigned int:");
    Serial.println(sizeof(unsigned int));
    Serial.print("uint16_t:");
    Serial.println(sizeof(uint16_t));
    Serial.print("unsigned short int:");
    Serial.println(sizeof(unsigned short int));

結果↓

    int:4
    unsigned int:4
    uint16_t:2
    unsigned short int:2

(2017/8/21追記)
公式のリファレンスには、Arduino Unoなら2バイト、Arduino Dueなら4バイトと書いてありました。

On the Arduino Uno (and other ATMega based boards) an int stores a 16-bit (2-byte) value. This yields a range of -32,768 to 32,767 (minimum value of -2^15 and a maximum value of (2^15) - 1).
On the Arduino Due and SAMD based boards (like MKR1000 and Zero), an int stores a 32-bit (4-byte) value. This yields a range of -2,147,483,648 to 2,147,483,647 (minimum value of -2^31 and a maximum value of (2^31) - 1).

いつのまにかIRremoteESP8266の仕様が変わってる?

1年くらい前から、esp-wroom-02Arduinoスケッチを書き込んで遊んでます。
このたびPCの環境が変わったので、新たにArduinoIDEをインストールし、スケッチは前のPCから移行してきました。

すると、1年くらい前に書いて、そのときはちゃんと動いてたスケッチが、今はコンパイルすら通らない!

エラーメッセージをよく読んでみたら、IRremoteESP8266という赤外線リモコンを扱うためのライブラリを使うところで何かが起きている。
どうやら、最新のIRremoteESP8266ライブラリをダウンロードしたので、1年前に書いたスケッチではうまく動かなくなってたらしい。

変わったこと1

ソースファイルが分割された。旧スケッチでは、

#include <IRremoteESP8266.h>

だけ済んだが、最新のライブラリでは、例えばIRsendを使うなら、

#include <IRremoteESP8266.h>
#include <IRsend.h>

としないといけない。

変わったこと2

1年前に書いたスケッチではIRsend.sendRaw()を使っていたのだが、この関数の引数の型が変わっていた。
こんなコンパイルエラーが出た。

no matching function for call to 'IRsend::sendRaw(unsigned int*&, int&, const int&)

no known conversion for argument 1 from 'unsigned int*' to 'uint16_t* {aka short unsigned int*}'

sendRaw()の3つの引数の型が全てuint16_tになっていた。なんでだ。
Fix almost all Google cpplint issues & use c99 types. (#185) · markszabo/IRremoteESP8266@1967455 · GitHub

あとakaってなんやねん、と思ってググったら「also known as」という意味らしい。ほー。
エラーメッセージ C++の意味 - 万年素人からHackerへの道


ともかく、ライブラリの(新しい)サンプルスケッチを参考にしつつつ、第1引数の、赤外線パターンの配列をuint16_tで宣言したら一件落着。

修正前

unsigned int CH1_ON[67] = {10200,5150, 600,700, 650,650, 650,1900, 650,650, 650,650, 650,650, 650,650, 600,1950, 650,2000, 650,650, 650,650, 650,650, 600,2000, 600,700, 600,2000, 600,700, 600,700, 600,700, 600,700, 600,700, 600,700, 600,700, 600,700, 600,700, 600,1950, 600,2000, 600,2000, 600,1950, 600,2000, 600,2000, 600,1950, 650,2000, 600};

修正後

uint16_t CH1_ON[67] = {10200,5150, 600,700, 650,650, 650,1900, 650,650, 650,650, 650,650, 650,650, 600,1950, 650,2000, 650,650, 650,650, 650,650, 600,2000, 600,700, 600,2000, 600,700, 600,700, 600,700, 600,700, 600,700, 600,700, 600,700, 600,700, 600,700, 600,1950, 600,2000, 600,2000, 600,1950, 600,2000, 600,2000, 600,1950, 650,2000, 600};


第2引数、第3引数も型が合ってないから気持ち悪いんだけど、これらは合ってなくてもコンパイル通る(勝手に型変換されてる?)。
たぶん第1引数は配列を渡していて、ということは実はポインタを渡しているから、こっちは型が合ってないとダメなんだろうなー、ということぐらいしかわからん。詳しい人教えて。

IFTTTのUIが変わったのでMaker channelの使い方をメモしておく

ESP-WROOM-02(ESP8266)でLチカ(ブラウザからLEDをオンオフ)をSTAモード、固定IPでやってみる

挙動は動画の通り。
www.youtube.com

やってることは以下のサイトをそっくり真似してるだけです。コードもコピペです。インターネットありがたい。

qiita.com
この記事の素晴らしいところは、単なるLチカだけどESP-WROOM-02をAPモードではなくSTAモードで使うことで、操作する側のPC/スマホwifiの接続先をいちいち変えなくてもいいところ。それからブラウザから操作するためのUIをAjaxでつくってるところ。
まさに俺がやりたかったのはこれだよ!って感じです。

が、同じようにやろうとしても、どうしても次の2点だけうまくいきませんでした。何が悪いんだろ。

  1. mDNSでローカルネットワーク内のみのドメイン名を使う →うまくいかない
  2. ファイルシステムを使って別に用意したindex.htmlを返す →うまくいかない

なので、それぞれ代替策をとりました。といっても、ただ諦めただけです。

1に関しては、たしかにDHCPだとルーター再起動等のきっかけでIPアドレスが変わってしまって不便ですが、だったらIPアドレス固定すればええやん、と考えました。想定している用途によりますが、家庭内の無線通信手段としてwifiを使おうとしているだけなら、むしろ固定IPのほうがシンプルに思えます。

2に関しては、あきらめてArduinoのスケッチの中に、UI用のhtmlを書いてしまうことにしました。C++の中にhtmlが書いてあって、そのhtmlの中にJavascriptが書いてあるという気持ち悪さはありますが。


さて、STAモードでESP-WROOM-02wifiアクセスポイントに接続するとき固定IPをつかう方法ですが、調べてみると、どうやらWiFi.config()というのを使うらしい。
arduinoのリファレンスをみると、 デフォルトではDHCPであり、WiFi.config()をつかえば手動で設定できる、ということみたい。


※※※【2016年11月26日追記】※※※
なんとなく疑問が残ったので調べてみたんですが、
https://www.arduino.cc/en/Reference/WiFiConfigにそのまま従うと

WiFi.config(ip, dns, gateway, subnet);

という順で書くのに対して、ESP8266の場合は、

WiFi.config(ip, gateway, subnet, dns);

の順で書き、しかも最後のdns以外は省略できないようです。
参考:

※※※【追記ここまで】※※※


そのあたりを書き加えると、こんな感じのコードになりました。

#include <WiFiClient.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#define LED 13                    //LED点灯に使用するピン
ESP8266WebServer server(80);

void onroot() {
    String msg ;
    msg += "<!DOCTYPE html><html><head><meta charset=\"utf-8\"><meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\"><title>LED Button</title></head><body>";
    msg += "<script>";
    msg += "function sendOn(){" ;
    msg += "send(\"/on/\");";
    msg += "document.getElementById(\"LEDstatus\").innerHTML=\"ON!\";";
    msg += "}";
    msg += "function sendOff(){";
    msg += "send(\"/off/\");";
    msg += "document.getElementById(\"LEDstatus\").innerHTML=\"OFF!\";";
    msg += "}";
    msg += "function send(url){";
    msg += "var xhr = new XMLHttpRequest();";
    msg += "xhr.open(\"GET\", url, true);";
    msg += "xhr.send();";
    msg += "}";
    msg += "</script>";
    msg += "<button id=\"on\" onClick=sendOn()>LED ON</button>";
    msg += "<button id=\"off\" onClick=sendOff()>LED OFF</button>";
    msg += "<p id=\"LEDstatus\"></p>";
    msg += "</body></html>";

    server.send(200, "text/html", msg);
}

void LedOn(){
  Serial.println("ON");
  digitalWrite(LED,HIGH);
  server.send(200, "text/html","OK");
}

void LedOff(){
  Serial.println("OFF");
  digitalWrite(LED,LOW);
  server.send(200, "text/html","OK");
}

void setup() {

    pinMode(LED, OUTPUT);

    Serial.begin(115200);
    Serial.println("");
    Serial.println("ESP8266 Wifi test");

    WiFi.config(IPAddress(192, 168, 0, 99), WiFi.gatewayIP(), WiFi.subnetMask()); //使いたいIPアドレスを指定
    WiFi.begin("xxxxSSIDxxxx", "xxxxPASSWORDxxxx");   //接続先のwifiアクセスポイント
    WiFi.mode(WIFI_STA);

    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }

    Serial.println("");
    Serial.print("Connected as ");
    Serial.println(WiFi.localIP());

    // Web server setting
    server.on("/", onroot);
    server.on("/on/", LedOn);
    server.on("/off/", LedOff);
    server.begin();
}

void loop() {
    server.handleClient();
}

ご覧の通り、サーバーが返すhtmlの内容が見難いので、msgの中身だけ取り出してみたのが以下。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <title>LED Button</title>
</head>
<body>
  
  <script>
    function sendOn(){
      send("/on/");document.getElementById("LEDstatus").innerHTML="ON!";
    }
    function sendOff(){
      send("/off/");document.getElementById("LEDstatus").innerHTML="OFF!";
    }
    function send(url){
      var xhr = new XMLHttpRequest();xhr.open("GET", url, true);xhr.send();
    }
  </script>

  <button id="on" onClick=sendOn()>LED ON</button>
  <button id="off" onClick=sendOff()>LED OFF</button>
  <p id="LEDstatus"></p>
  
</body>
</html>


ブラウザで見たときの、“ON!”や“OFF!”の表示は、実際のLEDの状態を監視して取得しているわけではなくて、ただ単にボタンがクリックされたら文字を書き換えてるだけです。


早速、ESP-WROOM-02に書き込んで、指定したIPアドレスhttp://192.168.0.99/をブラウザのアドレスバーに入れてEnter。ちゃんとhtmlが返されました。

念のため、ルーターの設定画面でIPアドレスの割当状況を見てみると、192.168.0.99は「*** STATIC IP ADDRESS **」となっていました。
f:id:teramorosu:20161023162829p:plain

例外処理とか全然考えてないので公開するようなもんじゃないですが、最低限これでやりたいこと実現できたよ、という意味で。