技术笔记:NML工程入门

简介: 技术笔记:NML工程入门

NML工程入门-三步使用


撰写人:李峻翔


特别鸣谢:刘伯凯


版本:V1.0


第一步、RCS安装


第二步、配置NML文件(configuration file)


第三步、程序中调用NML库函数


编写C++NMLmessage


主程序采用NML进行消息传递


NML-demo


三模块双机通信


NML常见报错和解决思路TOC


NML是RCS库中的一部分,NML英文全称是neutral message language。它是由美国国家标准与技术研究院(NIST,National Institute of Standard and Technology)针对分布式通信而设计的一种通信协议与方式。


无人车开发过程中,使用NML通信,并不需要对NML了解很深。由于目前可参考的资料并不多,建议使用尽量采用现成模板,直接套用即可。但是,由于不知道基本运行原理,容易在遇到问题时束手无策。出于该目的, 笔者将经验总结,以供参考。


简单的说来,程序中要使用NML通信,只需要以下简单的三步。


第一步、RCS安装


参考文件:


以下方法针对的是Ubuntu系统,如果是windows系统或者遇到了安装困难可以参加附件中的word文档。


确认依赖环境:boost(常用版本有1.54,1.55和1.58)和Java,如果没有Java,需要按以下步骤安装java。(其实安装java的过程即把安装包解压到合适的位置,之后建立软连接)


update-alternatives --install /usr/bin/java java /opt/jdk1.7.0_79/bin/java 300


update-alternatives --install /usr/bin/javac javac /opt/jdk1.7.0_79/bin/javac 300


update-alternatives --install /usr/bin/jar jar /opt/jdk1.7.0_79/bin/jar 300


下载RCS安装包/获取团队现成安装包:


解压安装包


执行下列语句


cd rcslib-2014.04.29(对应安装包名字)


./configure -enable-ALLJAVA


【修改Makefile中的prefix选项为 /opt/rcslib/build,此处将生成lib与include】


make


make check


make install(可能需要root权限)


第二步、配置NML文件(configuration file)


以下部分是对NML官方文档的说明和一些实践中经验的补充。不同于官方文档,我们直接以我们车上的NML(bin/UGVAuto.nml)为模板,来说明。如果想使用,建议直接用模板修改,而不要从头到尾写。


NML配置文件主要包括四个部分,分别是:注释,消息,进程,server。


1.注释


注释以'#'开头,我们可以看到有一行以#开头,如下:


# Name Type Host size neut RPC# buffer# MP . . .


这就是注释。


为了更好的表示消息的写法,特意加了该注释。


2.消息(buffer)


消息对应在src/message里面的文件,只有定义了消息的头文件,才能够被其他程序调用。只有此处配置正确,才能保证消息的正常收发。


对于代表buffer的.hh文件,可用Makefile文件对message进行修改和编译,每次修改.hh文件都需要重新编译,编译生成新的/Test/lib/libTest.a文件。


Message名称都以n结尾,如MessageAn.hh MessageBn.hh MessageCn.hh等。这是在message文件夹里的Makefile中约定的,方便统一管理。而在.nml配置文件中,我们将后缀n略去。


消息以B开头,我们以现有模板的注释行为例,一一介绍该如何编写和定义消息。


# Buffers


# Name Type Host size neut RPC# buffer# MP . . .


B MessageA SHMEM 172.23.100.205 1024 0 1001 50001 bsem=5421 TCP=5421 xdr


Name是消息名称,对应到src/message里面的文件。


Type表示的是消息的使用形式,包括三种方式:SHMEM(share memory),GLOBMEM(global memory),LOCMEM(local memory)(对远程的Buffer有三种方式:TCP, //代码效果参考:http://www.jhylw.com.cn/044822979.html

UDP, RPC)。

Host表示的是buffer所在的主机名,如果消息只是在同一台机器上传递,则这里写什么都问题不大,最好写localhost。需要特别注意的是,如果是不同机器传递某一个消息,需要给消息写一个server,来负责传递,则这里要写的是该消息的server所在的主机名(或主机IP地址)。这里可以看到,host1和host4是有通信关系的,很多消息都在这两台机子中间传递。因此, 规划模块在host1上,与之相关的server也在host1上,因此此处的Host也是写host1。


