四畳半テクノポリス

コロナのストレスで気が狂い、D進した院生

マイクロマウスの基板再修正

 テストが迫っておりそんな本来余裕は無いのであるが、現実逃避の癖で以前は全くやる気の失っていたマイクロマウスの設計になぜか打ち込んでいる。あまり良い事ではないが進捗は産めてしまっている。自分のこういうところは本当に嫌になってしまう、何かを成し遂げるのに十分な集中力は持っているがそれをまともに使うことが出来ないという事が浮き彫りになってしまうからである。

 そんなこんな、で本日も何故かマイクロマウスの基板の修正を行ったり、モータードライバ周りの部品を後輩氏に発注したりと、言ったことを行っていた。前回の記事では、マイクロマウスの基板の修正を行った話をしたが、あの後他のパーツも基板上のフットプリントに実装できるか、確かめてみようと考え、マイクロマウスの基板上に実際に載せ確認していたところ、アートワークの汚さが目立ち、居ても立っていられなくなり、基板の修正を始めてしまった。

前回基板を発注した時はかなりの突貫工事であり、余りアートワークにこだわって居られなかったが、今回修正を行ったことでかなりの、非効率的で無駄に絡み合った配線をしていた事が分かった。ユニバーサル基板や、エッチングの片面基板を含めると、過去に数十枚の基板を回路CADで設計してきているのだが、やはり、配線が複雑に絡まり合う基板の様なものは時間をかけて、設計せねばならないと痛感させられた。

f:id:toriten1024:20170211034313p:plain

 Kicadの機能として作成した基板の設計データを3D化するというものがある。これは、3Dデータで基板上に部品を並べることで、部品の干渉などの問題を予め予想できるという便利な機能である。僕はすぐ調子に乗り、ケアレスミスを起こしまくるタイプの人間なのでこの機能には何回か助けられている。

 

f:id:toriten1024:20170211034306p:plain

 

以上が現在のマイクロマウスの進捗である。どうにかサークルの新入生歓迎会までに直進できるようにしたいと考えている。

 

マイクロマウスの基板修正

 なんとなくツイッターを見ていたら、某大の学生が、ロボットを作らない「ロボットを作っていた人」が本当に嫌いだと言っていた。なんとなく自分に当てはまってしまう気がする。僕は現在はサークルで水中ロボットを作っているし、マイクロマウスは完成していないだけで去年は一年間チョビチョビ作っているので、全くの「ロボットを作っていた人」なわけではないがそれでもいたわけだが一向に完成が見えてこないのと、発注した基板にバグが見つかってしまい、最近はほぼ進捗を埋めていない

というわけでその基板のバグを修正したというのが今日の作業である。具体的には電源レギュレータのICのフットプリントが間違っていたという初歩的で恥ずかしいバグではある。

 こんなことを書いていてもしょうがないので僕のマイクロマウスの基板を公開する。メインのマイクロコントローラはPSOC5でメモリはたっぷりと64kbある。ジャイロセンサはMP9250を使用する。ロータリーエンコーダはこじまうす氏のものを参考にし、自作する予定である。

 現状の進捗として基板の第一バージョンを発注し、それにバグが見つかったので修正しているのと、ギアボックスとホイールをKicadで設計し、後輩氏に頼んで加工してもらった。という状況である。

f:id:toriten1024:20170202190015p:plain

 

f:id:toriten1024:20170207233320p:plain

この回路図はツイッターでは見せびらかしているのだけども、周りのマイクロマウス参加者から見て一向にマウスを完成させない僕はどのように写っているのだろうか。

近況

 最近どんどんクズになっている気がする。というのはろくに授業に出ていないからだと思う。ろくに授業で出ていないと言っても僕が悪いわけじゃない、もともと取れる授業はほとんど取っていたのだが、大学の後期前半が終わったあたりで単位を取るのが難しいと思った科目を2つ捨てたのと、後期前半で一つ科目が終わってしまい、その結果僕の時間割はかなりスカスカになってしまっている。基本的に一日数授業しか無かったり、全休の日も発生してしまっている。更に言うと休講と授業変更は大量発生しておりかなり不規則的である。後期中盤で受講取り消ししたり、終わってしまった科目は、朝一番の1限目に集中しているから起きる時間も不規則になって、夜寝るのも遅くなったり、かなりダメ人間な生活習慣になっている。

 一応講義にはちゃんと出席しているし、講義中はノート取りながら席に座っているが、高専情報科から環境生命工学化に編入したはいいものを結局化学のことは好きにはなれなかったので半分くらいの授業はコンピュータについて、あれこれ妄想して終わっている気がする。

 前にも書いたけど今大学に編入しようとしている高専生がいるんなら願書の第二志望に大して行きたくも無い学科の名前を書くのはやめよう、他の大学や専攻科に落ち結局その学科に行くことになった場合貴重な二十代の二年間と二年分の学費をつまらないことに突っ込んでしまうことになる。こうなるくらいだったら就職したほうが絶対に良いと思う。僕の周りの大学に行かずに就職した人たちはロボコンをやっていた高専卒ということもあってか、誰もが知っている大企業の設計チームだったり、開発チームだったりで活躍している人も多いから

