第26回マイクロマウス九州地区大会で再現性の高さを見せつけてきた

九州大会

どうしてこんな遠いところに来てしまったんだろうか……(遠い目)

今年2回めの飛行機で,初めての九州上陸です.
航空会社はSTAR FLYERを使いましたが,国内線なのにモニタがついていたりしていてとてもすごかったです(小並感).

屋台

着日の夜には頭の悪い人たちと天神の屋台に行きました.

ずーーーーーっと歩き続けた後,とりあえず入った照ちゃんが大当たりで最高でした.
おでんもうまい,肉がうまい,酒がうまい,ラーメンがうまい.

僕はアジの唐揚げ(800円)をしゃぶり尽くして満面の笑みを浮かべていたと思います.

戦績

さて,前の記事で目標を書いていたような気がします.
前回の東北大会では照明の影響が大きく,まともに走ることができませんでした.

今回の九州大会では,どうにかゴールをすることができました!
……が,なんと帰り探索でクラッシュ.5回連続で同じところで止まってしまい,最短走行をすることができませんでした.

反省点は,

  • スラロームの調整が甘い
  • 探索でコケた時に迷路データが消えるのはダメ
  • 前壁補正入れよう
  • 壁切れ補正入れよう

要するに準備不足なので,今週もがんばります.

進捗

出走が終わり,しょげていた時にぽちぽちとコードを書いていました.

おかげで迷路データのMRAMへの保存ができるようになりました!
これで,仮に探索でコケてもそれまでのデータが消えることはなくなりました!!

次の中部大会では,

  • 走行の安定
  • モード機能の実装

あたりを強化したいと思っています.

僕の考えた最強のパラメータ格納法

パラメータ格納

マイクロマウスではいろいろなパラメータ,調整項目があります.きれいに走るためには,たくさんのパラメータを真心込めて調整してあげる必要があります.ほんとうにしんどい.

さて,乱雑なコードを書いているといろんなよくない問題が発生します.
例えば,

  • 同じパラメータが複数ヶ所で定義されている
  • 使われていないパラメータが乱立している
  • 変更したいパラメータがどこに書かれているか見つからない

……などなど.ちなみに全て実話です

というわけで,パラメータの格納方法はこだわったほうがいいというのがこの記事で言いたいことです.

先駆者

某先輩がポインタまみれのスラロームパラメータ保存を紹介していました.全容を把握するのには苦労しますが,すべてのパラメータを#defineするよりも良い方法だと思います.
C言語を頑張りたい人はこの記事を読んで,ポインタとは何者なのか理解しちゃいましょう!