size表示的是消息的大小,单位字节,这里要根据msg定义的数据结构来确认


neut 0或1都可以,区别是什么官方文档并未介绍清楚,如果没有处理器不兼容,则设0。通常取0即可。


RPC# 已经被官方弃用,因此统一用符号来占位。


buffer# buffer的序列号,需要保证唯一即可。


MP:max_procs,可以用符号占位。


【Type-spec data】:对于SHMEM,需要一个唯一的共享内存键。后面接着“TCP=”,后面的数字必须大于1024。后面接着"bsem=",后面的数字与TCP不同即可。


这里要注意的是,如果用了两个不同的nml文件,如果有共同的buffer,后面的【Type-spec data】必须是一致的,否则无法通信。


3.进程(Process)


进程以P开头。


# Name Buffer Type Host Ops server timeout master cnum


# ModuleA


P ModuleA //代码效果参考:http://www.jhylw.com.cn/491621979.html

MessageA LOCAL 172.23.100.205 R 0 0.1 1 1 waitformaster

Name是进程名称,一般对应到bin里面的可运行程序,有可能一个程序有多个进程。


Buffer表示的是该进程使用的消息名称,必须在Buffer中定义。


Type只能是 "LOCAL" , "REMOTE","AUTO"。这个与进程的位置无关,表示的是进程如何访问消息。对于SERVER来说直接访问,则是用LOCAL。如果用TCP、UDP访问或者本行的Buffer需与其他主机通信(读或写),且server程序不在本机,则是用REMOTE。


Host表示的是进程所在主机ip地址。


Ops表示进程对消息的操作方式,R表示读,W表示写,RW表示既读又写。


server 对于svr而言为1,否则为0。


timeout 互斥时间通常写为0.1。


master 表示指定消息的传递指定哪一个process是master,注意master可以不唯一,且至少需要有一个master,建议如现有文件中所有process对应buffer都为1。如果对于不是master的process,其在c++使用NML,建立new CHANNEL时,会一直等待程序的master建立好后,才能够正常初始化,否则会一直中断在此。这个Bug通过调试模式可以发现;或者发现程序没有报错,但也并没有运行至期望的语句时可能出现。


cnum 除非GLOBMEM,否则没用。GLOBMEM时表示Process的序列标示,互不相同即可。


4.Server


Server是一种特殊的进程,其写法与进程类似。在/src/server下可用Makefile文件对server进行修改和编译,每次修改.cc文件都需要重新编译,编译生成新的/Test/bin/svr 文件。


#Server


# Name Buffer Type Host 0ps server timeout master cnum


P ServerAsvr MessageA LOCAL 172.23.100.210 RW 1 0.1 1 51


注意:


server的Type都是LOCAL,Host是server程序所在主机地址。Ops一般为RW操作,server为1,master为1即可。


第三步、程序中调用NML库函数


这一部分,介绍内容分为两部分:一是如何使用C++来编写NMLmessage,二是主程序中如何使用NML来通信。


编写C++NMLmessage


NML message存放在src文件夹下,通常与应用程序在同一级目录下。这种目录结构能够最小化修改文件目录。


message文件夹内需要copy以下几个基本的文件:


-Makefile


-NMLmsgExn2.cc


-NMLmsgExn.hh


-CommonDefinitionX可用可不用,如果不用,则对应将头文件中的引用注释即可。


其中,


Makefile文件,该文件需要针对头文件、目标文件和NML_CODEGEN的安装位置,进行修改。通常NML_CODEGEN的安装位置为:/usr/local/bin/CodeGenCmdLine.jar。


如果编译message时,出现unable to access jarfile,这种情况下需要利用错误信息和之前rcd的安装信息来查找jar文件,find命令参考如下:


find /opt -name CodeGenCmdLine.jar


find /usr -name CodeGenCmdLine.jar


要特别注意makefile文件中,如果定义了make clean -\rm -f .cc的话最后把其删除,以免make clean误删除一些自定义的cc文件。


clean:


-\rm -f .o lib.a lib.so lib.la .lib .ddll


CommonDefinitionX和NMLmsgExn.hh不用改,是NML通信使用的模块。


