V-REPとC/C++で自作ロボットを動かす

皆さん初めまして.もりゅー(@Moryu_io)と申します.
東京でしがない理系学生をやっております.

本ブログは,もりゅーが学んだ技術的なことを中心に,備忘録代わりに更新していくものです.
よろしくお願い致します.

さて,記念すべき最初の更新は,rogy Advent Calendar 2017 - Adventar 16日目の記事になります.
すなわち,V-REPというロボット用動力学シミュレーション開発環境を用いて,自作のロボットを動かしてみます.

V-REPの詳細はググるなり公式サイトをご覧ください.
www.coppeliarobotics.com

ロボットを動力学シミュレーションするのに適した環境が提供されており,
サンプルを弄ってるだけでもかなり面白いです.

本記事では,サンプルで既に入ってるモデルではなく,自分で用意したロボットをV-REP上で動かします.
また,ただ動かすだけでなく,マイコンで動かす際とプログラムを一部共通化しやすくするため,
remoteAPIを用いて,C/C++から動作させます(デフォルトではLuaによるスクリプトで動かす).

さて早速やっていきましょう.

1.V-REPのダウンロード

Coppelia Robotics V-REP: Create. Compose. Simulate. Any Robot: Downloads
こちらのサイトからV-REP PRO EDUをDLし,インストールします.

2.モデルの作成

まず,stlファイルを作ります.今回は画像のような1自由度のアームを使用します.
自分が用いたものはFusion360で公開しますので,とりあえずこれをダウンロードし,
アセンブリファイルをstlファイルでエクスポートしてください.
※承認されるまでモデル待ってください!
gallery.autodesk.com
f:id:Moryu_io:20171216210539p:plain:w300

3.V-REPでの設定

インストールしたV-REPを起動します.

stlファイルのimport

Import->meshから作成したstlファイルを選択します.設定はデフォルトで大丈夫です.importするとこんな感じ
f:id:Moryu_io:20171216211339p:plain:w500

部品の分割

モデルを右クリック→Edit→Grouping/Merging→Divide selected shapesで分ける.そこそこ賢いので,結構これでうまく部品が分割できます.
出来ない場合は,モデルの作成時,アセンブリではなく部品ごとにstlファイルにしてimportしましょう.
ちなみに,軸と穴は同径でも別パーツとして認識してくれます(多分メッシュ構造の関係).
面と面は,少しだけ隙間を空けておくといいかと.
f:id:Moryu_io:20171216211726p:plain:w500

ジョイントの追加

軸を追加します.menu barのAdd->Joint->Revolute で回転対偶を追加できます.(画像では物に埋まってて見えませんが,Scene hierarchyにjointが追加されているのが分かると思います)
f:id:Moryu_io:20171216212107p:plain:w500

部品の名前をつける

Scene hierarchyで名前をダブルクリックすると名前の変更ができます.特にジョイントの名前は後で使うので,分かりやすいように変えておきましょう.
今回は「Joint1」とか適当につけておきます.

ジョイントの移動

位置をうまく調整します.ここをクリックし,ジョイントを選択すると,並進と回転を指定できます.
f:id:Moryu_io:20171216212510p:plain
サンプルのデータだとαを90°,(x,y,z) = (0, 0, 0.12)にすればうまく軸のところにジョイントが来るはずです.
f:id:Moryu_io:20171216212554p:plain:w300f:id:Moryu_io:20171216212609p:plain:w300
ちなみにそろそろsceneを保存しておきましょうね.

階層構造の作成

階層構造を作ります.Baseを親にして,その下にJoint1,更にその下にArmを置きます.こうすることで,Joint1が回転すると,その先の子オブジェクトも回転します.
f:id:Moryu_io:20171216212729p:plain:w300

各種オプションの設定

Scene hierarchyでモデルなどのアイコンをクリックすると設定を変えられます.

ジョイント