ぼくのかんがえた(以下略

では,僕の考えた最強のパラメータ格納法をででんと紹介します.

あ,予め言っておきますがC++11とSTLを使いまくっているので,用法用量にはお気をつけください.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
namespace slalomparams{
enum class RunType : uint8_t {
SLALOM90SML_RIGHT,
SLALOM90SML_LEFT,
SLALOM90_RIGHT,
SLALOM90_LEFT,
SLALOM180_RIGHT,
SLALOM180_LEFT,
SLALOM45IN_RIGHT,
SLALOM45IN_LEFT,
SLALOM45OUT_RIGHT,
SLALOM45OUT_LEFT,
SLALOM135IN_RIGHT,
SLALOM135IN_LEFT,
SLALOM135OUT_RIGHT,
SLALOM135OUT_LEFT,
SLALOM90OBL_RIGHT,
SLALOM90OBL_LEFT,
TRAPACCEL,
PIVOTTURN,
};

struct pack{
float d_before;
float d_after;
float acc_rad;
float deg;
float const_deg;
float in_vel;
float out_vel;
float min_vel;
float acc_lin;
};
typedef struct pack pack_t;
}

array< map<float,pack_t>* , 16> slalomparams::getParams(){
static map<float, pack_t> SLALOM90SML_RIGHT = {
// { vel, {d_bef, d_aft, a_rad, deg, cnsdeg, in_vel, out_vel, min_vel, acc_lin}},
{0.25, {0.010, 0.012, 9000,95.5, 30, 0.25, 0.25, 0.25, 0.0}},
};
static map<float, pack_t> SLALOM90SML_LEFT = {
// { vel, {d_bef, d_aft, a_rad, deg, cnsdeg, in_vel, out_vel, min_vel, acc_lin}},
{0.25, {0.010, 0.012, 9000,95.5, 30, 0.25, 0.25, 0.25, 0.0}},
};
static map<float, pack_t> SLALOM90_RIGHT = {};
static map<float, pack_t> SLALOM90_LEFT = {};
static map<float, pack_t> SLALOM180_RIGHT = {};
static map<float, pack_t> SLALOM180_LEFT = {};
static map<float, pack_t> SLALOM45IN_RIGHT = {};
static map<float, pack_t> SLALOM45IN_LEFT = {};
static map<float, pack_t> SLALOM45OUT_RIGHT = {};
static map<float, pack_t> SLALOM45OUT_LEFT = {};
static map<float, pack_t> SLALOM135IN_RIGHT = {};
static map<float, pack_t> SLALOM135IN_LEFT = {};
static map<float, pack_t> SLALOM135OUT_RIGHT = {};
static map<float, pack_t> SLALOM135OUT_LEFT = {};
static map<float, pack_t> SLALOM90OBL_RIGHT = {};
static map<float, pack_t> SLALOM90OBL_LEFT = {};

static array< map<float,pack_t>* , 16> params = {
&SLALOM90SML_RIGHT,
&SLALOM90SML_LEFT,
&SLALOM90_RIGHT,
&SLALOM90_LEFT,
&SLALOM180_RIGHT,
&SLALOM180_LEFT,
&SLALOM45IN_RIGHT,
&SLALOM45IN_LEFT,
&SLALOM45OUT_RIGHT,
&SLALOM45OUT_LEFT,
&SLALOM135IN_RIGHT,
&SLALOM135IN_LEFT,
&SLALOM135OUT_RIGHT,
&SLALOM135OUT_LEFT,
&SLALOM90OBL_RIGHT,
&SLALOM90OBL_LEFT,
};

return params;
}

struct pack がスラロームの1パラメータを格納した構造体です.
スラロームには,代表的なターンが16種類あるので,
1種類のスラロームパラメータをまとめたもの(A) へのポインタを,サイズ16の配列(B) にしています
**(A)map<float, pack_t>で,(B)**がarray< map<float, pack_t>*, 16>です.

(A)にstd::mapを使うことで,パラメータの存在確認を可能にしました.
スラロームのターン速を引数に取ることで,欲しいパラメータを参照することができます.

具体的には,次のようなコードでターンパラメータを取得・参照できます.

1
2
3
4
5
6
using namespace slalomparams;
auto it = getParams().at(static_cast<uint16_t>(RunType::SLALOM90SML_RIGHT))->find(0.25f);
if(it == getParams().at(static_cast<uint16_t>(RunType::SLALOM90SML_RIGHT))->end()) printf("Undefined parameter");

it->second.deg; //95.5
it->second.d_before; //0.01

ちなみに,諸事情あってconstにはしていませんが,問題なくconstをつけられると思います.

第29回マイクロマウス東北地区大会で足立法を実装した話

東北大会

マイクロマウス東北地区大会は,我々Miceが毎年大変お世話になっている大会です.
毎年多くのフレッシュマンが精神と時の部屋でとてつもない成長を遂げます.

本年度も6人のフレッシュマンがエントリーし,うち3名が完走.そしてその3名が上位1〜3位を独占という結果になりました! まずは良い結果になり,ホッとしています.正直自分の出走より何倍もドキドキしていました.

反省点も色々と考えているようなので,次の大会も期待しています.博多ラーメン食べられるのが今週の活力.

精神と時の部屋での成長

調整時間にあまり他の人に構えなくて申し訳なく思っていますが,なんせ自分の進捗が怪しいので頑張っていました.

今年のマウスはマイコンを変えただけでなく,プログラムをイチから書き直しています.というのも,コンパイラを変えたことでC++14が使えるようになったので,色々と直したいところが出てきたためです.
ついでにクラス設計も考え直しました.今のところ,いい感じにコードが動いているように思います.

さて,そのせいもあり,容易には昨年度のプログラムを流用することができなくなっています.
精神と時の部屋では,壁情報の保存,歩数マップの展開,足立法の実装を終えることができました.(あれっ,進捗遅くない???)
そういえばモードを実装しようと思っていましたが,間に合いませんでした.そのうちがんばります.

さて,ここからは技術的な話.毎度言っていますが,参考にするときは完全に自己責任で.より良い方法があればご教示いただきたいです.
足立法で走行するプログラムは,こんな感じになっています.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
VelocityControl vc;
Position pos;

Adachi adachi;
Map map;
Walldata walldata;
WallSensor wall;

adachi.setGoal(11, 11);
vc->runTrapAccel(0.0f, 0.25f, 0.25f, 0.045f, 2.0f); while(vc->isRunning());

while(true){
walldata = wall->getWall();
map.addWall(pos.getPositionX(), pos.getPositionY(), pos.getAngle(), walldata);

adachi.setMap(map);
adachi.renewFootmap();
slalomparams::RunType runtype = adachi.getNextMotion(pos.getPositionX(), pos.getPositionY(), pos.getAngle(), walldata);

if(runtype == slalomparams::RunType::TRAPACCEL){
vc->runTrapAccel(0.25f, 0.25f, 0.25f, 0.078f, 2.0f); while(vc->isRunning());
} else if(runtype == slalomparams::RunType::PIVOTTURN){
vc->runTrapAccel(0.25f, 0.25f, 0.0f, 0.045f, 2.0f); while(vc->isRunning());
vc->runPivotTurn(360, 180, 1000); while(vc->isRunning());
vc->runTrapAccel(0.0f, 0.25f, 0.25f, 0.045f, 2.0f); while(vc->isRunning());
} else if(runtype == slalomparams::RunType::SLALOM90SML_RIGHT){
vc->runSlalom(RunType::SLALOM90SML_RIGHT, 0.25f); while(vc->isRunning());
} else if(runtype == slalomparams::RunType::SLALOM90SML_LEFT){
vc->runSlalom(RunType::SLALOM90SML_LEFT, 0.25f); while(vc->isRunning());
} else {
vc->runTrapAccel(0.25f, 0.25f, 0.0f, 0.045f, 2.0f); while(vc->isRunning());
break;
}

pos.setNextPosition(runtype);

if(pos.getPositionX() == 11 && pos.getPositionY() == 11){
vc->runTrapAccel(0.25f, 0.25f, 0.0f, 0.045f, 2.0f); while(vc->isRunning());
break;
}
}
adachi.setMap(map);

壁情報を Walldata クラスでやり取りできるので,記述がなかなか楽になっています.
それから,足立法と座標管理部分と実際のセンサやモータ駆動部分を分離したため,シミュレータにそのまま移植できるはずです.

第34回マイクロマウス東日本地区大会を見に行ってきた

本年度の予定

マイクロマウスシーズンが始まりました.
今年は,これだけの大会に参加しようと思います.

日程 大会 目標(または結果)
7月10日 関西大会 スタートセンサを切った
9月11日 台湾大会 台湾旅行を楽しんだ
10月2日 東日本大会 団体特別賞をいただいた
10月9日 東北大会 ゴールする
10月16日 九州大会 最短ゴールする
10月23日 中部大会 速度を上げる
10月30日 学生大会 シードを取る
11月6日 北信越大会 賢いパスを考える
11月19・20日 全日本大会 決勝で最短ゴールする

と,なかなか旅行三昧かつ高めの目標を立てていますが,頑張っていきたいと思います.
(なんせ就活に使うには今年の大会で成績を残しておかないといけない)

他の目標

成績面での目標は挙げましたが,他に実装したい機能がいくつかあります.
どこまでできるかわかりませんが,とりあえず書き留めておきます.

  • マウス単体でのパラメータ調整
    僅かな数値調整のためにいちいちコンパイル&書き込みするのが鬱陶しいので,マウスで調整したいと思いました.
    一応案はあるので,そのうち実装したいと思っています.
  • 最短経路の時間ベース導出
    ターンに要する時間を考慮した上での最短経路を出したいと思っていました.
    ひとまずは,なんとか松先輩から聞いた方法で試そうかなと考えています.
  • 位置補正
    海外勢がやっている,壁センサのみで区画中心に戻る動作をやりたいです.
    尻当てができない形状なので,格好良くシュッと補正したいと思っています.
  • 最短経路導出プログラムのライブラリ化
    シミュレータと同じコードで動かしたいので,ライブラリにしたいです.
    動的リンクでなかなか苦しんでいるけど…….

以下完全に妄想

  • 迷路中の自己位置推定
    探索でコケた際,それまでに記録した迷路データと周囲の壁情報から自己位置が推定できそうな気がしています.
    壁情報の比較アルゴリズムの最適化と,区画中心に戻る方法をこれから考えていきたいところ.
  • 最短パラメータの自動設定
    最短パラメータを人間が設定しているのは正直イマイチ.
    ロボットを置くことと,スタートボタンを押すことだけにしたいなあと妄想中.

東日本地区大会のまとめ

今更まとめることもないと思いますが,感想はいくつか.

  • 今年のフレッシュマンは強い
    一昨年のフレッシュマン(大嘘)は詐欺です.
    それに比べ,今年のフレッシュマンは未経験からのスタートで本当に頑張ってるなと思います.クォーターではいろいろなバッヂを手に入れ,エキスパートマウスも何台か誕生しました.部室で苦しんでいる姿をよく見ますが,これからの活躍にとても期待しています!
    あ,一応補足しておきますが FND,お前はフレッシュマンじゃねえぞ (エキスパートとして応援しています)
  • 中学生すごい
    中学3年生でハーフサイズゴールをキメていました.本当にすごいと思います.(授業では加速度を習っているところだそう)
    ただでさえ難しい競技の上,ノウハウも全然ないそうなので,相当苦労されているんじゃないかと思います.是非今度遊びに来てください.
  • 副部長つよい
    しかし部長が副部長には負けてられない.
    今シーズンも頑張っていきます.

関数を作る

この記事の目的

この記事は部員向けに書いています.初めて壁情報を保存しようと頑張っている人,使いやすい関数を作りたい人,キーの打ち間違えが多くて困っている人は読んでみてください.
壁の追加関数を作りながら,関数の作り方を学習していきましょう.

この記事ではC言語の関数のみを扱います.また,あくまで僕の考えをまとめたものなので,すべての内容が正しいことは保証されません.

関数とは

関数とはなんでしょうか?
具体的なコードを見てみましょう.

1
2
3
4
5
6
7
8
int sum(int a, int b){
return a+b;
}

int main(){
int n = sum(3, 5);
printf("%d", n);
}
1
8

関数sumは,与えた2つの引数の和を返す関数です.超便利な関数ですよね!
「’+’使えばいいじゃん」
……なるほど,ではこれはどうでしょうか?

1
2
3
4
5
6
7
8
9
10
11
12
13
int sum2(int a, int b){
int i;
int w=0;
for(i=a; i<=b; ++i){
w += i;
}
return w;
}

int main(){
int n = sum2(3, 5);
printf("%d", n);
}
1
12

関数sum2は,与えた引数a以上b以下の数字の和を返す関数です.なるほどこれは便利だ!

という感じで,ある一つの機能を持った小さなプログラムが関数だと思ってください.

関数を作る

作る関数を決める

では,関数を作ってみることにしましょう.今作りたい機能は,マイクロマウスを走らせながら迷路(壁)情報を保存し,読み出すことができる機能だとします.
初めにすべきことは,機能の分割です.今言った機能はすごく大雑把な表現なので,どのような関数が必要か考えてみましょう.

壁を何らかの変数(おそらく配列)に格納すると思います.この変数に,任意の1枚の壁を追加する関数が必要そうです.同時に,この変数から任意の1枚の壁が存在するかどうかを調べる関数も必要でしょう.
というわけで,まずは1枚の壁を追加する関数を作っていきたいと思います.

さて,関数を作る時に意識すべきことは,使いやすい引数を設定することです.
壁を追加する時に,どのような命令で壁を指定すると便利でしょうか?

僕は「壁の面する座標と,壁の存在する方角」を引数にすると便利だと考えました.というわけで,関数のプロトタイプ宣言はこのようにしてみます.

1
int addSingleWall(int x, int y, int dir);

引数として追加したい壁のx,y座標,壁の存在する方角を取り,
返り値は壁の追加に成功した場合0,失敗した場合それ以外の数字を返すようにします.

そういえば,引数にある int dir は具体的にどうやって指定すればいいのでしょうか? いまいちわかりにくいので,改良しておきましょう.

1
2
3
4
5
6
7
8
enum Direction {
DIR_NORTH,
DIR_EAST,
DIR_SOUTH,
DIR_WEST
}

int addSingleWall(int x, int y, enum Direction dir);

関数を実装する

では,addSingleWallを実装していきましょう!
まずはとりあえず実装してみます.
(壁情報の持ち方については,**旧ブログ記事**を参照してください)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
unsigned short wall_column[15];
unsigned short wall_row[15];

int addSingleWall(int x, int y, enum Direction dir){
switch(dir){
case DIR_NORTH:
wall_row[y] |= (0x1 << (15-x));
break;
case DIR_EAST:
wall_column[x] |= (0x1 << (15-y));
break;
case DIR_SOUTH:
wall_row[y-1] |= (0x1 << (15-x));
break;
case DIR_WEST:
wall_column[x-1] |= (0x1 << (15-y));
break;
}
return 0;
}

さて,このプログラムは正しく動作するでしょうか?
もちろんお気づきかと思いますが,問題がありますね.引数値として,例えば(0, 0, DIR_WEST)を与えた場合に配列の領域外にアクセスすることになります.もしくは,(-100, 150, DIR_NORTH)などの範囲外を与えた場合にもエラーが返って来ず,恐ろしいことになりそうです.

今回気をつけなければいけなかったことは,次のようなことです.

  • 正しい処理をする
    言うまでもなく,適切な壁を追加してくれないと困ります.
  • 誤った引数が来ても問題なくする
    今回の場合,壁が追加できないような引数が来た場合には何もせずにエラーコードを返すべきです.
    誤った壁を追加したり,配列の領域外にアクセスするといったことは絶対にしないように気をつけます.

以上を踏まえた上で実装を行いました.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
unsigned short wall_column[15];
unsigned short wall_row[15];

int isInRange(int x, int min, int max){
if(x >= min && x <= max) return 1;
else return 0;
}

int addSingleWall(int x, int y, enum Direction dir){
switch(dir){
case DIR_NORTH:
if(!isInRange(x, 0, 15)) return 1;
if(!isInRange(y, 0, 14)) return 1;
wall_row[y] |= (0x1 << (15-x));
break;
case DIR_EAST:
if(!isInRange(x, 0, 14)) return 1;
if(!isInRange(y, 0, 15)) return 1;
wall_column[x] |= (0x1 << (15-y));
break;
case DIR_SOUTH:
if(!isInRange(x, 0, 15)) return 1;
if(!isInRange(y, 1, 15)) return 1;
wall_row[y-1] |= (0x1 << (15-x));
break;
case DIR_WEST:
if(!isInRange(x, 1, 15)) return 1;
if(!isInRange(y, 0, 15)) return 1;
wall_column[x-1] |= (0x1 << (15-y));
break;
default:
return 1;
break;
}
return 0;
}

壁が存在するかを読み取る関数や,他に必要と思った関数は自分で実装をしてみてください.

関数を拡張する

さて,先程作ったaddSingleWall関数を改良してみましょう.

壁情報を複数個持ちたい場合があるかもしれません.まずは壁情報であるunsigned short wall_column[15]unsigned short wall_row[15]をまとめて構造体にしておきます.

1
2
3
4
struct WallData{
unsigned short column[15],
unsigned short row[15]
}

では,安直に次のように実装してみます.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
struct WallData wd1;
struct WallData wd2;

int isInRange(int x, int min, int max){
if(x >= min && x <= max) return 1;
else return 0;
}

int addSingleWall1(int x, int y, enum Direction dir){
switch(dir){
case DIR_NORTH:
if(!isInRange(x, 0, 15)) return 1;
if(!isInRange(y, 0, 14)) return 1;
wd1.row[y] |= (0x1 << (15-x));
break;
case DIR_EAST:
if(!isInRange(x, 0, 14)) return 1;
if(!isInRange(y, 0, 15)) return 1;
wd1.column[x] |= (0x1 << (15-y));
break;
case DIR_SOUTH:
if(!isInRange(x, 0, 15)) return 1;
if(!isInRange(y, 1, 15)) return 1;
wd1.row[y-1] |= (0x1 << (15-x));
break;
case DIR_WEST:
if(!isInRange(x, 1, 15)) return 1;
if(!isInRange(y, 0, 15)) return 1;
wd1.column[x-1] |= (0x1 << (15-y));
break;
default:
return 1;
break;
}
return 0;
}

int addSingleWall2(int x, int y, enum Direction dir){
switch(dir){
case DIR_NORTH:
if(!isInRange(x, 0, 15)) return 1;
if(!isInRange(y, 0, 14)) return 1;
wd2.row[y] |= (0x1 << (15-x));
break;
case DIR_EAST:
if(!isInRange(x, 0, 14)) return 1;
if(!isInRange(y, 0, 15)) return 1;
wd2.column[x] |= (0x1 << (15-y));
break;
case DIR_SOUTH:
if(!isInRange(x, 0, 15)) return 1;
if(!isInRange(y, 1, 15)) return 1;
wd2.row[y-1] |= (0x1 << (15-x));
break;
case DIR_WEST:
if(!isInRange(x, 1, 15)) return 1;
if(!isInRange(y, 0, 15)) return 1;
wd2.column[x-1] |= (0x1 << (15-y));
break;
default:
return 1;
break;
}
return 0;
}

……どう考えても冗長なコードです(先日部員がこのようなコードを書いていて驚愕しました).
これでは満足行かないので,addSingleWallの引数を次のように工夫してみます.

1
int addSinglewall(int x, int y, enum Direction, struct WallData *);

実装すると次のような感じでしょうか.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
struct WallData wd;

int isInRange(int x, int min, int max){
if(x >= min && x <= max) return 1;
else return 0;
}

int addSingleWall(int x, int y, enum Direction dir, struct WallData *wall){
switch(dir){
case DIR_NORTH:
if(!isInRange(x, 0, 15)) return 1;
if(!isInRange(y, 0, 14)) return 1;
wall->row[y] |= (0x1 << (15-x));
break;
case DIR_EAST:
if(!isInRange(x, 0, 14)) return 1;
if(!isInRange(y, 0, 15)) return 1;
wall->column[x] |= (0x1 << (15-y));
break;
case DIR_SOUTH:
if(!isInRange(x, 0, 15)) return 1;
if(!isInRange(y, 1, 15)) return 1;
wall->row[y-1] |= (0x1 << (15-x));
break;
case DIR_WEST:
if(!isInRange(x, 1, 15)) return 1;
if(!isInRange(y, 0, 15)) return 1;
wall->column[x-1] |= (0x1 << (15-y));
break;
default:
return 1;
break;
}
return 0;
}

まとめ

関数は使いやすさが第一です.自分の使いやすい関数を作り,楽に開発を進めましょう.
機能ごとに関数を分割することでデバッグも楽になるはずです.

2016年マイクロマウス台湾大会に付き添ってきた話

出発まで

すべての元凶であるF先輩が台湾大会に行きたいと言い出し,僕とM先輩が巻き込まれました.そして大勢のマウス関係者のご協力のおかげで無事参加できることになりました.ところがどっこい,F先輩が「金ないから行かない」とか言い出したのでLCCを使った最高のプランを提案し,無事3人で参加することになりました.まったく迷惑かけさせんなよ

初めての台湾

Vanilla Airを使って格安で台湾に行くことができました.現地では,予め契約しておいたルーターのおかげでインターネットに困ることはありませんでした.

台湾で先輩たちと合流した後,ノープラン台湾旅行1日目が始まりました.僕とF先輩は全く分からなかったので,何かしらの情報を持っていたM先輩の案内のもと九份に行くことにしました.
これは九份にあったセブンイレブンの様子です.

九份でお茶を飲んだときの様子です.

台湾の交通系ICカードの写真です.

台北101でちびっているF先輩の様子です.

夜に遊びに行ったときのM先輩の様子です.

たまこまグッズを見つけてテンションが上がったときの僕の様子です.

大会

ものすごい坂道に建っている大会会場に到着しました.
無事に二人とも最短走行が成功してよかったです.僕も頑張らないと.

帰国

最終日はマウス関係者の皆さんに誘われて淡水観光をしました.どでかい川があったり,アニキ撮影会があったり,よくわからない文化遺産があったりして,とても楽しかったです.

今回ご協力いただいた皆さん,本当にありがとうございました.これに懲りず,また参加しようと目論んでいるのでそのときはよろしくお願いします.
無謀な計画に付き合ってくれたみなさん,ありがとうございました.僕は全く反省していないので,どんどん連れ回しますがお付き合いください.

はてなサマーインターン2016で最高の夏を過ごしてきた

はてなサマーインターン

とは

はじめまして,id:hantasです(誰だお前).
はてなではhantas,それ以外ではtanihoを使っているのでややこしいですが,今回はid:hantasとしてはてなサマーインターンに参加してきました!

はてなサマーインターンとは,あの有名な株式会社はてなが1年に1度実施しているインターンシップです.20日間のうち前半は講義,後半はチームに配属されて開発を行います.なんと後半課程では給与が発生します! 嬉しい!
詳しくは次の募集サイトを見てみてください.
はてなサマーインターン2016

なぜ参加したのか

「時代は静的ブログだ!」とか言ってはてなブログ(hantas’s blog)からhexoに乗り換えた自分が,どうしてはてなのインターンに参加してしまったのでしょうか?
僕が小学生の頃.ロボットを通してプログラミングを学び始めた頃から,ちらほらと「プログラマーかっこいいなー」と思っていました.中学ではその世界から離れ,高校ではプログラムは少しだけ書いていたものの,ろくな活動はしていませんでした.「大学ではバリバリコード書くぞ!」と思っていたのですが,電気工学科がバリバリコードを書ける環境にあるかというと,ぶっちゃけそうでもなく.気づいたら 悪徳宗教サークルMice に入部して組み込み開発と機械設計の毎日を送っていました.
学生生活もあと2年を切り,悔いのないようにしたいと思ったのが学部3年の5月.セキュリティキャンプの応募を考えている頃に,同時に将来のことなんかも考えていました.将来どんな仕事をしようか? 定年まで働くの? 大学院は? いろいろ考えないといけないことがあります.周りの友達が「インターン,インターン! インターン!!」と叫び出したので,とりあえずの気持ちでインターンに応募し始めました.
ハーフマウスの開発にお金が吹き飛んでいったことを言い訳にして「無給インターンは行きたくない! お金の出るところだけ応募するぞ!」というとても厚かましいことを言い出し,LINE,yahoo,pixiv,はてなの4社に応募しました.結果,yahoo以外はすべて1次選考通過したのですがスケジュールの兼ね合いで一番行きたかったはてなに行くことにしました!
はてなインターンシップの選考ではポートフォリオを出すように指定されたので,参考にも僕のポートフォリオサイトを公開しておきます.デザインがひどい件については,幅広くアドバイスを募集しています.
Portfolio - taniho0707

おいマウスやれよ

誰かに会う度に言ってる気がするんですが,インターンにこの夏のすべてを捧げた感じがします.

休日が壊滅的に存在しない

マウスで圧倒的進捗して台湾大会で優勝する予定(大嘘)だったのですが,インターンシップがたいへんハードなスケジュールだったので進捗を出せるはずもなく.Perl書きすぎてC++書けなくなってるかもしれませんが,10月からは頑張りたいと思います.

前半

前半の講義が始まる前に,環境構築の時間がありました.僕のパソコンではMySQLが起動しないという大変な事態が起こっていたのですが,id:polamjagくんやメンターのid:windymeltさんに助けてもらい,あっという間に解決しました.感謝!
この内容については別記事を書く予定です.

講義が始まったら,毎日新しい分野の専門講義を受講し,午後にそれを用いた課題に取り組みます.特にトラブルがなければ,必須課題は終わります.遅くても帰る時間(22時)には絶対終わると思います.ただ,応用課題はすごいざっくりとした課題なので,好きなだけ凝ることができます.そして気付いたら22時になって悲しくなります.初めの2週間は,大体こんな感じで過ぎていきました.
そういえば,この講義では超基本的なことはあまり触れられません.事前課題があるので,最低ラインの知識があること前提なのでしょう.しかし,最高の教科書と最高のメンターと,最高の講義のおかげもあり,メキメキと知識がついていくことが実感できました.

前半のハイライトです.

グリーンカレー初めて食べたけど美味しかった.

生まれて初めてのファミコン.

id:nanto_viさんに京都観光に連れて行ってもらいました!
コースは,平等院鳳凰堂からの下鴨神社! 晩御飯は美味しい京野菜のお店に行きました!

帰った後たまこラブストーリー観ました.subsonic最高だわ.

中間

京都にいるのでいろんな人といろんなところに遊びに行きました.この章ははてなと関係ありません.

  • 東京から友達が来たので,ダリ展とか,日本橋とか,〜禁則事項〜地とか,深夜の伏見稲荷大社とか,地主神社とか行きました.

  • コミケの打ち上げを京都でやりました.近々DLSiteに登録するので,是非ご購入ください!

  • 地元の友達と花火しました.儚く落ちる線香花火.夏っぽくていいですね.

後半

配属

後半では,それぞれのチームに2人ずつ配属されました.僕たちは機械学習・自然言語処理・アドテクノロジーコースということで,はてなブックマークなどなどを扱っている最高のチームに配属され,メンターのid:syou6162さんにサポートしてもらいながら作業していました! チームメンバーとなった id:takuya-nakamura くん,2週間の間お世話になりました!
後半課程として与えられた課題は,検索結果を改善すること.前半課程で学んだ機械学習の知識をフル活用し,検索エンジンの改良に取り組みました.

事件

とある昼休みにはこんなことがありました.

なんでもインターンあるあるだとか.
そんなこともあったブログチームですが,なんと最速リリースをして「優勝! 優勝!」と叫んでいました.

定時後

3週目の定時後には毎日イベントが開催されており,毎日飲んで食べて踊っていました.

面談

社長面談があるということは事前に聞いていたのですが,まさかCTO面談,人事面談,社長面談と,3つも面談があるとは思っていませんでした!
社長とお話できる時間が用意されているのは,はてなインターンの魅力の一つではないかと思います.面談でなくてもお昼休みには役員・社員のみなさんが一緒にご飯を食べているので,話しかけ放題です.

最終発表

最終日,配属されたチームごとに最終発表を行いました.僕達のチームは「機械学習とはなんぞや?」というところから易しく説明して,いかに苦労してフィルタが完成したか,というところを発表しました.
残念ながら1票という僅差で3位でしたが,多くの社員さんが感想と共に投票してくださり,とても嬉しかったです.

その他

ダメ

インターンもあと1週間となった頃,ふと良くないことに気付いてしまいました.
「帰り道に,ゲーセンあるじゃん」

インターン生

楽しいインターン生ばかりでした.特に印象的だった出来事を3つだけピックアップ.

超便利画像

さてさて,最後になりましたが
超便利画像を大公開! はてなで出たご飯,はてなでおごってもらったご飯一覧です!!!

ほんの少しでも興味がある人へ

Web系の仕事に興味がある人!
プログラムを作ることが好きな人!
共同でコードを書いてみたい人!
すごい人たちと知り合いたい人!
はてなが大好きな人!

是非このインターンに参加すべきです! 来年の夏休みの予定をあけて,パソコンとエディタを用意しておきましょう! 心配することはなにもありません.インターンに合格するくらいなら,きっとついていけます.

その中で,インターン絶対合格したいという人は何か作りましょう! 「ものを作っている人,それを完成させた人であれば,はてなに来てもやっていけるだろう」という考えを聞きました.「ゲーム作りたいなー」というのは簡単ですが,本当に完成させるのはなかなか大変です.ゲームじゃなくてロボットでも良いです.もちろんWebサービスでもいいでしょう.要するに,手を動かして何かを完成させる経験をするべきです.僕はマウスをサボってが完成していないので偉そうには言えませんが,このことを心がけるといいでしょう.

総括

お世話になった皆さん,お仕事が特に忙しい中に,本当にありがとうございました! 最高だったはてな京都オフィスで,最高の経験をすることができました!

夏休みが終わったら

やらないといけないことがたくさん溜まっている気がしますが多分幻想だと思うので,これに尽力します.

セキュリティ・キャンプ2016全国大会に参加した

セキュリティキャンプとは

セキュリティ・キャンプ全国大会2016:IPA 独立行政法人 情報処理推進機構
詳しくはこちらを見てください.とても熱いイベントでした.

宣伝

美味しいご飯の様子など,キャンプ中に書いた記事があります.個別の講義の内容などもこちらにまとめてあります(頑張って内容を充実させようと思います……そのうち).良ければご覧ください.

seccamp2016 DAY1 | taniho’s blog
seccamp2016 DAY2 | taniho’s blog
seccamp2016 DAY3 | taniho’s blog
seccamp2016 DAY4 | taniho’s blog
seccamp2016 DAY5 | taniho’s blog

今回の記事では,キャンプ中には触れなかった話,すごいどうでもいい感想や,真面目な話をしようと思います.

参加するまでの経緯

僕がこのキャンプを知ったのが大学に入学してすぐでした.「情報に興味があるんだったらこんなイベント好きそう」とか言って先輩に紹介を受けました.
その年はまだトラック制だった時代で,僕が応募したネットワーク・セキュリティ・クラスは謎のファイルが与えられ,その解読から始まるという課題が出されていました.僕はまだWindowsしか使っていない頃で,fileコマンドすら知らずに苦労した覚えがあります.そのため,とにかく問題をなんとしてでも解かなければいけないと思って必死に調べ回りました(今思えば,あんなのの何が’必死’だ,という感じですが).
当時の応募用紙を見返しているのですが,まあ当然知識量は(まだまだ未熟ではあるけれど)今よりずっと少ないです.ただ一番の問題はそこではなく,圧倒的に熱意が足りていないと思います.当時は知識問題というものがありましたが,一言二言で答えている問題が多くありました.多分,知識がなくて困った人は必死に調べ回ったり人に聞いたりして勉強したはずです.そのプロセスをアピールしないと,熱意は伝わらないと思います.

ちなみに今年の応募用紙は,偉大なる先輩に読んでもらって,意味がわからないところや不自然に感じたところなどを指摘していただきました.大いに熱意を伝えるのは良いことだと思いますが,読みやすく伝わりやすい文章を作ることも大切ではないかと思います.
(まあ補欠の自分が偉そうに言えた立場じゃないですけどね)

少し話がそれましたが2014年はお祈りメールが届き(コミケは初当選),続く2015年もダメでした.この年はそもそも準備を始めるのが遅かったことが原因です(と言い訳).

年齢制限のため最後の2016年は本気で頑張ろう……と思い立ち,1ヶ月まるまるかかって応募用紙を作りました.
詳しくはこちらの記事を見てください.
セキュリティ・キャンプ2016に応募した | taniho’s blog

DAY0

キャンプが始まるまでの間は,グループウェア上で受講する講義の抽選や,事前課題の発表,他にもOSやプログラミング言語などの話題で交流をしていました.また,twitterでは参加者のリストを作られているチューターさんがいたのですが,そのリストも賑わっていました.みなさんすごいリプ飛ばし合っててすごいなあと思っていました.(もしかしたらミニキャンプとかで既に知り合っているとかなのかな)
Facebookの申請も飛び交っていましたが,みなさんイケメンですごいですね(小並感)

さて僕はというと,「考えてみましょう」・「調べておいてください」系の課題をやりつつ,激重課題の「サーバに対する攻撃とその影響度を調べてディスカッションする講義」を進めていました.
予め用意された「攻撃された形跡のある」サーバに接続し,その内容を解析し,発表資料を作るというものです.まあとりあえず何らかのログファイルを見ればいいだろうなあとは思いましたが,かなりの種類・分量のファイルがあるため非常に大変でした.詳しくはDAY3の記事に書いているので(これから書くつもりなので)そちらもご覧ください.

DAY1

会場に入ると早速お土産が置いてありました.セキュリティキャンプシールがもらえてとても嬉しい! のですが,オンボロのThinkPadに貼るのはもったいない気がして保留中…….

そういえばThinkPadに貼ったシールを見て話しかけてくれた方が何名かいましたが,Emacsよりも,ボコ(ガルパン)よりも,FA機器.comが一番注目されていたようです.そんなに不思議なシールだったのかなー.
(FA機器.comでは学生無料のお持ち帰り企画が開催されています.とてもありがたいイベントでした.良ければ是非.)
メカトロ部品学生無料|FA機器.com 産業用部品買取販売サイト

1日目はまあ静かに終わりました.ずっと話を聞き続けていたので結構疲れてしまい,コンビニツアーにも行かずすぐ寝ました.

DAY2

この日は集中講義でしたが相変わらず詳細は個別の記事を見てください.

CTFは散々でした.テスト用の問題と,シーザー暗号の問題の2問だけでタイムアップです.チーム「.t」は200点.

この後CTFのチームを作ってる人たちに声をかけて,一つのグループに招待してもらいました.始めたばかりですが,これから頑張っていこうかなと思っています.

DAY5

グループワーク

ごそっと時間が飛びますが,最終日にはグループワークの発表がありました.
僕のチームは,倫理問題について新しい解決法を提案しました.

残念ながら賞をもらうことはできませんでしたが,5日間にわたってチームのメンバーと活動できて,とても楽しかったです.また,講師の方々にインタビューに伺い,色んな話を聞けたことも良い経験になりました.ご協力いただいた方々,ありがとうございました.

閉講式

閉講式では修了証と大臣からのお言葉を頂き,全員が10秒のコメントを残していきました.

みんな「twitterでもよろしくね!」みたいなことを言ってて,かぶるのも面白くないなあと思ったので「セキュキャンはいいぞ」と一言だけ残しました.イマイチ受けが良くなかったような気がしますが気にしない.あ,みんなtwitterでも今後ともよろしくね!

写真撮影

「今日も一日〜」
「「「頑張るぞい!」」」パシャッ
って10回位やりました.

コミケin幕張

無作為に選ばれた班から順に退出し,本などをいただくことができました.


僕は本を頂いたあと,頂いた書籍のサイン集めに走り回っていました.一番狙っていた本は取れませんでしたが,どちらも欲しかった本なのでとてもうれしいです.

ご提供いただいた企業の方々,また翌日のコミケで出す新刊をくださった@nekoruriさんありがとうございました.
いま本が手元にないのですが,家に帰ったら楽しく読みたいと思います.

受講した講義のすべての講師の方々にもサインをいただきました.写っているお魚はニジマスとのことです.

大切な宝物になりました.

感想

雑多なこと

グループワークの資料提出の形式が.pdfでよいと言われたことがとても新鮮でした.普段は.pptか.pptxって言われるので,pdfで良いかわざわざ確認を取りに行っています.
EmacsとVimの話が普通に通じる環境もとても楽しかったです.三対一,一対三というチーム名を見たときは爆笑しました.いまだにどっちがヴィムでどっちがイーマックスなのかわかりません.
デスクトップ環境について良い情報ももらえました.チューターさんにQtileをオススメしてもらったので,インターンが終わり次第試してみようと思います.
とにかく,技術的な話題がどんどん出てきて,みなさん本当に詳しかったのでとても楽しかったです.僕もいつかプロになりたい.

コミュニケーション

キャンプの5日間は,おそらく人生で一番コミュ力を発揮してコミュニケーションを取っていました.5日間の間に100人を超える方々とお会いし,それに近い枚数の名刺を交換し,食事の度に違う人とお話をしました.もう脳が何度もパンクしていたと思います.名刺もらったのに名刺くださいと言っちゃった人ごめんなさい.もらった名刺は見れば思い出せるし,顔とtwitterアカウントは覚えてるので許してください.

普段ならまずお話できないような方ともお話する機会がありました.IPAの理事長と相席させてもらったときは,情報処理技術者試験についてお話を聞くことができました.答えが出る問題を作るのは簡単だけれど,答えが一つしかない問題を作るのは相当に難しいそうです.力を入れて,本当に良い問題を作られているのだなと思いました.

僕は幸いにも年齢制限限界で参加することができたのですが,年下の参加者が大勢いて,若さを感じました(老害感).僕が高校の頃はC言語も勉強したてで,技術的なことは何も分からなかった記憶がありますが,すごい人は本当にすごいです.隣の席に座ったミズゴロウくん(アカウント名より言いやすいのでこれで勘弁)は普段からバグ探しをしていて,過去の報告で名前が載ったこともあるそうです.すごいなあ.

ネット上でフォローしている方ともお会いしました.とさいぬくん,BDの件ではお世話になりました.詳しくは次の記事をどうぞ.
ArchLinuxでBlu-rayを再生する | taniho’s blog

山下さんにはとても雑な話題で話しかけに行ってしまい,すみませんでした.たまこまーけっとが好きな人がいてとても嬉しかったのでつい話しかけてしまいました.再上映がもしかすると実現するかも知れないので,要チェックです.
映画 たまこラブストーリーを映画館で上映しよう! | ドリパス

今後は,このように大勢と交流する機会があるかも知れませんが,僕にとってはこんなに一気に交流することは初めてでした(入学式でも少人数としか話さないと思う).本当に良い機会をいただきました.キャンプでの積極さは絶対に忘れず,存分に発揮していきたいと思います.
また,キャンプ中お話してくださった方々,本当にありがとうございました.これからもよろしくお願いします.

興味がある人へ

つべこべ言わず応募用紙を書きましょう.とにかく提出しましょう.恐れる必要は何もないです.
当日の講義はかなりレベルが高そうなことが書いてありますが,初心者でも大丈夫です.そのためにチューターさんがいっぱいいるし,そのために丁寧なテキストまで用意されています.遠慮なく質問しまくって,どんどん突っ込んでいけばいいと思います.

僕は,今年何か成果を出すことができたら,来年以降のチューターに応募してみようかと思っています.
その時は是非幕張でお会いしましょう!

seccamp2016 DAY5

おつかれさまでした

今日で長くも短かったキャンプのおわりです(なおブログを書いているのはかなり後の模様).
とりあえず最終日の雑なまとめだけでも書いておきます.
総まとめは事後課題と一緒に投稿しようと思います.

いただきました

恒例のキャンプTシャツです!! 今年は参加者がピンク,チューター・講師・運営の方々がもうちょい濃い色(何色?)でした. いろはすも毎日増えていったのでお持ち帰りします. なお,外にはもっと大量においてある模様……

コミケ会場

有明でこみっくまーけっととかいうイベントが開催されていたようですが,幕張の方が熱いコミケ会場になっていました.

お家に帰って

これだけのものを頂いてきました.
提供いただいた企業や個人の方々,本当にありがとうございます.
書籍の詳細は別の記事に書こうと思います.

もっと詳しいまとめ

がんばってまとめ記事書くので楽しみにしていてください(誰がこんなブログ好き好んで読むのか知らないけど)

今日の飯テロ

seccamp2016 DAY4

6-C 車載LAN上を流れるメッセージの解析

車載LANであるCANネットワークに接続し,そこを流れるパケットをキャプチャ解析して遊びました.
今回の機材は安価で手に入れられるということなので,問題のない範囲で遊びたいと思います.

7-A ID連携基礎

今回のセキュリティ・キャンプのなかでは非常に高いレイヤの話でした.具体的にはHTTPより上のレイヤでした.
非常に残念ながら最後まで演習をする時間がありませんでしたが,とても興味が湧いたのでまた演習したいと思います.
Burp使えるようになりたい.

企業プレゼンテーション

AAとかtwitterアカウントとかコミケのブースとか紹介されました.
質問の時間も多くとっていただきました.インターンシップの話なんかは良い情報を聞きました.

グループワーク

今日はチューターさんが「寝ろ」と言わずにデブ活している……
一部の方には「夜は自分の部屋にいなkくぁwせdrftg……
徹夜つらい……
徹夜つらい……
徹夜つらい……

今日の飯テロ

朝ごはん

昼ごはん

夜ごはん

謎ごはん

seccamp2016 DAY3

いろはす

室内でもいろはすが無限に増え続けている件について.

3-B フィジカル・リバースエンジニアリング入門

JTAGまで行けなくてとても残念でした.
法を破らない範囲で楽しく分解調査をしていきたいと思いました.

4-C オンラインゲームアタック&ディフェンスチャレンジ

ほぼすべて演習という感じの講義でしたが,なかなかにつらかったです.僕の仕事は強い人を観察することということなので色々と様子を見ていたのですが,本当に強いですね…….
jsはインターンで扱わないといけないので,これから頑張っていきたい所存.あとWebSocketもとても手軽に扱えそうなので,是非触ってみたいです.

5-C サーバに対する攻撃とその影響度を調べてディスカッションする講義

唐突な差し入れで受講者の心を鷲掴みにする川口先生素敵でした!!

一番目の発表者がスライド40枚分作ってきていて,できる人はこんなにいっぱい調べられるんだなあと驚きました.
僕は問題点2個だけピックアップしてプレゼンしました.
模範解答の発表では色々と納得の行く調査をしていて,やはり本業の方はすごいなあという感想を抱きました.

企業プレゼン

DNPさんのプレゼンを聞きに行きました.
「TAME Range」というサーバセキュリティの演習環境を開発されているそうです.印刷業のメーカーからしては全然イメージできないジャンルでしたが,色々な紹介を聞くことができました.

グループワーク

すすめています(白目)

今日の飯テロ

seccamp2016 DAY2

おはようございます

今日から(と言っても書いてるのは翌日の朝ですが)専門講義が始まりました.
とてもわくわくしながら朝ごはんを食べていました.

1・2F 作って学ぶ低レイヤネットワーク

午前

坂井講師作のpkt-toolsの使い方を学習した後,
** 0806 0001 0800 0406 0002 **
この凶悪なパケットを送りまくったり,
超簡易型リピーターの暴走っぷりを眺めたり,
頑張ってICMPパケットを作ったり,
pkt-toolsを改造したり,
幕張に閉じ込められているのに運動会を始めたりしました.
(ちなみに運動会は これ を使いました.カッコイイですね)

※8/30追記
講義では隔離されたネットワークの中のみでパケットを送信しました.運動会をやりたいと思われた方は,必ず外部のネットワークから隔離するようにしてください.

午後

午後は,なんと変態改造を施したArduinoのGPIOポートをそのままLANケーブルにつなぎ(!?),ARPパケットを送ってみようという実習でした.
自作したLANケーブルというのがこちら

これは帰ってから自分で試してみたい! と思いました.
「イーサネットコントローラの言いなりにはならないぞ!」

※8/30追記

CTF

僕はこのチームで出場しました.
他のメンバーは気付かずのうちにこのチーム名に決定したようでしたが,

** Perlはいいぞ **

結果は10位200点.
まあ残念でしたが,うんうん唸っているのがとても楽しかったので,またチャレンジしたいと思いました.

そういえば生の友利奈緒さんを二人目撃することができたので幸せでした.

今日の飯テロ

seccamp2016 DAY1

はじまりました

セキュリティ・キャンプが始まっちゃいました.

頑張っていこうと思います.

開講

荷物を預けたら名刺交換です.
数えたら今日だけで51枚の名刺+2枚のステッカーをいただきました.みていてとても楽しいですね.
デレステマシンを覚えて頂いてる方が数人いらっしゃって,とてもうれしかったです.

そういえばいきなり会場のアクセスポイントが楽しいことになっていました.

共通講義

スーツのおじさまのお話が終わった後,楽な格好のおじさんのお話が始まりました.はじめの「セキュリティ基礎」ではいきなりグループワークで,応募フォームの問題点のあら捜しをしました.自己紹介から入ったのですが,うちのグループはみなさんVim使いでEmacserが一人もいませんでしたつらいかなしい.
**(Emacserのお友達を切実に募集しています)**
こういった話が普通に通じてしまうコミュニティが大学にはとても少なく,楽しかったです.

その後は,キャンプのためだけに来ていただいたと言う,福森さんの講義でした.
ただ単に力をつけるだけではダメだと痛感し,「技術」とは何なのか考えさせられた講義でした.

他にも色々あった気がしますが朝ごはんを食べたいので一旦投稿してしまいます.

本日の飯テロ

本日のお部屋情報

普通に快適でした.

ArchLinux道、始めます!

この記事は2016年1月の下書きに加筆修正したものです.

今更感のあるこの記事について

ついにArchLinuxに手を出してしまいました(2016年1月頃の発言)。
手持ちのPCはこんな感じになってます。

  • Win7 + ArchLinux デスクトップ
  • Win10 + Ubuntu14.04 ノート → Win10 + ArchLinux ノート (Ubuntuアップデート失敗のため,乗り換えました)
  • Ubuntu12.04 サーバー

せっかくなので次のインストールの為にも,セットアップ手順を残しておきます。
OSのインストールに関しては情報がたくさん見つかったので,省略します。
主に次の記事を参考にさせていただきました.
ビギナーズガイド | ArchWiki
Arch Linuxインストール | 普段使いのArch Linux
今回の記事では,デスクトップ環境の導入からとりあえずのPC環境にするまでをまとめます。

デスクトップ環境の導入

今回はデスクトップ環境としてGDM+Cinnamonを選択しました。

1
sudo pacman -S gdm cinnamon

パッケージなど

いれないと死んでしまうパッケージ

1
2
3
4
5
6
7
8
9
sudo
gnome-terminal #端末,Ubuntuの標準
alsa-utils #音の再生には必須
bzip2
make
git
zsh #シェルはzshを愛用しています
emacs #迷ったらEmacsを
mikutter #ツイ廃さん御用達

日本語関係

emacs-mozcを使う場合,FcitxではなくiBusを使う必要があります.

その他

1
2
3
4
5
6
7
8
9
10
11
12
13
14
nemo #シンプルで使い勝手の良いファイラ
eog #gnomeの画像ビューワです
evince #pdfなどのドキュメントビューワです
firefox
flashplugin
jre7-openjdk
asunder #CDのリッピングツール
vlc
mplayer #メディアプレーヤー
gnome-mplayer #mplayerのフロントエンド.無難に使いやすい
filezilla
libreoffice
shutter #スクリーンショットツール
vim

トラブルシュート

今回次のような問題が発生しました。
合わせて対処法もまとめておきます。

  • 日本語キーボードが使えない
    デスクトップ環境であれば簡単でした.
    設定画面を開き,キーボード > レイアウトから,レイアウトを日本語にします.

  • Cinnamonの設定が開けない
    Cinnamonの設定をGUIで行うには次のパッケージが必要だそうです。

    1
    sudo pacman -S cinnamon-settings
  • mozcが起動しない
    まずキー割り当てを見直してみてください.
    iBusのキー割り当て,mozcのキー割り当ての2種類があります.
    僕の場合,iBusには一切割り当てず,mozcのモード切替に全角半角キーを割り当てています.

  • 通知領域にmozcアイコンが表示されない
    まだ原因がわかっていません.ごめんなさい.

  • CapsLockをCtrlキーとして使いたい
    デスクトップ環境であれば簡単でした.
    設定画面を開き,キーボード > レイアウト > オプションから,CapsLockをCtrlとして使う設定を有効化できます.

  • プライベートIPアドレスを固定する
    Ubuntuに比べて少しややこしくなっていました.
    こちらの記事を参考に設定しました.
    Arch Linuxで固定IP設定にはまる | netanote.com

  • Cinnamonが起動しなくなった,Cinnamonのアイコンが表示されなくなった
    Gnome-shell 3.2.2 updated: extension and tray icons missing | Arch Linux Forums

ArchLinuxでBlu-rayを再生する

エンバンデビュー!

先日,初めてBlu-ray,いわゆる円盤を購入しました.

とりあえずいつものArchWikiより,Blu-rayについての記事を見ながら再生環境を整えようとしました.
しかし,方法1を試しても鍵の認証ができない,方法2はそもそも鍵データが古すぎる……,ということで嘆いていました.ああ,心待ちにしていた円盤が再生できない…….
どうやら,今回買った円盤はAACS v46だそうで,この方法は古すぎるようです.

と,そこに素晴らしい記事が舞い込んできました.
対Blu-ray用決戦部隊、通称MakeMKV

詳しくはこちらの記事を参照してください.
簡単に言うと,

一般的に使われているライブラリの代わりにMakeMKVで使われてるライブラリを使うことで,VLCでBDの再生ができる

ということです.
MakeMKVというのはBlu-rayのリッピングツールであるため,取り扱いにはくれぐれも注意してください.

というわけで,ArchLinuxの場合はユーザーリポジトリに入っているようなので

1
yaourt -S makemkv-libaacs

を実行し,VLCを起動し,Blu-rayディスクを再生しようとすると……,

参考にしたサイトの管理者の方,本当にありがとうございました.

ただし,メニューには対応していないようでした…….どうにかできないのでしょうか.

余談

今回の再生環境や,Windowsの怪しいフリーソフトでの再生時には,映像が乱れたり画面が止まったりすることが何度かありました.PowerDVDなどの純正ソフトで再生したときにはこんなことなかった気がします.
何が違うのでしょうか……?
きれいに再生する方法をご存知の方,教えてください.

dアニメストアはいいぞ

アニメ好きな人たちへ

dアニメストア はご存知でしょうか?
アニメ番組の配信サイトです.最近特に頑張っています.もともとはドコモの契約者のみに提供されていたサービスらしいですが,今は誰でも入会できるようになっています.
その魅力をまとめ,沼に落とそうみなさんにおすすめしようと思います.

dアニメストアとは

値段

公式サイトにこんな文言がありました.(アクセス日:2016年6月6日)

月額400円(税抜)で約1,600作品、 約30,000話のアニメが見放題!
ドコモじゃなくてもOK! 初回31日間は無料で見放題!

え,まって,すごくないですか?
月額400円でほぼすべての作品が見放題.一部有料作品(レンタル販売という扱い)がありますが,現時点で13作品だけです.2016年6月6日早朝段階で全作品数は1673作品でした.つまり,1660作品が見放題というわけですね,すごい.

配信作品

一番の問題はどんなアニメが配信されているかということですね.
例えば2016年春アニメを例に挙げると,残念ながらすべての作品が配信されているわけではないです.僕が見ようとしたアニメだけでも,

  • 甲鉄城のカバネリ
  • 彼女と彼女の猫 -Everything Flows-
  • ばくおん!!

は配信されていませんでした.
また,最新作の配信についても,配信日程が遅いものも見受けられます.Re:ゼロから始める異世界生活はテレビ放映の2週間後に配信されています…….もちろん,TV放映の翌日に配信される作品も多々ありますよ.

ではdアニメストアがどういった作品を多く置いているかについてです.
例えばノイタミナ作品は多く配信されています.僕だけがいない街や,PSYCHO-PASSなど,話題を呼んだ作品が見放題です.もちろん,有名なタイトルも多く配信されています.個人的イチオシですが,電脳コイルが配信されています.良いアニメだよほんとに.
昔のアニメも揃っているようです.アルプスの少女ハイジ,パーマン,おそ松くん(おそ松さんじゃないですよ),他にも新世紀エヴァンゲリオンも配信中です.
劇場版も配信作がそろっています.図書館戦争,あの花,花咲くいろは,雲のむこう、約束の場所,などなど.たまこラブストーリーは配信されていませんでした……残念!
他にも,ショートアニメもラインナップがそろっています.ゆるめいつ全シリーズや,あいまいみー(残念ながら1期のみ)が配信中.

独自のサービス

面白い配信サービスも展開されています.
例えば,アニソン配信です.なんとフルサイズの楽曲にムービーがついて配信されているのです.例えばGod knows,ガーネット,紅蓮の弓矢,などなど,全124曲のラインナップになっています.

また,dアニメストアはリクエストが可能です.観たいけど配信されていない作品は,是非リクエストを入れましょう.毎月のように新規作品が配信されているので,いつか配信開始されるかもしれません(一方で,しばしば配信終了もされています.また,復活することもよくあります).

他のサービスと比較して

大手アニメ配信サイトであるバンダイチャンネルに,バンダイチャンネルのおすすめポイントがまとめられていました.ここ.この表を見ながら確認していきましょう.

  1. 作品数自体はdアニメストアのほうが少ないですが,見放題作品数はおよそ1.5倍もあります.
  2. ガンダムシリーズは一部有料配信なんですよね…….こればかりはバンダイチャンネルに劣ります.仕方ない.
  3. 最新作の追加はリアルタイムで通知が来ます.しかも最新作の追加更新は毎日12時に行われています.
  4. 特撮は扱っていなかったはずです.まあ”アニメ”ストアなので……
  5. 自動連続再生に対応しています.
  6. 途中で再生を停止した場合,次回再生時には続きから再生します.この情報はアカウントごとに保存されているため,再生するデバイスを変えても再生位置は変わりません.
  7. PC版の場合,シークバーにサムネイル表示されていました.
  8. 視聴履歴はもちろん,気になるリストや,マイリスト機能が用意されています.
  9. アニメごとに口コミが見られるわけではありませんが,1シーズンに1回,おすすめアニメ投票が行われています.
  10. ファンがオススメアニメを公開はできません.その代わり,ユーザーへのおすすめアニメが公式から紹介されます.他にも,ジャンル別のアニメ特集が組まれています.
  11. 全話視聴したら”Complete”って書かれます……,別にエンブレムとかはいらないと思う.
  12. 決済手段はクレジットのみです.
  13. 対応デバイスはWin,Mac,Android,iOSです.しかし,GoogleChrome(Chromium)ブラウザを使えばLinuxからも視聴ができました!(これが言いたいがためにブログ更新したと言っても過言ではない)
  14. レベルなんて概念はありません.
  15. 動画の画質は3〜4種類用意されており,再生時に選択可能です(Edge,Chromeを除く).
  16. 会員限定のプレゼント企画が毎月開催されています.
  17. 月額料金の支払いごとにdポイントが貯まるようです.
  18. 特典……そんなのあったっけ.
  19. 過去ライブの配信はされているようです.
  20. iOSとAndroidは専用アプリがあります.使い勝手は問題ないと思っています.

結論

dアニメストアはいいぞ.最新作を一番乗りで観たい! という人にはあまりオススメできませんが,過去作品をゆっくり観たいという人にはとてもオススメです.

ちなみに,僕は基本的にdアニメストアでアニメを観て,配信されていない作品はAmazonビデオ(AmazonStudentなので年額1900円)で観ています.それでも配信されていない作品などはDMM月額レンタルで借りることにしています.割れ,ダメ,絶対!

それではみなさん,dアニメストアで楽しいアニメライフを!

セキュリティ・キャンプ2016に応募した

応募した

セキュリティキャンプに応募しました.
年齢制限があるので今年で最後です.
悔いのないように頑張って原稿を書き上げました.
さらに悔いの残らないようにブログに掲載しておきます.
合否結果は6月中旬までお待ちください.
※2016年6月14日追記 残念ながら参加見送りとなりました
※2016年6月16日追記 欠員補充により参加できることになりました

共通問題1

この設問は省略します.

あなたが今まで作ってきたものにはどのようなものがありますか? いくつでもいいので、ありったけ自慢してください。

reminder,思い継ぎ語り,タニタンv1.0・v1.1,迷路自動取得ソフト,マイクロマウスタイマー,タニタンv2.0H,STM32 writer,デレステ自動演奏機,について超簡単にまとめました.

それをどのように作りましたか?ソフトウェアの場合にはどんな言語で作ったのか、どんなライブラリを使ったのかなども教えてください。

それぞれ数文でまとめました.

開発記のブログなどあれば、それも教えてください。コンテストなどに出品したことがあれば、それも教えてください。

省略します.

共通問題2

あなたが経験した中で印象に残っている技術的な壁はなんでしょうか?(例えば、C言語プログラムを複数ファイルに分割する方法)

近年で一番印象的だった壁はマングリングです.
組み込みで,初めてC++での開発をしようとしたときの話です.割り込みに関する部分のプログラムを追加したところ,定義しているはずの関数が見つからないというリンカエラーが発生しました.プログラムの見直しや構造の見直しなどいろいろと試してみたのですが,2週間ほど何もわからずに苦しんでいました.開発はC++ですが,自動生成されるファイルは一部がC言語やアセンブリで書かれていたため,これらのファイルの間でマズいことが起きているのではないかと考えましたが,具体的に何が悪いのかわかりませんでした.また,所属していたサークルにC++で開発をしている人がおらず,身近に解決手段を聞ける相手がいませんでした.

また、その壁を乗り越えるために取った解決法を具体的に教えてください。(例えば、知人に勧められた「○○」という書籍を読んだ)

マングリングに悩まされていた問題ですが,たまたま大学に来られていたサークルOBの人にプログラムを見てもらい,マングリングではないかとアドバイスを受けました.ひとまず対処法を検索し,C++はコンパイルの際にシンボル名が変わることが原因であるため,シンボル名が変わらないように対策すれば良いことがわかりました.
原因はわかりましたが,実際にどのようなことが起こっているか確認したかったので,簡単なプログラムを作成して実験してみました.作成したのは次のコードです.

1
2
3
4
5
6
int test_func(){
return 0;
}
int main(){
return test_func();
}

これをmainc.c,maincpp.cppの2つのファイルに分けて保存し,gccとrx-elf-gcc(Renesas RXシリーズマイコン用のコンパイラ)の2種類でコンパイルし,その中身を解析してみました.実行したコマンドは次の通りです.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
$ gcc mainc.c -o gccmainc.o
$ g++ maincpp.cpp -o gccmaincpp.o
$ rx-elf-gcc mainc.c -o rxmainc.o
$ rx-elf-g++ maincpp.cpp -o rxmaincpp.o

$ objdump -x gccmainc.o
(中略)
SYMBOL TABLE:
(中略)
0000000000000000 g F .text 000000000000000b test_func
(後略)

$ objdump -x gccmaincpp.o
(中略)
SYMBOL TABLE:
(中略)
0000000000000000 g F .text 000000000000000b _Z9test_funcv
(後略)

$ rx-elf-objdump -x rxmainc.o
(中略)
SYMBOL TABLE:
(中略)
00000000 g F P 0000000f _test_func
(後略)

$ rx-elf-objdump -x rxmaincpp.o
(中略)
SYMBOL TABLE:
(中略)
00000000 g F P 0000000f __Z9test_funcv
(後略)

これらの実行結果から,C++で実装された関数のシンボルがマングルされていることを確認しました.また,コンパイラによって関数の頭に”_”がついたりつかなかったりするということも確認しました.
ここで,先ほど調べた解決法を試してみました.次のコードをmaindemangle.cppとして保存し,コンパイルした後に解析してみました.

1
2
3
4
5
6
7
8
9
extern "C" {
int test_func(){
return 0;
}
}

int main(){
return test_func();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ g++ maindemangle.cpp -o gccmaindemangle.o
$ rx-elf-g++ maindemangle.cpp -o gccmaindemangle.o

$ objdump -x maindemangle.o
(中略)
SYMBOL TABLE:
(中略)
00000000004004a6 g F .text 000000000000000b test_func
(後略)

$ rx-elf-objdump -x maindemangle.o
(中略)
SYMBOL TABLE:
(中略)
fff40168 g F .text 0000000f _test_func
(後略)

無事にシンボルをCと同じ名前にすることができました.
これらを踏まえてプログラムを修正したところ,無事にリンカエラーが解消しました.

その壁を今経験しているであろう初心者にアドバイスをするとしたら、あなたはどんなアドバイスをしますか?

マングリングによるエラーに悩んでいる人がいるとしたら,まずは自分のブログなどを紹介し,解決法を教えます.解決した後に,objdumpという便利なツールがあるということを教え,自分のプログラムを解析させます.
いきなり解決法を提示するというのには理由があります.私は今ソフトウェアだけでなく「ものづくり」をしていますが,やはり物が動かなくてはモチベーションも続きません.そのため,はじめはできるだけ解決を優先し,モチベーションを高めてあげることが重要だと考えています.
しかし,解決法の提示だけではあくまで一つの対処法を学んだだけに過ぎません.今後のことを考えると,解決へ至るプロセスや,調査方法などにも触れさせるべきだと思います.次に似たような問題に直面したときに,自力で解決できるようにすべきだからです.
今回の例では,objdumpでシンボルを確認することで,マングリングを目で見ることができます.それだけでなく,シンボル以外にも様々な情報を得ることができることに気づくことができます.何気なく動かしていた自分のプログラムが,実は様々なライブラリやソフトウェアなどによって支えられていて初めて動いていることを知ることは,コンピュータに強い興味を抱かせる理由の一つとなりました.初心者には,プログラムの内部を見てみることで新しい興味を抱き,単にトラブルの解決法を知るだけでなく,より多くの知識を広げていってほしいと考えています.

共通問題3

あなたが今年のセキュリティ・キャンプで受講したいと思っている講義は何ですか?(複数可)そこで、どのようなことを学びたいですか?なぜそれを学びたいのですか?

すべての講義を受けたいのですが,そういうわけにもいかないので,2つだけピックアップして述べます.

  1. 6-C 車載LAN上を流れるメッセージの解析
    昨年,驚くべき脆弱性情報を目にしました.CVE-2015-5611,クライスラー社の車がインターネットを通じて遠隔操作され,ブレーキやハンドル操作まで乗っ取られるという脆弱性です.これまではインターネットとは程遠い存在だった車が,近距離ネットワークを構築したり,インターネットに接続したりするように開発が進められています.制御も複雑化しており,複数のECUと複数のセンサなどが通信しあって動作しています.このような技術の進歩は喜ぶべきことですが,同時に強い恐れを抱いています.なぜなら,人の命を預かる車が乗っ取られたときの被害が,あまりに甚大であるからです.自動車は,これまではセキュリティと無縁だと思っていましたが,これからのセキュリティ問題に大きく関わってくるキーワードであると思っています.そこで,車に関わるこの講義に興味を惹かれました.
    今回の講義はCANの通信解析ということですが,CANにもセキュリティ上の問題が指摘されています.盗聴はもちろん,なりすましや不正メッセージの送信なども行えるということを知りました.CANにはエンジンやブレーキなどを制御するECUも接続されているため,攻撃を受けると致命的な問題が発生します.私はこれまで,動作の確認という意味でSPIバス通信の解析をしたことはありますが,攻撃やその防御策を考える意図で解析をしたことはありません.バスに対する攻撃と防御を学ぶ第一歩としてこの講義を受講したいです.
    攻撃されたときの深刻性は,自動車はもちろん大きなものでありますが,他の機械でも大きな問題となる可能性があります.私はこの講義を受講して攻撃者や防御者という立場での解析法を学び,将来技術者となったときに万全のセキュリティ対策を施せるようになりたいです.

  2. 3-A Webアプリケーションの脆弱性の評価と発見
    この講義を受けたいと思った理由は2つあります.
    まず1つ目ですが,より幅広い分野の技術者がWebアプリケーションのセキュリティについて学ぶ必要があると考えているからです.近年流行しているIoTにより,あらゆるデバイスがインターネットに接続するようになってきました.このため,多くのサーバやWebアプリケーションを用意する必要があります.サーバやWebアプリケーションが増えるということは,それだけ攻撃の対象が増えることを意味します.したがって,ソフトウェアのみならず,ハードウェアを扱う技術者にとっても,Webアプリケーションに関するセキュリティ知識が必須であると考えます.
    次に2つ目の理由ですが,脆弱性やその対策法について,より実践的な経験を得たいと思っているからです.私は自宅にサーバを設置していくつかのサービスを運用しています.運営する上で,書籍を読みセキュリティ対策について勉強をしてきたつもりです.基本的な知識や,代表的な攻撃の手法,その対策法など,これまで知らなかったことを学ぶことができました.しかし,新たな脆弱性を発見するためには何をすべきかわかっていません.この講義を受講して,脆弱性の検出プロセスや,そもそも脆弱性が発生する根本的な原因を学びたいと考えています.

Webアプリケーションのセキュリティはどのような分野においても必要不可欠だと思います.私は将来どんな職種になるかわかりませんがここで得た知識は必ず役に立ちますし,仕事を通して社会利益に貢献したいです.また将来の仕事以外でも,趣味での開発やブログ等での情報発信は今後も引き続き行っていくつもりです.ここで得た知識を元に,よい技術者としての発信を続けていきたいと思っています.以上の理由から,私はこの講義を受講したいです.

あなたがセキュリティ・キャンプでやりたいことは何ですか?身につけたいものは何ですか?(複数可)自由に答えてください。

このセキュリティキャンプでやりたいことは,主に2つあります.

  1. セキュリティに対する意欲を,今後も伸ばしていきたいと思っています.そのため,セキュリティへの意欲が高い学生の方々や専門の講師の方々と知り合い,技術的な交流をしたいです.
    私は大学入学前からコンピュータネットワークに強い興味があり,入学時には応用情報技術者試験に合格しました.しかし,大学には情報・セキュリティに関する活動を行っているクラブ・サークルがなかったため,ロボット製作をメイン活動としているサークルに入部しました.このサークルに入部したことは自分にとってプラスとなりました.サークルOBには全国トップクラスの技術力を持っている方々がいらっしゃり,現在も著名企業でご活躍されています.こういった方々と知り合い,頻繁にお話を聞くことができるようになったため,ハードウェアについての知識を多く得ることができました.これまではソフトウェア一本でしたが,ハードウェアや組み込み系に強い人々と交流することがいい刺激となり,ハードについても強い興味が出てきました.
    一方で,私はネットワークやセキュリティについて話し合える知り合いがほしいと常々思っています.近年ではIoTといったワードをよく聞きますが,ハードウェアとネットワークはもはや切り離せない関係にあり,同時にセキュリティは必要不可欠です.私は,今はハードをメインに活動していますが,元々はネットワークに興味があり勉強をしてきました.いずれの領域においてもセキュリティは共通して重要な要素です.したがって,ハード面のみならずソフト面でも強い意欲を伸ばしていくために,このキャンプに参加し,ソフトウェアやセキュリティに強い関心がある人たちと知り合い,互いに刺激し合えるような関係を作りたいと思っています.

  2. セキュリティについて,適切な指導を受けて力を伸ばしたいです.
    私はこれまでずっと,独学で勉強をしてきました.残念ながらソフトウェアやセキュリティに強い知り合いがおらず,本やインターネットで調べて得た知識を吸収してきただけです.自力で勉強することは大切なことですが,これだけではだめだとも思っています.独学では,手を動かして課題に取り組んだ際にフィードバックを得ることができません.また,最新のセキュリティについても,書籍ではなかなか得ることができません.セキュリティの分野で活躍されているプロの方々からの指導を受けることで,このような知見を得たいと考えています.同時に,セキュリティ問題に取り組む姿勢や考え方なども吸収したいです.

選択問題1

ローカル変数はスタック領域に,mallocを使った動的なメモリ確保はヒープ領域にメモリが確保されることは予め知っていましたが,今回のプログラムにはなんの違和感も感じませんでした.そこで,まずは与えられたプログラムを手元の環境で実行してみました.
ただし今回の実行環境は次の通りであり,以降の問題でも特筆していなければこの環境で動作させています.

1
2
3
4
$ uname -a
Linux arch_thinkpad 4.5.1-1-ARCH #1 SMP PREEMPT Thu Apr 14 19:19:32 CEST 2016 x86_64 GNU/Linux
$ gcc --version
gcc (GCC) 5.3.0

実行結果は次の通りです.

1
2
3
$ ./1-1
hoge address = 0x7ffe049bf300
fuga address = 0x1038010

fuga addressが明らかに違うことが判明しました.そこで,mallocの動作を調べることにしました.
manでmallocについての情報を見ると,mallocは内部でsbrkを用いてヒープからメモリを割り当てていることがわかりました.また同時に,MMAP_THRESHOLDバイトより大きな領域を確保する場合,glibcのmallocは代わりにmmapを用いることがわかりました.sbrkとmmapでどの領域からメモリを確保しているのか,実際に試してみました.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(){
int fp = open("/dev/zero", O_RDONLY);
void* p1;
void* p2;
if((p1 = mmap(NULL, 1, PROT_WRITE, MAP_PRIVATE, fp, 0)) == MAP_FAILED) printf("ERROR\n");
p2 = sbrk(1);
printf("mmap: %p\n", p1);
printf("sbrk: %p\n", p2);
return 0;
}

このプログラムは,p1にmmapでメモリを割り当て,p2にsbrkでメモリを割り当て,それぞれのアドレスを表示するプログラムです.
実行結果は次の通りです.

1
2
3
$ ./1-3
mmap: 0x7f39b4c2c000
sbrk: 0x157f000

この結果から,sbrkとmmapでは確保されるメモリ領域が異なることが判明しました.手元で課題のコードを動作させたときのfuga addressが,このプログラムのsbrkで確保したアドレスに似通っているため,実は内部でsbrkが呼ばれていたのではないかと考えました.
mallocのmanページをもう少し読むと,malloptを使ってMMAP_THRESHOLDが変更可能であると書かれていました.そこで,課題のコードを少し書き換え,MMAP_THRESHOLDを0,つまり常にmmapを使うようにコードを変更してみました.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
int main(int argc, char **argv){
char c;
int hoge[10];
int *fuga;
mallopt( M_MMAP_THRESHOLD, 0 );
fuga = malloc(1);
printf("hoge address = %p\n", hoge);
printf("fuga address = %p\n", fuga);
free(fuga);
return 0;
}

このコードの実行結果は次の通りです.

1
2
3
$ ./1-4
hoge address = 0x7ffd8c819780
fuga address = 0x7fde0b040010

課題文中の実行結果と似た出力となりました.また,今回コード中で指定したMMAP_THRESHOLDを,環境変数で指定できることがわかったので,実行してみました.出力結果は省略しますが,次のコマンドを順に実行すると,先ほどと同様の出力が得られました.なおプログラム実行後に環境変数は通常の値に戻しておきました.

1
2
3
$ export MALLOC_MMAP_THRESHOLD_=0
$ ./1-1
$ export MALLOC_MMAP_THRESHOLD_=131072

これらの結果から,課題文中の実行結果は,何らかの理由で環境変数MALLOC_MMAP_THRESHOLD_が0になっている環境で実行されたのではないかと考えます.この環境では,割当を解除したメモリ空間を将来的な割当に再利用できなくなるため,不効率である可能性があります.

選択問題4

次のコードをC言語で作成しました.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

struct packet{
char Magic [2];
char Source[20];
char Destination[20];
uint32_t DataLength;
char* Data;
} __attribute__((packed));

int strcmp_upper(const char* s1, const char* s2){
int i=0;
while(toupper(s1[i]) == toupper(s2[i])){
if(s1[i++] == '\0') return 0;
}
return 1;
}

int chk1(struct packet* p){
if(strncmp(p->Magic, "RH", 2) == 0) return 1;
else return 0;
}

int chk2(struct packet* p){
if(!strcmp_upper(p->Source, "rise-san")) return 1;
if(!strcmp_upper(p->Source, "cocoa-san")) return 1;
return 0;
}

int chk3(struct packet* p){
if(!strcmp_upper(p->Destination, "Chino-chan")) return 1;
if(!strcmp_upper(p->Destination, "Chino")) return 1;
return 0;
}

int chk4(struct packet* p){
if((!strcmp(p->Source, "cocoa-san"))&&(!strcmp(p->Destination, "Chino"))) return 0;
return 1;
}

int chk5(struct packet* p){
if(strstr(p->Data, "BlueMountain") != NULL) return 1;
if(strstr(p->Data, "Columbia") != NULL) return 1;
if(strstr(p->Data, "OriginalBlend") != NULL) return 1;
return 0;
}

int chk6(struct packet* p){
if(strstr(p->Data, "DandySoda") != NULL) return 0;
if(strstr(p->Data, "FrozenEvergreen") != NULL) return 0;
return 1;
}

uint32_t convEndian(uint32_t t){
uint32_t ret = 0;
ret = (t<<24)&0xFF000000;
ret |= (t<<8)&0x00FF0000;
ret |= (t>>8)&0x0000FF00;
ret |= (t>>24)&0x000000FF;
return ret;
}

int readPacket(FILE* fp, struct packet* p){
if(fread(p, 1, 46, fp) != 46) return 0;
p->DataLength = convEndian(p->DataLength);
if(p->Data != NULL){
free(p->Data);
p->Data = NULL;
}
p->Data = malloc((size_t)(p->DataLength)+1);
memset(p->Data, 0, p->DataLength+1);
if(fread(p->Data, 1, p->DataLength, fp) != p->DataLength) return 0;
return 1;
}

int main(){
struct packet* p = malloc(sizeof(struct packet));
memset(p, 0, 50);
p->Data = NULL;
FILE* fp = fopen("pyonpyon.rh", "r");
while(readPacket(fp, p)){
if(chk1(p)&&chk2(p)&&chk3(p)&&chk4(p)&&chk5(p)&&chk6(p))
printf("PASS\n");
else
printf("REJECTED\n");
}
if(p->Data != NULL){
free(p->Data);
p->Data = NULL;
}
free(p);
fclose(fp);
return 0;
}

実行結果は次の通りとなりました.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
$ ./4-1c
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
REJECTED
PASS
PASS
PASS
REJECTED
REJECTED
PASS
PASS
PASS
REJECTED
REJECTED
REJECTED
PASS
PASS
PASS
REJECTED
REJECTED
REJECTED
REJECTED
PASS
PASS
PASS
REJECTED
REJECTED
REJECTED
REJECTED
REJECTED
PASS
PASS
PASS
REJECTED
REJECTED
REJECTED
REJECTED
REJECTED
REJECTED

念の為バイナリを確認してみましたが,正しく動作しているようでした.

続いて,このプログラムが使用したメモリ使用量と動作時間(CPUサイクル)を測定しました.まずメモリ使用量ですが,/usr/bin/timeを用いて計測し,次のような結果となりました.

1
2
3
$ /usr/bin/time -f "%M KB" ./4-1c
(./4-1c実行結果は省略)
1350 KB

また動作時間については,rdtscp命令を利用して,消費したCPUサイクル数を計測することにしました.
提出したコードに次のようなコードを追加し,動作時間(CPUサイクル数)を測定しました.

unsigned long long rdtsc() {
  unsigned long long ret;
  __asm__ volatile ("rdtscp" : "=A" (ret));
  return ret;
}

int main(){
  struct packet* p;

  unsigned long long st, et;
  st = rdtsc();

  p = malloc(sizeof(struct packet));
  (中略)
  fclose(fp);

  et = rdtsc();
  printf("%lld, %lld, %lld\n", st, et, et-st);

  return 0;
}
1
このプログラムを実行すると,次の出力が得られました.
$ 4-1c-calc (実行結果は省略) 3752867116, 3753241296, 374180
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
したがって,今回のプログラムのサイクル数が374180サイクルという実行結果を得られました.

# 選択問題5
はじめにJIS規格におけるOSの定義を示しておきます.
「プログラムの実行を制御するソフトウェアであって,資源割り振り,スケジューリング,入出力制御,データ管理などのサービスを提供するもの」
これを踏まえたうえで,組み込み開発での体験を元にした,自分なりの考えをまとめます.

私は,組み込みを始めるまではWindows向けのアプリケーションなどを作成していました.その時は,プログラムは慣れさえあれば簡単なものだと勘違いしていました.用意された関数を呼べば線を描画でき,画像も表示できます.関数を呼べばシリアルからデータを送信でき,時間待ちも簡単にできます.そんなに高度なことはしていませんでしたが,ハードについて全然知識を持ち合わせていなくても,このようなプログラムを書くことができていました.
大学に入り,組込み開発をするようになってから,この認識が大きく変わりました.普段の組込み開発ではOSは使用せず,いわゆるベアメタルでの開発をしています.プログラムは唯一のものしか無く,入出力制御は直接レジスタを操作し,データ管理のシステムは自分で整備します.私個人は,このようなプログラムを作ることは楽しいと感じています.直接レジスタを操作し,直接マイコンを操作しているように思うからです.同時に,これまでのプログラミングに関しての知識は,まったくの不十分であることも実感しました.例えば,C言語でLinux向けのアプリケーションを書く時のことを考えます.1秒待ちたい場合は,"sleep(1);"と書くだけで時間を待つことができます.一方,組み込みで1秒の時間待ちをしたい場合,自分で専用の関数を作る必要があります(もちろん標準で用意されている場合もありますが).このときには,マイコン周辺回路の一つであるタイマを利用する必要があります.タイマのレジスタを設定し,割り込み周期を設定し,種々の設定を行い,タイマをスタートさせる.これだけの長い処理を書くことで初めて時間待ちができるようになります.当然,設定するためには相応のハードウェアの知識が必要となります.
先ほどの例で,Linuxアプリケーションでは"sleep(1);"だけで良いと書きました.これはC標準ライブラリに用意されているから使えるわけですが,その根本にはOSが関わっています.ハードウェアを強く意識させること無く,シグナルという概念を使ってプログラムを作ることができるようになっています.OSの機能の,一番大きな役割ではないかと考えます.

つまり,OSとは
「低レベルの操作を統括し抽象化することにより,ユーザーには低レベル操作を意識させることなくプログラムの開発を進められるようにする仕組み」
であると考えます.

# 選択問題8
問題文を見た時,とても不思議なコードだと感じました.objdumpは何度も使ったことがありますが,これほどpushqが連続した逆アセンブル結果を見たことがなかったからです.
いくつか気になるところがあったので,次の点に注意しながらプログラムを解析していくことにしました.
1. 0x4000a2で64bit長のデータをスタックに格納している.何か重要なデータかもしれない.
2. 0x400110で,このプログラム中唯一比較演算をしている.
3. 0x400129に,このプログラム中唯一の分岐命令がある.

複雑な動作をしているため,問題文と同じプログラムを作成して検証してみることにしました.8-5.sというファイルにアセンブリコードを保存しています.ただし,0x400129のjne命令でのジャンプ先アドレスを問題文と同じようにできませんでした.そのためジャンプ先アドレスを変更しています.
$ as -march=corei7 8-5.s -o 8-5.o $ ld 8-5.o -o 8-5_run $ objdump -d 8-5_run 8-5_run: ファイル形式 elf64-x86-64 セクション .text の逆アセンブル: 0000000000400078 <_start>: 400078: 90 nop 400079: 90 nop 40007a: 90 nop 40007b: 90 nop 40007c: 90 nop 40007d: 90 nop 40007e: eb 00 jmp 400080 <main> 0000000000400080 <main>: 400080: 68 19 01 40 00 pushq $0x400119 400085: 6a 01 pushq $0x1 400087: 68 06 01 40 00 pushq $0x400106 (中略) 400126: 48 ff c9 dec %rcx 400129: 0f 85 01 00 00 00 jne 400130 <main+0xb0> 40012f: c3 retq 400130: 41 5a pop %r10 400132: c3 retq
1
このプログラムをgdbを使って実行しました.
$ gdb 8-5_run -q Reading symbols from 8-5_run...done. (gdb) run Starting program: /home/nonoho/ownCloud/Event/SecurityCamp2016/8-5_run 12345678 [Inferior 1 (process 8199) exited with code 01]
1
2
3
おそらくsyscallで標準入力を読んでいると予想されるので,"12345678"を入力しました.ステータスが1で終了しているので,何か問題があったのではないかと考えられます.

続いて,ステップ実行をしてどのようにプログラムが進んでいるのかを確かめてみます.
$ gdb 8-5_run -q Reading symbols from 8-5_run...done. (gdb) start Temporary breakpoint 1 at 0x400080: file 8-5.s, line 13. Starting program: /home/nonoho/ownCloud/Event/SecurityCamp2016/8-5_run Temporary breakpoint 1, main () at 8-5.s:13 13 push $0x400119 (gdb) set logging on main () at 8-5.s:14 14 push $0x1 (gdb) si (以降siを繰り返す) (gdb) si main () at 8-5.s:61 61 syscall (gdb) [Inferior 1 (process 8750) exited with code 01]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
出力されたgdb.txtファイルを見ながら,プログラムの流れを予想してみました.ただし,ここに掲載したログは見やすさのために,不要な行を飛ばしています.

1. はじめはスタックにデータを格納しているだけです.ただし注意すべきことがあります.今回の場合,スタックに格納されるのは8バイト単位です.したがって,pushqを実行するたびにスタックポインタ(%rsp)は8ずつ小さい値を指すようになります.
13 push $0x400119
14 push $0x1
15 push $0x400106
(中略)
41 push $0x400106
42 push $0x0
43 push $0x400102
2. 次に,0x400101に到達したときの動作を考えます.ret命令が実行された時,スタック最上位に格納されているアドレスにジャンプし,スタックポインタを8バイト増やします.したがって,今回はスタック最上位の0x400102にジャンプすることになります.
44 ret
3. 続いてレジスタにデータを格納し,システムコールを呼び出しています.この時,システムコール番号を%raxに,引数を順に%rdi,%rsi,%rdx,%r10に格納します.では,今回はどのシステムコールが呼び出されたかを確認します.

main () at 8-5.s:61
61 syscall
(gdb) i r
rax 0x0 0
rbx 0x0 0
rcx 0x0 0
rdx 0x8 8
rsi 0x7fffffffdfd8 140737488347096
rdi 0x0 0
rbp 0x0 0x0
rsp 0x7fffffffdff8 0x7fffffffdff8
r8 0x0 0
r9 0x0 0
r10 0x0 0
r11 0x0 0
r12 0x0 0
r13 0x0 0
r14 0x0 0
r15 0x0 0
rip 0x400119 0x400119 <main+153>
eflags 0x202 [ IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0

%raxに0が入っているため,予想通りreadが呼ばれています.readの引数は,ssize_t read(int fd, void *buf, size_t count);となっています.したがって,ファイルディスクリプタは0(stdin),格納先の先頭アドレスは0x7fffffffdfd8,読み出すバイト数は8バイトであることがわかります.
4. 続いて,次の命令が実行されました.
62 ret
51 pop %rbp
52 ret
53 pop %rcx
54 ret
このときの%rcxの値は7になっていることを確認しました.
5. この後,次の命令が8回実行されていました.
59 xorb $0x55,(%rsi,%rcx,1)
60 ret
68 dec %rcx
69 jne 0x400130
71 pop %r10
72 ret
55 add %rbp,%rsp
56 ret
%rcxをデクリメントし,0になるまで繰り返しているようです.また,1回ループするごとにxor演算をしています.この動作をメモリダンプして確認しました.
確認時には次の命令を実行しました.
(gdb) x/128 (0x7fffffffe0a0-(128*4))
ただし,文字数と見やすさの都合で,ここには該当箇所のみ記載します.

1) xor実行前
0x7fffffffdfc0: 0x0040011c 0x00000000 0x35343332 0x0a383736
2) xor1回実行後
0x7fffffffdfc0: 0x0040011c 0x00000000 0x35343332 0x5f383736
3) xor2回実行後
0x7fffffffdfc0: 0x0040011c 0x00000000 0x35343332 0x5f6d3736
4) xor8回実行後
0x7fffffffdfc0: 0x0040011c 0x00000000 0x60616667 0x5f6d6263