Scratchの仕様について

 Scratchという教育や学習様に作られたプログラミング言語がある。かく言う私も中学生の頃、Scratchが日本に来たあたりにScratchでコンピュータプログラミングを学んだ、言うなればScratch第一世代である。

 以前よりタートルだのRobo Designerだの色々な教育用プログラミング言語があったが、Scratchが今現在のプログラミング教育ムーブメントにおいて多く使われている理由はオブジェクト指向で構造化プログラミングという泥臭さだと思う。それまでの教育用プログラミング言語は僕が知っている限りフローチャートをそのまま実行する様な方式のものが多かったがScratchはそれらに比べ、実践的な文法を取っていて、c言語あたりにも少し勉強すれば容易に移行できるんじゃないとかと思う(僕の高専時代の友達はScratch風のc言語エディタを作っていたし)。

 どうでもいい前置きが長くなってしまったが、最近インタプリタとかを作っているうちにScratchのマルチパラダイムや、実行順序という物が気になって、暇を見つけてはちびちび調べていたのでそれについてここにメモしておく。

あくまでも僕個人が手探りで調べたものなので間違いがあったら教えていただけると助かります。

Scratchの1処理の実行範囲

Scratchのプログラムはマルチパラダイムであるが、実行する際はOSがひとつのCPUで複数のプログラムを動作させる様に、あるスクリプトのある区間を実行して、また別のスプライトのスクリプトのある実行区間を実行してということを繰り返している。

 具体的に言えば緑色のフラッグのStartブロックが呼び出されてプログラムが動作すると、下につながっているブロックを実行していき、描画ブロックと言った特殊なブロックを実行したら、そこでそのプログラムの実行を停止してスタンバイ状態にし、次のプログラム実行権を譲る。次に呼び出された時には特殊なブロックの下からまた実行すると言った具合である。

私が調べた結果、プログラムをスタンバイ状態に遷移させる命令は次に示す通りだ

  • {見た目ブロック、動きブロック、音ブロック、ペンブロック}を含む制御ブロックの終端

    f:id:toriten1024:20170131233931p:plain

  • クローンを呼び出した時(この時はプログラムが中断されクローン内部のプログラムを実行してから戻ってくるようだ)

多分他にもあるような気がするが僕が確認出来なのはこの2種類、赤丸で囲ったように、制御ブロックのうちスタンバイ状態に移行してしまうものは丁寧に↺マークががかいある。

Scratchのフレームレート

 Scratchは他のプログラミング言語と違いフレームという概念を気にせずプログラミングできるが、コンピュータプログラムである以上、フレームレートが存在する。スクラッチのフレームレートは30FPSで固定でフレームごとにすべてのスプライトのすべてのスクリプトがスタンバイ状態に遷移するまで実行される。また、ターボモードを使えばフレームレート関係なく最速で実行されることになる。

 次のプログラムを実行してみれば実際にフレームレートを計測することができる。おそらく結果は31になるはずだ。

f:id:toriten1024:20170201000014p:plain

 

Scratchの実行順序

 Scratchはマルチパラダイムプログラミング言語だという、僕が使ってきた言語の中でマルチパラダイムと言えそうなのはVerilogくらいしか無いのだけど、ScratchはVerilogのマルチパラダイムと違って、プログラムの呼び出されるすべて並列していたり、入り乱れたたりしない事が分かった。僕が調べて分かったのはルールと次の様な感じである。

  • あとから作られたスプライトの方が先に実行される。
  • スプライト中の同じ条件で実行されるスクリプトがある場合最後、最初に作られたスプライトの方が先に実行される

次のプログラムを見てほしい、プログラムを見ただけでは実行結果がどうなるかわからない、このような場合は最初に操作されたものから実行され、最後に操作されたものが最後に実行される。例えばそれぞれのスクリプトの上にふられた番号の通りにプログラムを作成したとすると結果は-5となる。

f:id:toriten1024:20170201001804p:plain

