NAOqi(ver1系)用 独自モジュールの作成



## はじめに

* "ALTextToSpeech" 等と同様の最低限の機能のモジュールを作成し、バーチャルロボットで動作確認してみました。
* SDK のバージョンは naoqi-sdk-1.14.5、バーチャルロボットは webots-for-nao-7.4.3　になり、NAOqi ver1系が対象です。Pepper 実機・最近の Choregraphe のバーチャルロボット等の NAOqi ver2系の環境では動かないと思われます。
* 新しいバージョンの SDK が入手できたら、改めて実機・Choregraphe のバーチャルロボットで確認したいと思います。
 
## モジュールの作成

### 雛形の生成

```bash
$ qisrc create HelloWorldModule
New project initialized in /path/to/project/HelloWorldModule

$ cd HelloWorldModule
```

### コードの修正

基本的にはドキュメントの [Example: HelloWorld module](http://doc.aldebaran.com/1-14/dev/cpp/examples/core/helloworld/example.html#cpp-examples-helloworld) と同じですが、元のサンプルから(取り急ぎは)不要な箇所をさらに削ったものになってます。

#### helloworld.cpp (新規作成)

```helloworld.cpp
#include <iostream>
#include <alcommon/albroker.h>
#include <alproxies/altexttospeechproxy.h>
#include "helloworld.h"

using namespace AL;

HelloWorld::HelloWorld(boost::shared_ptr<ALBroker> broker, const std::string& name):
  ALModule(broker, name)
{
  setModuleDescription("HelloWorld module");

  functionName("sayHello", getName(), "Say hello to the world");
  BIND_METHOD(HelloWorld::sayHello);
}

HelloWorld::~HelloWorld()
{
}

void HelloWorld::init()
{
  std::cout << "HelloWorld: init" << std::endl;
}

void HelloWorld::sayHello()
{
  const std::string phraseToSay("HelloWorld");

  std::cout << "HelloWorld: Saying hello to the console ..." << std::endl;
  std::cout << "HelloWorld: " << phraseToSay << std::endl;
  std::cout << "HelloWorld: Calling say method of ALTextToSpeech module ..." << std::endl;

  ALTextToSpeechProxy tts(getParentBroker());
  tts.say(phraseToSay);

  std::cout << "HelloWorld: Done!" << std::endl;
}
```

#### helloworld.h (新規作成)

```helloworld.h
#ifndef HELLOWORLD_H
#define HELLOWORLD_H

#include <boost/shared_ptr.hpp>
#include <alcommon/almodule.h>

namespace AL
{
  class ALBroker;
}

class HelloWorld : public AL::ALModule
{
 public:
  HelloWorld(boost::shared_ptr<AL::ALBroker> pBroker, const std::string& pName);
  virtual ~HelloWorld();

  virtual void init();

  void sayHello();
};

#endif // HELLOWORLD_H
```

#### main.cpp

```main.cpp
#include <alcommon/albroker.h>
#include <alcommon/albrokermanager.h>
#include "helloworld.h"

extern "C"
{
  int _createModule(boost::shared_ptr<AL::ALBroker> pBroker)
  {
    AL::ALBrokerManager::setInstance(pBroker->fBrokerManager.lock());
    AL::ALBrokerManager::getInstance()->addBroker(pBroker);

    AL::ALModule::createModule<HelloWorld>(pBroker, "HelloWorldModule");

    return 0;
  }

  int _closeModule()
  {
    return 0;
  }
}
```

#### CMakeLists.txt

```CMakeLists.txt
cmake_minimum_required(VERSION 2.8)

project(HelloWorldModule)

find_package(qibuild)

set(CMAKE_CXX_FLAGS "-stdlib=libstdc++")

set(_srcs
  helloworld.cpp
  helloworld.h
  main.cpp
)

qi_create_lib(HelloWorldModule SHARED ${_srcs} SUBFOLDER naoqi)

qi_use_lib(HelloWorldModule ALCOMMON)
```

### configure & make

```bash
$ qitoolchain create mytoolchain /path/to/sdk/toolchain.xml
mytoolchain already exists, updating without removing
Updating toolchain mytoolchain with feed: /path/to/sdk/toolchain.xml
Now try using
  qibuild configure -c mytoolchain
  qibuild make -c mytoolchain
```

```bash
$ qibuild configure -c mytoolchain
Current build worktree: /path/to/project
Using toolchain: mytoolchain
Build type: Debug
* (1/1) Configuring HelloWorldModule
-- The C compiler identification is AppleClang 6.0.0.6000056
-- The CXX compiler identification is AppleClang 6.0.0.6000056
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Using qibuild 3.7
-- Library: HelloWorldModule
-- Configuring done
-- Generating done
-- Build files have been written to: /path/to/project/HelloWorldModule/build-mytoolchain
```

```bash
$ qibuild make -c mytoolchain
Current build worktree: /path/to/project
Using toolchain: mytoolchain
Build type: Debug
* (1/1) Building HelloWorldModule
Scanning dependencies of target HelloWorldModule
[ 50%] Building CXX object CMakeFiles/HelloWorldModule.dir/helloworld.cpp.o
[100%] Building CXX object CMakeFiles/HelloWorldModule.dir/main.cpp.o
Linking CXX shared library sdk/lib/naoqi/libHelloWorldModule.dylib
[100%] Built target HelloWorldModule
```

libHelloWorldModule.dylib ができました。

## バーチャルロボットへのモジュールのインストール

### インストール先のパスについて

最初に書いたように今回の確認には　Webots を使いますので、先にランタイムのパスを設定しておきます。

```bash
export NAOQI_RUNTIME=/path/to/Webots for NAO/resources/projects/robots/nao/aldebaran/naoqi-runtime
```

### 作成したモジュールをバーチャルマシン配下にインストール(コピー)

```bash
$ ls -la build-mytoolchain/sdk/lib/naoqi/libHelloWorldModule.dylib
-rwxr-xr-x  1 suna  staff  75288  1  6 03:25 build-mytoolchain/sdk/lib/naoqi/libHelloWorldModule.dylib

$ cp -p build-mytoolchain/sdk/lib/naoqi/libHelloWorldModule.dylib "$NAOQI_RUNTIME/lib/naoqi/"
```

### autoload.txt を修正

バーチャルロボットが作成したモジュールを読み込むよう autoload.txt を修正します。

```bash
$ ls -la "$NAOQI_RUNTIME/etc/naoqi/autoload.ini"
-rw-r--r--  1 suna  admin  267  1  6 03:29 /path/to/webots/resources/projects/robots/nao/aldebaran/naoqi-runtime/etc/naoqi/autoload.ini

$ vi "$NAOQI_RUNTIME/etc/naoqi/autoload.ini"

$ tail "$NAOQI_RUNTIME/etc/naoqi/autoload.ini"
framemanager
pythonbridge
videoinput
redballdetection
behaviormanager
memorywatcher
alnavigationinterface
navigation

HelloWorldModule
```

## 動作確認

### Webots 起動

作成したモジュールが読み込まれ、初期化されているようです。

![2015010601.png](https://qiita-image-store.s3.amazonaws.com/0/20418/7d8d8d55-9b15-806e-70c1-f78564a53cb4.png "2015010601.png")

### ALProxy 経由でモジュールに接続してメソッド実行

```bash
$ /usr/bin/python
Python 2.7.6 (default, Sep  9 2014, 15:04:36)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.39)] on darwin
Type "help", "copyright", "credits" or "license" for more information.

>>> from naoqi import ALProxy

>>> hwm = ALProxy("HelloWorldModule", "localhost", 9559)
[INFO ] Starting ALNetwork
[INFO ] NAOqi is listening on 127.0.0.1:54011

>>> hwm.sayHello()
```

sayHello メソッド実行後、Webots のコンソールに諸々が表示されて、想定通り動いているようです。

![2015010602.png](https://qiita-image-store.s3.amazonaws.com/0/20418/67a8038d-bc6d-7ebd-8336-18af77a1c308.png "2015010602.png")


## 感想

* 最初に SDK でできるだろうことのイメージがこの形でした。まだ HelloWorld なのですが、ようやくここまで来た感じ。
* Pepper 実機では*.dylib でなく、*.so を作らないといけないのではないかと思うので、make の方法も見ておかないといけない。