ROSIntegration ROSIntegrationVision与虚幻引擎4(Unreal Engine 4)的配置

ROSIntegration ROSIntegrationVision与虚幻引擎4(Unreal Engine 4)的配置

操作系统:Ubuntu 18.04

虚幻引擎:4.26.2

 

一、虚幻引擎源代码下载与编译运行

参照官方文档:虚幻引擎Linux快速入门

 

二、ROSIntegration下载与配置运行

1、配置ROSBridge

要启用虚幻和ROS之间的通信,需要一个正在运行的ROSBridge和bson_mode

注意:请使用 rosbridge 版本=>0.8.0 以获得完整的 BSON 支持

安装rosbridge的推荐方法是在ROS工作空间使用源代码进行编译,即把rosbridge作为其中一个功能包,按照如下命令顺序执行

sudo apt-get install ros-ROS1_DISTRO-rosauth # 将 ROS1_DISTRO 替换为ROS对应的版本名称
cd ~/ros_workspace/ # 替换 ros_workspace 为工作空间目录名称
source devel/setup.bash
cd src/
git clone -b ros1 https://github.com/RobotWebTools/rosbridge_suite.git
cd ..
catkin_make
source devel/setup.bash

此外,ROSIntegration使用包含在PyMongo包中的BSON,可以单独安装

sudo pip3 install pymongo

 

2、配置ROSIntegration

使用git命令下载ROSIntegration,放置在虚幻引擎项目文件Plugins文件夹下

cd unreal_engine_project # 替换 unreal_engine_project 为项目目录文件夹路径
mkdir Plugins # 如果没有 Plugins 文件夹则手动创建
cd Plugins
git clone https://github.com/code-iai/ROSIntegration.git

此时,ROSIntegration在虚幻项目中的文件结构如下:

unreal_engine_project/Plugins/ROSIntegration/ROSIntegration.uplugin

 

在虚幻引擎源代码UnrealEngine下的Engine/Source/Developer/DesktopPlatform/Private/DesktopPlatformBase.cpp文件中执行此操作

查找此行:

Arguments += " -Progress -NoEngineChanges -NoHotReloadFromIDE";

替换为:

Arguments += " -Progress";

然后重新编译引擎:

cd UnrealEngine
./Setup.sh
./GenerateProjectFiles.sh
make

 

编译完成后,启动项目并接受重建

(如果不进行上述步骤可能会遇到虚幻引擎自建项目打不开或遇到engine modules are out of date and cannot be compiled while the engine is running的情况)

 

创建一个新的C++虚幻项目,或打开现有项目

新建

新建

在内容浏览器中查找(在内容浏览器的右下角启用“查看选项”>“显示插件内容”)

点击“添加/导入”按钮下方的三条线按钮,展开左侧区域

选中“ROSIntegration“>“Classes”,右键ROSIntegrationGameInstance,点击下图黄色选项

在这里插入图片描述

打开新的C++类/蓝图对象,并更改ROSBridgeSeverHostROSBridgeServerPort,如果是本地运行的ROSBridge,则改为127.0.0.1即可

在这里插入图片描述

打开“地图和模式”>“项目设置”,并将游戏实例设置为与新的游戏实例对象匹配,比如MyROSIntegrationGameInstance,而不是插件中的ROSIntegrationGameInstance

在这里插入图片描述

使用Ctrl + Shift + S保存所有更改

 

3、使用ROSIntegration

要进行与 ROS 的简单发布/订阅通信,需要在创建一个新的C++ Actor,而非中文的角色(Charactor)。
接着创建 SamplePubliser

SamplePublisher.h
#include "ROSIntegration/Classes/RI/Topic.h"
#include "ROSIntegration/Classes/ROSIntegrationGameInstance.h"
#include "ROSIntegration/Public/std_msgs/String.h"

注意:上述代码必须在#include "SamplePublisher.generated.h"之前,否则会报错

SamplePublisher.cpp
// Initialize a topic
UTopic *ExampleTopic = NewObject<UTopic>(UTopic::StaticClass());
UROSIntegrationGameInstance* rosinst = Cast<UROSIntegrationGameInstance>(GetGameInstance());
ExampleTopic->Init(rosinst->ROSIntegrationCore, TEXT("/example_topic"), TEXT("std_msgs/String"));

// (Optional) Advertise the topic
ExampleTopic->Advertise();

// Publish a string to the topic
TSharedPtr<ROSMessages::std_msgs::String> StringMessage(new ROSMessages::std_msgs::String("This is an example"));
ExampleTopic->Publish(StringMessage);

注意:上述代码放置在BeginPlay()函数中

 