特别注意车上的模板是NMLmsgExn2.cc。此文件同样不要重命名,不要删除。


自定义message,以“...n.hh”结尾,以表明是用NML通信。


其中,需要引入头文件包括:


// Prevent Multiple Inclusion


#ifndef MESSAGEAN_HH


#define MESSAGEAN_HH


// Include Files


#include "rcs.hh" // Common RCS definitions


#include "NMLmsgExn.hh"


#include "CommonDefinitionX.hh"


定义MESSAGEA_MSG_TYPE.


// Define the integer type ids.


#define MESSAGEA_MSG_TYPE 40101


接下来则是消息的定义,可以根据自己的需要,自定义一些数据结构:


struct UserType{


int int_array【2】;


std::string v_str;


};


// Define the NML Message Classes


class MESSAGEA_MSG : public NMLmsgEx


{


public:


//Constructor


MESSAGEA_MSG();


// CMS Update Function


void update(CMS );


// Place custom variables here.


char v_char;


double v_double;


UserType usertype_data;


};


// Declare NML format function


extern int MessageAFormat(NMLTYPE, void , CMS );


#endif // MESSAGEAN_HH


主程序采用NML进行消息传递


NML通信模块启用


在主程序中需要引用使用的NMLmessage的头文件。此外,在启用NML时使用,使用以下语句:


set_rcs_print_destination(RCS_PRINT_TO_STDOUT);


nml_start();


在程序通信结束后,需要清空和关闭NML:


nml_cleanup();


NML通信类的初始化


NML的使用建立在NML通信类的基础上,初始化NML通信类采用以下命令,但需要已经写好nml配置文件,关于配置文件的要求,可以参见“配置NML文件(configuration file)”一节:


NML MESSAGE_CHANNEL = new NML(formatFunction,"buffer", "process", "config.nml");


其中,参数buffer对应配置文件中B的名称,process对应P的名称,config.nml对应nml的文件名。


formatFunction一般在nml message文件的最后有同名的定义。


如果配置文件中Process对应的master为1,NML 通信类初始化后,才会启动buffer的master。


NML通信消息的初始化


针对写消息的模块,采用


Message_data = new MESSAGEA_MSG;


针对读消息的模块,采用


Message_data = (MESSAGEC_MSG *) MESSAGE_CHANNEL->get_address();


需要注意的是,接收的buffer,不需要重新new MESSAGEA_MSG。发送的Buffer,需要在构造函数中new MESSAGEA_MSG开辟新空间。


消息读写


消息读采用以下命令判断接收是否正常,如果正常,可以直接使用buffer中定义变量:


MESSAGE_CHANNEL ->blocking_read(0.2)


消息写采用以下命令:


MESSAGE_CHANNEL ->write(Message_data)


NML-demo


三模块双机通信


(written by Bokai Liu)


下载地址:


该程序在两台计算机上运行,有三个模块,分别为(计算机1)模块A,模块B和(计算机2)模块C。


程序运行流程为:


模块B(发送消息A,B)--->模块A(接收消息A,B,并进行处理,发送消息C)。


模块A(发送消息C)--->模块C(接收消息C)。


NML常见报错和解决思路


(Welcome to update and supplement)


出现如下错误


解释: 这个表示配置文件中缺乏process-line。


出现如下错误


编译错误MsgAn.cc:-1: error: undefined reference to NMLmsgEx::NMLmsgEx(long, long)或


