目录
前言
利用VTD作为虚拟仿真软件,并对场景中的信号灯数据进行解析提取,关于场景的搭建可参照官方的ScenarioEditorRevM.pdf
文档,本文建立在场景已搭建成功的基础上。
一、RDB总线介绍
VTD将所有的数据分类别存储至自定义的结构体中,并在RDB总线上进行传输,当要取出某种数据时,则需要连接RDB总线,对其上的数据流进行筛选,筛选出我们所需要的结构体数据,而后再进行进一步的解析。
RDB总线通过tcp连接。成功安装VTD后,在/Develop/Communication/RDBClientSample/
目录下找到ExampleConsole.cpp
,是官方所给的RDB总线解析的源码示例,连接RDB总线以及提取数据流的功能已经写好了,我们需要做的就是在parseRDBMessageEntry
函数中筛选出我们所需要的数据所在的结构体,而后再做进一步的解析,如下所示:
void parseRDBMessageEntry( const double & simTime, const unsigned int & simFrame, RDB_MSG_ENTRY_HDR_t* entryHdr )
{
if ( !entryHdr )
return;
int noElements = entryHdr->elementSize ? ( entryHdr->dataSize / entryHdr->elementSize ) : 0;
if ( !noElements ) // some elements require special treatment
{
switch ( entryHdr->pkgId )
{
case RDB_PKG_ID_START_OF_FRAME:
fprintf( stderr, "void parseRDBMessageEntry: got start of frame\n" );
break;
case RDB_PKG_ID_END_OF_FRAME:
fprintf( stderr, "void parseRDBMessageEntry: got end of frame\n" );
break;
default:
return;
break;
}
return;
}
unsigned char ident = 6;
char* dataPtr = ( char* ) entryHdr;
dataPtr += entryHdr->headerSize;
while ( noElements-- )
{
bool printedMsg = true;
switch ( entryHdr->pkgId )
{
case RDB_PKG_ID_OBJECT_STATE:
handleRDBitem( simTime, simFrame, *( ( RDB_OBJECT_STATE_t* ) dataPtr ), entryHdr->flags & RDB_PKG_FLAG_EXTENDED );
break;
case RDB_PKG_ID_TRAFFIC_LIGHT:
handleTrafficLight(simTime, simFrame, *( ( RDB_TRAFFIC_LIGHT_t* ) dataPtr ), entryHdr->flags & RDB_PKG_FLAG_EXTENDED);
break;
default:
printedMsg = false;
break;
}
dataPtr += entryHdr->elementSize;
}
}
当要提取信号灯数据时,只需要在switch case中添加信号灯结构体对应PKG_ID的判断,并触发自己的自定义处理函数。
关于结构体以及相应的PKG_ID定义均在viRDBIcd.h
中,也可通过打开/Doc/RDB_HTML/
下的annotated.html
进行HTML导引查看,如下所示:
个人觉得还是通过html的方式方便些,在html中可以很直观的通过结构体名找到自己所要提取的数据所在结构体,继而按照结构体定义自定义解析函数,而后在上述parseRDBMessageEntry
中添加相应PKG_ID的case判断,并触发自定义的解析函数。
二、TrafficLight结构体解读
RDB_TRAFFIC_LIGHT_t
/** ------ complete traffic light data (basic and extended info) ------- */
typedef struct
{
RDB_TRAFFIC_LIGHT_BASE_t base; /**< information about a traffic light state @unit RDB_TRAFFIC_LIGHT_BASE_t @version 0x0100 */
RDB_TRAFFIC_LIGHT_EXT_t ext; /**< extended information about a traffic light @unit RDB_TRAFFIC_LIGHT_EXT_t @version 0x0100 */
} RDB_TRAFFIC_LIGHT_t;
如上所示,关于信号灯的数据均在RDB_TRAFFIC_LIGHT_t
中,该结构体也是我们进行数据解析的入口,其共有两个成员变量:base和ext,其中base
是信号灯的基础信息,ext
为信号灯的一些扩展信息,其详细定义见后。
RDB_TRAFFIC_LIGHT_BASE_t
/** ------ information about a traffic light (state) ------ */
typedef struct
{
int32_t id; /**< unique ID of the traffic light @unit _ @version 0x0100 */
float state; /**< current state (normalized) @unit [0.0..1.0] @version 0x0100 */
uint32_t stateMask; /**< current state mask (light mask, e.g. for gfx) @unit _ @version 0x0100 */
} RDB_TRAFFIC_LIGHT_BASE_t;
如上所示为RDB_TRAFFIC_LIGHT_BASE_t
结构体的定义,其中id
为当前信号灯的id;state
为当前信号灯处于一段循环周期(如绿-黄-红循环变换)中的哪一阶段,简单地说,就是处于当前信号灯循环周期内的哪一时间点,其大小为0.0…1.0,可用于判断当前灯光的剩余时间;stateMask
为当前信号灯的灯光状态,0x100000为绿灯,0x1000000为黄灯,0x10000000为红灯。
RDB_TRAFFIC_LIGHT_EXT_t
/** ------ extended information about a traffic light (phases, state details) ------
* @note this package is followed immediately by "dataSize" bytes of data, containing "noPhases" phase information entries RDB_TRAFFIC_LIGHT_PHASE_t */
typedef struct
{
int32_t ctrlId; /**< ID of the traffic light's controller @unit _ @version 0x0100 */
float cycleTime; /**< duration of a complete cycle of all phases @unit s @version 0x0100 */
uint16_t noPhases; /**< number of phases provided by this traffic light @unit _ @version 0x0100 */
uint32_t dataSize; /**< total size of phase data following the package @unit _ @version 0x0100 */
} RDB_TRAFFIC_LIGHT_EXT_t;
如上所示为RDB_TRAFFIC_LIGHT_EXT_t
结构体的定义,其中ctrId
为当前信号灯的控制id,信号灯所能变换的灯光便在controller里进行定义,如:红灯-stop等,未定义的灯光不会出现在信号灯的变换次序中;cycleTime
为当前信号灯的循环周期时间,如13s,则当前信号灯完整变换所有定义的灯光共需13s,每隔13s进行重复变换;noPhases
为当前信号灯所拥有的相位数(灯光数),若只有红绿黄灯,则其值为3;dataSize
为该结构体后面所拥有的额外的字节数,即phase数组,其数据用来详细指示当前信号灯所拥有的灯光状态、各自的持续时间以及灯光变换顺序(ps:phase数组的顺序仅表征controller中所定义灯光的先后顺序,与灯光如何变换无关),在对其进行解析时,需要将RDB_TRAFFIC_LIGHT_t
后面的数据地址给到RDB_TRAFFIC_LIGHT_PHASE_t
指针,这样便可以按照RDB_TRAFFIC_LIGHT_PHASE_t
结构体的定义来解析后续的数据。
//获取信号灯各相位的持续时间(红绿黄灯各自的持续时间)
RDB_TRAFFIC_LIGHT_PHASE_t* phasePtr = ( RDB_TRAFFIC_LIGHT_PHASE_t* )(((char*)item )+ sizeof( RDB_TRAFFIC_LIGHT_t ) );
RDB_TRAFFIC_LIGHT_PHASE_t
/** ------ traffic light phase information entry ------ */
typedef struct
{
float duration; /**< normalized duration of the phase, invalid phases will have duration 0.0 @unit [0.0..1.0] @version 0x0100 */
uint8_t type; /**< type of the phase @unit @link RDB_TRLIGHT_PHASE @endlink @version 0x0100 */
uint8_t spare[3]; /**< spares for future use @unit _ @version 0x0100 */
} RDB_TRAFFIC_LIGHT_PHASE_t;
如上所示为RDB_TRAFFIC_LIGHT_PHASE_t
结构体的定义,注意这里的数据都是静态数据,即仅是用来指示说明而用,并不会随着灯光的变化而变化。其中duration
为当前灯光的持续时间,大小为0.0…1.0,与上面base.state
的定义类似,为当前信号灯循环周期的占比,如0.3,则当前灯光持续时间占循环周期时间的1/3;type
为当前的灯光种类,关于type的定义见下图;spare
用于未来扩充使用。
* ------ traffic light phases ------
* @{
*/
#define RDB_TRLIGHT_PHASE_OFF 0 /**< traffic light is off @version 0x0100 */
#define RDB_TRLIGHT_PHASE_STOP 1 /**< traffic indicates STOP @version 0x0100 */
#define RDB_TRLIGHT_PHASE_STOP_ATTN 2 /**< traffic indicates STOP/ATTENTION @version 0x0100 */
#define RDB_TRLIGHT_PHASE_GO 3 /**< traffic indicates GO @version 0x0100 */
#define RDB_TRLIGHT_PHASE_GO_EXCL 4 /**< traffic indicates GO EXCLUSIVELY @version 0x0100 */
#define RDB_TRLIGHT_PHASE_ATTN 5 /**< traffic indicates ATTENTION @version 0x0100 */
#define RDB_TRLIGHT_PHASE_BLINK 6 /**< traffic indicates BLINK @version 0x0100 */
#define RDB_TRLIGHT_PHASE_UNKNOWN 7 /**< traffic indicates an unknown state @version 0x0100 */
/** @} */
总结
以上便是VTD中信号灯数据的提取及解析,由此可知,若想判断当前信号灯的状态以及所剩时间需要结合当前信号灯的状态state、信号灯各相位的持续时间duration、信号灯所有相位的循环周期cycletime以及各相位的变换顺序,其中除变换顺序外的数据,都可以直接从RDB总线中取得,但是变换顺序却无法直接获取,这里只能在场景定义时就将其严格按照标准灯光变换顺序来定义,如此对数据进行一定的处理转换后,便可用于填充CSAE SPAT消息集,后续再写如何用拿到的数据填充SPAT。