曹凤海,宋占武,李 燕,刘 潇,乔永杰,黄兴琪
(东方地球物理公司,河北 涿州 072750)
无人机航摄拍照瞬间精确空间位置的确定
曹凤海,宋占武,李燕,刘潇,乔永杰,黄兴琪
(东方地球物理公司,河北 涿州 072750)
近年来,随着无人机与数码相机技术的发展,无人机航测以其高效、精确、作业成本低、适用范围广等特点,在地表复杂地区高分辨率影像的获取方面优势明显。无人机像片后续处理需要布设大量像控点,工作量大,耗时耗力,特别是在地表复杂地区。如果通过卫星定位的手段计算出拍照瞬间照片中心的精确位置和姿态,则可以节省大量施工投入,有效提高生产效率。本文即利用PPK作业方式进行航摄拍照瞬间空间位置的确定以进行研究。
一、硬件配置
利用ARM板配GNSSOEM板组成简单的GNSS接收机。通过综合测试并考虑体积方面的要求,建议GNSSOEM板采用Trimble公司的BD930板卡;为了适应控制过程中的多线程操作,ARM板配WinCE操作系统,要用两个串口与GNSS差分板连接,其中一个记录原始数据,另一个输出NMEA数据。
二、整体设计
系统整体设计思路为:在地面控制点架设基站持续接收GNSS定位数据;空中(机载)ARM板持续记录GNSS定位数据,接收飞控拍照指令,收到飞控指令后控制相机拍照并记录拍照的精确时刻;施工完成后,地面基站和空中GNSS数据联合处理,计算出每个历元(根据设置参数记录,如果设置成5Hz,则每200ms一个历元)的精确坐标,根据记录的拍照精确时间内插出每个拍照点的坐标。本文只讨论空中数据记录和控制部分的几个关键问题的解决思路。
三、空中数据记录和控制部分的几个关键问题解决思路
1. 精确时刻的确定
GNSS差分板在锁定卫星后会通过一个针脚发送PPS信号,将该针脚引到ARM板的“中断”接口,通过监控该脉冲的到来确定每秒开始的精确时刻。
为了应用方便,在WinCE底层驱动中,将“PPS到达”写成事件驱动,具体过程如下:
1) 将与GNSS的PPS连接的针脚配置成“中断模式”。
2) 建立通知用户事件,命名为“GPS1PPS”:
g_hUserEvent=CreateEvent(NULL,FALSE,FALSE,_T("GPS1PPS"));
其中,“g_hUserEvent”为用户事件句柄。
3) 建立中断事件:
g_hEINT3Event=CreateEvent(NULL,FALSE,FALSE,NULL);
4) 初始化中断事件:
KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &g_IRQ,sizeof(UINT32), &g_SYSINTR,sizeof(UINT32),NULL);
其中,“g_IRQ”是采用的中断号,在笔者的实际设计中,该针脚接到了“中断3”,即“g_IRQ=IRQ_EINT3”。
5) 建立中断服务线程:
hPPS=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadForEINT3,0,0,NULL);
6) 服务线程函数实现:
DWORDWINAPIThreadForEINT3(void){
DWORDdwResult;
while(TRUE)
{
dwResult=WaitForSingleObject(g_hEINT3Event,INFINITE);
SetEvent(g_hUserEvent);
InterruptDone(g_SYSINTR);
}
return0;
}
该线程函数一直接收PPS信号,当PPS信号到达“中断3”,该函数从驱动层向应用层产生事件报告。
7) 应用层捕获PPS到达事件。建立线程,接收驱动层发上来的“GPS1PPS”事件,该事件发生后,记录该时刻:
DWORDWINAPIGPS1PPSThread(LPVOIDlpParameter){
HANDLEhGPS1PPSEvent=NULL;
hGPS1PPSEvent=OpenEvent(EVENT_ALL_ACCESS,FALSE,TEXT("GPS1PPS"));
while(1)
{
WaitForSingleObject(hGPS1PPSEvent,INFINITE);
m_dPPSTick=GetTickCount64();
}
return1;
}
由于PPS只提供每秒开始的精确时刻,要得到任意一时刻的精确时间,需要以PPS时刻为基础加上到需要确定时刻的偏移值,该偏移值的确定需要用其他方式定时。为了应用方便,笔者利用CPU距开机以来的时间进行相对定时,即需要确定时刻的时间=PPS时刻+(需要确定时刻的CPU定时-PPS时刻的CPU定时)。
为了得到精确的CPU开机以来的时间,重写“GetTickCount64()”函数:
doubleGetTickCount64(){
staticLARGE_INTEGERTicksPerSecond= {0};
LARGE_INTEGERTick;
if(!TicksPerSecond.QuadPart)
{
QueryPerformanceFrequency(&TicksPerSecond);
}
QueryPerformanceCounter(&Tick);
doubleRet= (double)Tick.QuadPart*1000.0/TicksPerSecond.QuadPart;
returnRet;
}
该方法的实现思路为:首先获得CPU时钟到该时刻的震动次数,然后获取CPU时钟每秒钟的震动次数(震动频率),其比值即为开机以来的秒数,该方法定时精度很高。
2. 捕获飞控拍照指令信号
飞控发送的拍照指令是一个闭合信号(短路信号),如果要捕捉到该信号并产生中断事件,需要通过逻辑电路将闭合信号转换成电平信号,逻辑实现思路如下:
如图1所示,一般情况下DI_A与DI_B不闭合,Q1截止,XEINT2为高电平;当DI_A与DI_B闭合时Q1导通,XEINT2由高电平变成低电平,即产生下降沿,发生中断。当DI_A与DI_B由闭合到断开后,Q1则从导通变为截止状态,XEINT2由低电平变成高电平,即上升沿,不产生中断。
闭合信号转换为电平信号后,实现中断的驱动和应用层事件的捕获思路与处理PPS事件的道理相同,在笔者的实际设计中,该针脚接到了“中断2”, 中断触发方式为下降沿触发。应用层接收到拍照信号后,由ARM板产生触发相机拍照指令,并记录拍照瞬间的精确时刻。
图1 实现原理
3. GNSS原始数据记录
本文采用“双缓冲”的方式接收和记录GNSS原始数据,具体实现思路如下:
1) 定义两个byte类数组,根据实现情况定义大小,可以是64KB或更大。
2) 用一个变量记录当前工作于哪个数组,另外用两个变量记录两个byte数组存储数据长度。
3) 当接收到GNSS原始数据,将其存储到当前工作byte数组,如果当前数组已保存部分数据,则将新数据连接到原有数据后面,为了提高数据转存效率,用“memcpy”内存拷贝的方法。
4) 当当前工作byte数组存储数据达到指定的长度,则将当前工作byte数组指定为另一个byte数组,同时启动一个新的线程将达到指定长度的数据写到Flash。
5) 两个数组交替进行存储数据,配合多线程写Flash方式,接收GNSS原始数据和记录两不耽误,达到“双缓冲”的效果。
4. 各线程的优先级
根据实际工作要求,对各线程优先级作以下设计:
1)PPS线程优先线设为“高”。
2) 捕获飞控拍照指令信号线程优先级设为“一般”。
3)GNSS原始数据记录线程优先级设置为“一般”。
四、结束语
在无人机低空航拍技术迅速发展的今天,如何提高作业效率、精度和质量是行业内一直追求的目标,本文从实用的角度阐述了利用PPK技术解决确定相机在空中拍照瞬间空间位置的思路。
本文只对该方法实现思路的几个关键问题进行了描述,且只涉及了原始数据采集部分,如果要实现产品化的应用,还需要诸多的辅助技术、空中姿态数据的获取及后处理应用相关的开发。
(本专栏由天宝测量部和本刊编辑部共同主办)
天宝测绘解决方案专栏