moos-ivp安装与使用
moos-ivp是一种基于C++的开源软件,用于构建和管理大型海洋机器人系统
其提供了一种分布式的、基于消息的架构,用于传输数据和控制命令
本文介绍了moos-ivp的特点、应用、安装以及一些基本的使用方法
moos-ivp简介
moos-ivp是一种用于海洋无人系统的开源软件平台,基于C++的,是MOOS (Mission Oriented Operating Suite) 和 IvP (Interval Programming) 的组合。项目位于麻省理工学院机械工程系和海洋工程中心,是自主海洋传感系统实验室(LAMSS)的一部分。核心开发人员也是麻省理工学院计算机科学和人工智能实验室 (CSAIL) 的一部分。核心MOOS软件由牛津机器人研究所(ORI)维护和分发。
相关文档
特点
分布式架构:提供了一种分布式的、基于消息的架构,用于传输数据和控制命令,模块之间通过发布-订阅机制进行通信。如下图所示MOOSDB是一个用于存储和传输消息的数据库,支持多种消息类型,供各个模块进行订阅和发布。
模块化设计:允许开发者编写独立的模块(MOOSApp)来执行特定的任务,如导航、控制、感知等。模块之间通过消息传递进行通信,使得系统易于扩展和维护。
IvP技术:集成了IvP技术,用于路径规划和控制。IvP基于区间理论,将不确定性和环境变化考虑在内,通过动态地调整路径和控制策略来适应环境。
开源软件:moos-ivp是开源软件,可以免费获取和使用。它提供了一套完整的开发工具和文档,方便开发者进行开发和调试。
应用
MOOS-IvP平台可以应用于多个领域和场景,包括但不限于以下几个方面:
海洋勘测和测绘:利用无人船、无人潜水器等装备,对海洋环境进行测量、探测和地图绘制,用于海洋资源调查、海底地形测绘、水文气象监测等任务。
水下探测与调查:通过搭载各种传感器的无人潜水器,对海洋底部、水体中的物理、化学和生物信息进行监测和研究,用于海洋科学研究、生态环境保护等领域。
海洋环境监测:部署无人系统进行海洋环境参数的实时监测,如水质、海洋污染、水下声学环境等,为海洋生态保护、海洋灾害预警等提供数据支持。
海洋安全与国防:利用无人船、无人潜水器等执行巡逻、监视、搜索和搜救任务,加强对海洋领域的监控与管控,提升海洋安全和国防能力。
安装MOOS
moos-ivp-22.8已在Ubuntu 18.04 LTS及Ubuntu 20.04 LTS上进行了测试,可以通过以下步骤进行安装。
下载MOOS
首先,在目标目录下打开一个终端,输入以下命令,下载moos-ivp-22.8的源代码:
1
svn co https://oceanai.mit.edu/svn/moos-ivp-aro/releases/moos-ivp-22.8 moos-ivp
如果提示没有安装svn,可以在终端中输入sudo apt install subversion -y
,然后再执行上面的命令下载源代码。
安装依赖项
源代码下载完成后,在终端中继续输入以下命令,安装moos-ivp-22.8所有的依赖项:1 | sudo apt-get install g++ subversion xterm cmake libfltk1.3-dev freeglut3-dev libpng-dev libjpeg-dev libxft-dev libxinerama-dev libtiff5-dev -y |
g++是GNU的C++编译器
subversion是一个开源的版本控制系统
xterm是一个终端模拟器
cmake是一个跨平台的自动化建构系统
libfltk1.3-dev是FLTK图形库的开发包
freeglut3-dev是OpenGL的开发包
libpng-dev是PNG图像格式的开发包
libjpeg-dev是JPEG图像格式的开发包
libxft-dev是X FreeType库的开发包
libxinerama-dev是Xinerama库的开发包
libtiff5-dev是TIFF图像格式的开发包。
编译MOOS
首先cd到moos-ivp路径 生成MOOS的链接文件,方便编译
这样moos-ivp路径下增加了MOOS文件夹,打开MOOS文件夹等同于打开MOOS_Jul0519文件夹。1
2cd moos-ivp
ln -s MOOS_Jul0519 MOOS然后在终端中继续输入以下命令,开始编译moos-ivp:
参数1
2./build-moos.sh -j # 编译moos下的文件
./build-ivp.sh -j #编译ivp下的文件-j
表示使用多线程编译,可以加快编译速度。
编译完成后,会在目录下生成bin文件夹,里面包含了moos-ivp的可执行文件。以后创建的MOOSApp模块的可执行文件,也会自动存放在这个文件夹下。
- 添加可执行文件路径 终端输入
gedit ~/.bashrc
(~
在ubuntu下代表主目录),最后一行增加export PATH=$PATH:~/moos-ivp/bin
,保存并退出。
export PATH=$PATH:~/moos-ivp/bin
这行命令中~/
后面要根据moos-ivp所在的路径进行修改
比如我是在home下的project文件夹下,所以是export PATH=$PATH:~/project/moos-ivp/bin
如果你是在home下的moos-ivp文件夹下,那就是export PATH=$PATH:~/moos-ivp/bin
source ~/.bashrc
使其生效。这样就可以在终端中直接输入可执行文件名,而不用输入完整的路径了。
运行示例
官方提供了一些示例,可以用来测试moos-ivp是否安装成功。在终端中输入以下命令,运行一个示例: 1
2cd moos-ivp/ivp/missions/s1_alpha #进入示例文件夹
pAntler alpha.moos
如果提示moos-ivp/ivp/missions/s1_alpha: 没有那个文件或目录
,请检查cd
的路径是否正确。
使用MOOS
下面介绍一些MOOS的基本使用方法,包括MOOS的开发、基本模块的配置和MOOS的调试。
MOOS的开发
开发一个MOOSApp模块,需要继承自CMOOSApp
类,然后实现一些函数,包括OnStartUp()
、OnNewMail()
、Iterate()
等。下面以一个简单的模块为例,简单介绍一下MOOSApp的开发。
创建MOOSApp
在moos-ivp中可以使用GenMOOSApp
命令创建一个新的MOOSApp模块。在moos-ivp/ivp/src
目录下(推荐在src下新建一个文件夹,方便代码管理)打开终端输入GenMOOSApp Example p "Bean"
,会在终端所在目录下生成一个名为pExample
的文件夹,里面包含了一个新的MOOSApp的源代码,之后可以在这个文件夹下进行开发。
Example
为MOOSApp的名称
p
为文件夹的前缀
“Bean”
为作者署名
消息的发布和订阅
消息的订阅与发布是MOOSApp模块之间进行通信的基本方式。在MOOSApp中,可以通过Register()
函数进行消息的订阅,通过Notify()
函数进行消息的发布,下面我们以刚创建好的pExample
模块为例,介绍一下消息的发布和订阅,以及整个代码的运行流程。
打开头文件可以看到模板APP自动创建了一个继承自CMOOSApp
的Example
类,public表示这里是公有继承。接着定义了一些函数,包括OnStartUp()
、OnNewMail()
、Iterate()
、OnConnectToServer()
。
OnStartUp()函数是在程序启动时,还未进入
Iterate()
函数之前调用的,用于实现程序初始化,特别是从文件中读取配置参数。里面调用了函数registerVariables()
,用于注册需要订阅的消息。下面是1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24bool Example::OnStartUp()
{
printf("OnStartUp\n");
list<string> sParams;
m_MissionReader.EnableVerbatimQuoting(false);
if(m_MissionReader.GetConfiguration(GetAppName(), sParams)) {
list<string>::iterator p;
for(p=sParams.begin(); p!=sParams.end(); p++) {
string line = *p;
string param = tolower(biteStringX(line, '='));
string value = line;
if(param == "foo") {
//handled
}
else if(param == "bar") {
//handled
}
}
}
RegisterVariables();
return(true);
}RegisterVariables()
函数的定义,用于注册需要订阅的消息。在这个函数中,调用了Register()
函数,注册了一个名为“A”的消息。当有新的“A”消息到来时,OnNewMail()
函数便会被调用。1
2
3
4void Example::RegisterVariables()
{
Register("A", 0);
}Iterate()函数是程序的主循环函数,用于执行一些周期性的任务,通常在这里编写此模块负责执行的工作。配置文件
.moos
中的AppTick
参数决定了这个函数的最大调用频率。在下面的代码中,我们通过Notify()
函数发布了一个名为“A”的消息,消息的内容是一个double
类型的变量x
,值为12
。
1 | bool Example::Iterate() |
- OnNewMail()函数是在程序接收到新消息时调用的,用于处理新消息。(在调用
Iterate()
函数之前,CMOOSApp
基类会检查是否有新的邮件,如果有新的邮件,CMOOSApp
基类会调用OnNewMail()
) 在下面的代码中,通过GetKey()
函数获取了消息的变量名,然后通过GetDouble()
函数获取了消息的值,并将值乘以2,然后通过Notify()
函数发布了一个名为“B”的消息,消息的内容是一个double
类型的变量y
,值为x
的两倍,如果顺利的话,我们可以在MOOSDB中看到名为B
的消息,消息的值为24
。
由于消息B
只是发布没有涉及到订阅,所以不必在Iterate()
函数中订阅消息B
。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 bool Example::OnNewMail(MOOSMSG_LIST &NewMail)
{
MOOSMSG_LIST::iterator p;
printf("OnNewMail\n");
for(p=NewMail.begin(); p!=NewMail.end(); p++) {
CMOOSMsg &msg = *p;
string key = msg.GetKey();
if(key == "A") {
double y = msg.GetDouble() * 2;
Notify("B", y);
}
string key = msg.GetKey(); //获取消息的变量名
string comm = msg.GetCommunity(); //获取消息的来源-配置文件中定义的Community
double dval = msg.GetDouble(); //获取double类型变量的值
string sval = msg.GetString(); //获取string类型变量的值
string msrc = msg.GetSource(); //获取消息的源头-即MOOSApp的名称
double mtime = msg.GetTime(); //获取消息发出的时间
bool mdbl = msg.IsDouble(); //判断消息是否为double类型
bool mstr = msg.IsString(); //判断消息是否为string类型
}
return(true);
}
OnConnectToServer()意义不明,暂时不用管。
1
2
3
4
5bool Example::OnConnectToServer()
{
RegisterVariables();
return(true);
}
编译和运行
- 编译: 函数编写完成后,我们需要编译这个模块,回到moos-ivp文件夹下,打开终端输入
./build-ivp.sh -j
,编译完成后,我们可以在bin文件夹下找到pExample
可执行文件。
- 运行: 首先打开一个终端输入
MOOSDB
启动MOOS;
然后在pExample
所在的文件夹下打开终端输入pExample pExample.moos
,程序开始运行;
如果想要监测消息的状态,可以打开另一个终端输入uMS
,可以看到消息的发布和订阅情况。
如下图所示,在MOOSDB中看到名为“A”和“B”的消息,类型为D-Double,消息的值分别为12和24。
基本模块的配置
moos-ivp提供了一些基本的模块,如pShare、plogger、pAntler等,下面我们介绍一下这些模块的基本使用方法。
pShare模块
pShare模块是一个用于共享数据的模块,可以将数据共享给其他服务器,它基于UDP协议,通过网络进行数据传输。 使用起来非常简单,只需要在下文介绍的pAntler的配置文件中添加以下配置即可。
- 主机1的配置文件:
1
2
3
4
5
6
7
8
9
10
11
12ProcessConfig = pShare
{
AppTick = 4
CommsTick = 4
input = route = localhost:9201
output=src_name=CONTROL_MSG,route=192.168.0.10:9200
output=src_name=CONFIG_MSG,route=192.168.0.10:9200
output=src_name=DEBUG_MSG,route=192.168.0.10:9200
output=src_name=MISSION_MSG,route=192.168.0.10:9200
}input = route = localhost:9201表示从本地服务器的9201端口接收数据
#output
表示输出消息。src_name
表示消息的名称
route
表示输出消息的目的地,可以有多个目的地,用&
分隔。
如route=192.168.0.10:9200&192.168.0.11:9200 - 主机2的配置文件: 上面的配置文件便把同一局域网内的两台主机连接起来了,主机1的pShare模块将CONTROL_MSG、CONFIG_MSG、DEBUG_MSG、MISSION_MSG发送到主机2的pShare模块,主机2的pShare模块将NET_MSG、NETSTA_MSG发送到主机1的pShare模块,这样两台主机之间就可以进行通讯了。
1
2
3
4
5
6
7
8ProcessConfig = pShare
{
AppTick = 4
CommsTick = 4
input = route = localhost:9200
output=src_name=NET_MSG,route=192.168.0.100:9201
output=src_name=NETSTA_MSG,route=192.168.0.100:9201
}
plogger模块
plogger模块是一个用于记录数据的模块,可以将数据记录到文件中,方便后续分析。 同样,只需要在MOOSApp的配置文件中添加以下几行代码即可。
1 | ProcessConfig = pLogger |
pAntler模块
pAntler模块是一个用于控制MOOSApp的模块,可以一次性启动多个MOOSApp。像上文,我们运行一个pExample
程序需要打开三个终端,分别启动MOOSDB、pExample和uMS,实际情况下可能需要启动多个程序,这样一个个打开终端启动是不现实的。pAntler可以通过配置文件一次性启动多个模块,非常方便。 我们把上文的pExample
模块的配置文件的内容修改如下:
1 | ServerHost = localhost #服务器的IP地址,如果是本地服务器,可以不用修改 |
然后在此路径的终端中输入pAntler pExample.moos
,就可以一次性启动MOOSDB、pExample和uMS了。
MOOS的调试
当开发完一个MOOSApp模块后,我们需要对其进行调试,以确保其正常运行,下面介绍一下如何进行调试。
使用打印语句
我们可以在代码中加入一些打印语句,用于输出一些调试信息,以便我们了解程序的运行状态。如之前的pExample
模块中,我们在OnStartUp()
、Iterate()
、OnNewMail()
函数中加入了一些打印语句,用于输出一些调试信息,进而判断函数是否被调用。 同样,我们也可以打印一些变量的值,以便了解变量的状态。如下面的代码中,我们在OnNewMail()
函数中打印了消息的变量名和值。
1 | bool Example::OnNewMail(MOOSMSG_LIST &NewMail) |
如果将Run = pExample @ NewConsole = true
中的NewConsole
改为false
,则不会在新的终端中打开pExample
,而是在当前终端中打印调试信息。
GDB调试
GDB是一个强大的调试工具,可以用于调试C/C++程序。我们可以使用GDB对MOOSApp模块进行调试,以便找出程序的错误。
首先,我们需要在编译时加入-g
参数或者在程序目录下的CMakeLists.txt中加入set(CMAKE_BUILD_TYPE "Debug")
,以便在编译时生成调试信息。然后,我们可以在终端中输入gdb pExample
,进入GDB调试界面。在GDB调试界面中,可以使用一些命令:
run
:运行程序,如run pExample.moos
表示运行pExample
程序。
break
:设置断点,如break Example::OnStartUp
表示在Example::OnStartUp
函数处设置断点;break 10
表示在第10行设置断点。
(gdb) break main.cpp:main:10
表示在main.cpp文件的main函数的第10行设置断点。
next
: 单步执行程序,不进入函数内部,如next
表示执行下一行代码。
print
: 打印变量的值,如print x
表示打印变量x的值。
1
2
3
4
5
6gdb pExample
(gdb) run pExample.moos
(gdb) break Example::OnStartUp
(gdb) next
(gdb) print x
(gdb) continue
总结
本文介绍了moos-ivp的特点、应用、安装以及一些基本的使用方法,希望对大家有所帮助。 学识所限,如有错误,还请评论指正。