クローンの最大数

 Scratchにはスプライト自身がクローンを作成するという機能があるが、この複製できる最大数はすべてのスプライト合わせて301となっている。次のプログラムを実行してもらえばクローンの最大数が301である事が確認できると思う。

f:id:toriten1024:20170201002330p:plain

 

以上で今まで調べて来た仕様に関する説明を終える。間違っている部分も多いと思われるが、もし誰かの参考になるのであれば嬉しい限りである。

TOEIC

 目覚まし時計の単調なビープ音で目が覚める。うるさいので叩く様にしてけした。今日はTOEICを受けに行かねばならないのだが、開場は11:45ごろだったはずなので移動時間を2時間程度と予想するとあと1時間半程度寝られるので二度寝した。私の下宿は駅から遠く自転車で一時間程度かかってしまう、そこからまた会場の名古屋まで電車で1時間程度かかるという計算だ。別に近所の豊橋会場で受けてもいいのだけれど、理由をつけて名古屋まで出かけたかったので、毎回名古屋会場を指定して申し込んでいる。

 そこから何度か二度寝、三度寝と繰り返していると9:30あたりになっていた。適当に着替えようと思ったが、洗濯をサボっていたため、あまり洗いたての服が残っていない、仕方なく下着とズボンは洗ったものを、シャツは昨日着たものを洗濯カゴから引っ張りだしてまた着る。昨日は家でじっとしていたので、あまり汚れていないだろう。それから、必要なものを適当にトートバッグに突っ込んでマウンテンバイクに乗り駅に向かう、以前は週末になるたびに駅前に遊びに言っていたのだが、最近は飽きてしまってあまり足を運ばなくなっている。

 駅につくと腕時計を家に忘れたことに気づいた。 しょうが無いので駅ビルの中で時計が安く売っていないか探していると、運良く100円ショップが見つかった。腕時計はなかったが親指サイズの小型の置き時計を見つける事ができたのでそれを購入した。

 駅に向かい券売機で切符を購入した。名鉄を利用したかったのだが間違えてJRの切符を購入してしまった。「まあ降りるときに精算すればいいだろう」と考え、改札をくぐり名鉄のホームに向かう。すでに11時近くなってしまっていることに気づきかなり焦ったがなんとか、11:15の名古屋行きに乗車した。

 適当に席に座り先ほど買った時計の時間合わせをしようとした。スマートフォンを開き時間を確認するとすぐに電源が切れてしまった。しょうが無いので電車の発車時刻に合うように時間を合わせ、ドアが閉まった瞬間にスタートさせた。普段電車に乗る機会が無いので電車に乗るだけでも十分に楽しく感じる。何より車窓から見える景色にだんだん大きな建物が増え都会に近づいているのが見えるのが楽しかった。

 今回の名古屋会場は金山駅の近くなのでそこで降りる。駅を出て受験票の裏に描いてある地図を眺めているとそちらへ向かっていく人の流れがあったのでその後を追った。開場は東海興業専門学校という学校の裏にある施設だった。よくわからないが教室のようなものがたくさんあった。多分専門学校の一部としても使われているのだろう。

 入り口で自分の受験する部屋を確認し、部屋の前の受付で身分証明書と受験票を見せ、部屋に入った。部屋にはほとんどの受験者がすでに着席していた。適当に参考書を開いて眺めてると、試験官がいつものやたら冗長な注意書きを読み始める。証明写真付きの身分証明書と受験票を机の上に置くように言われたので、そのとおりにした。ふと横を見ると隣の受験者は大学生らしく名古屋大学の学生証を机の上にだしていた。なんだか僕の劣等感を煽り、きっとこの人は僕より全然良いスコアを取るのだろうと思うと試験を受ける前からなんかアレな気分になった。

 試験はリスニングとリーディングで構成されているが、リスニングはいつもどおりの半分しかわからない感じ、リーディングはパート7の中盤までしか終わらせることができなかった。テスト終盤には隣のやつの名古屋大学の学生書が頭の中でチラチラして集中できなくなってしまった。あまり真面目に対策せず、自分で精一杯やったと思えていいないからこうなってしまうのだろう。自分を恨むしか無い。

 院試の願書提出が6月だからあと受けることのできるTOEICは3月と4月しか無い、そんな時に真面目に取り組まないとは「全く私は何を考えているのだろう」とか思ってしまった。

つづく

 

ガバガバなステレオマッチングとか

