ROS、OpenAI和Gazebo機(jī)器人與人工智能仿真與實(shí)踐教研雜記(二)環(huán)境構(gòu)建
這篇博文側(cè)重環(huán)境,動(dòng)態(tài)和靜態(tài),確定與不確定,結(jié)構(gòu)與非結(jié)構(gòu)化等。

如何利用ROS、OpenAI和Gazebo構(gòu)建一種動(dòng)態(tài)、不確定、非結(jié)構(gòu)化的復(fù)雜環(huán)境,
用于機(jī)器人和人工智能算法的測(cè)試呢?
參考鏈接:
https://github.com/onlytailei/gym_ped_sim
行人模型:
更多內(nèi)容稍后補(bǔ)充。
參考gazebosim官網(wǎng)文檔:http://gazebosim.org
制作動(dòng)畫(huà)模特(演員actor)
本教程適用于Gazebo 8+版本(Gazebo 8/9/10均可)
概述
本教程解釋了如何使用Gazebo的“actor”來(lái)創(chuàng)建腳本動(dòng)畫(huà)。
如果希望在模擬仿真中使用預(yù)定義路徑的實(shí)體而不受物理引擎影響,則動(dòng)畫(huà)非常有用。這意味著它們不會(huì)因重力而下落或與其他物體碰撞。然而,它們將具有可由RGB相機(jī)看到的3D可視化,以及可由基于GPU的深度傳感器檢測(cè)的3D網(wǎng)格。
該教程詳細(xì)解釋了如何創(chuàng)建不與模擬其余部分交互的開(kāi)環(huán)軌跡。接下來(lái),將快速瀏覽一個(gè)示例插件,該插件根據(jù)環(huán)境反饋控制動(dòng)畫(huà)。
演員actor
在Gazebo中,動(dòng)畫(huà)模型被稱為actor。Actors擴(kuò)展了常見(jiàn)模型,增加了動(dòng)畫(huà)功能。
有兩種類型的動(dòng)畫(huà)可以單獨(dú)使用或組合使用:
骨架動(dòng)畫(huà),是一個(gè)模型中鏈接之間的相對(duì)運(yùn)動(dòng)
沿著軌跡運(yùn)動(dòng),將全世界所有演員的鏈接作為一個(gè)整體
兩種類型的動(dòng)作都可以組合起來(lái),以實(shí)現(xiàn)在世界中移動(dòng)的骨架動(dòng)畫(huà)
Gazebo的演員就像模特一樣?,所以你可以像往常一樣把鏈接和關(guān)節(jié)放在里面。主要區(qū)別是:
演員總是靜止的(即沒(méi)有施加力,無(wú)論是重力還是接觸或其他任何東西)
Actors支持從COLLADA和BVH文件導(dǎo)入的骨架動(dòng)畫(huà)。
演員可以在SDF中直接編寫(xiě)軌跡。
不能有嵌套在actor中的模型,因此我們僅限于動(dòng)畫(huà)網(wǎng)格,鏈接和關(guān)節(jié)。
提示:在此處查看
腳本軌跡
這是演員的高級(jí)動(dòng)畫(huà),包括指定在特定時(shí)間到達(dá)的一系列姿勢(shì)。Gazebo負(fù)責(zé)插入它們之間的運(yùn)動(dòng),因此運(yùn)動(dòng)是流動(dòng)的。
示例世界
讓我們來(lái)看看Gazebo附帶的簡(jiǎn)單示例世界:
gazebo worlds/animated_box.world
你會(huì)看到一個(gè)浮動(dòng)的盒子一次又一次地以方形軌跡移動(dòng)。軌跡經(jīng)過(guò)四點(diǎn)世界,并在它們之間需要1秒。[-1,?-1,?1][-1,?1,?1][1,?1,1][1,?-1,?1]
代碼解析
可以在這里看到整個(gè)世界的描述?。按部分來(lái)學(xué)習(xí)一下。
首先定義一個(gè)地平面和光源(太陽(yáng))的世界。
創(chuàng)建了一個(gè)名為的actor,animated_box并給它一個(gè)帶有視覺(jué)框的簡(jiǎn)單鏈接:
現(xiàn)在是actor演員,
在
waypoint:軌跡中可以有任意數(shù)量的航點(diǎn)。每個(gè)航路點(diǎn)由a?time和a組成pose:
time:以腳為單位的時(shí)間,從腳本開(kāi)頭算起,應(yīng)該達(dá)到姿勢(shì)。
pose:應(yīng)該達(dá)到的姿勢(shì)
提示:定義航點(diǎn)的順序并不重要,它們將遵循給定的時(shí)間。
注意:軌跡整體平滑。這意味著您將獲得流暢的運(yùn)動(dòng),但可能無(wú)法達(dá)到航路點(diǎn)中包含的確切姿勢(shì)。
提示:非演員模型也可以遵循腳本軌跡,但這需要使用插件。請(qǐng)參閱本教程以了解具體方法。
現(xiàn)在輪到你實(shí)踐了!在繼續(xù)下一部分之前,嘗試不同的trejctory描述!
骨架
Gazebo支持兩種不同的骨架動(dòng)畫(huà)文件格式:?COLLADA(.dae)和?Biovision Hierarchy(.bvh)。
嘗試一下Gazebo附帶的簡(jiǎn)單示例文件。首先,創(chuàng)建一個(gè)新的世界文件:
gedit walk.world
并粘貼以下SDF,它有一個(gè)sun和一個(gè)使用walk.dae?作為皮膚的?actor:
在Gazebo看看它,會(huì)看到一個(gè)人在原地走動(dòng)。
gazebo walk.world
皮膚
上面示例中的actor非常簡(jiǎn)單,它加載的所有內(nèi)容都是
注意:如果之前制作過(guò)?自定義?Gazebo模型,則可能已將COLLADA文件用作模型的視覺(jué)效果和碰撞。在鏈接中使用時(shí),COLLADA動(dòng)畫(huà)會(huì)被忽略,但在皮膚中使用時(shí),它們會(huì)被加載!
指定的文件
/home/
還可以告訴Gazebo在環(huán)境變量中包含的所有目錄中查找網(wǎng)格?GAZEBO_MODEL_PATH,如下所示:
model://skeketon_model/skeleton.dae
最后,可以使用一些與Gazebo一起安裝的示例網(wǎng)格,直接引用它們的文件名。以下是可用的列表。看看他們中的一些代替上面的walk.world
moonwalk.dae
run.dae
sit_down.dae
sitting.dae
stand_up.dae
stand.dae
talk_a.dae
talk_b.dae
walk.dae
動(dòng)畫(huà)
結(jié)合不同的皮膚和動(dòng)畫(huà)
有時(shí),將不同的皮膚與不同的動(dòng)畫(huà)組合起來(lái)很有用。Gazebo允許我們從一個(gè)文件中獲取皮膚,從另一個(gè)文件中獲取動(dòng)畫(huà),只要它們具有兼容的骨架。
例如,文件和兼容,這樣他們可以相互混合。走路的人有一件綠色襯衫,月球徒步者穿著一件紅色襯衫。walk.daemoonwalk.dae
如果想一個(gè)人月球漫步與綠色襯衫,使用walk對(duì)皮膚和moonwalk為動(dòng)畫(huà)。
如果想一個(gè)人走了紅襯衣,使用moonwalk對(duì)皮膚和walk為動(dòng)畫(huà)。
動(dòng)畫(huà)標(biāo)簽與皮膚標(biāo)簽一起使用,它需要一個(gè)name參數(shù)。像這樣:
提示:查看本教程以了解有關(guān)COLLADA動(dòng)畫(huà)的更多信息。在涼亭的背景下,作為皮膚COLLADA文件必須有
立即嘗試不同的組合!
同步動(dòng)畫(huà)和軌跡
到目前為止,已經(jīng)了解了創(chuàng)建軌跡和加載靜態(tài)動(dòng)畫(huà)的所有信息。是時(shí)候?qū)W習(xí)如何組合它們了。
可能會(huì)想“只是添加
繼續(xù)加載它,看看會(huì)發(fā)生什么。這不是預(yù)期,對(duì)嗎?演員的腿根本不動(dòng)。那是因?yàn)镚azebo不知道哪個(gè)動(dòng)畫(huà)與哪個(gè)軌跡匹配。所以讓改變動(dòng)畫(huà)名稱以匹配軌跡類型,如下所示:
好吧,所以演員都在世界上來(lái)回移動(dòng),并且移動(dòng)他的腿。但那看起來(lái)不太自然,對(duì)吧?他的腳在地上滑動(dòng)。
骨架動(dòng)畫(huà)在X軸上包含一個(gè)平移組件,通過(guò)運(yùn)行沒(méi)有任何軌跡的動(dòng)畫(huà)來(lái)注意到這一點(diǎn)。但是這個(gè)動(dòng)畫(huà)還沒(méi)有與軌跡同步。可以通過(guò)
注意:y或者z軸沒(méi)有插值標(biāo)記,因此請(qǐng)確保您的原位動(dòng)畫(huà)沿x軸移動(dòng)。
現(xiàn)在終于讓兩個(gè)動(dòng)畫(huà)完美同步了。應(yīng)該看到這個(gè)人從一側(cè)走到另一側(cè),一個(gè)方向更快,另一個(gè)方向更慢。
閉環(huán)軌跡
剛學(xué)會(huì)了如何創(chuàng)建演員并通過(guò)SDF設(shè)置他們的軌跡。對(duì)此的限制是軌跡在開(kāi)環(huán)中運(yùn)行,也就是說(shuō),它沒(méi)有從環(huán)境中獲取任何反饋。現(xiàn)在來(lái)看看如何使用插件改變軌跡的示例。
提示:如果不熟悉Gazebo插件,請(qǐng)先查看一些插件教程。
Gazebo有一個(gè)示范世界,演員四處移動(dòng),同時(shí)避開(kāi)障礙物。看看它在運(yùn)行:
gazebo worlds/cafe.world
SDF中的插件
就像模型一樣,可以為任何actor編寫(xiě)自定義插件,并在SDF描述中分配插件。來(lái)看看?cafe.world?中引用視頻中某個(gè)演員的部分:
可以看到,不是給出要遵循的特定路點(diǎn)列表,而是給出了一個(gè)插件。在插件標(biāo)簽內(nèi),有幾個(gè)參數(shù)可以專門(mén)針對(duì)這個(gè)插件進(jìn)行調(diào)整。我們不會(huì)詳細(xì)介紹插件的工作原理,這里的目的是展示一些參數(shù)可以暴露出來(lái),確定軌跡的邏輯將在插件內(nèi)部。
插件C ++代碼
ActorPlugin可在此處找到?該源代碼。而?這里?是頭。
第一個(gè)技巧是聽(tīng)這樣的世界更新開(kāi)始事件:
this->connections.push_back(event::Events::ConnectWorldUpdateBegin(
std::bind(&ActorPlugin::OnUpdate, this, std::placeholders::_1)));
這樣,指定一個(gè)回調(diào),它將在每次迭代時(shí)調(diào)用。這是我們將更新演員軌跡的功能。讓看一下插件在該函數(shù)中的作用:ActorPlugin::OnUpdate
void ActorPlugin::OnUpdate(const common::UpdateInfo &_info)
{
// Time delta
double dt = (_info.simTime - this->lastUpdate).Double();
ignition::math::Pose3d pose = this->actor->GetWorldPose().Ign();
ignition::math::Vector3d pos = this->target - pose.Pos();
ignition::math::Vector3d rpy = pose.Rot().Euler();
double distance = pos.Length();
// Choose a new target position if the actor has reached its current
// target.
if (distance < 0.3)
{
this->ChooseNewTarget();
pos = this->target - pose.Pos();
}
它首先檢查當(dāng)前信息,如時(shí)間和演員姿勢(shì)。如果它已經(jīng)到達(dá)目標(biāo)目的地,選擇一個(gè)新目的地。
// Normalize the direction vector, and apply the target weight
pos = pos.Normalize() * this->targetWeight;
// Adjust the direction vector by avoiding obstacles
this->HandleObstacles(pos);
// Compute the yaw orientation
ignition::math::Angle yaw = atan2(pos.Y(), pos.X()) + 1.5707 - rpy.Z();
yaw.Normalize();
// Rotate in place, instead of jumping.
if (std::abs(yaw.Radian()) > GZ_DTOR(10))
{
pose.Rot() = ignition::math::Quaterniond(1.5707, 0, rpy.Z()+
yaw.Radian()*0.001);
}
else
{
pose.Pos() += pos * this->velocity * dt;
pose.Rot() = ignition::math::Quaterniond(1.5707, 0, rpy.Z()+yaw.Radian());
}
// Make sure the actor stays within bounds
pose.Pos().X(std::max(-3.0, std::min(3.5, pose.Pos().X())));
pose.Pos().Y(std::max(-10.0, std::min(2.0, pose.Pos().Y())));
pose.Pos().Z(1.2138);
然后繼續(xù)計(jì)算目標(biāo)姿勢(shì),同時(shí)考慮障礙物并確保我們有平穩(wěn)的運(yùn)動(dòng)。以下步驟是最重要的,因?yàn)樗鼈兩婕疤囟ㄓ赼ctor的API。
// Distance traveled is used to coordinate motion with the walking
// animation
double distanceTraveled = (pose.Pos() -
this->actor->GetWorldPose().Ign().Pos()).Length();
this->actor->SetWorldPose(pose, false, false);
this->actor->SetScriptTime(this->actor->ScriptTime() +
(distanceTraveled * this->animationFactor));
this->lastUpdate = _info.simTime;
}
首先將actor的世界姿勢(shì)設(shè)置為靜態(tài)模型SetWorldPose。但這不會(huì)觸發(fā)動(dòng)畫(huà)。這是通過(guò)告訴演員它的骨架動(dòng)畫(huà)應(yīng)該在哪個(gè)點(diǎn)來(lái)完成的SetScriptTime。
總之,在編寫(xiě)自己的插件時(shí),可以使用您選擇的邏輯在每個(gè)時(shí)間步驟定義所需的姿勢(shì)。另外,不要忘記選擇適當(dāng)?shù)哪_本時(shí)間來(lái)同步動(dòng)畫(huà)。在此處查看該類?的完整API?。physics::Actor
中級(jí)教程:連接到ROS 1.0
概述
Velodyne傳感器功能齊全,但沒(méi)有像ROS這樣的機(jī)器人中間件的插件。使用Gazebo和ROS的好處之一是它可以在現(xiàn)實(shí)世界和模擬世界之間輕松切換。為了實(shí)現(xiàn)這一目標(biāo),需要讓我們的傳感器與ROS生態(tài)系統(tǒng)很好地配合。
添加ROS傳輸
修改當(dāng)前的插件以包含ROS傳輸機(jī)制,其方式與我們?cè)谇耙粋€(gè)教程中添加Gazebo傳輸機(jī)制的方式類似。
我們假設(shè)您的系統(tǒng)上當(dāng)前已經(jīng)安裝了ROS。
將頭文件添加到文件中。velodyne_plugin.cc
#include
#include "ros/ros.h"
#include "ros/callback_queue.h"
#include "ros/subscribe_options.h"
#include "std_msgs/Float32.h"
向插件添加一些成員變量。
/// \brief A node use for ROS transport
private: std::unique_ptr
/// \brief A ROS subscriber
private: ros::Subscriber rosSub;
/// \brief A ROS callbackqueue that helps process messages
private: ros::CallbackQueue rosQueue;
/// \brief A thread the keeps running the rosQueue
private: std::thread rosQueueThread;
在Load函數(shù)結(jié)束時(shí),添加以下內(nèi)容。
// Initialize ros, if it has not already bee initialized.
if (!ros::isInitialized())
{
int argc = 0;
char **argv = NULL;
ros::init(argc, argv, "gazebo_client",
ros::init_options::NoSigintHandler);
}
// Create our ROS node. This acts in a similar manner to
// the Gazebo node
this->rosNode.reset(new ros::NodeHandle("gazebo_client"));
// Create a named topic, and subscribe to it.
ros::SubscribeOptions so =
ros::SubscribeOptions::create
"/" + this->model->GetName() + "/vel_cmd",
1,
boost::bind(&VelodynePlugin::OnRosMsg, this, _1),
ros::VoidPtr(), &this->rosQueue);
this->rosSub = this->rosNode->subscribe(so);
// Spin up the queue helper thread.
this->rosQueueThread =
std::thread(std::bind(&VelodynePlugin::QueueThread, this));
如果仔細(xì)閱讀代碼,會(huì)注意到需要兩個(gè)新功能:OnRosMsg和QueueThread。現(xiàn)在加上這些。
/// \brief Handle an incoming message from ROS
/// \param[in] _msg A float value that is used to set the velocity
/// of the Velodyne.
public: void OnRosMsg(const std_msgs::Float32ConstPtr &_msg)
{
this->SetVelocity(_msg->data);
}
/// \brief ROS helper function that processes messages
private: void QueueThread()
{
static const double timeout = 0.01;
while (this->rosNode->ok())
{
this->rosQueue.callAvailable(ros::WallDuration(timeout));
}
}
要處理的最后一項(xiàng)是cmake構(gòu)建。
打開(kāi)。CMakeLists.txt
修改文件的頂部部分如下所示。
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
find_package(roscpp REQUIRED)
find_package(std_msgs REQUIRED)
include_directories(${roscpp_INCLUDE_DIRS})
include_directories(${std_msgs_INCLUDE_DIRS})
修改插件的目標(biāo)鏈接庫(kù)。
target_link_libraries(velodyne_plugin ${GAZEBO_LIBRARIES} ${roscpp_LIBRARIES})
現(xiàn)在應(yīng)該是這樣的。CMakeLists.txt
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
find_package(roscpp REQUIRED)
find_package(std_msgs REQUIRED)
include_directories(${roscpp_INCLUDE_DIRS})
include_directories(${std_msgs_INCLUDE_DIRS})
# Find Gazebo
find_package(gazebo REQUIRED)
include_directories(${GAZEBO_INCLUDE_DIRS})
link_directories(${GAZEBO_LIBRARY_DIRS})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GAZEBO_CXX_FLAGS}")
# Build our plugin
add_library(velodyne_plugin SHARED velodyne_plugin.cc)
target_link_libraries(velodyne_plugin ${GAZEBO_LIBRARIES} ${roscpp_LIBRARIES})
# Build the stand-alone test program
add_executable(vel vel.cc)
if (${gazebo_VERSION_MAJOR} LESS 6)
include(FindBoost)
find_package(Boost ${MIN_BOOST_VERSION} REQUIRED system filesystem regex)
target_link_libraries(vel ${GAZEBO_LIBRARIES} ${Boost_LIBRARIES})
else()
target_link_libraries(vel ${GAZEBO_LIBRARIES})
endif()
確保已經(jīng)成功配置好ROS:
source /opt/ros/
重新編譯插件。
cd ~/velodyne_plugin/build
cmake ../
make
從ROS控制Velodyne
我們現(xiàn)在可以像往常一樣加載Gazebo插件,它將監(jiān)聽(tīng)ROS主題以獲取傳入的浮動(dòng)消息。然后,這些消息將用于設(shè)置Velodyne的旋轉(zhuǎn)速度。
開(kāi)始?roscore
source /opt/ros/
roscore
在新的終端,啟動(dòng)Gazebo
cd ~/velodyne_plugin/build
source /opt/ros/
gazebo ../velodyne.world
在新終端中,用于rostopic發(fā)送速度消息。
source /opt/ros/
rostopic pub /my_velodyne/vel_cmd std_msgs/Float32 1.0
更改上述命令的最后一個(gè)數(shù)字以設(shè)置不同的速度。
結(jié)論
恭喜,現(xiàn)在擁有構(gòu)建自定義模型,共享模型和生成公共API的工具。玩得開(kāi)心,快樂(lè)模擬!
機(jī)器人
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。