多旋翼无人机

    返回首页    发表留言
本文作者:李德强
          第二节 应用级驱动
 
 

        我们接着上一节的内容来学习驱动程序的开发,本节要学习的是用应级驱动的开发:

        与系统级驱动不同的是,应用级驱动只需要对已存在的设备节点进行操作,并与上层应用程序做交互即可。也就是说,应用级驱动的作用是将已存在的设备与上层应用建立起一个链接。通常可以使用任何方式的数据通讯,但在PX4里采用的方式是uORB机制。例如:我们在/dev下有一个串口设备结节/dev/ttyS2,我们将一个GPS设备接入到这个串口节点上,然后就可以通过标准的驱动程序调用(open、close、read、write、seek、ioctl等)来对这个设备节点/dev/ttyS2来操作了。下面我们来通过一个简单的例子来实现这样的一个应用级驱动程序。

        1.配置编译选项:在cmake/configs/nuttx_px4fmu-v3_default.cmake中config_module_list列表中加入gps驱动的编译选项:

        2.创建驱动程序:在src/drivers/目录下创建一个叫gps的文件夹src/drivers/gps,并在其中创建两个文件CMakeLists.txt和gps.c(这里作者是采用C语言来编写的驱动程序,如果使用C++的话需要创建gps.cpp不再赘述):

px4_add_module(
	MODULE drivers__gps  #模块名称
	MAIN gps             #入口函数 int gps_main(int argc, char *argv[])
	STACK_MAIN 2000      #栈大小
	SRCS                 #源代码文件
		gps.c
	DEPENDS              #依赖模块
		platforms__common
	)

 

        3.编写入口函数:在gps.c中声明并实现一个叫gps_main()的主函数,在这里我们通过对argv[1]参数来判断用户的两个操作:start和stop,即为启用/停用gps驱动程序,在启用时调用start()函数,在停用时调用stop()函数:

 

int gps_main(int argc, char *argv[]);

int gps_main(int argc, char *argv[])
{
	if (strcmp(argv[1], "start") == 0)
	{
		start();
		return 0;
	}

	if (strcmp(argv[1], "stop") == 0)
	{
		stop();
		return 0;
	}

	info();
	return 0;
}

 

        4.创建后台运行进程:关于创建进程和线程或是工作队列的相关知识,我们在后续章节中来学习,这里读者只需要知道我们是通过px4_task_spawn_cmd()函数创建了一个进程即可:

 

static int _running = 0;

void start(void)
{
	_running = 1;
	int taskid = px4_task_spawn_cmd("gps", 
                                    SCHED_DEFAULT, 
                                    SCHED_PRIORITY_SLOW_DRIVER, 
                                    CONFIG_PTHREAD_STACK_DEFAULT, 
                                    &gps_core, NULL);
	if (taskid < 0)
	{
		printf("gps start err.\n");
	}
}

void stop(void)
{
	_running = 0;
}

        程序中定义了一个静态变量static int _running = 0;在start()函数中将其赋值为1,表示运行;在stop()函数中将其赋值为0,表示停止,这个_running在下面的核心函数中的while(_running)作为循环的条件。

 

        5.驱动核心函数:在这里我们将核心函数命名为gps_core(),在它内部通过一个while(_running),来循环读取/dev/ttyS2中的数据,并显示出来:

 

int gps_core(int argc, char *argv[])
{
	char buff[200];

	int fd = open("/dev/ttyS2", O_RDONLY | O_NONBLOCK);
	if (fd < 0)
	{
		printf("open dev err.\n");
		return -1;
	}

	while (_running)
	{
		int len = read(fd, buff, 200);
		if (len > 0)
		{
			for (int i = 0; i < len; i++)
			{
				putchar(buff[i]);
			}
		}
		usleep(10 * 1000);
	}

	return 0;
}

        这样我们就通过对/dev/ttyS2的读取操作,将gps设备中的数据显示出来,结果如下:

$GPGGA,,,,,,0,,,,,,,,*66
#BESTVELA,COM1,0,69.0,UNKNOWN,0,88.400,004c0000,10a2,14392;
INSUFFICIENT_OBS,NONE,0.000,0.000,0.0000,0.000000,0.0000,0*663f14ae
$GPGGA,,,,,,0,,,,,,,,*66
#BESTVELA,COM1,0,73.5,UNKNOWN,0,88.600,004c0000,10a2,14392;
INSUFFICIENT_OBS,NONE,0.000,0.000,0.0000,0.000000,0.0000,0*d557333d
$GPGGA,,,,,,0,,,,,,,,*66
#BESTVELA,COM1,0,73.5,UNKNOWN,0,88.800,004c0000,10a2,14392;
INSUFFICIENT_OBS,NONE,0.000,0.000,0.0000,0.000000,0.0000,0*f23a6b0d

        此测试结果不是在户外运行的结果,所以没有经度纬度和速度内容,但基本数据的格式已经显示出来,说明我们的驱动程序已经可以正常工作了。

 

        6.发布uORB:通过上面的程序可以将gps的数据显示出来,但我们的目的是通过uORB机制将数据提供给上层应用使用,所以还需要将数据组织成uORB的msg格式,并用“公告”、“发布”的方式向上层应用发布uORB:

struct gps_s _orb_gps = {0};
_orb_gps_topic = orb_advertise_multi(ORB_ID(gps), 
                                     &_orb_gps, 
                                     &_orb_gps_instance, 
                                     ORB_PRIO_DEFAULT);
while (_running)
{
	int len = read(fd, buff, BUFF_SIZE);
	//组织uORB的msg数据到_orb_gps结构体对象中
	...
	orb_publish(ORB_ID(gps), _orb_gps_topic, &_orb_gps);
	usleep(MS_SLEEP * 1000);
}

        关于uORB的原理与使用我们已经在前面的章节中学习过了,这里不再赘述。

    返回首页    返回顶部
  看不清?点击刷新

 

  Copyright © 2015-2018 问渠网 辽ICP备15013245号