要用X-Plane进行二次开发,免不了需要进行参数的传递,下面我们来看看与X-Plane进行数据交互都有哪些方式。
与FSX和Flightgear基本一样,X-Plane支持插件,自然也支持通过插件进行数据交互,另外还可以通过在UI界面直接设置将数据显示在主屏上(二次开发并不需要这种方式,下面不讨论),然后还支持通过UDP通过网络进行通信。实际上主要的就这几个,有一些第三方工具实际上在这三种方式基础上做了一些开发,但有时候更好用了。如NASA通过插件做了一个代理,即NASA写了个插件直接与X-Plane通信获取数据,同时该插件还通过UDP与外部程序通信,经过定制后的通信更加方便了,不需要再考虑X-Plane原生的UDP通信方式中数据对齐的问题了。下面就一一进行介绍。
一、X-Plane原生支持的通信方式
1、通过Plugin进行数据交互
在X-Plane插件开发中提供了DataRefs API(http://www.xsquawkbox.net/xpsdk/mediawiki/DataRefs)来允许Plugin读取或者与其他X-Plane Plugin交换数据数据。
在X-Plane中数据名称是一个很长的字符串,如:sim/flightmodel/position/latitude代表其对应的latitude。X-Plane中现有的变量可以从这个表中查到http://www.xsquawkbox.net/xpsdk/docs/DataRefs.html。
关于如何使用这个些变量具体在页面中并没有给出不过可以到下面这个页面下载最新的例程。
http://www.xsquawkbox.net/xpsdk/mediawiki/Category:Sample_Code 其中SDK 2.1 Sample Code例SDK210Tests这个例程,其中就有相关用法。如下:
1 // Datarefs to get the aicraft position 2 SDK210Tests_refx = XPLMFindDataRef("sim/flightmodel/position/local_x"); 3 SDK210Tests_refy = XPLMFindDataRef("sim/flightmodel/position/local_y"); 4 SDK210Tests_refz = XPLMFindDataRef("sim/flightmodel/position/local_z");
另外要实际使用的时,相应的详细说明查阅www.xsquawkbox.net/xpsdk/mediawiki/XPLMDataAccess的API文档即可。
通过X-Plane插件进行数据交互好处是容易写,无需考虑字节对齐问题。但不好的一点是,plugin代码是和X-Plane主程序一起运行的,X-Plane的每一帧都会去调用X-Plane Plugin的相关内容,一旦Plugin出错很有可能导致X-Plane崩溃,这是对要命的,要知道启动一次X-Plane需要至少3分钟,这还是配置比较高的电脑。。。。所以更好,更方便的是通过外部程序与X-Plane通信获取需要的数据。那就是下面这种方式。
2、通过UDP进行通信
不得不吐槽一下,对开发者来说,X-Plane的文档写的真是太随意,太乱了,而且很多重要的内容压根就没写。所以要找到一些文档还需要自己去搜罗,比如,X-Plane自带一个UDP通信的说明文档,在其安装目录XXXX\X-Plane 10\Instructions\Sending Data to X-Plane.rtf目录下,名字叫TXT.rtf (这个文档名也是醉了)。这个文档在我第一次通过Digital安装的时候是有的,后来用DVD装完之后居然没有。。。。不管了,反正就是这个文件,如果你没找到的话,建议随便找个论坛要一下。
该文档说明的内容主要是如何与X-Plane直接进行数据交互,其中我们主要关注的是其中UDP通信部分。这部分总结一下主要是如下内容:
1)可以通过UDP与X-Plane间收发一定结构的structs(结构体)来和X-Plane进行通信。
2)这些结构体的字节对齐方式必须符合当前Intel 64-bit X-Code alignment。也就是说如果结构体中最大的数据类型是int 或是 float 那么按照4字节对齐,如果包含double,那么按照8字节对齐。
3)通过向X-Plane发送 一种命令来进数据交互,这种命令的格式为 以\0结尾的 四字节的命令字符串加数据结构体组成,例如:“PROS”这个命令是让X-Plane以一定的频率返回一套固定的数据。
需要发送以下内容:
"RPOS"+'\0'(null terminated )+ struct rpos_struct_in { xint rpos_freq;//实际发送时,结构体对象中rpos_freq应该有值。 };//(其中 “+” 不发送)
再来段原版英文解释:
So what is the 5-char message prologue? Easy! The first 4 chars are the message type, So, to send a UDP message to X-Plane, just send: |
然后,将对应的这一串数据发送到X-Plane所在计算机的49000端口上,然后X-Plane就会向外发送一组预先定义好的数据(X-Plane will send the minimum data needed to drive an external visual or moving map to the same IP address and port number you sent this message from! Easy!)
X-Plane发送回来的数据格式将是如下样式的:
“RPOS”+'\0'(null-terminated!)+ struct position_struct { double longitude,latitude; // double is needed for smooth data here. this is good for simple 2-d maps float elevation_MSL,elevation_AGL; // we have AGL so you can correct the heigh above ground for your visuals to match X-Plane, if desired float pitch,heading,roll; // this is for making your own visuals float Vx,Vy,Vz; // Vxyz are the speeds in the east, up, and south directions, in meters per second. you can use these to predict longitude, latitude, and elevation smoothly. float Pdeg,Qdeg,Rdeg; // P Q R are the roll, pitch, and yaw rates, in aircraft axis, in degrees per second. you can use these to predict pitch, heading, and roll smoothly. }
实际数据肯定不是一个结构体的定义,而是整个结构体的一个对象,我们只需要自己定义这样一个结构体,将UDP收到的数据赋给该结构体,就可以取出相应的数值。
1 struct position_struct 2 { 3 char cmd[5]={'R','P','O','S','\0'}; 4 double longitude,latitude; // double is needed for smooth data here. this is good for simple 2-d maps 5 float elevation_MSL,elevation_AGL; // we have AGL so you can correct the heigh above ground for your visuals to match X-Plane, if desired 6 float pitch,heading,roll; // this is for making your own visuals 7 float Vx,Vy,Vz; // Vxyz are the speeds in the east, up, and south directions, in meters per second. you can use these to predict longitude, latitude, and elevation smoothly. 8 float Pdeg,Qdeg,Rdeg; // P Q R are the roll, pitch, and yaw rates, in aircraft axis, in degrees per second. you can use these to predict pitch, heading, and roll smoothly. 9 }
现在我们已经和X-Plane接上头了,它可以给我发送数据了,现在我还需要给它发送数据,或者我想得到某个确定的参数,而且不是周期性的怎么办呢?
X-Plane中还是祭出了dataref的法宝,在采用UDP通信的这种方式中称之为RREF。标题也是很屌-SEND ME ALL THE DATAREFS I WANT: RREF
对应的命令就是“RREF”
"RREF"+‘\0’+ struct dref_struct_in { xint dref_freq ; xint dref_en ; xchr dref_string[400] ; };
dref_freq :是X-Plane回传输数据的频率(每秒多少次)
dref_en:是一个编号,你自己定义的,因为你可能向X-Plane请求了多组参数,需要一个东西去区分开你收到的到底是哪组参数的回复。
dref_string:是希望X-Plane返回的dataref的那串string,即官方称之为冗余的一长串名称。
当你想知道的dataref数据是一个数组(如引擎推力,可能有8个引擎,需要8个引擎推力参数),只需要在参数名后面加上[xxx]指明即可。如“sim/flightmodel/engine/POINT_thrust[1]”,得到第2个引擎的推力。
之后,X-Plane向源地址发回对应的数据
struct dref_struct_out { xint dref_en ; xflt dref_flt ; };
其中的dref_en就是之前自己定义的编号。
如果想关闭数据返回,只需要再发一次命令,只不过dref_freq设置为0即可。
好了,说完数据获取,该说说如何设置参数的值了。
通过命令“DREF”,也就是发送
“DREF”+‘\0’+ struct dref_struct { xflt var; xchr dref_path[strDIM]; };
不过要注意,这里的dref_path需要填满,DREF0+(4byte byte value)+dref_path+0+spaces 使整个消息达到509字节。
例如:
DREF0+(4byte byte value of 1)+ sim/cockpit/switches/anti_ice_surf_heat_left+0+spaces(填充到509字节)
好了,就是这样。数据发送与接收就搞定了。
当然,基本流程其实就是这样,唯一难的是需要不停的调试UDP程序、调节struct的对齐方式。虽然这非常糟心,但一旦调好了,你会很开心。
不过通过以上过程你也可能会看到,使用UDP其实也并不是很好的一种方式,中间通信的变量太多了,而且有好多流程是冗余的,而且又没有稳定连接保证,如果在网络中稍出现抖动很容易造成接收混乱,所及这种通信方式说是UDP的,但还是只适合于在近距离本地网中使用,最好是直接通过一根网线相连接的这种方式。
二、第三方通信工具
1、GitHub上的开源项目
1)NASA的X-Plane Connect(https://github.com/nasa/XPlaneConnect)简称XPC。
NASA做了一个简化版的通过UDP和X-Plane通信的插件,通过这个插件做代理,可以实现X-Plane自带的UDP那种功能。但使用起来却简单多了。
而且语言支持C、Python、Java、MATLAB等,非常强大,你可以下载对应的代码和例程学习一下。
The X-Plane Connect (XPC) Toolbox is an open source research tool used to interact with the commercial flight simulator software X-Plane. XPC allows users to control aircraft and receive state information from aircraft simulated in X-Plane using functions written in C, C++, Java, MATLAB, or Python in real time over the network. This research tool has been used to visualize flight paths, test control algorithms, simulate an active airspace, or generate out-the-window visuals for in-house flight simulation software. Possible applications include active control of an XPlane simulation, flight visualization, recording states during a flight, or interacting with a mission over UDP.
2)Flight Simulator Panels(https://github.com/dmolin/flightSimPanels)
2、jefflewis.net的博客(http://www.jefflewis.net/XPlaneUDP_9.html)
X-Plane, UDP, and Visual Basic(http://www.jefflewis.net/XPlaneUDP.html)
用VB写的通信功能。
3、http://www.nuclearprojects.com/xplane/xplaneref.html 讲解了X-Plane UDP-Message通信的基本内容,与txt.rtf 的内容基本一样。
4、一个有意义的讨论,其中包含了一段参考代码
http://forums.x-plane.org/index.php?/forums/topic/30281-help-with-udp-packets-knowledge-please/
其他资料:
其中部分可能需要花点力气到墙的另一边去。
https://www.youtube.com/watch?v=LojOSIwPpD0
http://ardupilot.org/dev/docs/testing-with-replay.html