# PX4固件调试 #
[toc]
Ubuntu下Eclipse的安装参考我的博客;
如何在Eclipse下搭建PX4开发环境参见[一个国外的网站](https://uav-lab.org/2016/07/28/px4-research-log-2-how-to-set-up-px4-development-environment-on-ubuntu/)之第5项;
参考资料:
- PX4固件在github上的代码仓库:https://github.com/PX4/Firmware;
- 我自己在github上的代码仓库:邮箱(408513516@qq.com)或用户名(thrillerqin)登录;
- 我在CSDN上的博客地址:是用我的QQ号登录的;
- git学习参考[廖雪峰的git教程](www.liaoxuefeng.com),通俗易懂;
- [PX4串口、主题发布订阅方面很实用的博客](http://blog.csdn.net/freeape/article/details/47837415),也是我在编写天腾大气探测项目是参考的框架;
- 串口调试工具:gtkterm,不是很好用,不方便,每次插拔usb串口时需重新配置打开串口,而且配置的方式也不方便,就因为这个导致调试mavlink时耽误了很长时间;
- cutecom,挺好用的串口调试工具,就用这个了以后;
- git图形化工具,我选用了gitkraken,跨平台的;
**大气探测模块项目在本地的位置:src/examples/tt_atmos_detect**
### 2017年5月8日 ###
v1.5.0上创建atmos_detect分支,用于开发大气探测无人机;
### 2017年6月6日 ###
由于昨天的失误,执行make distclean指令后将自己后加的代码全部清除,所以今天就从头再来,从git clone开始!!!
1. 从[PX4固件的官方仓库](https://github.com/PX4/Firmware)fork一份PX4固件到[自己仓库](https://github.com/thrillerqin),我此时fork的版本是1.6.1,该PX4在[我代码仓库的地址](https://github.com/thrillerqin/Firmware),以后我就可以在我的这个代码仓库里工作了,不影响官方的PX4仓库。
1. 从我的PX4 Firmware代码仓库clone一份到本地。由于PX4固件包含子模块(位于别的代码仓库里的模块),在克隆代码仓库或checkout特定的版本仓库后,一定要记得更新相应的子模块(若代码仓库有的话),因为克隆代码仓库时不会自动克隆子模块。须执行git submodule,否则会造成子模块缺失或和主代码仓库不兼容。
关于submodule具体参考网页:
[网页1](http://blog.csdn.net/wangjia55/article/details/24400501)
[网页2](http://www.tuicool.com/articles/jqiEJzU)
克隆过程如下:
```
mkdir src
cd src
git clone git@github.com:thrillerqin/Firmware.git
cd Firmware
git submodule update --init --recursive
```
1. 准备创建自己的分支,复习下常用的git指令:
```
git status |查看当前的状态
git tag |列出所有的标签,这里列出的标签有v1.4.1,v1.5.0等
git branch |列出所有分支,这里的分支只有master
git checkout |切换至相应的分支或者标签
```
克隆代码以后,checkout到v1.5.0上,并创建atmos_detect分支,用于开发大气探测无人机,过程如下:
在本地PX4 Firmware目录下,
```
git status |查看当前的状态
git tag |列出所有的标签,这里列出的标签有v1.4.1,v1.5.0等
git branch |列出所有分支,这里的分支只有master
git checkout v1.5.0 |切换至相应的标签v1.5.0
HEAD detached at v1.5.0
git submodule update --init --recursive
qb@qb-Lenovo-XiaoXin-310-15IKB:~/tt_atmos_detect/Firmware$ git branch tt_atmos_detect |创建分支tt_atmos_detect
qb@qb-Lenovo-XiaoXin-310-15IKB:~/tt_atmos_detect/Firmware$ git branch |查看分支
* (HEAD detached at v1.5.0)
master
tt_atmos_detect
qb@qb-Lenovo-XiaoXin-310-15IKB:~/tt_atmos_detect/Firmware$ git checkout tt_atmos_detect |切换至分支tt_atmos_detect
Switched to branch 'tt_atmos_detect'
qb@qb-Lenovo-XiaoXin-310-15IKB:~/tt_atmos_detect/Firmware$ git status |查询状态,目前在分支tt_atmos_detect
On branch tt_atmos_detect
```
1. 把该工程导入eclipse,具体过程参考一国外网页(https://uav-lab.org/2016/07/28/px4-research-log-2-how-to-set-up-px4-development-environment-on-ubuntu/之第5项)。由于PX4原生固件代码包含了eclipse工程文件,导入过程非常简单:在源码文件目录(如,~/tt_atmos_detect/Firmware),“eclipse.cproject”重命名为“.cproject”, “eclipse.project”重命名为“.project”。
启动eclipse,创建一个新的工作区,单击File->Import...在弹出对话框选择General->Existing Projects into Workspace,单击next弹出下一个对话框,单击Select root directory右侧的按钮Browse… ,选择代码的目录单击Ok. You should see PX4-Firmware in available projects. Select the project and click finish.
到工程界面,build target(px4fmu-v2_default),编译时出错,按照出错提示安装相应的软件即可(注意,由于系统配置的不同,需安装的程序也不同,我之前第一次编译时就是直接通过的,这期间可能是因为在整mavlink时配置python环境整的),一定要看系统错误或提示信息,他有时会给解决方案,以下是这次按错误提示信息所做的工作,仅限这次,下次还不一定出什么别的幺蛾子:
qb@qb-Lenovo-XiaoXin-310-15IKB:~$ sudo pip install catkin_pkg
qb@qb-Lenovo-XiaoXin-310-15IKB:~$ sudo pip install catkin_pkg
重新build target(px4fmu-v2_default),编译链接成功!
在左侧工程管理窗口Build Targets右键选择create...新建名为px4fmu-v2_default upload的Target,用于向飞控烧写程序。
1. 创建用户自定义消息,并公告发布订阅主题。
固件中消息位于Firmware/msg/*.msg,可以参考现有消息格式新建自定义消息。在Firmware/msg/下新建文件sensor_atmos.msg,有关大气主题的消息内容:
```
#天腾大气传感器数据项
int8 temperature #温度,int8
uint8 humidity #湿度,uint8
uint16 O3
uint16 CO
uint16 PM2_5
uint16 PM10
uint16 NO2
uint16 SO2
```
把在文件名sensor_atmos.msg添加至Firmware/msg/CMakeList.txt
build Targets->all(必须选择all,其它不行),会生成该消息的头文件Firmware/uORB/sensor_atmos.h
### 编写一个简单的hello sky程序 ###
先初始牛刀,添加一个简单的hello sky程序熟悉下编译链接下载执行的流程,还是参考开发手册(教程->编写应用程序):
1. 现有固件代码中已包含hello sky例程,位于Firmware/src/example/px4_simple_app/,已经有现成的就可以直接用,若要使自己重写的话,参考example里的格式编写xx.c和对应的CMakeList.txt文件即可,一定要参考别的程序格式!
2. 有了自己的代码之后,需要添加到该工程,否则不能被build,肿么添加?因为PX4原生固件工程是由CMake组织管理的,具体怎么管理我也不清除,跟着PX4开发手册走就行了:Pixhawk v1/2的CMake总工程文件:Firmware/cmake/configs/nuttx_px4fmu-v2_default.cmake,在该文件中参考其它程序添加第一步的源码文件名,格式参考文件中的其它代码;
3. Build Targets -> px4fmu-v2_default -> px4fmu-v2_default upload,下载程序,OK!!!在upload程序时若一直uploading没有进度的话,可以重新插拔下usb接口;
4. 确认Pixhawk没插SD卡,重启Pixhawk,进入nsh模式。据本人不准确的信息,v1.5.0和之前的版本支持无sd卡启动进入nsh模式,之后的版本不支持,若还想之前那样进入nsh模式需修改启动文件
>[warning]Firmware/ROMFS/px4fmu_common/init.d/rcS,具体添加什么内容、添加到什么位置参考之前的版本。
5. 怎么登录Pixhawk的nsh命令终端,在Ubuntu下打开命令行终端,输入一下命令(通过串口连接至pixhawk串口/dev/ttyACM0,波特率115200,参数8n1):
>qb@qb-Lenovo-XiaoXin-310-15IKB:~$ screen /dev/ttyACM0 115200 8n1
回车后进入nsh模式,由于PX4+Pixhawk是基于嵌入式操纵系统nuttx开发的,nuttx类似有点类似linux,所谓nsh就是nuttx shell,在该模式下支持许多类linux的命令,如ls、cd等等。输入命令help查看nsh支持的指令(按组合键ctrl+a+[可以翻屏),包括系统命令和用户的命令,在这里你会惊喜的发现之前编写的程序居然成了用户命令“px4_simple_app”。输入该命令试试:
>nsh> px4_simple_app
INFO [px4_simple_app] Hello Sky!
WARN [px4_simple_app] [px4_simple_app] Accelerometer: -0.0596 -0.0030 -9.9813
WARN [px4_simple_app] [px4_simple_app] Accelerometer: -0.0810 -0.0107 -9.8812
WARN [px4_simple_app] [px4_simple_app] Accelerometer: -0.0454 0.0130 -9.8755
WARN [px4_simple_app] [px4_simple_app] Accelerometer: -0.0602 0.0118 -9.8558
WARN [px4_simple_app] [px4_simple_app] Accelerometer: -0.0745 0.0102 -9.9096
INFO [px4_simple_app] exiting
**居然有反应!!!成功的开始!!!**
### 开始自己的项目 ###
熟悉了PX4开发的基本流程后,开始自己的项目:天腾大气监测,英文名是tianteng_atmos_detect,这名字是不是很大气?对,就是这么大气!
这个项目的架构如下:
- 大气传感器(via串口) --> PX4飞控板 --> 地面站(via mavlink协议);
- 程序负责通过串口读取大气传感器数据,跟新自定义大气传感器消息,公告发布基于大气传感器消息的主题,发送有关大气传感器数据的mavlink消息给地面站
虽然有了以上的一些些基础,等到要去做一个具体的项目是还是觉得欠的太多,有时间的话可以挑出一个nsh的用户指令,再找到对应的代码研究,这样会逐步熟悉PX4原生固件的架构,掌握整个项目。现在没时间去这么一步步学习,幸好有度娘,找到了一篇好的csdn博客,PX4串口、主题发布订阅方面很实用的博客,也是我在[编写天腾大气探测项目时参考的框架](http://blog.csdn.net/freeape/article/details/47837415)。
PX4进程间通过uORB通讯,如何公告发布订阅主题,可以参考开发手册->中间件及架构->uORB部分。
1. 新建src/modules/tianteng_atmos_detect/tianteng_atmos_detect.c,添加大气传感器头文件:
>#include <uORB/topics/sensor_atmos.h>
2. 在此编写代码实现串口接受数据并公告发布主题。
3. build并upload之后,在nsh就能显示该用户命令了,调试的时候可以这么办,总不能让用户也这么用吧,还是有办法的。可以把该程序添加到启动文件Firmware/ROMFS/px4fmu_common/init.d/rcS,在该文件“# End of autostart”之前添加内容:tianteng_atmos_detect start /dev/ttyS6,之所以写成这个形式请自行分析代码tianteng_atmos_detect.c。
### 2017年6月10日 ###
重新实现了读取串口消息->公告发布消息主题,测试的方式是tianteng_atmos_detect在开机时自动启动,负责接收串口(SERIAL 4,/dev/ttyS6)消息,并公告发布sensor_atmos主题,px4_simple_app负责订阅消息,并打印出来,在Ubuntu用的串口调试工具是GtkTerm.
#### 发送用户自定义mavlink消息 ####
根据开发文档->中间件及架构->自定义MAVLink消息,还有CSDN上[一篇非常有用的FantasyJXF的博客](http://blog.csdn.net/oqqenvy12/article/details/56849572)学习实现。
1. 创建自定义uORB消息msg/custom_messages.msg,build all之后会生成对应的头文件uORB/custom_messages.h;
1. 在custom_messages.xml中创建自定义MAVLink消息;
1. 使用Python -m mavgenerate打开mavlink消息生成器导入上面的xml文件,生成相应的C文件;
1. 将生成的custom_messages文件夹拖到Firmware/mavlink/include/mavlink/v1.0目录下;
1. 发送自定义MAVLink消息;
1. 添加mavlink的头文件和uorb消息到mavlink_messages.cpp;
1. 在mavlink_messages.cpp中创建一个新的类;
1. 附加流类streams_list的到mavlink_messages.cpp底部;
1. 最后在mavlink_main.cpp加入自定义的消息以及期望的更新频率;
以上写的这些步骤是在fantasyJXF的博客中摘抄的,描述的具体详细,经本人实践没有问题!
实际调试的时候遇到了问题,PX4接收到串口消息后,发布消息(确认发布成功),按道理应该发送对应的mavlink消息,结果却在串口调试工具(GTKterm)中没有发现该消息,就因这个问题折腾了将近一周的时间,总以为是是在以上步骤中哪步有问题,后来发现是串口调试工具(GTKterm)的问题,每次烧写或开机重启PX4后须重新设置下这个串口工具,否则不能正常通讯。工欲善其事必先利其器。
#### 接收到的消息,存入SD卡 ####
从串口接收到消息以后存入SD卡,具体参考如下代码:
```
int tianteng_atmos_detect_thread_main(int argc, char *argv[])
{
if (argc < 2) {
errx(1, "[YCM]need a serial port name as argument");
usage("eg:");
}
const char *uart_name = argv[1];
warnx("[YCM]opening port %s", uart_name);
char data = '0';
char buffer[5] = "";
/*
* TELEM1 : /dev/ttyS1
* TELEM2 : /dev/ttyS2
* GPS : /dev/ttyS3
* NSH : /dev/ttyS5
* SERIAL4: /dev/ttyS6
* N/A : /dev/ttyS4
* IO DEBUG (RX only):/dev/ttyS0
*/
int uart_read = uart_init(uart_name);
if(false == uart_read)return -1;
if(false == set_uart_baudrate(uart_read,9600)){
printf("[YCM]set_uart_baudrate is failed\n");
return -1;
}
printf("[YCM]uart init is successful\n");
thread_running = true;
/*初始化数据结构体 */
struct sensor_atmos_s sensor_atmos_data;
memset(&sensor_atmos_data, 0, sizeof(sensor_atmos_data));
/* 公告主题 */
orb_advert_t sensor_atmos_pub = orb_advertise(ORB_ID(sensor_atmos), &sensor_atmos_data);
/////////////////////////////
FILE *fd = NULL;
char pname[64];
time_t timeSec = time(NULL);//1970.01.01
struct tm *timeinfo=localtime(&timeSec);
sprintf(pname, PX4_ROOTFSDIR"/fs/microsd/TIANTENG(%d_%d_%d).txt", timeinfo->tm_year+1900,timeinfo->tm_mon+1,timeinfo->tm_mday);
//sprintf(pname, PX4_ROOTFSDIR"/fs/microsd/TIANTENG.txt");
fd = fopen(pname,"a");//
fsync(fileno(fd));
fclose(fd);
/*
FILE *f = fopen(PX4_ROOTFSDIR"/fs/microsd/inav.log", "a");
if (f) {
char *s = malloc(256);
unsigned n = snprintf(s, 256,
"%llu %s\n\tdt=%.5f x_est=[%.5f %.5f] y_est=[%.5f %.5f] z_est=[%.5f %.5f] x_est_prev=[%.5f %.5f] y_est_prev=[%.5f %.5f] z_est_prev=[%.5f %.5f]\n",
(unsigned long long)hrt_absolute_time(), msg, (double)dt,
(double)x_est[0], (double)x_est[1], (double)y_est[0], (double)y_est[1], (double)z_est[0], (double)z_est[1],
(double)x_est_prev[0], (double)x_est_prev[1], (double)y_est_prev[0], (double)y_est_prev[1], (double)z_est_prev[0],
(double)z_est_prev[1]);
fwrite(s, 1, n, f);
n = snprintf(s, 256,
"\tacc=[%.5f %.5f %.5f] gps_pos_corr=[%.5f %.5f %.5f] gps_vel_corr=[%.5f %.5f %.5f] w_xy_gps_p=%.5f w_xy_gps_v=%.5f mocap_pos_corr=[%.5f %.5f %.5f] w_mocap_p=%.5f\n",
(double)acc[0], (double)acc[1], (double)acc[2],
(double)corr_gps[0][0], (double)corr_gps[1][0], (double)corr_gps[2][0], (double)corr_gps[0][1], (double)corr_gps[1][1],
(double)corr_gps[2][1],
(double)w_xy_gps_p, (double)w_xy_gps_v, (double)corr_mocap[0][0], (double)corr_mocap[1][0], (double)corr_mocap[2][0],
(double)w_mocap_p);
fwrite(s, 1, n, f);
n = snprintf(s, 256,
"\tvision_pos_corr=[%.5f %.5f %.5f] vision_vel_corr=[%.5f %.5f %.5f] w_xy_vision_p=%.5f w_z_vision_p=%.5f w_xy_vision_v=%.5f\n",
(double)corr_vision[0][0], (double)corr_vision[1][0], (double)corr_vision[2][0], (double)corr_vision[0][1],
(double)corr_vision[1][1], (double)corr_vision[2][1],
(double)w_xy_vision_p, (double)w_z_vision_p, (double)w_xy_vision_v);
fwrite(s, 1, n, f);
free(s);
}
fsync(fileno(f));
fclose(f);
*/
/////////////////////////////
while(!thread_should_exit){
read(uart_read,&data,1);
if(data == 'R'){
for(int i = 0;i <4;i++){
read(uart_read,&data,1);
buffer[i] = data;
data = '0';
}
//strncpy(sonardata.datastr,buffer,4);
//sonardata.data = atoi(sonardata.datastr);
sensor_atmos_data.CO = (buffer[0] & 0x0f) * 1000;
sensor_atmos_data.CO += (buffer[1] & 0x0f) * 100;
sensor_atmos_data.CO += (buffer[2] & 0x0f) * 10;
sensor_atmos_data.CO += (buffer[3] & 0x0f);
//printf("[YCM]sensor_atmos_data.CO=%d\n", sensor_atmos_data.CO);
orb_publish(ORB_ID(sensor_atmos), sensor_atmos_pub, &sensor_atmos_data);
write(uart_read,buffer,4); //串口消息回传用于调试
//存储数据
fd = fopen(pname,"a");//
///if (!fd){ //(fd != NULL) {
timeSec = time(NULL);//1970.01.01
timeinfo=localtime(&timeSec);
//fwrite("abcde", 5 , 5, fd);
fprintf(fd,"CO:%04d\t", sensor_atmos_data.CO);
fprintf(fd,"%d-%d-%d %d:%d:%d \n",timeinfo->tm_year+1900,timeinfo->tm_mon+1,timeinfo->tm_mday,timeinfo->tm_hour+8,timeinfo->tm_min,timeinfo->tm_sec);
// fclose(fd);
//}
fsync(fileno(fd));
fclose(fd);
}
//PX4_INFO("Hello Sky!");//printf("[YCM]qinbao\n");
//sleep(2); //延时2秒
}
//fclose(fd);
warnx("[YCM]exiting");
thread_running = false;
close(uart_read);
fflush(stdout);
return 0;
}
```
### 2017年5月14日 ###
暂时放弃tests模块的调试,先参考tests的代码先做大气传感器调试的工作。
基本的思路是:读传感器数据,解析数据,存储数据,争取这周能搞定,下周踏实去三亚;
pixhawk硬件部分的参考网站:http://www.pixhawk.com/modules/pixhawk
### 2017年5月15日 ###
在查找串口号和对应设备号关系的过程中发现查找官方资料的好的路径:
>[PIX HAWK官网](www.pixhawk.org) -> OVERVIEW -> INDEX
然后在user栏找到WIRING就ok了;
### 2017年5月16日 ###
按照[一篇博客的文章编写串口相关的程序](http://blog.csdn.net/freeape/article/details/47837415)
在Ubuntu上的串口调试工具:
1. 图形话调试工具,gtkterm,按命令提示安装;
2. 在网上找到一个在终端命令行调试的如下:
>cat /dev/ttyUSB0
某Makefile片段,代码:
```
#------------------------------------------
monitor:
stty -F /dev/ttyUSB0 9600 cs8 -parenb -cstopb
# stty -F /dev/ttyUSB0 5:0:8bd:0:3:1c:7f:15:4:0:1:0:11:13:1a:0:12:f:17:16:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
cat /dev/ttyUSB0
#------------------------------------------
```
### 2017年5月18日 ###
前两天主要是调试了串口,用gtkterm发送一组以0x0d结尾的数据,qb_atmos_detect接收以后,通过串口发送出去,可以通过gtkterm看到;
今天还是在那篇博客的指导下,熟悉订阅主题、发布主题的流程;
### 2017年5月20日 ###
Firmware/msg,新建文件sensor_atmos.msg,用于新建消息;
编译,Build Targets->all,注意选择的编译目标为all,编译过程中通过genmsg_cpp自动生成相应的头文件sensor_atmos.h,具体的生成过程在该头文件中有所描述,是这样的:Auto-generated by genmsg_cpp from file /home/qb/qinbao_px4_atmos_detect/Firmware/msg/sensor_atmos.msg。
### 2017年5月21日 ###
今天把发布主题和订阅主题了,接下来把这个过程记录下;
```
(argv) ? (char * const *)&argv[2] : (char * const *)NULL);
int qb_atmos_detect_thread_main(int argc, char *argv[])
{ char sample_test_uart[25] = {'S', 'A', 'M', 'P', 'L', 'E', ' ', '\n'};
PX4_INFO("Hello Sky!");
/*
NuttX UART PX4FMUv1 UART PX4FMUv2 (Pixhawk) UART
/dev/ttyS0 UART1(NSH console) IO DEBUG (RX only)
/dev/ttyS1 UART2 TELEM1 (USART1)
/dev/ttyS2 UART5 TELEM2 (USART2)
/dev/ttyS3 UART6 GPS (UARTX)
/dev/ttyS4 N/A N/A (UART5, IO link)
/dev/ttyS5 N/A SERIAL5 (UART7, NSH console do only use as console)
/dev/ttyS6 N/A SERIAL4 (UART8)
*/
int serial_port_fd = uart_init("/dev/ttyS6"); //SERIAL4 (UART8)
if(false == serial_port_fd) return -1;
if(false == set_uart_baudrate(serial_port_fd, 9600)){
printf("[YCM]set_uart_baudrate is failed\n");
return -1;
}
printf("[YCM]uart init is successful\n");
/* 订阅主题sensor_combined */
int sensor_sub_fd = orb_subscribe(ORB_ID(sensor_combined));
orb_set_interval(sensor_sub_fd, 1000);
/* 发布主题(advertise) attitude */
struct vehicle_attitude_s att;
memset(&att, 0, sizeof(att));
orb_advert_t att_pub = orb_advertise(ORB_ID(vehicle_attitude), &att);
/* 发布主题,天腾大气检测传感器主题 */
struct sensor_atmos_s atmos;
memset(&atmos, 0, sizeof(atmos));
orb_advert_t atmos_pub = orb_advertise(ORB_ID(sensor_atmos), &atmos);
/* one could wait for multiple topics with this technique, just using one here */
px4_pollfd_struct_t fds[] = {
{ .fd = sensor_sub_fd, .events = POLLIN },
/* there could be more file descriptors here, in the form like:
* { .fd = other_sub_fd, .events = POLLIN },
*/
};
int error_counter = 0;
for (int i = 0; i < 50; i++) { //qinbao 50
/* wait for sensor update of 1 file descriptor for 1000 ms (1 second) */
int poll_ret = px4_poll(fds, 1, 1000);
/* handle the poll result */
if (poll_ret == 0) {
/* this means none of our providers is giving us data */
PX4_ERR("[px4_simple_app] Got no data within a second");
} else if (poll_ret < 0) {
/* this is seriously bad - should be an emergency */
if (error_counter < 10 || error_counter % 50 == 0) {
/* use a counter to prevent flooding (and slowing us down) */
PX4_ERR("[px4_simple_app] ERROR return value from poll(): %d"
, poll_ret);
}
error_counter++;
} else {
if (fds[0].revents & POLLIN) {
/* obtained data for the first file descriptor */
struct sensor_combined_s raw;
/* copy sensors raw data into local buffer */
orb_copy(ORB_ID(sensor_combined), sensor_sub_fd, &raw);
PX4_WARN("[px4_simple_app] Accelerometer:\t%8.4f\t%8.4f\t%8.4f",
(double)raw.accelerometer_m_s2[0],
(double)raw.accelerometer_m_s2[1],
(double)raw.accelerometer_m_s2[2]);
/* set att and publish this information for other apps */
att.roll = raw.accelerometer_m_s2[0];
att.pitch = raw.accelerometer_m_s2[1];
att.yaw = raw.accelerometer_m_s2[2];
orb_publish(ORB_ID(vehicle_attitude), att_pub, &att);
}
//接收到以0x0d结尾的字符串后,??
int nread = 0;
int index = 0;
char c;
do {
nread = read(serial_port_fd, &c, 1);
if (nread > 0)
{
//printf("%c", c);
sample_test_uart[index++] = c;
}
} while (c != 0x0d);
orb_publish(ORB_ID(sensor_atmos), atmos_pub, &atmos);
write(serial_port_fd, sample_test_uart, index);//n);
/* there could be more file descriptors here, in the form like:
* if (fds[1..n].revents & POLLIN) {}
*/
}
}
PX4_INFO("exiting");
return 0;
}
```
### 2017年6月2日 ###
实现采集数据自动存入SD卡的功能,目前发现格式化SD卡之后用能正常读写,连续的SD使用就有问题,今天太晚了,明天再说;
```
int tianteng_atmos_detect_thread_main(int argc, char *argv[])
{
if (argc < 2) {
errx(1, "[YCM]need a serial port name as argument");
usage("eg:");
}
const char *uart_name = argv[1];
warnx("[YCM]opening port %s", uart_name);
char data = '0';
char buffer[5] = "";
/*
* TELEM1 : /dev/ttyS1
* TELEM2 : /dev/ttyS2
* GPS : /dev/ttyS3
* NSH : /dev/ttyS5
* SERIAL4: /dev/ttyS6
* N/A : /dev/ttyS4
* IO DEBUG (RX only):/dev/ttyS0
*/
int uart_read = uart_init(uart_name);
if(false == uart_read)return -1;
if(false == set_uart_baudrate(uart_read,9600)){
printf("[YCM]set_uart_baudrate is failed\n");
return -1;
}
printf("[YCM]uart init is successful\n");
thread_running = true;
/*初始化数据结构体 */
struct sensor_atmos_s sensor_atmos_data;
memset(&sensor_atmos_data, 0, sizeof(sensor_atmos_data));
/* 公告主题 */
orb_advert_t sensor_atmos_pub = orb_advertise(ORB_ID(sensor_atmos), &sensor_atmos_data);
/////////////////////////////
FILE *fd = NULL;
char pname[64];
time_t timeSec = time(NULL);//1970.01.01
struct tm *timeinfo=localtime(&timeSec);
sprintf(pname, "/fs/microsd/TIANTENG(%d_%d_%d).txt", timeinfo->tm_year+1900,timeinfo->tm_mon+1,timeinfo->tm_mday);
fd = fopen(pname,"a+");//
fclose(fd);
/////////////////////////////
while(!thread_should_exit){
read(uart_read,&data,1);
if(data == 'R'){
for(int i = 0;i <4;i++){
read(uart_read,&data,1);
buffer[i] = data;
data = '0';
}
//strncpy(sonardata.datastr,buffer,4);
//sonardata.data = atoi(sonardata.datastr);
sensor_atmos_data.CO = (buffer[0] & 0x0f) * 1000;
sensor_atmos_data.CO += (buffer[1] & 0x0f) * 100;
sensor_atmos_data.CO += (buffer[2] & 0x0f) * 10;
sensor_atmos_data.CO += (buffer[3] & 0x0f);
//printf("[YCM]sensor_atmos_data.CO=%d\n", sensor_atmos_data.CO);
orb_publish(ORB_ID(sensor_atmos), sensor_atmos_pub, &sensor_atmos_data);
//存储数据
fd = fopen(pname,"a+");//
timeSec = time(NULL);//1970.01.01
timeinfo=localtime(&timeSec);
fprintf(fd,"CO:%04d\t", sensor_atmos_data.CO);
fprintf(fd,"%d-%d-%d %d:%d:%d \n",timeinfo->tm_year+1900,timeinfo->tm_mon+1,timeinfo->tm_mday,timeinfo->tm_hour+8,timeinfo->tm_min,timeinfo->tm_sec);
fclose(fd);
write(uart_read,buffer,4); //串口消息回传用于调试
}
//PX4_INFO("Hello Sky!");//printf("[YCM]qinbao\n");
//sleep(2); //延时2秒
}
warnx("[YCM]exiting");
thread_running = false;
close(uart_read);
fflush(stdout);
return 0;
}
```
我安装的系统是ubuntu10.04。
sd卡插上之后,自动mount了。
所以,第一步,umount。
```
$sudo -i
```
输入自己的密码取得root权限。
```
# mount
```
可以看到最后一行的设备号
```
/dev/mmcblk0 on /media/60C5-3EC0 type vfat (rw,nosuid,nodev,uhelper=udisks,uid=1000,gid=1000,shortname=mixed,dmask=0077,utf8=1,flush)
```
umount这个sd卡
```
# umount /dev/mmcblk0
```
下面上场的是fdisk工具。
```
# fdisk /dev/mmcblk0
```
fdisk命令都是非常简单的。
>WARNING: DOS-compatible mode is deprecated. It's strongly recommended to
switch off the mode (command 'c') and change display units to
sectors (command 'u').
Command (m for help): m
Command action
a toggle a bootable flag
b edit bsd disklabel
c toggle the dos compatibility flag
d delete a partition
l list known partition types
m print this menu
n add a new partition
o create a new empty DOS partition table
p print the partition table
q quit without saving changes
s create a new empty Sun disklabel
t change a partition's system id
u change display/entry units
v verify the partition table
w write table to disk and exit
x extra functionality (experts only)
1. 先P,看看sd卡的分区现状。
1. 然后d,删除原分区
1. n,创建分区
>Command (m for help): n
Command action
e extended
p primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-62528, default 1): 1
Last cylinder, +cylinders or +size{K,M,G} (1-62528, default 62528): +1500M
t,指定分区类型,
Command (m for help): t
Selected partition 1
Hex code (type L to list codes): L
0 Empty 24 NEC DOS 81 Minix / old Lin bf Solaris
1 FAT12 39 Plan 9 82 Linux swap / So c1 DRDOS/sec (FAT-
2 XENIX root 3c PartitionMagic 83 Linux c4 DRDOS/sec (FAT-
3 XENIX usr 40 Venix 80286 84 OS/2 hidden C: c6 DRDOS/sec (FAT-
4 FAT16 <32M 41 PPC PReP Boot 85 Linux extended c7 Syrinx
5 Extended 42 SFS 86 NTFS volume set da Non-FS data
6 FAT16 4d QNX4.x 87 NTFS volume set db CP/M / CTOS / .
7 HPFS/NTFS 4e QNX4.x 2nd part 88 Linux plaintext de Dell Utility
8 AIX 4f QNX4.x 3rd part 8e Linux LVM df BootIt
9 AIX bootable 50 OnTrack DM 93 Amoeba e1 DOS access
a OS/2 Boot Manag 51 OnTrack DM6 Aux 94 Amoeba BBT e3 DOS R/O
b W95 FAT32 52 CP/M 9f BSD/OS e4 SpeedStor
c W95 FAT32 (LBA) 53 OnTrack DM6 Aux a0 IBM Thinkpad hi eb BeOS fs
e W95 FAT16 (LBA) 54 OnTrackDM6 a5 FreeBSD ee GPT
f W95 Ext'd (LBA) 55 EZ-Drive a6 OpenBSD ef EFI (FAT-12/16/
10 OPUS 56 Golden Bow a7 NeXTSTEP f0 Linux/PA-RISC b
11 Hidden FAT12 5c Priam Edisk a8 Darwin UFS f1 SpeedStor
12 Compaq diagnost 61 SpeedStor a9 NetBSD f4 SpeedStor
14 Hidden FAT16 <3 63 GNU HURD or Sys ab Darwin boot f2 DOS secondary
16 Hidden FAT16 64 Novell Netware af HFS / HFS+ fb VMware VMFS
17 Hidden HPFS/NTF 65 Novell Netware b7 BSDI fs fc VMware VMKCORE
18 AST SmartSleep 70 DiskSecure Mult b8 BSDI swap fd Linux raid auto
1b Hidden W95 FAT3 75 PC/IX bb Boot Wizard hid fe LANstep
1c Hidden W95 FAT3 80 Old Minix be Solaris boot ff BBT
1e Hidden W95 FAT1
Hex code (type L to list codes): 6
Changed system type of partition 1 to 6 (FAT16)
这样就分好了第一个分区,并且指定了分区为fat16。
第二个,我试做分区为linux分区
>Command (m for help): n
Command action
e extended
p primary partition (1-4)
p
Partition number (1-4): 2
First cylinder (48002-62528, default 48002):
Using default value 48002
Last cylinder, +cylinders or +size{K,M,G} (48002-62528, default 62528):
Using default value 62528
Command (m for help): t
Partition number (1-4): 2
Hex code (type L to list codes): 83
好了,看看成果。
>Command (m for help): p
Disk /dev/mmcblk0: 2048 MB, 2048917504 bytes
4 heads, 16 sectors/track, 62528 cylinders
Units = cylinders of 64 * 512 = 32768 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x6f20736b
Device Boot Start End Blocks Id System
/dev/mmcblk0p1 1 48001 1536024 6 FAT16
/dev/mmcblk0p2 48002 62528 464864 83 Linux
好了,把分区信息写入磁盘。
Command (m for help): w
The partition table has been altered!
Calling ioctl() to re-read partition table.
WARNING: If you have created or modified any DOS 6.x
partitions, please see the fdisk manual page for additional
information.
Syncing disks.
下面开始格式化。
首先是fat16分区
>#mkdosfs /dev/mmcblk0p1
然后是linux分区
>#mkfs.ext3 /dev/mmcblk0p2
完成之后,取出sd卡,再安装上去,linux系统已经自动识别了两个分区,可以用了。
### 2017年6月3日 ###
大气数据传感器程序已经实现了串口接受数据,并发布相关的主题消息,同事通过串口回传,并记录至SD卡,具体过程如下:
### 2017年6月4日 ###
今天开始做mavlink消息发送,实现的目的是把采集的传感器数据通过mavlink消息发送至QGC地面站,并在地面站显示,具体过程如下:
先去summer培训群里咨询了下,也没有什么正经的回答,靠天靠地靠培训,不如靠csdn博客。
参考了如下博客:
1. [Mavlink地面站编写之八–MAVLINK消息自定义](http://blog.csdn.net/gen_ye/article/details/53886586)
2. [Pixhawk原生固件PX4之MAVLink协议解析](http://blog.csdn.net/oqqenvy12/article/details/61615609)
3. 官方相关的[mavlink介绍](http://mavlink.org/messages/common)是最关键的
看来看去还是回到了官方的开发文档,这才是正途。
PX4 Developer Guide->中间件及架构->[MAVLink消息机制](https://dev.px4.io/zh/middleware/mavlink.html)
根据文档描述过程如下:
1.创建uORB消息,假设你已经在 msg/ca_trajectory.msg 有了一个自定义uORB ca_trajectory 消息;
2.创建mavlink消息。[参考这里](http://qgroundcontrol.org/mavlink/create_new_mavlink_message)
>Definition of one Message in XML,Custom Message Definition File
>Compiling XML to C/C++ or Python
把XML文件编译成C/C++文件时出现了问题,正常的话如下三条指令就可以完成:
```
git clone --recursive https://github.com/mavlink/mavlink mavlink-generator
cd mavlink-generator/
python mavgenerate.py
```
正常情况下到此就能启动mavlink generator,天不遂人愿,未果,咋办?
参考[mavlink generator的github仓库](https://github.com/mavlink/mavlink),按照其Installation指导在克隆是增加"--recursive",
添加本地仓库目录到PYTHONPATH,export PYTHONPATH=$PYTHONPATH:/home/qb/mavlink-generator
查看是否设置成功,输入如下指令
>xx@yyy:~/mavlink-generator$ echo $PYTHONPATH
:/home/qb/mavlink-generator
官方要求Python2.7+,查看python的版本如下,符合要求:
>xx@yyy:~/mavlink-generator$ python --version
Python 2.7.12
经过了以上的确认,再次运行python mavgenerate.py,结果出现以下错误信息:
>Traceback (most recent call last):
File "mavgenerate.py", line 42, in <module>
from pymavlink.generator import mavgen
File "/home/qb/mavlink-generator/pymavlink/generator/mavgen.py", line 12, in <module>
from future import standard_library
ImportError: No module named future
肿么办?后来又参考了[国外的一个网站](https://stackoverflow.com/questions/31086530/importerror-no-module-named-concurrent-futures-process)jedema回答说“如果你用Python2.7,必须安装如下module,pip install futures,Python2.x没包含futures,Python3.2之后的版本包含了futures”,其实这段回到不是针对我遇到的问题,但是却提醒了我。接下来就是安装future,注意没有s!过程如下:
>sudo apt-get install future //用apt-get install指令安装不行
pip install future //提示pip没安装,先安装pip,sudo apt install python-pip
sudo apt install python-pip //安装python-pip
pip install future //安装pip
python mavgenerate.py //运行mavlink generator,成功!!!
以上过程的详细界面如下:
>qb@qb-Lenovo-XiaoXin-310-15IKB:~/mavlink-generator$ sudo apt-get install future
Reading package lists... Done
Building dependency tree
Reading state information... Done
E: Unable to locate package future
qb@qb-Lenovo-XiaoXin-310-15IKB:~/mavlink-generator$ pip install future
The program 'pip' is currently not installed. You can install it by typing:
sudo apt install python-pip
qb@qb-Lenovo-XiaoXin-310-15IKB:~/mavlink-generator$ sudo apt install python-pip
...安装OK
qb@qb-Lenovo-XiaoXin-310-15IKB:~/mavlink-generator$ pip install future
Collecting future
Downloading future-0.16.0.tar.gz (824kB)
100% |████████████████████████████████| 829kB 522kB/s
Building wheels for collected packages: future
Running setup.py bdist_wheel for future ... done
Stored in directory: /home/qb/.cache/pip/wheels/c2/50/7c/0d83b4baac4f63ff7a765bd16390d2ab43c93587fac9d6017a
Successfully built future
Installing collected packages: future
Successfully installed future-0.16.0
You are using pip version 8.1.1, however version 9.0.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
qb@qb-Lenovo-XiaoXin-310-15IKB:~/mavlink-generator$ python mavgenerate.py
OK!!!
### 2017年6月5日 ###
本想今天开始整PX4发送mavlink消息,结果在eclipse中执行了make distclean之后,悲催了!!!!!!!!!!!!!!!!!!!!!!!!!!!
这条指令把之前自己写的代码给清除了,真的很无语!!!想哭却哭不出来,重头再来!
这次做好记录。
### 2017年6月16日 ###
凌晨1点,终于能发送mavlink消息的,真的很虐心(由于gtkterm串口调试工具不给力耽误了将近一周的时间),过程回头在详述。发送消息的过程是这样的:
PX4通过串口接收传感器的参数,公告发布传感器uORB主题消息,mavlink进程订阅到该消息后发送一条mavlink消息给地面站。
洗洗睡了!
### 2017年6月22日 ###
存储功能也加上了,基本的功能包括串口接收->公告发布消息->发送mavlink消息->存储,已基本完成!!!
小结一下。
### 2017年6月24日 ###
准备安装图形化的git工具,初步选择GitKraken(官方介绍其为The most popular Git GUI for Windows,Mac AND Linux),下面记录Ubuntu下安装过程:
1. 登录gitkraken官网:https://www.gitkraken.com/
2. 下载版本为Linux(.deb),(Ubuntu LTS 12.04+,Debian 8+),文件(.deb)是类似windows下的安装文件,下载双击执行安装即可;
3. CTR+ALT+T,启动命令行终端,输入gitkraken即可启动;
***
# 参考文档 #
1. [px4~summer的博客](http://blog.csdn.net/qq_21842557/article/details/50799636)
2. [fantasyJXF的博客](http://blog.csdn.net/oqqenvy12/article/details/54577063)
3. [Jethro Hazelhurst's Blog (18)](http://diydrones.com/profiles/blog/list?user=1oj2q1uwsuh9z)
4. [Graphics for Wiki Documentation](http://diydrones.com/profiles/blogs/graphics-for-wiki-documentation),无人机的组件示意图,挺好的;
5. [PX4自定义消息,发布主题,参考fantasy的博客](http://blog.csdn.net/oqqenvy12/article/details/54577063)