toioで生き物っぽい何かを作ってみた

ご覧いただきありがとうございます。
この記事は[SB-AI Advent Calendar 2019](https://adventar.org/calendars/4324)の18日目の記事となります。

#はじめに
突然ですが皆様は「人工生命」と聞いてどんなものをイメージしますか？
SFに出てくる怪物のようなイメージを持つ方も多いかもしれませんが、家を掃除してくれるルンバも人工生命の一つと言えます。
「人工生命」は国際的には「ALIFE」という名称で世界各国で研究が進められており、人工的に生命を作る事を通じて生命とは何かを理解しようとする研究分野の事です。

私はこの分野の研究者でもなんでもない、ただのサラリーマンですが、仕事でロボットに関わる機会が多く、
また昨年ALIFE関連のハッカソンに参加しチームで作品を作った経験から、プライベートで「人工生命」を１つのテーマとしてモノづくりをしております。
（嬉しい事にチームで作った作品が、今年の文化庁メディア芸術祭のアート部門で[審査委員会推薦作品](http://festival.j-mediaarts.jp/works/art/moment-of-perception/)として選出されました！動画は[こちら](https://www.youtube.com/watch?v=zqtqyJ1UA7Y)）

今回の記事は、私が最近注目している「toio（トイオ）」というロボットのあるアプリに着目し、それを参考にtoioで生き物っぽい何かを作ってみた。という記事です。
※この記事は筆者がtoioで遊んでみて勝手に思った事を書いているだけの記事となりますので、ALIFEの研究記事等ではございません。ご了承ください。

#toioについて
toioはsonyから2019年3月に発売されたロボットトイです。
![https___toio.io_images_body_cover.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90062/1f5b9ae5-98c3-e59c-ac7e-d13cdeccd36a.jpeg)
※画像は[こちら](https://note.toio.io/n/nfa0db46614cb)より引用：

[公式サイト](https://toio.io/)を見ていただけると一目瞭然ですが、主に子供向けのプログラミングトイとしての用途が主で、
カセットを用いて遊べる内容を変えたり、白いキューブにレゴなどを用いてオリジナルな何かを作ったりできるようになっています。
またスクラッチベースのビジュアルプログラミング環境の提供もされています。

画像にある白いキューブが「toio core cube」と言われるロボット本体なのですが、このcubeの仕様はネット上に[公開](https://toio.github.io/toio-spec/)されており、
また[toio.js](https://github.com/toio/toio.js)というnode.js用のライブラリも合わせて提供されていたり等、子供から上級者な大人まで遊べるようになっています。

今後も新たなエンタメ系ソフトやアプリの登場が予定されており、今後の展開が楽しみなtoioですが、
個人的に気になったtoio用スマホアプリが11月から提供開始となりました。

##「ウロチョロス」現る
11月12日にtoioの新プロジェクトの発表があり、その際に発表された一つに「[ウロチョロス](https://morikatron.com/urochoros/)」というアプリがありました。
（開発元のモリカトロンさんの記事より引用：https://morikatron.ai/2019/11/toio_urochoros/）

当時はtoioを買おうか迷っていたものの、TLに流れてきた下記のツイートの動画たちを見てすぐにamazonで購入しました。
生き物っぽいものを作りたい私にとって、まさに目指すべき一例でしたので即決でした。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ウロチョロスたちが鬼ごっこをしています。よく見ると個体ごとの性格の違いが見えるかも。<a href="https://twitter.com/hashtag/toio?src=hash&amp;ref_src=twsrc%5Etfw">#toio</a> <a href="https://t.co/6meUmeykBM">pic.twitter.com/6meUmeykBM</a></p>&mdash; モリカトロンAIラボ (@morika_ailabo) <a href="https://twitter.com/morika_ailabo/status/1194129176514580480?ref_src=twsrc%5Etfw">November 12, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

動画では鬼ごっこをしていますが、この他にも自由にcube達に動き回ってもらうモードや、ユーザーの表情判定をcube達が行うモードがあったりします。
（※顔の撮影はスマホで行う）
なお、ユーザーの表情判定は純粋に画像認識したときのスコアで順位をつけているのではなく、最終的に個々のcubeが持つ評価基準を用いて判定が下されるのだとか。

##ウロチョロスの生き物らしさとは
自分も実際にウロチョロスを試してみて、自由に動き回るモードでは様々なcube達のやり取りが観察できました。
・会話をしているようなアクション
・モノマネ（一方のcubeが他方のcubeに技を教える）
・パワー切れのcubeに対してのサポートアクション
・ダンス　等。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ウロチョロス観察日記その1 <a href="https://t.co/N8JUm0kXnk">pic.twitter.com/N8JUm0kXnk</a></p>&mdash; MARVO@anima (@marvo737) <a href="https://twitter.com/marvo737/status/1208763083398643712?ref_src=twsrc%5Etfw">December 22, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ウロチョロス観察日記その2 <a href="https://t.co/XnxS6CFTY3">pic.twitter.com/XnxS6CFTY3</a></p>&mdash; MARVO@anima (@marvo737) <a href="https://twitter.com/marvo737/status/1208763528426840065?ref_src=twsrc%5Etfw">December 22, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


そこでわかってきたのは、ウロチョロスはcube同士の相互作用によって、生き物らしく見せているのではないか、という点でした。
コードは確認できないため、あくまでも想像ではありますが、一方のアクションが他方のアクションに影響を及ぼすような制御が多くなされていると見受けられます。
ここで考えたいのは、双方のアクションを把握するためには、toioがどこにいるかなど、周辺環境の情報取得の方法です。
昨今のロボットはカメラやセンサーによって周辺環境位を把握し自己位置推定等を行いますが、toioには見た目の通りカメラなどはありません。
そこでポイントになってくるのが「プレイマット」です。

##toioのプレイマットについて
![id_position_id_coordinate.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90062/9233c2e3-3f7f-b30b-ac2e-134f9d361eb4.png)
※画像は[こちら](https://toio.github.io/toio-spec/docs/ble_id#%E5%BA%A7%E6%A8%99-x-%E5%BA%A7%E6%A8%99-y-%E5%BA%A7%E6%A8%99)より引用
ウロチョロスで遊ぶには、「トイオコレクション」と言う別売のキットに付属する「プレイマット」と呼ばれる台紙が必要となります。
この台紙はただの台紙ではなく、紙面上に座標を示すPositionIDが印刷されている特殊な台紙となっています。
cubeにはそのPositionIDを読み出すセンサーが搭載されており、そのおかげでcubeの現在のx,y座標、さらにはcubeのx軸に対しての時計回りの角度を利用したプログラミングをすることが可能です。

つまり、このプレイマット上であればtoioを自由に操ることが可能であり、次からは２台のcubeの座標データを用いてそれっぽいものを作ってみたいと思います。

##生き物っぽい何かを作ってみる
■実行環境
・macOS Catalina 10.15.2
・Node.js v12.13.0
・toio.js 42ae66a

細かいセットアップ及び関数の説明については省略いたします。
下記が今回作成したコードとなります。toio.jsのサンプルをベースとしています。

```js:random_chase.js
const { NearScanner } = require('@toio/scanner')

// calculate chasing cube's motor speed
function chase(jerryX, jerryY, tomX, tomY, tomAngle) {
  const diffX = jerryX - tomX
  const diffY = jerryY - tomY
  const distance = Math.sqrt(diffX * diffX + diffY * diffY)
  if (distance < 70) { 
    return [0, 0] // stop
  }

  let relAngle = (Math.atan2(diffY, diffX) * 180) / Math.PI - tomAngle
  relAngle = relAngle % 360
  if (relAngle < -180) {
    relAngle += 360
  } else if (relAngle > 180) {
    relAngle -= 360
  }

  const ratio = 1 - Math.abs(relAngle) / 90
  let speed = 80
  if (relAngle > 0) {
    return [speed, speed * ratio]
  } else {
    return [speed * ratio, speed]
  }
}

async function main() {
  // start a scanner to find nearest two cubes
  const cubes = await new NearScanner(2).start()

  // connect two cubes (tom chases jerry)
  const jerry = await cubes[0].connect()
  const tom = await cubes[1].connect()

  //set movable area
  const min_x = 100
  const max_x = 400
  const min_y = 100
  const max_y = 400

  // set light color and store position
  let jerryX = 0
  let jerryY = 0
  let jerryAngle = 0
  jerry.turnOnLight({ durationMs: 0, red: 255, green: 0, blue: 255 })
  jerry.on('id:position-id', data => {
    jerryX = data.x
    jerryY = data.y
    jerryAngle = data.angle
  })

  // set light color and store position
  let tomX = 0
  let tomY = 0
  let tomAngle = 0
  tom.turnOnLight({ durationMs: 0, red: 0, green: 255, blue: 255 })
  tom.on('id:position-id', data => {
    tomX = data.x
    tomY = data.y
    tomAngle = data.angle
  })

  const randRange = (min, max) => Math.floor(Math.random() * (max - min) + min);

  var random_x = 100
  var random_y = 100
  
  setInterval(() => {
    random_x = randRange(min_x,max_x)
    random_y = randRange(min_y,max_y)
  },2000)

  setInterval(() => {
    jerry.move(...chase(random_x, random_y, jerryX, jerryY, jerryAngle), 100)
    console.log("jerryX : " + random_x + " jerryY : " + random_y + " jerryAngle" + jerryAngle + "\n");
  }, 50)
  
  setInterval(() => {
    tom.move(...chase(jerryX, jerryY, tomX, tomY, tomAngle), 100)
  }, 100)
}

main()
```
これで動かしてみるとこのような動きになります。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">自作ウロチョロスもどき <a href="https://t.co/tczSdCawtk">pic.twitter.com/tczSdCawtk</a></p>&mdash; MARVO@anima (@marvo737) <a href="https://twitter.com/marvo737/status/1208763813069127680?ref_src=twsrc%5Etfw">December 22, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

X,Y座標を指定範囲内でランダムに一定時間で変化させ、cube1（jerry）がその座標を追いかけて、cube2(tom)がcube1を追いかける、といった内容です。

ただ、この状態だとcube同士がよくぶつかるため、cube内のモーションセンサで衝突検知して距離を取るなどしてあげないといけないのですが、そちらの実装はまた次回にしたいと思います。。
それができてやっと相互作用について少し語れるようになるかと思うのですが、時間の都合上今回はここまでといたします。

#最後に
今回はウロチョロスアプリの影響を受け、toioで生き物っぽい（定義が曖昧で申し訳ありません、、）何かを作ってみました。
本当はもう少しALIFEと絡めることができれば良かったのですが、完全に力不足です。。修行あるのみですね。。

toioのcubeとプレイマットの組み合わせは、まだまだ面白そうなものが作れそうな予感がします。
マット上であれば座標だけでなく角度も取得できるので、cubeを出力デバイスではなく、入力デバイスとして使ってみるのも面白そうです。
（個人的にはTouchDesignerのコントローラーにしてみたいと考えています。）

以上、ありがとうございました。