この結果から,先程のシステムコールで入力した値の,すべてのバイトを,0x55との排他的論理和をとっていることがわかりました.
6. 最後に,次の命令が実行されてプログラムが終了していました.
49 pop %rdi
50 ret
45 pop %rax
46 ret
57 cmp %rax,(%rsi)
58 ret
45 pop %rax
46 ret
69 jne 0x400130
71 pop %r10
72 ret
49 pop %rdi
50 ret
61 syscall
cmp命令実行前の,レジスタの値とメモリダンプを確認しました.

(gdb) i r
rax 0x63391a67251b1536 7149774913733858614
rbx 0x0 0
rcx 0x0 0
rdx 0x8 8
rsi 0x7fffffffdfc8 140737488347080
rdi 0x0 0
rbp 0xffffffffffffffe0 0xffffffffffffffe0
rsp 0x7fffffffe058 0x7fffffffe058
r8 0x0 0
r9 0x0 0
r10 0x400102 4194562
r11 0x302 770
r12 0x0 0
r13 0x0 0
r14 0x0 0
r15 0x0 0
rip 0x400110 0x400110 <main+144>
eflags 0x202 [ IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0

%raxの値と,%rsiの指すメモリ内容を比較しています.この時,%rsiの指すアドレスには次の値が入っていることが,先ほどのダンプ結果からわかっています.
0x7fffffffdfc8: 0x60616667 0x5f6d6263
この値は,プログラム実行時に入力した値を,0x5555555555555555でxor演算した値と等価です.今回は,入力した"12345678"と予めセットされている値が一致しなかったため,ステータスコード1で終了しました.そこで,2つの値が一致するような入力値を求めると,"c@Np2Ol6"であることがわかりました.

ここまでを踏まえて,もう一度プログラムを動作させてみます.
$ gdb ./8-5_run -q Reading symbols from ./8-5_run...done. (gdb) run Starting program: /home/nonoho/ownCloud/Event/SecurityCamp2016/8-5_run 12345678 [Inferior 1 (process 13998) exited with code 01] $ gdb ./8-5_run -q Reading symbols from ./8-5_run...done. (gdb) run Starting program: /home/nonoho/ownCloud/Event/SecurityCamp2016/8-5_run c@Np2Ol6 [Inferior 1 (process 14003) exited normally] ``` "c@Np2Ol6"を入力すると,ステータスコードが0で終了しました. 以上の調査より,このプログラムは,パスワード"c@Np2Ol6"を認証するプログラムであると考えられます. このプログラムについての個人的な感想ですが,このプログラムは難読化のためにあえて読みづらいコードにしているのではないかと感じました.あわせて,認証するパスワードもxor演算を施しておくことで,解析しづらくしているのではないかと思います.

Apacheでletsencryptを使う

Let’s Encryptとは

Let’s Encryptは無料で使えるSSL認証局です.
Let’s Encryptで証明書を取得し,Apacheで動作させるまでの方法を書き残しておきます.

動作環境は,

  • Ubuntu 12.04
  • Apache 2.4.12

証明書の取得

クライアントの導入

githubからクライアントを持ってきて,依存関係の確認などを行います.
3行目でヘルプを確認していますが,このときに依存関係の確認・更新などを行うようです.

1
2
3
git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt
sudo ./letsencrypt-auto --help

証明書の取得

今回,証明書はサブドメインごとに取得します.
なお,80番ポートを使うので動作中のApacheは停止しておきます.

1
2
3
sudo service apache2 stop
./letsencrypt-auto certonly --standalone -d www.taniho.net
./letsencrypt-auto certonly --standalone -d blog.taniho.net

初回はメールアドレスなどを入力させるダイアログが出てくるので,いい感じに入力していきます.

IMPORTANT NOTES:

  • Congratulations! Your certificate and chain have been saved at
    /etc/letsencrypt/live/(ドメイン)/fullchain.pem. Your
    cert will expire on (有効期限). To obtain a new version of the
    certificate in the future, simply run Let’s Encrypt again.

この画面が出れば取得完了です.
見れば解ると思いますが,Let’s Encryptで取得した証明書は有効期限が90日しかありません.
証明書の更新は次のコマンドを打つことで行えます.
また,更新後にApacheを再起動する必要があります.

1
letsencrypt-auto renew --force-renew

今回取得した証明書は,/etc/letsencrypt/live/(ドメイン)/の中に入っています.

Apacheの設定

とりあえず

Apache2.4.8以降では,それ以前と設定の仕方が変わっているので気をつけてください.
とりあえず,https://blog.taniho.net/にアクセスできるように設定してみます.

1
2
3
4
5
6
7
8
9
10
11
<VirtualHost *:443> 
ServerName www.hoge.net
DocumentRoot /var/www/html

ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined

SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/blog.taniho.net/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/blog.taniho.net/privkey.pem
</VirtualHost>
1
sudo service apache2 restart

設定を有効化する

/etc/apache2/site-availableにsite設定を書いたら,次のコマンドで有効化,無効化することができます.

1
2
a2ensite (設定ファイル名)
a2dissite (設定ファイル名)

同様に,Apacheのモジュールを有効化・無効化させる場合は次のコマンドを使います.

1
2
a2enmod (モジュール名)
a2dismod (モジュール名)

今回はmod_sslを有効化する必要があるので,次のコマンドを叩いておきます.

1
a2enmod ssl

httpに来たアクセスをhttpsにリダイレクトさせる

必ずhttpsでアクセスさせたい場合や,その逆の場合もあると思います.
ひとまず,http://blog.taniho.net/にアクセスされた場合にhttpsに転送する設定をまとめておきます.
VirtualHost設定の中に次の内容を書きます.

1
2
3
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*) https://blog.taniho.net$1 [R,L]

参考

CentOS 7 + Apache 2.4 で Let’s Encrypt の証明書を導入する手順
Let’s Encrypt サーバー証明書の取得と自動更新設定メモ
apacheでhttpへのアクセスをhttpsへ自動リダイレクトする

e2studioを用いてGCC(C++)で開発する

目的

ルネサスが提供しているRX用C++コンパイラはなかなかに使えないので,お手軽にC++11を使える方法を考えます。
ルネサスが公式サポートしている,KPIT GNU Toolse2studioで使えるようにします。

環境を整える

KPIT GNU Toolsの入手

KPIT GNU Tools公式サイトでユーザー登録を行う必要があります。
パスワードの発行に少し時間がかかる可能性があるので,予め済ませておきましょう。

ログインして,使うマイコンのコンパイラ(今回の場合GNURX v12.xx Windows Tool Chain (ELF))をダウンロード,インストールします。
※4/26追記 バージョン違いだったようです。最新版をインストールしてください。

e2studioの入手

e2studioをダウンロード,インストールしておきます。
KPIT GNU Toolsがインストール済みであれば,初めての起動の際に何か聞かれるので,Toolchainを登録しておきましょう。

プロジェクトの作り方

e2studioの使い方は省略します。
基本的にはルネサス公式のコンパイラを使う場合と同じように,新規C++プロジェクトを作成します。
ただし,利用するツールチェインを”KPIT GNURX-ELF Toolchain”にします。
その他はいい感じに設定を進めていきます。

C++11を使えるようにする

このままではC++98のままなので,C++11を使えるように設定しておきます。

メニューバーの「プロジェクト」->「プロパティ」を開き,
「C/C++ビルド」->「設定」を選びます。
「ツール設定」の中の「Compiler」->「その他」の画面で,
ユーザー定義オプションに”-std=c++11”を追加しておきましょう。
これでC++11が使えるようになります。

余談ですが,KPIT GNU ToolsはまだC++14に対応していないようです。

動かしてみて

動いた

時間が無く十分な検証ができていませんが,次のコードが正しく動作しました。

1
2
3
4
5
6
7
8
9
#include "iodefine.h"
#include <array>
using namespace std;
int main(){
array<int, 1> a = {123};
if(a.at(0) == 123) (LED点灯);
while(true);
return 0;
}

わからん

ビルドは通るし,プログラムも動作しているようですが,なぜか”-std=c++11フラグをつけるのならrx-elf-g++を使えよ!”という警告が出ます。
確かにrx-elf-gccで動かしているので,そりゃそうだと思ってコマンドをrx-elf-g++に変更するとコンパイルができなくなりました。

また,コンパイルは通っているのにe2studioのシンタックスチェックでシンボルが見つからないよ! というエラー表示が出てしまいます。
とりあえず動いているので問題はなさそうですが,うーん……

※4/26追記 シンタックスチェックを無効化すればいいとの意見をいただきました。
参考に設定方法を掲載しておきます。
Window>設定>C>コード解析 「シンボルが解決されません」「メソッドが解決されません」のチェックを外す

C++/C++11を始めよう

本を読んでください
としか言わないのは悲しいので,Miceでも使ってもらえそうな(とっつきの良さそうな)C++の新機能をリストアップします。
毎度のごとく,自分で詳しく調べなおしてください。

C++03

変数の定義位置

C言語でははじめに変数宣言をする必要がありましたが,C++では好きなところで変数宣言ができます。
すごく便利なのが次のコード

1
for (int i=0; i<100; ++i) hoge();

namespace

名前空間が使えます。
別の名前空間に属していれば,名前の重複が起こりません。
モジュールごとに名前空間を分けるようにすれば,命名力不足に悩まされる心配もありません。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
namespace A{
int hoge = 0;
}
namespace B{
int hoge = 1;
}
int main(){
std::cout << hoge << endl; // hogeは存在しない
std::cout << A::hoge << endl; // 0
std::cout << B::hoge << endl; // 1
using namespace A;
std::cout << hoge << endl; // 0
}

vector

可変長配列です。
つまり配列の長さを自由に伸び縮みさせられる配列です。

1
2
3
4
5
6
7
8
#include <vector>
using namespace std;
int main(){
vector<int> hoge = {0, 1, 2};
hoge.at(1); //1
hoge.push_back(3);
hoge.at(3); //3
}

pair

これまでいちいち構造体で作っていたpairが標準で用意されるようになりました。

1
2
3
4
5
6
7
8
#include <utility>
using namespace std;
int main(){
pair<int, int> p1(10, 20);
p1.first + p1.second; // 30
pair<float, const char*> p2(1.3f, "abc");
return 0;
}

C++11

auto

自動型推論と呼ばれる機能です。
要するに型を”auto”としておけば自動でいい感じにしてくれます。

C流

1
2
3
4
5
6
7
8
9
#include <stdio.h>
void func(int t){
printf("Value: %d\n", t);
}
int main(){
void (*f)(int) = &func;
f(123);
return 0;
}

C++11流

1
2
3
4
5
6
7
8
9
10
#include <iostream>
using namespace std;
void func(int t){
cout << "Value: " << t << endl;
}
int main(){
auto f = &func;
f(123);
return 0;
}

array

より安全に使える配列です。
あわせて,下のサンプルではrange-based forという技も使っています。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <array>
using namespace std;
int main(){
array<int, 10> a = {};
for(auto ite = a.begin(); ite != a.end(); ++ite){
static int j = 0;
*ite = j++;
}
for(auto i: a){
cout << i << endl;
}
return 0;
}

enum class

C言語にも列挙型がありましたが,C++11で使い勝手が良くなりました。
列挙型のサイズを規定でき,スコープ演算子でアクセスするようになります。

1
2
3
4
5
6
7
8
9
10
11
12
13
using namespace std;
enum class N : unsigned char{
N1,
N2 = 100,
N3,
N4,
};
int main(){
N1; // 存在しない
N::N1; // 0
N::N4; // 102
return 0;
}

最後に

これだけでも十分便利そうなC++ですが,C++の底力はこんなもんじゃあないので,頑張って勉強していきたいところです。

gitとgithubの違い

違います

gitはバージョン管理をするソフトウェアの名前であり,githubは共有リポジトリのホスティングサービスです。

gitって?

バージョン管理をするためのソフトウェアのことです。
オープンソースで開発されており,無料で利用することができます。

バージョン管理

プログラムでもCADでも何でも良いですが,Windowsでは基本的に1つのファイルしか保存されず,
「あ゛あ゛あ゛あ゛あ゛あ゛間゛違゛え゛て゛上゛書゛き゛し゛た゛あ゛あ゛あ゛あ゛あ゛あ゛」
というやらかしをよく耳にします。
(シャドウコピーという機能はありますが,gitに比べれば屁みたいな機能です)

Windowsの保存機能をポケモンのセーブ機能とすると,
gitはノベルゲームのコメント付きセーブ機能みたいなものだと考えると,その凄さは分かってもらえると思います。

はじめは

なにはともあれgitをインストールしましょう。
Windowsの場合は こちら から,
Linuxの場合はお使いのパッケージ管理システムからインストールできます。

はじめのうちはコマンドを叩いてgitを使うことをオススメしますが,
便利なフロントエンドとして,Windowsの場合は TortoiseGit, Emacserの場合は Magit をオススメしておきます。
これらの使い方は省略するので,頑張って使いこなしてみてください。

コミットへの第一歩

gitの基本は実にシンプルです。

概要 コマンド
gitで管理するファイルを登録 git add
編集したファイルを”更新リスト”に追加 git add
“更新リスト”にコメントをつけて保存 git commit

これだけでローカル環境でのファイル管理は,とりあえずできます。
あわせて,共有リポジトリを使って複数人で開発を行う際は,次の表も頭に入れておく必要があります。

概要 コマンド
共有リポジトリ上の更新を確認 git pull
共有リポジトリに更新を反映 git push

更新が競合した場合の処理などは,ややこしいので今回は書きません。
「最新の(他の人の)更新を確認して,競合がなければアップロードする」
という手順で共有リポジトリを使います。

github

ではgithubが何かというと,今言ったばかりの「共有リポジトリ」を作らせてくれるサービスです。
さらにおまけとして,wikiやissue,pullrequestなどのサービスも提供されています。

普通に使う

github上に何らかのリポジトリが作成されているとします。
一番はじめは,何も考えずにリポジトリをコピーします。
(以下の説明はすべてgitのコマンドで示します。TortoiseGitなどを使っている場合は頑張って脳内補完してください)

1
git clone https://(自分のユーザー名)@github.com/(クローンしたいリポジトリのユーザー名)/(リポジトリ名).git

gitにこの共有リポジトリを登録しておきます。

1
git remote add origin master

あとはgit pullなりgit pushなりをすることでローカル環境とgithubを同期させることができます。

wiki

Wikiを作ることができます。
ソフトウェアのマニュアルや仕様書なんかを共有するのに使うと便利かと思います。

issue

バグ報告ができます。
分類わけのためのラベルを付けたり,マイルストーンを設定することもできます。
解決担当者を決めることもできるので,複数人で開発する際は便利ですね。

pull request

重要な更新などをした際,全員にpullしてもらえるように通知することができます。

というわけで

頑張ってgitを使いこなせるようになりましょう。

Emacser御用達gitクライアント

gitがようやく部内に広まりつつありますが,そのきっかけの一つはGUI操作のできるgitクライアントが紹介されたことでしょう。
僕もWindowsで使っている TortoiseGit は,エクスプローラに統合でき,かなり使い勝手のいいクライアントだと思います。
しかし,Linuxを常用しているのでなにかいいクライアントが無いものかと探していたら,Emacs向けのパッケージを見つけました。
(それまではコマンド直打ちをしていましたが,やはり面倒。gitの学習のためにはコマンドを自分で打つべきだとは思います。)

Magit

Magit
パッケージマネージャからインストールしてやりました。

起動

gitで管理しているファイルをEmacsで開き,

1
M-x magit-status

でMagitが起動します。

使い方は出てきたバッファ内で’?’を打つと表示されます。

すでにStaged, Unstaged, Untrackedなファイルがリストアップされてると思いますが,これらのファイルを操作するのは1キーの打鍵で済みます。
カーソルを合わせて’s’を押すとstage,’u’を押すとunstage,これだけです。

コミット

‘c’を押すとCommitのためのメニューが開きます。

もう一度’c’を押してコミット画面に遷移します。
下のバッファにコミットメッセージを書きます。
上のバッファにはgit-diffが表示されているのでコミットメッセージも書きやすくなっています。

あとは”C-c C-c”を押せばコミット完了です。

プッシュ

最後に’P’の打鍵でプッシュのメニューを開きます。
ここで登録されているremoteにプッシュするため,’p’を打鍵するとパスワードを求められます。

これにてプッシュ完了です。

利点

Magitの利点としては,次のようなことが考えられると思います。

  • コーディングからプッシュまでをすべてEmacsの中で済ませることができる
  • キーストローク数が最小限なのでスムーズにgitを操作できる
  • メニューに簡易的な説明が表示されるのでキー操作を忘れない

なんと言っても一番上ですね。
ファイルを編集中に逐一コミットすることが,とても楽ちんになります。

デレステ自動演奏機の問題点

なんだこれは

アイドルマスター シンデレラガールズ スターライトステージという,スマートフォン向けのゲームがあります。
いわゆる音ゲーです。
未だに先駆者が出ていないため,何を思い立ったか自動演奏機を作っています。
※ソフトウェア的に自動クリアする動画はありましたが,自動クリア(物理)はこれが初だと思います。

メカ

打鍵用にタカハソレノイドを2個,移動用にサーボモータを2個使っています。
スライダクランク機構で打鍵部を移動させています。

デレステは”スライド”と呼ばれる譜面があるため,打鍵しながら左右に動かせる機構が必要でした。
現時点では同時押しは2つまでしかないため,打鍵部は2つのみとしました。

制御

制御用のマイコンとして,STM32F401RE nucleo boardを使っています。
外付け部品が不要で使うことができ,おねだんも1700円(デバッガ付き)なのでオススメです。

ソフトウェア

譜面データをハードコーディングするのだけは絶対にやめたい(ダサいし楽曲追加が面倒)ので,譜面データを作成するソフトを作っています。
ついでにQtのお勉強もしています。

今後

1,2ヶ月はマイクロマウスと夏コミに専念したいため凍結させますが,夏休み頃から再開させようと考えています。
機械の精度を見直し,ソフトを完成させることができれば,それなりに演奏してくれるのではないでしょうか。

ブログ移転しました

ブログ移転しました。

このブログは,残り少ない2年間の大学生活を充実させるため,日々の取り組みをメモしていくブログです。
今年もいろいろなことに取り組んでいこうと思います。

とりあえずはバイトとマウスとデレステと。