解释: 这表示NMLmsgEx_TYPE无法读出来。通常是修改了NMLmsgExn2.cc的缘故。(注意脚本中可能出导致该文件被修改。


程序不报错,如果用调试模式,发现程序卡在new NML处。


解释: 这种错误是在nml配置文件中,没有给buffer指定master的缘故。如果指定了master,则必须要等master开启后,其它的Process才能够接收。


参考文献:


附件列表

相关文章
|
3月前
|
人工智能 Cloud Native IDE
超详细!JetBrains Rider 2025.1 安装到能用,激活 + 安装步骤—附安装包
JetBrains Rider 2025.1 是全能型跨平台全栈 IDE,深度集成 AI 编码助手,支持 .NET 9、Unity 2025、Blazor 等最新技术,覆盖 C#、Python、Go 等 20+ 语言,赋能游戏、云原生与微服务开发,实现 AI 辅助生成、调试、测试与文档一体化。
871 2
|
10月前
|
监控 Java API
1K star!这个开源项目让短信集成简单到离谱,开发效率直接翻倍!
SMS4J 是一款由国内技术团队打造的短信聚合框架,专为解决多短信服务商接入难题而生。它就像短信界的"瑞士军刀",目前已整合21家主流短信服务商,从阿里云、腾讯云到中国移动云MAS,开发者只需通过简单配置即可实现多平台无缝切换。
699 4
|
5月前
|
监控 安全 物联网
阿里云WAF是什么?
Web应用防火墙(WAF)是保护网站、APP及API的关键防线,可实时监控并阻断恶意流量,防范数据泄露与常见攻击。它通过分析HTTP请求,识别威胁,保障敏感信息,满足合规要求,支持云、主机、网络多场景部署,助力企业构建坚实的安全屏障。
|
4月前
|
监控 数据可视化 测试技术
16_LLM交互式调试:用Streamlit构建可视化工具
在大语言模型(LLM)的应用开发过程中,调试一直是一个复杂且具有挑战性的任务。传统的调试方法往往依赖于静态日志、断点调试和反复的命令行交互,这种方式在处理LLM这类黑盒模型时显得尤为低效。随着2025年LLM技术的普及和应用场景的多样化,开发人员迫切需要一种更加直观、高效的调试方式。
|
安全 Linux 网络安全
【工具使用】几款优秀的SSH连接客户端软件工具推荐FinalShell、Xshell、MobaXterm、OpenSSH、PUTTY、Terminus、mRemoteNG、Terminals等
【工具使用】几款优秀的SSH连接客户端软件工具推荐FinalShell、Xshell、MobaXterm、OpenSSH、PUTTY、Terminus、mRemoteNG、Terminals等
134738 0
|
SQL 存储 数据库
SQL语句给予用户权限:技巧、方法与最佳实践
在数据库管理中,为用户分配适当的权限是确保数据安全性和操作效率的关键步骤
|
传感器 存储 Ubuntu
Azure Kinect DK + ROS1 Noetic使用教程
本文是Azure Kinect DK在Ubuntu20.04下配合ROS1 Noetic使用的教程,内容包括一键安装脚本、硬件介绍、安装SDK相关软件包、设置Udev规则、SDK基本测试、DK ROS基本测试,以及存在的一些重要缺陷和相关参考文献。教程详细指导了如何配置和使用Azure Kinect DK,提供了安装步骤和解决常见问题的方法。
1293 1
Azure Kinect DK + ROS1 Noetic使用教程
|
存储 人工智能 缓存
【AI系统】核心计算之矩阵乘
本文探讨了AI模型中矩阵乘运算的优化实现及其在AI芯片设计中的重要性。文章首先介绍了卷积操作如何转化为矩阵乘,接着阐述了矩阵乘的分块(Tiling)技术以适应芯片内存限制,最后总结了几种常见的矩阵乘优化方法,包括循环优化、分块矩阵乘法、SIMD指令优化等,旨在提高计算效率和性能。
622 0
|
缓存 数据可视化 机器人
07 ROS的TF坐标管理工具
本文详细介绍了ROS(机器人操作系统)中TF(Transform)坐标管理工具的使用方法,包括如何监听和广播坐标变换消息,使用相关命令行工具查看TF关系,以及如何通过编写节点代码来创建TF广播器和监听器,并展示了如何在launch文件中配置TF相关的节点。
793 0
|
机器学习/深度学习 人工智能 自然语言处理
利用深度学习提升语音识别准确率的技术探讨
传统的语音识别技术在面对复杂的语音场景时常常表现出准确率不高的问题。本文探讨了如何利用深度学习技术,特别是深度神经网络,来提升语音识别的精度。通过分析深度学习在语音处理中的应用以及优势,我们展示了如何结合最新的研究成果和算法来解决现有技术的局限性,进一步推动语音识别技术的发展。 【7月更文挑战第3天】
1053 0

热门文章

最新文章