进入unreal_engine_project/Source/unreal_engine_project目录(替换 unreal_engine_project 为真实的项目名称),打开unreal_engine_project.Build.cs文件

找到:

		PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });

添加ROSIntegrationy依赖,形如:

		PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "ROSIntegration" });

 

进入ROS工作空间的src目录,创建测试功能包:

catkin_create_pkg ue_test std_msgs rospy roscpp

编译并source:

catkin_make
source devel/setup.bash

创建一个监听者cpp文件:

cd ue_test/src
touch listener.cpp

打开cpp并键入如下代码:

#include "ros/ros.h"
#include "std_msgs/String.h"

/**
 * This tutorial demonstrates simple receipt of messages over the ROS system.
 */
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
  ROS_INFO("I heard: [%s]", msg->data.c_str());
}

int main(int argc, char **argv)
{
  /**
   * The ros::init() function needs to see argc and argv so that it can perform
   * any ROS arguments and name remapping that were provided at the command line.
   * For programmatic remappings you can use a different version of init() which takes
   * remappings directly, but for most command-line programs, passing argc and argv is
   * the easiest way to do it.  The third argument to init() is the name of the node.
   *
   * You must call one of the versions of ros::init() before using any other
   * part of the ROS system.
   */
  ros::init(argc, argv, "listener");

  /**
   * NodeHandle is the main access point to communications with the ROS system.
   * The first NodeHandle constructed will fully initialize this node, and the last
   * NodeHandle destructed will close down the node.
   */
  ros::NodeHandle n;

  /**
   * The subscribe() call is how you tell ROS that you want to receive messages
   * on a given topic.  This invokes a call to the ROS
   * master node, which keeps a registry of who is publishing and who
   * is subscribing.  Messages are passed to a callback function, here
   * called chatterCallback.  subscribe() returns a Subscriber object that you
   * must hold on to until you want to unsubscribe.  When all copies of the Subscriber
   * object go out of scope, this callback will automatically be unsubscribed from
   * this topic.
   *
   * The second parameter to the subscribe() function is the size of the message
   * queue.  If messages are arriving faster than they are being processed, this
   * is the number of messages that will be buffered up before beginning to throw
   * away the oldest ones.
   */
  ros::Subscriber sub = n.subscribe("/example_topic", 1000, chatterCallback);

  /**
   * ros::spin() will enter a loop, pumping callbacks.  With this version, all
   * callbacks will be called from within this thread (the main one).  ros::spin()
   * will exit when Ctrl-C is pressed, or the node is shutdown by the master.
   */
  ros::spin();

  return 0;
}

在CMakeLists.txt添加:

add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})
add_dependencies(listener listener)

 

4、测试ROSIntegration

启动rosbridge

roslaunch rosbridge_server rosbridge_tcp.launch bson_only_mode:=True

运行新建功能包的监听者

# rosrun <your package> listener 
# 比如
rosrun ue_test listener 

将在UE中新建的SamplePublisher托入三维世界中,并点击运行

此时可以看到:

[INFO] [1588662504.536355639]: I heard: [This is an example]

 

恭喜你成功配置并运行了ROSIntegration!!!

  

三、ROSIntegrationVision下载与配置运行

1、虚幻引擎配置修改