visual propertiesのlengthとかを適当に修整して見えるようにしましょう.
f:id:Moryu_io:20171216212901p:plain:w300
また,Dynamic propertiesでは,motor enabledとcontrol loop enabledをonにしておく.
無限回転するタイヤなどのモータでは,後者はoffでも大丈夫ですが,今回はあとで位置を指令するので,この設定です.
f:id:Moryu_io:20171216213029p:plain:w300

オブジェクト

同じくDynamic propertiesを弄ります.Baseだけ「Body is respondable」と「Body is dynamic」の両方をonにします.armはとりあえず後者だけonにします.
ちなみに,前者は「接触判定」,後者は「動力学」を有効化するものだと思ってください.
f:id:Moryu_io:20171216213725p:plain:w300
また,Object propertiesの上の方のcommonを選択し,下の方の「Object is model base」をonにして,Baseだけモデルbaseパーツにします.
これにより,シーンごとではなくモデル単体で保存することも可能になります.
f:id:Moryu_io:20171216213732p:plain:w300

scriptを有効化

Baseを右クリックでAdd->Associated child script->Non threadedを選択するとobjectの名前のとなりに,ノートみたいなマークが現れます.
ここに色々書くことでモデルを動かすことができます(Lua).今回はremoteAPIで外部から動かすことを考えるので,中身をすべて消して以下の一行を書いておきます.

simExtRemoteApiStart(19999,1300,true,false)

4.remoteAPIをC/C++で叩く

これでV-REP側の準備は終了です.続いてC/C++からremoteAPIをたたく方法を紹介します.
今回はvisual studio 2017 communityで書きます.基本的にはインクルードpathの指定とプリプロセッサを変えるだけなので,
以下のURLにかかれていることを参考にすれば,どの環境でも動くと思います.
Enabling the Remote API - client side

インクルードpathの設定

の前に,V-REP3\V-REP_PRO_EDU\programmingにあるincludeとremoteAPIフォルダをソリューションと同階層にコピっておきます.
その後,以下のように設定します.
f:id:Moryu_io:20171216215502p:plain:w400

プリプロセッサの定義

以下のように書いておきます.一番上は,extApiPlatform.cでfopenを使っててエラーが出るので,とりあえず無視するためです.そっちを直してもいいかと.
_CRT_SECURE_NO_WARNINGS
NON_MATLAB_PARSING
MAX_EXT_API_CONNECTIONS=255
f:id:Moryu_io:20171216215618p:plain:w400

プログラム

こんな感じです.

#include <stdio.h>
#include <stdlib.h>
#define _USE_MATH_DEFINES
#include <math.h>


extern "C" {
#include "extApi.h"
}


int main(int argc, char* argv[]) {
	int _portNb = 19999;		// 使用するポートの番号.V-REP側と合わせる

	int time_ms = 0;			// シミュレーション時間
	int _clientID = -1;			// ID格納用変数
	int Joint_handle;			// 関節のハンドル格納用変数

	// サーバーと接続されるまで繰り返す
	while (_clientID == -1) {
		_clientID = simxStart((simxChar*)"127.0.0.1", _portNb, true, true, 2000, 5);
	}

	simxGetObjectHandle(_clientID, "Joint1", &Joint_handle, simx_opmode_blocking);		// ジョイントのハンドルを取得

	while (simxGetConnectionId(_clientID) != -1) {
		simxSetJointTargetPosition(_clientID, Joint_handle, 45.0*M_PI / 180.0 * sin(2.0*M_PI*time_ms/1000.0), simx_opmode_oneshot);		// ジョイントの角度の目標値を設定

		time_ms += 10;
		extApi_sleepMs(10);

	}

	simxFinish(_clientID);
	return 0;
}

5.シミュレーション

Cのプログラムを実行した状態で,V-REPのシミュレーションを実行してください.
アームが左右に揺れると思います.

Armやbaseの重さとか慣性モーメント、ジョイントの最大トルクなどを変えて動かすと,色々挙動が変わるのが分かると思います.




以上になります.急いで書いた記事なので,色々とつたない部分があると思います.
何か分からないことがあれば是非コメントを残していってくださると助かります.
また,今回はV-REPの導入編ですので,結構無視したことがあります.
今後の更新でその辺も紹介できればと思います.