どうも、とり天です。研究室配属ですが、なんか温室とかやってる研究室でセンサネットワークを使ったようなIoTな事ができそうなので良かったなと思います。

 最近ですがアルバイトに行き詰っています、というのはOpenCVを使ったアルバイトをしているのですが、呼び出しても動かないステレオマッチングの関数メンバがあったので、ソースコードを読んでみたところ、なんと関数内が空っぽで"return 0"になっていました。結構重要な機能だったのでショックでしたね。それと同時に自力でステレオマッチングを作ってみたので紹介します。EmacsでインデントしたあとGeditで編集してめちゃくちゃなインデントになっていますが気にしない、あとステレオ対応のWEBカメラ(ZED)とかで読み込んで分割する様に書かれてますが、ステレオカメラ持っていない人は適当に左右の視差のある画像を読み込むようにしてね。

 

#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>
#include <stdexcept>
#include <opencv2/core/utility.hpp>
#include <opencv2/core.hpp>
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"

//#include <cstdlib> 

//dvide image
void ImgDiv(cv::Mat src, cv::Mat right, cv::Mat left){
  int width = src.cols/2;
  int hight = src.rows;
  for(int i = 0; i < hight; i++){
    cv::Vec3b *p_src   = src.ptr<cv::Vec3b>(i);
    cv::Vec3b *p_right = right.ptr<cv::Vec3b>(i);
    cv::Vec3b *p_left  = left.ptr<cv::Vec3b>(i);
    for(int j = 0; j < width; j++){
      p_left[j] = p_src[j];
      p_right[j] = p_src[j + width];
    }
  }
}

void Depth2Hsv(cv::Mat src, cv::Mat res){
  if(src.cols != res.cols || src.rows != res.rows){
    //cout << "data size is not mach" << endl;
    return ;
  }
  int width = src.cols;
  int hight = src.rows;
  for(int i = 0; i < hight; i++){
    cv::Vec3b *p_src = src.ptr<cv::Vec3b>(i);
    cv::Vec3b *p_res = res.ptr<cv::Vec3b>(i);
    for(int j = 0; j < width; j++){
         p_res[j][0] = p_src[j][0] / 2;
         p_res[j][1] = 255;
         p_res[j][2] = 220;

    }
  }
}
void my_sad(cv::Mat right, cv::Mat left, cv::Mat dist ,int block_size, int diff ){
  if(right.channels() != 1 || left.channels() != 1 ||  dist.channels() != 1){
    std::cout << "Error : bad channnel" << std::endl;
    return ;
  }
  if(right.cols != left.cols || right.rows != left.rows){
    std::cout << "Error : not mach input image size" << std::endl;
    return ;
  }

  if(block_size % 2 != 1  ){
    std::cout << "Error : block size is not  2n + 1 " << std::endl;
    return ;
  }

  dist = cv::Scalar(0,0,0);
  std::cout << "width" << right.cols << " height" << right.rows << std::endl;
  int width = right.cols - block_size;
  int hight = right.rows - block_size;
  cv::Mat tmp = dist.clone();

  std::vector<std::vector<int> > arr;
  arr.resize(hight);
  for( int i=0; i < hight; i++ ){
    arr[i].resize(width,255);
  }
  for(int d = 0; d < diff ; d+=1){
    for(int i = (block_size/2+ 1) ; i < hight - (block_size/2+ 1) ; i += 1){
      cv::Vec3b *p_dist   = dist.ptr<cv::Vec3b>(i);
      cv::Vec3b *p_right = right.ptr<cv::Vec3b>(i);
      cv::Vec3b *p_left  = left.ptr<cv::Vec3b>(i);

      for(int j = (block_size /2) + 1; j < width - (block_size/2+ 1) -diff ; j+= 1 ) {
	int right_sum = 0;
	int left_sum = 0;      
	for(int l = 0; l < block_size ; l++){
	  cv::Vec3b *p_right = right.ptr<cv::Vec3b>(i - (block_size/2) + l);
	  cv::Vec3b *p_left  = left.ptr<cv::Vec3b>(i - (block_size/2) + l);
	  for(int m = 0; m <   block_size; m++){
	    right_sum += p_right[j/3][ - (block_size/2) + m + j % 3];
	    left_sum += p_left[j/3][ - (block_size/2) + m + d + j % 3];
	  } 
	}
	int delta =  ( (double)abs(right_sum - left_sum) / (double)(block_size * block_size *255)) * 255.0 ;

	if(delta < arr[i][j]) {
	  arr[i][j] = delta;
	  cv::Vec3b *p_dist = dist.ptr<cv::Vec3b>(i);
	  p_dist[j/3][ j % 3] =  (int)(( (double)d / (double)diff) * 255.0);
	}
      }
    }
  }
}