在PATH_TO_UNREAL/Engine/Source/Programs/UnrealBuildTool/Platform/Linux/LinuxToolChain.cs中找到GetCLArguments_Global函数,并在其中添加语句Result += " -mf16c";,形如:

		protected virtual string GetCLArguments_Global(CppCompileEnvironment CompileEnvironment)
		{
			string Result = "";

			// build up the commandline common to C and C++
			Result += " -c";
			Result += " -pipe";
            Result += " -mf16c";

			if (ShouldUseLibcxx(CompileEnvironment.Architecture))
			{
				Result += " -nostdinc++";
				Result += " -I" + "ThirdParty/Linux/LibCxx/include/";
				Result += " -I" + "ThirdParty/Linux/LibCxx/include/c++/v1";
			}

而后重新编译虚幻引擎(注意如下语句必须都执行才算是重新编译):

cd UnrealEngine
./Setup.sh
./GenerateProjectFiles.sh
make

 

2、配置ROSIntegrationVision

使用git命令下载ROSIntegrationVision,放置在虚幻引擎项目文件Plugins文件夹下

cd unreal_engine_project # 替换 unreal_engine_project 为项目目录文件夹路径
mkdir Plugins # 如果没有 Plugins 文件夹则手动创建
cd Plugins
git clone https://github.com/code-iai/ROSIntegrationVision/.git

 

如果你是在Linux上编译虚幻引擎4而非Windows,则在打开项目时可能会遇到

Building forest2Editor...
Performing 3 actions (6 in parallel)
[1/3] Compile Module.ROSIntegrationVision.cpp
In file included from .../Plugins/ROSIntegrationVision/Intermediate/Build/Linux/B4D820EA/UE4Editor/Development/ROSIntegrationVision/Module.ROSIntegrationVision.cpp:6:
.../Plugins/ROSIntegrationVision/Source/ROSIntegrationVision/Private/VisionComponent.cpp:754:4: error: use of undeclared identifier '_mm_div_epi16'; did you mean '_mm_min_epi16'?
_mm_div_epi16(
^~~~~~~~~~~~~
_mm_min_epi16
/home/pisces/Gitware/UnrealEngine/Engine/Extras/ThirdPartyNotUE/SDKs/HostLinux/Linux_x64/v17_clang-10.0.1-centos7/x86_64-unknown-linux-gnu/lib/clang/10.0.1/include/emmintrin.h:2412:1: note: '_mm_min_epi16' declared here
_mm_min_epi16(__m128i __a, __m128i __b)
^
1 error generated.
LogInit: Warning: Still incompatible or missing module: ROSIntegrationVision

这是由于官方参考了Windows for UVisionComponent上的编译问题::convertDepth #28这一问题的回答,将源码改为了适配Windows的环境,但在Ubuntu18.04中并不存在_mm_div_epi16这一函数

因而,改变代码

void UVisionComponent::convertDepth(const uint16_t *in, __m128 *out) const
{
  const size_t size = (Width * Height) / 4;
  for (size_t i = 0; i < size; ++i, in += 4, ++out)
  {
    // Divide by 100 here in order to convert UU (cm) into ROS units (m)
    *out = _mm_cvtph_ps(
      _mm_div_epi16(
        _mm_set_epi16(0, 0, 0, 0, *(in + 3), *(in + 2), *(in + 1), *(in + 0)),
        _mm_set_epi16(100, 100, 100, 100, 100, 100, 100, 100)
      )
    );// / 100;
  }
}

void UVisionComponent::convertDepth(const uint16_t *in, __m128 *out) const
{
  const size_t size = (Width * Height) / 4;
  for (size_t i = 0; i < size; ++i, in += 4, ++out)
  {
    // Divide by 100 here in order to convert UU (cm) into ROS units (m)
    *out = _mm_cvtph_ps(_mm_set_epi16(
      0, 0, 0, 0, *(in + 3), *(in + 2), *(in + 1), *(in + 0))) / 100;
  }
}

即可成功自动编译打开项目

 

3、使用ROSIntegrationVision

在内容浏览器ROSIntegrationVision/ROSIntegrationVision/Private中包含VisionActor C++文件,将其托入三维世界中即可现实摄像头图像信息

 

4、问题

注意:使用时需要先在VisionActor.cpp中作如下修改

AVisionActor::AVisionActor() : AActor()
{
	UE_LOG(LogTemp, Warning, TEXT("VisionActor CTOR"));

	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;
    
    RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("Root"));
    SetRootComponent(RootComponent);
    
    vision = CreateDefaultSubobject<UVisionComponent>(TEXT("Vision"));
    vision->DisableTFPublishing = true;   // 添加
    //vision->ParentLink = "/world";   注释掉
    vision->ParentLink = "desired_link";  // 添加
    vision->SetupAttachment(RootComponent);
}

将ROSIntegrationVision插件中的Binaries和Intermediate文件夹删除,重新打开项目,使引擎重新编译插件

 

如果在运行rosbridge时遇到如下问题

在这里插入图片描述

可以修改ROSIntegration/Source/ROSIntegration/Private/Conversion/Messages/sensor_msgs/SensorMsgsCameraInfoConverter.h文件

替换

	static void _bson_append_camera_info(bson_t *b, const ROSMessages::sensor_msgs::CameraInfo *msg)
	{
		// assert(CastMsg->D.Num() == 5); // TODO: use Unreal assertions
		assert(CastMsg->K.Num() == 9); // TODO: use Unreal assertions
		assert(CastMsg->R.Num() == 9);
		assert(CastMsg->P.Num() == 12);
		
		UStdMsgsHeaderConverter::_bson_append_child_header(b, "header", &msg->header);
		BSON_APPEND_INT32(b, "height", msg->height);
		BSON_APPEND_INT32(b, "width", msg->width);
		BSON_APPEND_UTF8(b, "distortion_model", TCHAR_TO_UTF8(*msg->distortion_model));
		_bson_append_double_tarray(b, "d", msg->D);
		_bson_append_double_tarray(b, "k", msg->K);
		_bson_append_double_tarray(b, "r", msg->R);
		_bson_append_double_tarray(b, "p", msg->P);	
		BSON_APPEND_INT32(b, "binning_x", msg->binning_x);
		BSON_APPEND_INT32(b, "binning_y", msg->binning_y);
		USensorMsgsRegionOfInterestConverter::_bson_append_child_roi(b, "roi", &msg->roi);
	}

	static void _bson_append_camera_info(bson_t *b, const ROSMessages::sensor_msgs::CameraInfo *msg)
	{
		// assert(CastMsg->D.Num() == 5); // TODO: use Unreal assertions
		assert(CastMsg->K.Num() == 9); // TODO: use Unreal assertions
		assert(CastMsg->R.Num() == 9);
		assert(CastMsg->P.Num() == 12);
		
		UStdMsgsHeaderConverter::_bson_append_child_header(b, "header", &msg->header);
		BSON_APPEND_INT32(b, "height", msg->height);
		BSON_APPEND_INT32(b, "width", msg->width);
		BSON_APPEND_UTF8(b, "distortion_model", TCHAR_TO_UTF8(*msg->distortion_model));
		_bson_append_double_tarray(b, "D", msg->D); // 替换
		_bson_append_double_tarray(b, "K", msg->K); // 替换
		_bson_append_double_tarray(b, "R", msg->R); // 替换
		_bson_append_double_tarray(b, "P", msg->P);	// 替换
		BSON_APPEND_INT32(b, "binning_x", msg->binning_x);
		BSON_APPEND_INT32(b, "binning_y", msg->binning_y);
		USensorMsgsRegionOfInterestConverter::_bson_append_child_roi(b, "roi", &msg->roi);
	}

 

如果相机图象FPS较低,可以考虑修改VisionComponent.cpp中 Framerate(1)Framerate(100)

UVisionComponent::UVisionComponent() :
Width(640),
Height(480),
Framerate(100),    // change 1 to 100
UseEngineFramerate(false),
ServerPort(10000),
FrameTime(1.0f / Framerate),
TimePassed(0),
ColorsUsed(0)

 

四、参考资料

[1] code-iai/ROSIntegration markdown说明文档及issues

[2] code-iai/ROSIntegrationVision markdown说明文档及issues

[3] ROS Communication Sample on Unreal Engine Using ROSIntegration

[4] upgrade c++ project from ue 4.24 to 4.25 under Linux

部分图片来源于网络

  


转载请注明出处!

本篇发布在以下博客或网站:

双鱼座羊驼 - 知乎 (zhihu.com)

双鱼座羊驼的博客_CSDN博客

双鱼座羊驼 - SegmentFault 思否

双鱼座羊驼 的个人主页 - 动态 - 掘金 (juejin.cn)

双鱼座羊驼 - 博客园 (cnblogs.com)

 

  • 30
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Unreal Engine 4 for Beginners, as its name implies, is specifically written with the beginner in mind. It is meant for those who wish to learn how to make video games with no prior game development, game design, or game programming experience. It concentrates on the fundamentals, in order to build a rock solid foundation upon which the reader can use to confidently explore more intermediate and advanced topics. It provides a thorough examination of the basics, covering each subject in fine detail. Great care has been taken to ad vance through the subject matter in an order that best ensures that everything needed to understand one piece of information has already been covered in the information prior. It makes a great textbook for an Intro to Unreal Engine, or Unreal Engine 101 course. In addition, the book has been formatted specifically for ease of use with tablets and other mobile devices. The book concentrates heavily on four key areas: Environments - Construct beautiful environments with moving objects and sounds Inputs - Enter and explore the worlds you construct by creating a Character and specifying how it can move and how to control those movements Menus & Displays - Learn how to create the user interfaces and on-screen displays that will enhance your game and bring it to the next level Logic - Learn how to construct logic and take full control over the first three subject areas. How should objects in your world move? What should cause a certain sound to play? How does the player win the game? You decide! No need to wait for shipping! Get started learning the fundamentals of game development right now with this specially formatted ebook textbook! Table of Contents Chapter 1 Getting Started Chapter 2 Basic Concepts Chapter 3 The Level Editor Chapter 4 Actors Chapter 5 Blueprints Chapter 6 Players & Input Chapter 7 Collisions Chapter 8 User Interfaces Chapter 9 Audio Chapter 10 Additional Topics Book Details QR code for Unreal Engine 4 for Beginners Title: Unreal Engine 4 for Beginners 收缩
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

双鱼座羊驼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值