花了两天的时间 ,终于在ARDrone SDK 1.8,firmware 1.7.4平台下将SDK自带的Win32 Demo编译完成。
跟随SDK1.8和firmware1.7.4的发布,Linux和IPhone端例子用程序均有更新,Windows平台下的例子程序貌似没有在更新了,而且Windows平台下的SDK编译时也会蹦出来一堆的错误,下面就来一一解决这些错误。
首先编译ARDrone SDK 1.8,出现了以下错误:
1、error C2065: 'tv' : undeclared identifier
error C2224: left of '.tv_sec' must have struct/union type
error C2065: 'tv' : undeclared identifier
error C2224: left of '.tv_usec' must have struct/union type
win32平台同样需要结构体tv。在ardrone_control.c文件中,修改为:
#ifdef _WIN32
int timeout_windows=1000;/*milliseconds*/
#endif
struct timeval tv;
即可。
2、error C2275: 'video_macroblock_t' : illegal use of this type as an expression
error C2065: 'macroblock_root' : undeclared identifier
error C2065: 'macroblock_root' : undeclared identifier
error C2065: 'macroblock_root' : undeclared identifier
error C2275: 'uint32_t' : illegal use of this type as an expression
error C2146: syntax error : missing ';' before identifier 'UI32_i'
error C2065: 'UI32_i' : undeclared identifier
error C2143: syntax error : missing ';' before 'type'
error C2275: 'uint32_t' : illegal use of this type as an expression
error C2146: syntax error : missing ';' before identifier 'y_size'
error C2065: 'y_size' : undeclared identifier
error C2065: 'c_size' : undeclared identifier
按照C语言严格的语法定义,函数内部所使用的变量,必须在函数的前部进行定义。
所以,按照这个标准来修改即可。
3、arpa/inet.h,ifaddrs.h文件无法找到。
Windows平台当然不需要这些Linux平台下的文件。连同wifi_config.c文件中使用到ifaddr结构体的地方直接注释掉即可。
4、无法找到文件<SDL/SDL.h>
新版SDL库的头文件中SDL.h文件直接放在include目录下,没有单独的目录。
修改为<SDL.h>即可。
5、无法找到<ardrone_at.c>文件。
很诡异的错误,SDK1.8的源代码包中并没有这个文件,但它的工程项目中却又包含了这个文件。
通过查看ARDroneLib\Soft\Lib\ardrone_tool\AT目录,发现其中包含了ardrone_at_mutex.c文件,是ardrone_at.c实现了线程同步的版本。
从SDK的工程项目中移除ardrone_at.c文件,将ardrone_at_mutex.c文件添加到工程项目中。
编译出现下面这个错误:AT_CODEC_FUNCTIONS_PTRS的使用方式非法。
将函数内部的代码修改为:
if( funcs != NULL)
{
memcpy(&func_ptrs, funcs, sizeof(*funcs));
}
else
{
#if defined (_MSC_VER)
AT_CODEC_FUNCTIONS_PTRS ptrs =
{
/*init*/host_init,
/*shutdown*/host_shutdown,
/*enable*/host_enable,
/*open*/host_open,
/*close*/host_close,
/*write*/host_write,
/*read*/host_read
};
#else
AT_CODEC_FUNCTIONS_PTRS ptrs =
{
.init = host_init,
.shutdown = host_shutdown,
.enable = host_enable,
.open = host_open,
.close = host_close,
.read = host_read,
.write = host_write,
};
#endif
vp_os_mutex_init(&at_mutex);
ATcodec_Init_Library( &ptrs );
}即可。
6、Error 2 error LNK2001: unresolved external symbol _ardrone_general_navdata_release navdata.obj Win32Client
Error 3 error LNK2001: unresolved external symbol _ardrone_general_navdata_process navdata.obj Win32Client
Error 4 error LNK2001: unresolved external symbol _ardrone_general_navdata_init navdata.obj Win32Client
函数有声明却没有实现,当然就链接出错了。
在ardrone_navdata_control.c文件的末尾添加以下几段代码即可:
C_RESULT ardrone_general_navdata_init( void* data ) {
return C_OK;
}
C_RESULT ardrone_general_navdata_process( const navdata_unpacked_t* const navdata ) {
return C_OK;
}
C_RESULT ardrone_general_navdata_release( void ) {
return C_OK;
}
7、Error 4 error LNK2001: unresolved external symbol _custom_configuration_headers
Error 5 error LNK2001: unresolved external symbol _available_configurations
这个错误很讨厌,是因为SDK里面没有包含全部所需的源文件所致。
将
config_keys.c添加到SDK工程项目中即可。
8、error LNK2019: unresolved external symbol _p264_codec_alloc referenced in function _video_codec_open_private
error LNK2019: unresolved external symbol _p264_codec_free referenced in function _video_codec_close_private
ardrone支持两种视频编码方式,即uvlc和p264编码方式,默认为uvlc方式,p264是可选的编码方式。官网上说,p264编码方式的用途
就在于网络状况较差的情况下,视频传输可以占用较少的带宽,以供导航数据和控制命令的传输。
所以,暂时就不使用p264编码方式了。
在
video_codec.c文件中,注释掉一下代码即可:
//extern void p264_codec_alloc( video_controller_t* controller );
//extern void p264_codec_free( video_controller_t* controller );
// case P264_CODEC:
// p264_codec_alloc( controller );
// break;
// case P264_CODEC:
// p264_codec_free( controller );
// break;
至此,ARDrone SDK 1.8应该能够编译通过了。
下面编译Win32 Demo,出现了如下的错误:
1、ardrone_at_set_toy_configuration无法识别的符号。在ardrone_api.h文件中查找了一番,确实没有找到这个函数的声明。但是对于SDk1.6,乃至1,7都是可用的,起码编译时,不会出现这种错误。
看了SDK1.6和1.7的工程项目,发现其包含了之前所述的ardrone_at.c文件,其中有ardrone_at_set_toy_configuration的实现方式。
然而在ardrone_at_mutex.c文件中,并没有
ardrone_at_set_toy_configuration的实现,而是替换成了ardrone_at_set_toy_configuration_ids。
由于ARDrone firmware 1.7.4支持多用户、多任务,所以,对其的配置方式也就发生了变化,在函数ardrone_at_set_toy_configuration_ids中,需要给出session_id,user_id和application_id等编号。
在ardrone_tool_win32.c文件中,函数static C_RESULT ardrone_tool_configure()中修改为:
// ardrone_at_set_toy_configuration( configure_data[configure_index].var, configure_data[configure_index].value );
ardrone_at_set_toy_configuration_ids( configure_data[configure_index].var, ses_id, usr_id, app_id,
configure_data[configure_index].value );
函数static void ardrone_tool_end_configure( struct _ardrone_control_event_t* event )中修改为:
//ardrone_at_set_toy_configuration( configure_data[configure_index].var, configure_data[configure_index].value );
ardrone_at_set_toy_configuration_ids( configure_data[configure_index].var, ses_id, usr_id, app_id,
configure_data[configure_index].value );
即可。
2、看到,在函数ardrone_at_set_toy_configuration_ids中使用到了session_id,user_id和application_id,以实现不同用户、不同会话中对ardrone的局部配置。故,相比于之前的ardrone_tool_win32.c文件,需要声明如下变量:
char app_id [MULTICONFIG_ID_SIZE] = "00000000"; // Default application ID.
char app_name [APPLI_NAME_SIZE] = "Default application"; // Default application name.
char usr_id [MULTICONFIG_ID_SIZE] = "00000000"; // Default user ID.
char usr_name [USER_NAME_SIZE] = "Default user"; // Default user name.
char ses_id [MULTICONFIG_ID_SIZE] = "00000000"; // Default session ID.
char ses_name [SESSION_NAME_SIZE] = "Default session"; // Default session name.
#ifndef __SDK_VERSION__
#define __SDK_VERSION__ "1.8" // TEMPORARY LOCATION OF __SDK_VERSION__ !!!
#endif
即可。
至此,Win32 Demo终于能够顺利通过编译了。
刷固件1.7.4,运行编译好的Win32平台的Demo程序,检测到ARDrone,1.7.4版本,好的,press Enter,连接超时。如下所示:
Input device DirectX Keyboard added
Input device DirectX Gamepad init failed
Starting thread directx_renderer_thread
Starting thread video_stage
Starting thread navdata_update
Video stage thread initialisation
Thread navdata_update in progress...
Starting thread ardrone_control
Sending flat trim - make sure the drone is horizontal at client startup.
[Pitch 0.000000] [Roll 0.000000] [Yaw 0.000000] [Gaz 0.000000] port 5554
[Pitch 0.000000] [Roll 0.000000] [Yaw 0.000000] [Gaz 0.000000]
Connection timed out
在开发者论坛搜索了一阵子,找到了如下的 解决方法:(firmware 1.6.6及其之后的版本)
分为两步:
(1)在ARDroneLib\Soft\Lib\ardrone_tool\Navdata\ardrone_navdata_client.c文件中,将原有代码 navdata_write( (void*)&navdata_socket, (int8_t*)"Init", &sizeinit ); 修改为navdata_write((void*)&navdata_socket, (int8_t*)"\1\0\0\0", &sizeinit);
(2)在
Soft\Lib\ardronetool\video\video_com_stage.c文件中,将原有代码:
sizeinit = strlen("Init");
vp_com_write_socket(&cfg->socket,"Init",&sizeinit);
修改为:
sizeinit = strlen("\1\0\0\0");
vp_com_write_socket(&cfg->socket,"\1\0\0\0",&sizeinit);
然后再次运行程序,连接上ARDrone以后,可以获得导航数据和视频信号,飞行器控制命令发送正常,飞行器运行良好。
可是问题又再次出现了。
切换前部和底部摄像头,分别获取不同的视频数据时,又出现了无法切换的问题。检查了代码,使用的是ardrone_at_zap方法实现摄像头切换的。查了下SDK 1.8的ardrone_api.h文件,该函数的声明尚在,很是费解。仔细查看了开发者手册之后,发现,原来在firmware1.6.6之后,切换摄像头命令需要发送的控制命令由"AT*ZAP"修改为"AT*CONFIG",猜想,是该版本的固件对"AT*ZAP"命令不在解析的缘故。(可是ardrone_at_zap函数尚在,这SDK更新的不够彻底嘎!)
手册里给出了解决方案,即使用ARDRONE_TOOL_CONFIGURATION_ADDEVENT宏来替代之前的ardrone_at_zap发送切换摄像头的控制命令, ARDRONE_TOOL_CONFIGURATION_ADDEVENT (video_channel, (int32_t*)value, myCallback);
按照手册里给出的方法,修改原有SDK 1.8的工程,将
ardrone_tool_configuration.h和ardrone_tool_configuration.c文件包含进工程项目中,重新编译SDK,然后在"gamepad.cpp"文件中添加#include <ardrone_tool/ardrone_tool_configuration.h>声明。
当用户按下"C"按键时,切换摄像头即video_channel,主要代码如下:
camMode += 1;
camMode %= 4;
switch (camMode)
{
case 0:
{
ARDRONE_TOOL_CONFIGURATION_ADDEVENT (video_channel, &camMode, NULL);
。。。。。。。。。
编译也没有错误,心想这下大功告成了。谁料运行程序时,一点下C键,就出现内存地址访问非法的错误,程序被强制关闭。
调试跟踪,进入了ARDroneLib\Soft\Common\config_keys.h文件中的ARDRONE_CONFIG_KEY_IMM_a10("video", video_channel, INI_INT, int32_t, int32_t*, (K_READ|K_WRITE|K_NOBIND|K_SHALLOW), (K_READ|K_WRITE), 0, video_channel_selection_callback,CAT_SESSION)
编译器指示该处内存访问非法。(这个搞不懂了,没办法,这个方法行不通,不知道是哪里出了问题)
要说有个可以相互交流论坛就是好,碰到问题了就有地方寻找解决方案了。
呵呵呵,有开发者提到使用ardrone_at_set_toy_configuration("video:video_channel", "0")可以用来切换摄像头。
赶忙试了下,编译错误,说是
ardrone_at_set_toy_configuration未知的符号。好吧,查找了一下ardrone_api.h,果然没有该函数的声明,看了下SDk1.6,居然有耶。
又有网友建议使用宏ARDRONE_TOOL_CONFIGURATION_SET(video_channel,ZAP_CHANNEL_NEXT);来解决此问题,又赶忙试了下,编译错误,未定义的宏,看了下ardrone_tool_configuration.h文件,该宏已经被注释掉了,在SDK1.8中不再使用了。(悲剧)
正郁闷的翻看着ardrone_api.h文件中函数的声明,偶然发现有个函数
avoid ardrone_at_set_toy_configuration_ids(const char* param,char* ses_id, char* usr_id, char* app_id, const char* value) API_WEAK;哈哈,原来是新版的ardrone_at_set_toy_configuration,支持多用户、多任务的版本。
拿来试一下,
if (EVENTKB(DIK_C) && TESTKB(DIK_C)) {
camMode += 1;
camMode %= 4;
switch (camMode)
{
case 0:
{
ardrone_at_set_toy_configuration_ids("video:video_channel", ses_id, usr_id, app_id, "0");
break;
}
case 1:
{
ardrone_at_set_toy_configuration_ids("video:video_channel", ses_id, usr_id, app_id, "1");
break;
}
case 2:
{
ardrone_at_set_toy_configuration_ids("video:video_channel", ses_id, usr_id, app_id, "2");
break;
}
case 3:
{
ardrone_at_set_toy_configuration_ids("video:video_channel", ses_id, usr_id, app_id, "3");
break;
}
}
}
效果很是不错,切换摄像头的功能可以使用了。^_^
可是目前阶段完全使用不到多用户、多任务的功能,这样调用岂不是太麻烦了。
既然开发者手册里面有讲切换video_channel的功能可以通过发送"AT*CONFIG"命令来实现。于是想着自己编写一个函数来发送切换video_channel的AT命令,然后编译到ArDroneAPI.lib 文件中,在外部程序中再来调用该方法。哈哈,赶忙试一下。
在ardrone_at_mutex.c文件中,添加如下的函数:
void ardrone_at_video_channel(const char* video, const char* channel)
{
if (!at_init)
return ;
vp_os_mutex_lock(&at_mutex);
ATcodec_Queue_Message_valist(ids.AT_MSG_ATCMD_CONFIG_EXE,
++nb_sequence,
video,
channel);
vp_os_mutex_unlock(&at_mutex);
}
然后在ardrone_api.h文件中添加如下的函数声明,以供外部程序调用:
void ardrone_at_video_channel(const char* video, const char* channel) API_WEAK;
在"gamepad.cpp"文件中将之前的控制代码换为:
if (EVENTKB(DIK_C) && TESTKB(DIK_C)) {
camMode += 1;
camMode %= 4;
switch (camMode)
{
case 0:
{
ardrone_at_video_channel("video:video_channel", "0");
break;
}
case 1:
{
ardrone_at_video_channel("video:video_channel", "1");
break;
}
case 2:
{
ardrone_at_video_channel("video:video_channel", "2");
break;
}
case 3:
{
ardrone_at_video_channel("video:video_channel", "3");
break;
}
}
}
恩、效果良好,使用起来也方便了许多。哈哈。
ARDrone SDk 1.8,固件 1.7.4,最新的平台,windows平台下新的demo程序,都可以跑起来了。
下面可以进行其他方面的实验了。