int main (void){
  cv::Mat src;
  cv::VideoCapture cap(0);
  int block = 7;
  int diff = 12;

  while(1){
    cap >> src;
    cv::resize(src, src, cv::Size(), 0.5, 0.5);
    cv::Mat right(src.rows, src.cols*0.5,src.type());
    cv::Mat left(src.rows, src.cols*0.5,src.type());
    ImgDiv(src,right,left);
    cv::cvtColor(right, right, CV_RGB2GRAY);
    cv::cvtColor(left, left, CV_RGB2GRAY);
    cv::Mat dist = right.clone();
     my_sad( right, left, dist , block, diff );
     cv::cvtColor(dist, dist, CV_GRAY2RGB);
     cv::Mat color(dist.rows, dist.cols, CV_8UC3);
     Depth2Hsv(dist, color);
     cv::cvtColor(color, color, CV_HSV2RGB);

     cv::imshow("window_r", right);
     cv::imshow("window_l", left);
     cv::imshow("window_d", color);
     
     cv::createTrackbar("block size","window_d",&block, 13,NULL,NULL);
     block = (block < 3  )? block = 3 : (block %2 != 1)? block - 1 : block;
     cv::createTrackbar("diffarence","window_d",&diff, 255,NULL,NULL); 
    int key = cv::waitKey(1);
    if(key == 113)//q
      {
	break;//
      }
    else if(key == 115)//s
      {
	cv::imwrite("img.png",dist );
      }
  }
}

まあアルゴリズムとしてはSADを用いたブロックマッチングを行っています。すごく適当な上に並列化もなにもしていないので、すごく重いです。

結果は次の画像に示す感じです。近いものほど赤く表示して、遠くのものほど青く表示しています。なんかキャリブレーションすら面倒くさくてしていませんがそれなりに遠くのものは遠くに、近くのものは近くと認識できているんじゃないかなぁ。部屋汚いね

左の画像

f:id:toriten1024:20170128205303p:plain

右の画像f:id:toriten1024:20170128205241p:plain

深度マップ

f:id:toriten1024:20170128205444p:plain

 

まあ詳しい話とかは今度の技術書展で豊橋技科大コンピュータクラブの出す部誌に載せようと思うので、そのあとブログにも簡単に載せようかな

研究室配属

さてさて、今年も12月を迎え研究室配属の季節がやってまいりました。

結論から言って死にたい

本当に嫌で仕方ない。こう言うの書けるのはブログだけだから書く、

と言うのは僕は第一志望の学科に落ちてしまい今の環境生命工学課程にいるわけですが、現に半分単位落としてますし(卒業単位は足りる予定)化学、生物学が大嫌いで、バイトのプログラミングが楽しくてしょうがないのが現在の状況です。

はっきり言って高専卒で就職した方が何倍も良かったと思うし、大学に来たのは20代の貴重な2年間を学費とともに溝に捨てる最悪の選択だったと思います。

何一つ将来役に立ちそうな事は学んで無いですからね。小心者なんで講義はちゃんと出てるんですけど、化学式を見るたびに胸が張り裂けそうな辛い気持ちになります。

そんな中で研究室配属とか言い出すと死にたくてしょうがないわけです。第二志望の欄に環境生命工学課程とか書いてしまった。自分に怒りしか湧いてこない、

と言うわけで、もうすぐb4の卒研発表会があって、その後に研究室配属があるんで、なるべく楽そうな研究室を志望する予定です。

高専の時は放任主義で進捗チェックもあまりしない研究室だったのと、教員が専門外の分野の研究をしていたので、週報を書く必要も無く、ひたすら自分のペースで研究を続ける事が出来ました。一日18時間卒研のプログラムを書き続けり、誰にも邪魔されずリソースをじゃんじゃんブチ込める状況が楽しくてしょうがなかったのをよく覚えています。

化学に対してはそんな風に取り組める気が全くしないです。有機化学は嫌いでしょうがないし、生物系は単位全滅だし、無機は頭が足りないし、そもそもピペットの類が嫌いでしょうがない、八方ふさがりの状況です。

だから楽ちんと噂の社会学系の研究室で希望を出そうと思います。なんかゴミの分別表のアプリ作ってる所もあったので、職業プログラマ気触れの僕としてはまあ案内アプリを作るのは苦労しないだろうと思うので。大学院はちゃんと情報系のところに行けると良いな、大学院落ちたら化学の学位が付くと嫌なので中退して就職しようかな。