Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
dd5a76aaf9
@ -4,6 +4,8 @@ LTAI5tDmuBc9sA3CDso9bwe3
|
|||||||
|
|
||||||
MzzUtOfOKx7CK3rFoSckNvujkQGBF3
|
MzzUtOfOKx7CK3rFoSckNvujkQGBF3
|
||||||
|
|
||||||
|
MzzUtOfOKx7CK3rFoSckNvujkQGBF3
|
||||||
|
|
||||||
yewuyadeimagewall
|
yewuyadeimagewall
|
||||||
|
|
||||||
oss-cn-hangzhou
|
oss-cn-hangzhou
|
||||||
@ -10,6 +10,25 @@ vnc启动
|
|||||||
vncserver -geometry 1920x1080
|
vncserver -geometry 1920x1080
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```sh
|
||||||
|
#!/bin/sh
|
||||||
|
unset SESSION_MANAGER
|
||||||
|
unset DBUS_SESSION_BUS_ADDRESS
|
||||||
|
startxfce4 &
|
||||||
|
[ -x /etc/vnc/xstartup ] && exec /etc/vnc/xstartup
|
||||||
|
[ -r $HOME/.Xresources ] && xrdb $HOME/.Xresources
|
||||||
|
xsetroot -solid grey
|
||||||
|
vncconfig -iconic &
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
vnc连接
|
vnc连接
|
||||||
|
|
||||||
* Mac
|
* Mac
|
||||||
|
|||||||
221
中国计量大学现代科技学院本科毕业设计(论文).md
Normal file
221
中国计量大学现代科技学院本科毕业设计(论文).md
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
# 中国计量大学现代科技学院本科毕业设计(论文)
|
||||||
|
|
||||||
|
## 基于Android的无人机自动巡检
|
||||||
|
|
||||||
|
**郑 重 声 明**
|
||||||
|
|
||||||
|
本人呈交的毕业设计论文,是在导师的指导下,独立进行研究工作所取得的成果,所有数据、图片资料真实可靠。尽我所知,除文中已经注明引用的内容外,本学位论文的研究成果不包含他人享有著作权的内容。对本论文所涉及的研究工作做出贡献的其他个人和集体,均已在文中以明确的方式标明。本学位论文的知识产权归属于培养单位。
|
||||||
|
|
||||||
|
## 摘要
|
||||||
|
|
||||||
|
随着无人机技术的发展,无人机在各个领域都发挥了巨大的作用,但是无人机的保有量年年升高,无人机操作员的数量却一直增长缓慢,培养一个优秀的无人机操作员需要一两年的时间,而生产一架无人机只需要一天甚至更短的时间。无人机操作员的培养是困难的,但是如果通过软件实现无人机自动巡检,通过软件代替人操作之后,在软件开发完成之后,软件就会取代人的作用,且软件的复制是极为迅速的,可以迅速填补无人机操作员的空缺。
|
||||||
|
|
||||||
|
本文设计了一款实现简单,同时效果不错的无人机自动化巡检软件,通过使用该软件巡检人员只需要录制一遍标准的航线,之后就可以通过装载航线实现全自动的巡检,将大大提高无人机巡检的效率,同时减小了对无人机操作员的要求,无人机操作员只需要会基本的无人机操作就可以完成巡检工作。
|
||||||
|
|
||||||
|
## Abstract
|
||||||
|
|
||||||
|
With the development of drone technology, drones play a huge role in various fields, but the number of drone ownership rises year after year, the number of drone operators has been growing slowly, and it takes one or two years to train a good drone operator, while it takes only one day or even less to produce a drone. The training of drone operators is difficult, but if automatic drone inspection is achieved through software, after the software replaces human operation, the software will take over the role of human after the software development is completed, and the software is extremely fast to replicate and can quickly fill the vacancies of drone operators.
|
||||||
|
|
||||||
|
This paper designs a simple to implement, while the effect is good UAV automatic inspection software, by using the software inspectors only need to record the standard route once, after which they can achieve fully automatic inspection by loading the route, will greatly improve the efficiency of the UAV inspection, while reducing the requirements of the UAV operator, the UAV operator only needs to know the basic UAV operation can complete the inspection work.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 目次
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 绪论
|
||||||
|
|
||||||
|
#### 引言
|
||||||
|
|
||||||
|
无人机技术的发展,无人机的优势,无人机数量远大于飞手数量,飞手培养难度大
|
||||||
|
|
||||||
|
无人机(Unmanned Aerial Vehicle),即无人驾驶飞行器,通常被称为无人驾驶飞机或无人驾驶飞机系统,是不需要人类飞行员操作的飞机,是一种由空气动力或电力驱动的航空器,人可以在地面通过无线电遥控或预编的程序来控制其飞行。
|
||||||
|
|
||||||
|
无人机分为三个大类,多旋翼无人机,固定翼无人机,无人机直升机,其中无人直升机最大的优势是灵活性强,可以随时随地垂直起飞和在空中悬停,但是其结构复杂,维护困难,同时成本较高;固定翼无人机在军用和民用领域应用较广泛,其飞机尺寸一般较大,其主要优点是飞行速度快、时间长、距离远、负载量大,缺点是不能定点悬停,因此相对多旋翼无人机和无人直升机其灵活性和功能性会大大降低。多旋翼无人机结构简单,操纵灵活,成本较低,在现阶段应用十分广泛。
|
||||||
|
|
||||||
|
随着技术的发展无人机在工业巡检发挥着越来重要的作用,现在无人机巡检已经广泛应用到各种巡检场景之中,如电网巡检,风力发电巡检,输油管道巡检,无人机在这些场景中的应用大大提高了巡检的效率,为了经济的发展做出了贡献 。
|
||||||
|
|
||||||
|
#### 研究目的与意义
|
||||||
|
|
||||||
|
随着无人机在巡检方面的应用的范围和规模越来越大,产生了自动化巡检的需求,现如今无人机的保有量已经达到数十万架,而合格的无人机操作员只有几万人,并且无人机操作员的培养是缓慢的,一个合格的无人机操作员可能要一两年的时间,但是一架无人机可能一个小时就生产出来了。无人机操作员的培养是困难的,但是如果通过软件实现无人机自动巡检,通过软件代替人操作之后,在软件开发完成之后,软件就会取代人的作用,且软件的复制是极为迅速的,可以迅速填补无人机操作员的空缺。本文的目的就是设计一款无人机的自动化巡检app。
|
||||||
|
|
||||||
|
### 相关技术分析
|
||||||
|
|
||||||
|
#### Android开发
|
||||||
|
|
||||||
|
Android是一种基于Linux的自由及开放源代码的操作系统,Android 分为四个层,从高层到低层分别是应用程 序层、应用程序框架层、系统运行库层和 Linux 内核层。谷歌公司推出了开源的Android 系统,现在应用非常广泛,开发环境不会受到各种条条框框的限制,开发者任意修改开放的源代码来实现与开发各种实用的手机App软件,具有高级图形显示、界面友好等特点。Android 系统因其免费开源的特性受到广大个人开发者和企业的青睐,同时网上存在大量的应用实例和开发经验,因此选择android 作为开发平台,可以减小我们的开发难度。
|
||||||
|
|
||||||
|
#### 无人机
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### 大疆SDK
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 系统分析与设计
|
||||||
|
|
||||||
|
#### 需求分析
|
||||||
|
|
||||||
|
为了能够实现无人机的自动化巡检,需要实现能够在录制过程中实时记录无人机的飞行数据,同时保存下来,在复飞的时候能够根据这些信息进行复现录制时无人机的飞行轨迹和动作。同时为了后期数据分析,优化效果需要有日志记录的功能。故本次毕业设计的需求共有以下四种,航点数据记录,航点数据处理,飞行控制,飞行日志记录。
|
||||||
|
|
||||||
|
##### 航点数据记录
|
||||||
|
|
||||||
|
要想要实现复飞中能够准确的复现录制时的飞行轨迹和无人机动作,就需要最大可能的记录飞行的数据,需要记录的数据主要包括无人机的实时GPS信息和无人机的航向,同时还需要记录无人机的云台相机的数据,包括是否拍照,是否录像。根据GPS信息可以记录无人机的飞行轨迹,根据云台相机信息可以记录无人机在什么时候怎么拍照的。通过以上信息就可以复现无人机录制时候的飞行轨迹个和飞行动作。
|
||||||
|
|
||||||
|
##### 航点数据处理
|
||||||
|
|
||||||
|
由于无人机的GPS更新频率只有10HZ 这个频率的数据并不能满足飞行控制的需求,且记录的数据不够平滑,直接使用原始数据来控制无人机的飞行会导致无人机的飞行不够平稳,飞行过程中会存在抖动。同时由于无人机记录的GPS信息是大地坐标系:也叫经纬高坐标系(LLA: Longitude Latitude Altitude),是无法直接用于导航控制的,所以需要将航点文件的中的坐标部分转换成站心坐标系:也叫东北天坐标系(ENU: East North Up),故航点数据处理一共要执行三个操作,首先是将航点文件记录的GPS信息由大地坐标系转成东北天坐标系,之后对转化后的数据做一次数据平滑的操作,最后对航点数据进行插值处理,手动提高控制频率。
|
||||||
|
|
||||||
|
##### 飞行控制
|
||||||
|
|
||||||
|
因为要复现录制过程中完整的飞行轨迹,所以无人机的飞行控制不能使用waypoint模式也就是航点模式,航点模式飞行虽然更加稳定,但是航点模式有个缺陷就是航点与航点之间是直线飞行,且航点之间的距离有最小限制,实测结果最小距离在3M的时候效果会比较出色,但是这样就无法实现完全复现录制时的全部飞行细节,所以无法通过waypoint模式来实现飞行控制,DJI SDK 提供了另外一种飞行方式,可以通过发送虚拟摇杆命令的形式控制无人机的飞行,这个模式可以满足需求。
|
||||||
|
|
||||||
|
由于在巡检过程中还需要无人机执行拍照或者录视频的动作来采集数据,所以需要无人机无人机在自动复飞的时候也可以准确复现无人机的拍照动作,同时由于无人机拍照或者录视频需要在指定地点拍出来的东西才有价值,所以需要精准控制无人机的拍照位置,保证无人机自动复飞时候的拍照点和录制时候的拍照点位置误差很小,这样自动复飞任务才有价值。
|
||||||
|
|
||||||
|
##### 飞行日志记录
|
||||||
|
|
||||||
|
由于无人机在飞行过程中很难由人眼或其他设备直接近距离观察无人机的飞行状况,无人机也有时会发生事故或者飞行不稳定。为了分析事故的原因,就需要把无人机在飞行过程中产生的数据记录下来,可以根据数据分析无人机发生事故的原因,同时也可以根据无人机的飞行数据对无人机的控制进行调优,优化无人机的飞行状况。
|
||||||
|
|
||||||
|
#### 可行性分析
|
||||||
|
|
||||||
|
* 航点数据记录 通过DJI SDK可以以10HZ的频率获取到无人机的飞行信息,同时也可以获取到当前无人机的云台角度和相机状态。
|
||||||
|
* 航点数据处理 可以写一个函数,实现对数据的转换和处理
|
||||||
|
* 飞行控制 通过DJI SDK的虚拟摇杆命令可以模拟遥控器发出的控制指令,从而达到控制无人机飞行的效果,同时可以通过DJI SDK的action实现无人机的拍照控制
|
||||||
|
* 飞行日志记录 可以自定义日志文件并保存到本地
|
||||||
|
* 综上所述整个系统是可以实现的。
|
||||||
|
|
||||||
|
#### 系统总体设计
|
||||||
|
|
||||||
|
根据需求分析,整个系统存在两个核心,一个是录制航线,一个是航线复飞,记录的数据可以实现录制航线的复现,这就需要对数据进行选择和处理,同时要设计一个简单可靠的控制器,实现对无人机的飞行控制。这个飞行控制系统可以根据采集到的数据对实现无人机对录制航线的精准复现。创建三个activity 分别是recordactivity(录制界面),reflyactivity(复飞界面),normalactivity(普通界面),recordactivity负责实现飞行数据的记录和存储,reflyactivity负责实现飞行数据的处理和复飞任务的执行,normalactivity是传统飞行界面。
|
||||||
|
|
||||||
|
#### 功能模块设计
|
||||||
|
|
||||||
|
##### 飞行界面设计
|
||||||
|
|
||||||
|
首先创建基础的飞行界面,这些基础的飞行界面要能显示无人机的飞行过程的中关键信息,之后在基础的飞行界面上根据不同的任务界面为不同的任务界面添加不同的组件。recordactivity在基础界面上加入设置航点文件名称、开始录制、停止录制的按键,reflyactivity在基础界面上加入选择航点文件、加载航点文件、开始执行复飞任务、停止复飞任务四个按键,normalactivity只显示基础界面。
|
||||||
|
|
||||||
|
##### 位置控制器
|
||||||
|
|
||||||
|
由于无人机要精准复现无人机录制时的飞行轨迹且通过使用大疆SDK可以直接控制无人机的速度,可以直接选用简单好用的位置控制器,且不需要使用串级PID因为内环的速度控制已经由大疆SDK实现,只需要使用位置控制器PID输出期望速度直接发送给无人机就可以实现对无人机的位置控制了。
|
||||||
|
|
||||||
|
##### 航点数据获取和存储
|
||||||
|
|
||||||
|
根据控制器的设置,实现位置控制器需要输入当前坐标和期望坐标,这就需要记录无人机的实时的GPS信息并保存下来,同时因为无人机要拍照和录视频所以需要记录无人机的航向、云台相机角度、是否拍照、是否录像。保存了这些参数就可以实现对无人机飞行控制和拍照控制了。这些数据可以通过DJI SDK提供的API接口获取。
|
||||||
|
|
||||||
|
为了存储这些数据可以设计一个list 数据,将录制中的所有信息按时间顺序存入数组中,在停止录制之后将数组中的数据转成json文件存储到本地文件。
|
||||||
|
|
||||||
|
##### 航点数据读取和处理
|
||||||
|
|
||||||
|
用户在点击选择文件按钮之后会弹出小窗显示文件列表,在选中文件之后小窗消失并提示选中航点文件的名称,用户点击装载之后执行对航点数据的读取和处理。
|
||||||
|
|
||||||
|
航点数据的读取通过将文件从json格式重新恢复成自定义的list数组。这部分是由于无人机的基础数据更新频率只有10HZ,数据频率太低会导致在复飞时无人机的飞行不够平稳,根据这一情况,需要对航点做优化处理。且由于GPS 信息记录的是大地坐标系:也叫经纬高坐标系(LLA: Longitude Latitude Altitude),是无法直接用于导航控制的,所以需要将航点文件的中的坐标部分转换成站心坐标系:也叫东北天坐标系(ENU: East North Up),将GPS坐标转成东北天坐标系之后就用于导航控制了。
|
||||||
|
|
||||||
|
##### 飞行轨迹复现
|
||||||
|
|
||||||
|
在用户点击开始按键之后将在装载过程中处理好的飞行数据传入复飞控制函数中,复飞函数中循环读取航点数据,并将读取到数据放入位置控制器中实现对无人机的飞行轨迹的复现,同时当读取到其他航点模式时执行拍照动作或者录视频的动作。
|
||||||
|
|
||||||
|
### 系统实现
|
||||||
|
|
||||||
|
#### 总体架构
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### 功能模块实现
|
||||||
|
|
||||||
|
##### 飞行界面
|
||||||
|
|
||||||
|
无人机的飞行界面需要显示很多信息,一般包括如下几点
|
||||||
|
|
||||||
|
显示相机的实时画面
|
||||||
|
显示无人机的状态(飞机遥测数据、电池电量、信号强度等)。
|
||||||
|
允许用户查看和改变产品设置
|
||||||
|
无人机具有的基本功能,如自动起飞、降落、回家。
|
||||||
|
|
||||||
|
制作一个无人机的飞行应用程序需要先提供这些基础的核心功能,然后才能在这个基础上添加独特的功能,DJI UX SDK提供了具有这些核心功能的UI元素,因此可以用来加快开发时间。通过使用默认的UX SDK 不需要添加其他的代码就可以创建一个基础的飞行界面,效果如下图所示
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
通过使用大疆的提供的DJI UX SDK来实现各个界面的基础飞行布局之后,再根据不同的界面需求添加不同的按键,录制节目添加设置文件名称,开始录制,停止录制三个按键,复飞节目添加选择航点文件,装载航线,开始,停止四个按键。普通模式只使用基础的飞行布局。
|
||||||
|
|
||||||
|
##### 位置控制器
|
||||||
|
|
||||||
|
使用pid 控制器实现对无人机的位置控制,通过读取无人机的当前位置以及期望位置,将两个值做差,得出的结果放入到pid 控制器中,得出的结果就是期望速度,通过DJI SDK 发送给无人机即可实现对无人机的位置控制。
|
||||||
|
|
||||||
|
##### 航点数据获取和存储
|
||||||
|
|
||||||
|
在录制界面中添加三个按键,分别是设置文件名称,开始录制,停止录制。用户先点击设置文件名称,如果创建的文件名称和之前的文件名重复则创建失败,提醒用户重新创建,当用户点击开始录制时需要无人机处于飞行状态否则无法开始,提醒用户起飞无人机后重新开始。用户点击停止录制时,会根据用户设置的文件名自动创建相应的文件,并将航点数据存储到本地。如下图所示。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
创建自定义航点数据类mylatlng用存储航点数据,包含的数据类型有Lat、lng、alt、uavyaw、WaypointActionType,其中WaypointActionType有四个种类,分别是STAY、STOP_RECORD、START_TAKE_PHOTO、START_RECORD。使用大疆SDK大疆SDK的LocationCoordinate3D获取当前无人机的经度纬度高度,创建相机状态的监听,获取相机的状态,当相机不在拍照时设置WaypointActionType为STAY,拍照时设置为START_TAKE_PHOTO,开始录视频时为START_RECORD,在录制视频期间时保持WaypointActionType为STAY,当视频录制结束时设置WaypointActionType为STOP_RECORD。记录数据时当相机没有活动时数据保持最大频率的记录,也就是10HZ,当相机发生活动时强制记录一条航点信息。点击停止录制时会自动把数据转成json格式并写入本地文件中。
|
||||||
|
|
||||||
|
##### 航点数据读取和处理
|
||||||
|
|
||||||
|
通过选择制定的文件,将指定文件路径的航点文件转成json文件,并将json文件转成自定义的list数组文件。这样就完成了航点数据的读取。读取完成的数据还需要进一步处理才能满足飞行控制的要求,首先要对航点数据进行数据平滑的处理,这里使用的是加权滑动平均法。简单来说,滑动平均法把前后时刻的一共2n+1个观测值做平均,得到当前时刻的滤波结果。滑动平均法还有一个升级版本,也就是我们要用的加权滑动平均法。实际场景中,每个观测值的重要程度不同,忽略每个观测值的置信度直接平均不能得到精确的结果,所以就需要给观测值加权。加权滑动平均法的公式如下:
|
||||||
|
|
||||||
|
![[公式]](https://www.zhihu.com/equation?tex=p_%7Bt%7D%3D%5Cfrac%7B%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%7B%28x_%7Bt-i%7D%2Aw_%7Bt-i%7D%2Bx_%7Bt%2Bi%7D%2Aw_%7Bt%2Bi%7D%29%2Bx_%7Bt%7D%2Aw_%7Bt%7D%7D%7D%7B2n%2B1%7D)
|
||||||
|
|
||||||
|
![[公式]](https://www.zhihu.com/equation?tex=w_%7Bt%7D) 为 ![[公式]](https://www.zhihu.com/equation?tex=t) 时刻的权重。(6)式表示的是把每个观测值乘以权重后再平均。这种方法适用于观测值本身带有置信度的情况。使用加权滑动平均法,将每个航点的前后三个航点代入到公式中得到处理之后的数据。在使用加权滑动平均法之后还需要使用差值的方法对处理后的航点文件的每个航点之间插入中位数,原因是原始数据只有10HZ的频率,10HZ的控制频率对无人机来说有点太低了,所以需要插入中位数来实现航点数据翻倍的效果,使用加倍后的航点数据可以使无人机的控制频率达到20HZ。处理后的航点数据在飞行之后的
|
||||||
|
|
||||||
|
##### 飞行轨迹复现
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 系统测试
|
||||||
|
|
||||||
|
#### 测试的重要性及目的
|
||||||
|
|
||||||
|
软件测试是程序的一种执行过程,目的是尽可能发现并改正被测试软件中的错误,提高软件的可靠性。它是软件生命周期中一项非常重要且非常复杂的工作,对软件可靠性保证具有极其重要的意义。通过测试也可以发现软件的不如,可以根据测试结果进行优化。同时无人机软件涉及到无人机的飞行控制,若软件在无人机的飞行期间发生故障,会造成无人机的失控,无人机的失控可能会对周围环境和人员造成巨大伤害。故需要完成软件测试才算是完成软件的开发任务。
|
||||||
|
|
||||||
|
#### 测试的方法及流程
|
||||||
|
|
||||||
|
由于本软件的主要功能是录制无人机航线并通过自动复飞复现录制的航线,涉及到无人机的飞行,故测试要首先在大疆提供的DJI assistant2软件中的无人机模拟器中进行,在模拟器中测试完成之后在进行室外的真机测试。
|
||||||
|
|
||||||
|
测试时首先在验证软件的各个按键是否有效,以及软件是否存在闪退现象,之后使用软件测试无人机在模拟器中的飞行情况,主要包括使用本软件操控无人机时是否正常,在确认无人机在模拟器中正常飞行之后,进入录制模式,录制航线,航线要求足够复杂,要涉及到实际飞行中的各个情况,包括直线,曲线,爬升,降低,转向,以及这些动作的组合,同时要设计不同的拍照点,不同的拍照形式,无人机悬停时拍照,无人机飞行中拍照,同一位置拍多张照片。在录制完测试航线之后,进入复飞模式,加载测试航线,执行复飞任务,观察两次飞行的轨迹是否重合,观察是否在相同的位置拍照。同时查看软件在复飞过程中是否存在bug。在复飞任务正常执行完成之后,读取log日志,通过查看日志判断无人机飞行数据是否正常。
|
||||||
|
|
||||||
|
在模拟器测试通过之后,需要前往室外测试点进行测试,首先在一片空旷的地方进行测试,在空旷的地方尽可能的设计复杂的航线进行测试,在复飞过程中暂时只能根据肉眼观察复飞效果,复飞结束之后根据日志信息和两次飞行的照片对比分析复飞过程中是否存在问题。空旷场地测试完成之后即可进行无人机真正的作业环境进行测试,根据作业环境的工作流程录制相应的航线并复飞,根据两次飞行过程中采集到信息来分析软件功能是否正常。
|
||||||
|
|
||||||
|
### 总结与展望
|
||||||
|
|
||||||
|
#### 本文的主要工作
|
||||||
|
|
||||||
|
本文主要通过DJI 提供的Mobile SDK 和UX SDK在android平台上开发了一款用于无人机自动巡检的app。对无人机的组成和应用控制无人机飞行原理以及移动端应用开发过程进行了深入的研究,所做的主要工作如下:
|
||||||
|
|
||||||
|
* 无人机的飞行控制
|
||||||
|
|
||||||
|
根据DJI SDK 可以直接对无人机发送速度控制指令的方法设计了一个简单的位置控制器,实现了对无人机位置的控制,并通过这个位置控制器实现了对无人机飞行轨迹的控制,同时使用DJI SDK action 的方法实现了对无人机的云台相机的控制,并将两种控制方式结合起来实现了对录制的飞行轨迹的复现。
|
||||||
|
|
||||||
|
* 无人机的数据采集和处理
|
||||||
|
|
||||||
|
根据设计的控制的需要对无人机的飞行数据进行采集和存储,并且对数据做了一定处理,首先将数据从大地坐标系转换为东北天坐标系,之后又对数据进行了平滑处理,主要用到的方法是加权滑动平均法,之后对数据做了插值处理,通过插值的方法间接提高了对无人机的控制频率,通过对数据的一系列处理,使得无人机的飞行变得更加平稳。
|
||||||
|
|
||||||
|
* 无人机自主飞行测试
|
||||||
|
|
||||||
|
将在开发工具中编写好的应用部署安装到 Android 系统的智能手机上,利用大疆提供的无人机模拟飞行 PC 软件 DJI assistant2,连接无人机和电脑,手机和遥控器,在应用中录制航线并复飞录制的航线,同时也在户外真实环境下进行了类似的测试。
|
||||||
|
|
||||||
|
### 不足与展望
|
||||||
|
|
||||||
|
本研究内容利用大疆的无人机结合其提供的移动开发平台 Mobile SDK 和 Android应用的开发知识开发出一款可以通过录制标准航线并加载航线实现自动化巡检的应用。但鉴于本人能力和水平的限度、时间紧迫、资料有限,取得阶段性的成果的同时,软件还有很多技术细节和想法有待加强和完善,还有许多待完善的功能,如设置云端登录账号,航点文件存储到云端便于随时读取。对无人机飞行日志的自动化分析和上传。同时本应用还可以开发IOS版本以覆盖到更多的使用人群。
|
||||||
|
|
||||||
|
## 参考文献
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 作者简历
|
||||||
|
|
||||||
|
## 学位论文数据集
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
139
交接内容.md
Normal file
139
交接内容.md
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
# 交接内容
|
||||||
|
## DJI MSDK 复飞
|
||||||
|
### 开发环境
|
||||||
|
* Android studio最新版
|
||||||
|
* Java 1.8
|
||||||
|
* DJI SDK 4.14 DJI UXSDK 4.14
|
||||||
|
* 开发平台Windows/Mac OS
|
||||||
|
### 功能要求
|
||||||
|
* 可以记录保存航线到本地
|
||||||
|
* 加载录制的航线可以自动复线记录航线的内容
|
||||||
|
* 不同的无人机可以使用同一航点文件
|
||||||
|
* 支持RTK
|
||||||
|
* 支持各个大疆机型
|
||||||
|
### 实现方法
|
||||||
|
#### 录制复飞流程图
|
||||||
|

|
||||||
|
|
||||||
|
#### 任务控制
|
||||||
|
|
||||||
|
具体代码参考reflywidgetactivity.java的missionctrl函数
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### 数据存储
|
||||||
|
|
||||||
|
在Mylatlng文件中自定义list 数组,用于存储航点信息。需要存储的数据有无人机的GPS信息(lat,lng,alt),偏航角度uavYaw,航点模式waypointactiontype,相机焦距camera_length,云台角度pitch。在Recordwidgetactivity文件中,有个admission 函数,用于往空的数组中添加航点数据,开始录制时保持最大频率(10hz)记录数据,持续调用admission函数。当停止录制时,将list数组转成json格式并写入到txt文件,文件存储路径由savePath参数决定。当读取航点时,只需要把过程逆向即可,读取txt文件内容,转成list数组保存。
|
||||||
|
|
||||||
|
#### 数据处理
|
||||||
|
|
||||||
|
* 数据平滑:使用滑动平均法进行优化航点使之更加平滑
|
||||||
|
* 航点数据插值:航点数据插值间接提高控制指令的发送频率
|
||||||
|
|
||||||
|
#### 参数配置
|
||||||
|
|
||||||
|
具体代码在reflywidgetactivity.java的btn_start_drone.setOnClickListener这个按键监听事件中
|
||||||
|
|
||||||
|
* 打开虚拟摇杆
|
||||||
|
* 设置无人机坐标系为大地坐标系
|
||||||
|
* 设置虚拟摇杆rollpitch控制为速度
|
||||||
|
* 设置yaw控制为角度
|
||||||
|
* 设置垂直方向(throttle)为速度
|
||||||
|
#### 坐标系转换
|
||||||
|
|
||||||
|
由于GPS坐标系无法进行导航,所以需要将GPS坐标系转成北东天坐标系。具体转换方法看GpstoEnu.java文件
|
||||||
|
|
||||||
|
### 后续改进
|
||||||
|
* 添加了变焦功能但是还未验证
|
||||||
|
* 大型飞机复飞时不太稳定,如M300,需要进行优化,优化方向有两个,使用waypoint V2进行M300的任务控制,和优化控制器的设计,对PID进行调参,或者使用更有效的控制器。
|
||||||
|
## DJI MSDK 自主降落
|
||||||
|
### 功能要求
|
||||||
|
* 使用机载相机检测停机坪,检测到后自动控制无人机降落到停机坪中。
|
||||||
|
### 实现方法
|
||||||
|
* 将获取到的图传数据流转码成YUV数据供aruco模块使用,视频流转码参考代码https://github.com/DJI-Mobile-SDK-Tutorials/Android-VideoStreamDecodingSample
|
||||||
|
* 使用opencv的aruco作为目标检测的方法
|
||||||
|
* 将aruco检测计算的结果放入控制器计算得出结果,发送给无人机
|
||||||
|
* 高度还剩一米时调用DJI SDK一键降落的API进行降落
|
||||||
|
* 对相机进行标定,将标定得到的相机内参传写入应用中。具体表达方法看标定方法那个文档。
|
||||||
|
### 实现难点
|
||||||
|
* 问题:相机自动对焦会改变相机内参,导致标定得出的参数无法长时间使用。
|
||||||
|
* 解决方案:设置自动对焦距离为一个固定的值。
|
||||||
|
* 问题:使用打印机打印出来的标定板和检测板都不能满足标定和检测要求,原因是黑色不够黑。
|
||||||
|
* 解决方案:使用KT板打印制作标定板和检测板。
|
||||||
|
### 后续改进
|
||||||
|
* 已经实现了降落的功能,但是还只是demo阶段,只能实施降落部分,没有飞行界面,没有任务管理。这部分的工作可以参考DJI MSDK复飞的代码来实现。
|
||||||
|
* 紧急停机按键存在问题,在使用紧急停机按键时可以夺回遥控器对无人机的控制,但是app会闪退,由于我手中没有飞机,无法协助解决,杭电同学也不清楚如解决。
|
||||||
|
## phenix mini 无人车编队
|
||||||
|
### 功能要求
|
||||||
|
* 使用phenix mini飞控控制麦克纳姆轮小车在lighthouse定位系统下实现可视化scratch编队编程。
|
||||||
|
* phenix mini可以接收来自定位器的定位数据和控制指令
|
||||||
|
* phenix mini可以对接收到的命令做出响应
|
||||||
|
* phenix mini可以控制麦克纳姆轮小车移动
|
||||||
|
* 定位器能够通过通过接收来自PC的控制信号转发给phenix mini 飞控
|
||||||
|
### 实现难点
|
||||||
|
* 按照lighthouse文档配置飞控相关参数,在无人机模式下phenix mini和pixhawk4都可以实现对定位数据的接收解码,在无人车模式下两者都不可以
|
||||||
|
* phenix mini 不支持无人车模式,需要移植最新版的飞控到phenix mini,相关工作已交给陈鹏华
|
||||||
|
* 在使用pixhawk4 1.12版本固件的时候,修改了编译配置文件和一些启动脚本,重新编译PX4 1.12版本的固件,使之在无人车模式下QGC能够显示LPE相关参数,参数按照lighthouse文档进行设置,进行测试时报错:lpe:timeout.具体原因未知。
|
||||||
|
* 根据官方文档在接入外部定位数据只提供给了多旋翼和垂直起降固定翼。
|
||||||
|
https://docs.px4.io/master/en/ros/external_position_estimation.html
|
||||||
|
https://docs.px4.io/master/en/advanced/switching_state_estimators.html
|
||||||
|
|
||||||
|
## lighthouse 室内定位系统使用和配置调参
|
||||||
|
* 定位器使用,电脑连接Wi-Fi:RSTSWARM2 密码:RST12345678
|
||||||
|
* 设置电脑IP为192.168.1.234。
|
||||||
|
* 子网掩码为255.255.0.0
|
||||||
|
* 网关为192.168.1.1
|
||||||
|
* 启动scratch脚本和server IP即可实现对无人机的控制。
|
||||||
|
|
||||||
|
|
||||||
|
## phenix mini 远程开发服务器
|
||||||
|
### vnc
|
||||||
|
* 安装VNC
|
||||||
|
sudo apt install tigervncserver
|
||||||
|
* 配置VNC
|
||||||
|
|
||||||
|
启动vnc
|
||||||
|
|
||||||
|
```sh
|
||||||
|
vncserver
|
||||||
|
```
|
||||||
|
|
||||||
|
第一次启动按照提示输入密码,这个密码是用于登陆VNC的密码
|
||||||
|
|
||||||
|
后续想修改VNC密码可以使用如下命令实现
|
||||||
|
|
||||||
|
```sh
|
||||||
|
vncpasswd
|
||||||
|
```
|
||||||
|
|
||||||
|
修改xstartup文件内容
|
||||||
|
|
||||||
|
```sh
|
||||||
|
vi /home/用户名/.vnc/sxtartup
|
||||||
|
```
|
||||||
|
|
||||||
|
将内容替换为如下内容
|
||||||
|
|
||||||
|
```sh
|
||||||
|
#!/bin/sh
|
||||||
|
unset SESSION_MANAGER
|
||||||
|
unset DBUS_SESSION_BUS_ADDRESS
|
||||||
|
startxfce4 &
|
||||||
|
[ -x /etc/vnc/xstartup ] && exec /etc/vnc/xstartup
|
||||||
|
[ -r $HOME/.Xresources ] && xrdb $HOME/.Xresources
|
||||||
|
xsetroot -solid grey
|
||||||
|
vncconfig -iconic
|
||||||
|
```
|
||||||
|
重新启动VNC就可以使用VNC访问远程访问图形化界面了。
|
||||||
|
|
||||||
|
### zerotier
|
||||||
|
* 账号:developers@robsense.com
|
||||||
|
* 密码:robsense2015
|
||||||
|
* robsense是用于phenix远程开发的虚拟局域网。
|
||||||
|
### gitlab
|
||||||
|
* 账号:root
|
||||||
|
* 密码:robsense2015
|
||||||
|
* 访问地址(处于zerotier虚拟局域网中):192.168.195.106
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
441
出题.md
441
出题.md
@ -1,47 +1,10 @@
|
|||||||
# 面试题
|
# 面试题
|
||||||
|
|
||||||
* 在ROS中,通过捕捉按键输入完成飞机的模式切换,该方式比较适合多机一键起飞或者其他模式切换操作。
|
## 1
|
||||||
简单说明:采用的是C++标准库提供的cin函数,但是这种方式为阻塞等待键盘按下,所以需要采用多线程或者多进程的方式,又采用了的是共享变量(标志位)的想法,故在一个进程中采用多线程即可。下面的示例给出一个简单的实现模板。在ROS中可以直接编译执行,在单C++函数中,需要在g++ -lpthread完成编译。join的作用为主函数运行结束后,子线程仍然可以一直运行,而不是一起结束
|
|
||||||
|
|
||||||
```c++
|
### 题目
|
||||||
#include <iostream>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
int count = 0;
|
H2O生成
|
||||||
void thr_fun1(void)
|
|
||||||
{
|
|
||||||
while(1)
|
|
||||||
{
|
|
||||||
if(count == 1)
|
|
||||||
{
|
|
||||||
std::cout<<"here!"<<std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int main(int argc,char** argv)
|
|
||||||
{
|
|
||||||
std::string str;
|
|
||||||
std::thread t1(thr_fun1);
|
|
||||||
// t1.join();
|
|
||||||
while(1)
|
|
||||||
{
|
|
||||||
std::cin>>str;
|
|
||||||
if(str=="arm")
|
|
||||||
{
|
|
||||||
std::cout<<"quadrotor armed!"<<std::endl;
|
|
||||||
count = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
count = 0;
|
|
||||||
std::cout<<"not the armed"<<std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
H2o生成
|
|
||||||
|
|
||||||
现在有两种线程,氧 oxygen 和氢 hydrogen,你的目标是组织这两种线程来产生水分子。
|
现在有两种线程,氧 oxygen 和氢 hydrogen,你的目标是组织这两种线程来产生水分子。
|
||||||
|
|
||||||
@ -59,13 +22,13 @@ H2o生成
|
|||||||
如果一个氢线程到达屏障时没有其它线程到达,它必须等候直到一个氧线程和另一个氢线程到达。
|
如果一个氢线程到达屏障时没有其它线程到达,它必须等候直到一个氧线程和另一个氢线程到达。
|
||||||
书写满足这些限制条件的氢、氧线程同步代码。
|
书写满足这些限制条件的氢、氧线程同步代码。
|
||||||
|
|
||||||
|
### 答案
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
class H2O {
|
class H2O {
|
||||||
public:
|
public:
|
||||||
// 氧气的计数
|
int cntO;// 氧气的计数
|
||||||
int cntO;
|
int cntH;// 氢气的计数
|
||||||
// 氢气的计数
|
|
||||||
int cntH;
|
|
||||||
mutex m;
|
mutex m;
|
||||||
condition_variable cv;
|
condition_variable cv;
|
||||||
|
|
||||||
@ -114,13 +77,401 @@ public:
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 2
|
||||||
|
|
||||||
|
### 题目
|
||||||
|
|
||||||
用图画出无人机姿态控制的串级反馈控制系统
|
用图画出无人机姿态控制的串级反馈控制系统
|
||||||
|
|
||||||

|
### 答案
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
进程间通信消息队列
|
进程间通信消息队列
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 3
|
||||||
|
|
||||||
|
### 题目
|
||||||
|
|
||||||
|
请你说一下多线程,线程同步的几种方式
|
||||||
|
|
||||||
|
### 答案
|
||||||
|
|
||||||
|
进程是对运行时程序的封装,是系统进行资源调度和分配的的基本单位,实现了操作系统的并发;
|
||||||
|
|
||||||
|
线程是进程的子任务,是CPU调度和分派的基本单位,用于保证程序的实时性,实现进程内部的并发;线程是操作系统可识别的最小执行和调度单位。每个线程都独自占用一个虚拟处理器:独自的寄存器组,指令计数器和处理器状态。每个线程完成不同的任务,但是共享同一地址空间(也就是同样的动态内存,映射文件,目标代码等等),打开的文件队列和其他内核资源。
|
||||||
|
|
||||||
|
线程间通信的方式:
|
||||||
|
|
||||||
|
1、临界区:
|
||||||
|
|
||||||
|
通过多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问;
|
||||||
|
|
||||||
|
2、互斥量 Synchronized/Lock:
|
||||||
|
|
||||||
|
采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限。因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问
|
||||||
|
|
||||||
|
3、信号量 Semphare:
|
||||||
|
|
||||||
|
为控制具有有限数量的用户资源而设计的,它允许多个线程在同一时刻去访问同一个资源,但一般需要限制同一时刻访问此资源的最大线程数目。
|
||||||
|
|
||||||
|
4、事件(信号),Wait/Notify:
|
||||||
|
|
||||||
|
通过通知操作的方式来保持多线程同步,还可以方便的实现多线程优先级的比较操作
|
||||||
|
|
||||||
|
## 4
|
||||||
|
|
||||||
|
### 题目
|
||||||
|
|
||||||
|
编写一个函数,作用是把一个char组成的字符串循环右移n个。比如原来是“abcdefghi”如果n=2,移位后应该是“hiabcdefg” 函数头是这样的:
|
||||||
|
//pStr是指向以'\0'结尾的字符串的指针
|
||||||
|
//steps是要求移动的n
|
||||||
|
|
||||||
|
```c++
|
||||||
|
void LoopMove ( char * pStr, int steps )
|
||||||
|
{
|
||||||
|
//请填充...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 答案
|
||||||
|
|
||||||
|
```c++
|
||||||
|
void LoopMove ( char *pStr, int steps )
|
||||||
|
{
|
||||||
|
int n = strlen( pStr ) - steps;
|
||||||
|
char tmp[MAX_LEN];
|
||||||
|
strcpy ( tmp, pStr + n );
|
||||||
|
strcpy ( tmp + steps, pStr);
|
||||||
|
*( tmp + strlen ( pStr ) ) = '\0';
|
||||||
|
strcpy( pStr, tmp );
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5
|
||||||
|
|
||||||
|
### 题目
|
||||||
|
|
||||||
|
把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。
|
||||||
|
|
||||||
|
输入描述
|
||||||
|
|
||||||
|
第一行是测试数据
|
||||||
|
|
||||||
|
输出描述
|
||||||
|
|
||||||
|
对输入的每组数据M和N,用一行输出相应的K。
|
||||||
|
|
||||||
|
输入例子
|
||||||
|
|
||||||
|
```
|
||||||
|
1
|
||||||
|
7 3
|
||||||
|
```
|
||||||
|
|
||||||
|
输出例子
|
||||||
|
|
||||||
|
```
|
||||||
|
8
|
||||||
|
```
|
||||||
|
|
||||||
|
### 答案
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include<stdio.h>
|
||||||
|
|
||||||
|
int fun(int m,int n) //m个苹果放在n个盘子***有几种方法
|
||||||
|
{
|
||||||
|
if(m==0||n==1) //因为我们总是让m>=n来求解的,所以m-n>=0,所以让m=0时候结束,如果改为m=1,
|
||||||
|
return 1; //则可能出现m-n=0的情况从而不能得到正确解
|
||||||
|
if(n>m)
|
||||||
|
return fun(m,m);
|
||||||
|
else
|
||||||
|
return fun(m,n-1)+fun(m-n,n);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int T,m,n;
|
||||||
|
scanf("%d",&T);
|
||||||
|
while(T--)
|
||||||
|
{
|
||||||
|
scanf("%d%d",&m,&n);
|
||||||
|
printf("%d\n",fun(m,n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6
|
||||||
|
|
||||||
|
### 题目
|
||||||
|
|
||||||
|
给定一个经过编码的字符串,返回它解码后的字符串。
|
||||||
|
|
||||||
|
编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。
|
||||||
|
|
||||||
|
你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。
|
||||||
|
|
||||||
|
此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。
|
||||||
|
|
||||||
|
示例 1:
|
||||||
|
|
||||||
|
输入:
|
||||||
|
|
||||||
|
```
|
||||||
|
s = "3[a]2[bc]"
|
||||||
|
```
|
||||||
|
|
||||||
|
输出:
|
||||||
|
|
||||||
|
```
|
||||||
|
aaabcbc
|
||||||
|
```
|
||||||
|
|
||||||
|
输入:
|
||||||
|
|
||||||
|
```
|
||||||
|
s = "3[a2[c]]"
|
||||||
|
```
|
||||||
|
输出:
|
||||||
|
|
||||||
|
```
|
||||||
|
accaccacc
|
||||||
|
```
|
||||||
|
|
||||||
|
初始代码
|
||||||
|
|
||||||
|
```c++
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
string decodeString(string s) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 答案
|
||||||
|
|
||||||
|
```c++
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
string getDigits(string &s, size_t &ptr) {
|
||||||
|
string ret = "";
|
||||||
|
while (isdigit(s[ptr])) {
|
||||||
|
ret.push_back(s[ptr++]);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
string getString(vector <string> &v) {
|
||||||
|
string ret;
|
||||||
|
for (const auto &s: v) {
|
||||||
|
ret += s;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
string decodeString(string s) {
|
||||||
|
vector <string> stk;
|
||||||
|
size_t ptr = 0;
|
||||||
|
|
||||||
|
while (ptr < s.size()) {
|
||||||
|
char cur = s[ptr];
|
||||||
|
if (isdigit(cur)) {
|
||||||
|
// 获取一个数字并进栈
|
||||||
|
string digits = getDigits(s, ptr);
|
||||||
|
stk.push_back(digits);
|
||||||
|
} else if (isalpha(cur) || cur == '[') {
|
||||||
|
// 获取一个字母并进栈
|
||||||
|
stk.push_back(string(1, s[ptr++]));
|
||||||
|
} else {
|
||||||
|
++ptr;
|
||||||
|
vector <string> sub;
|
||||||
|
while (stk.back() != "[") {
|
||||||
|
sub.push_back(stk.back());
|
||||||
|
stk.pop_back();
|
||||||
|
}
|
||||||
|
reverse(sub.begin(), sub.end());
|
||||||
|
// 左括号出栈
|
||||||
|
stk.pop_back();
|
||||||
|
// 此时栈顶为当前 sub 对应的字符串应该出现的次数
|
||||||
|
int repTime = stoi(stk.back());
|
||||||
|
stk.pop_back();
|
||||||
|
string t, o = getString(sub);
|
||||||
|
// 构造字符串
|
||||||
|
while (repTime--) t += o;
|
||||||
|
// 将构造好的字符串入栈
|
||||||
|
stk.push_back(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return getString(stk);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7
|
||||||
|
|
||||||
|
### 题目
|
||||||
|
|
||||||
|
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。
|
||||||
|
|
||||||
|
输入:
|
||||||
|
|
||||||
|
```
|
||||||
|
matrix = [[1,2,3],[4,5,6],[7,8,9]]
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
输出:
|
||||||
|
|
||||||
|
```
|
||||||
|
[1,2,3,6,9,8,7,4,5]
|
||||||
|
```
|
||||||
|
|
||||||
|
输入:
|
||||||
|
|
||||||
|
```
|
||||||
|
matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
|
||||||
|
```
|
||||||
|
|
||||||
|
输出:
|
||||||
|
|
||||||
|
```
|
||||||
|
[1,2,3,4,8,12,11,10,9,5,6,7]
|
||||||
|
```
|
||||||
|
|
||||||
|
初始代码
|
||||||
|
|
||||||
|
```c++
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
vector<int> spiralOrder(vector<vector<int>>& matrix) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 答案
|
||||||
|
|
||||||
|
```c++
|
||||||
|
class Solution {
|
||||||
|
private:
|
||||||
|
static constexpr int directions[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
|
||||||
|
public:
|
||||||
|
vector<int> spiralOrder(vector<vector<int>>& matrix) {
|
||||||
|
if (matrix.size() == 0 || matrix[0].size() == 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
int rows = matrix.size(), columns = matrix[0].size();
|
||||||
|
vector<vector<bool>> visited(rows, vector<bool>(columns));
|
||||||
|
int total = rows * columns;
|
||||||
|
vector<int> order(total);
|
||||||
|
|
||||||
|
int row = 0, column = 0;
|
||||||
|
int directionIndex = 0;
|
||||||
|
for (int i = 0; i < total; i++) {
|
||||||
|
order[i] = matrix[row][column];
|
||||||
|
visited[row][column] = true;
|
||||||
|
int nextRow = row + directions[directionIndex][0], nextColumn = column + directions[directionIndex][1];
|
||||||
|
if (nextRow < 0 || nextRow >= rows || nextColumn < 0 || nextColumn >= columns || visited[nextRow][nextColumn]) {
|
||||||
|
directionIndex = (directionIndex + 1) % 4;
|
||||||
|
}
|
||||||
|
row += directions[directionIndex][0];
|
||||||
|
column += directions[directionIndex][1];
|
||||||
|
}
|
||||||
|
return order;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8
|
||||||
|
|
||||||
|
### 题目
|
||||||
|
|
||||||
|
static的用法(定义和用途)
|
||||||
|
|
||||||
|
### 答案
|
||||||
|
|
||||||
|
1)用static修饰局部变量:使其变为静态存储方式(静态数据区),那么这个局部变量在函数执行完成之后不会被释放,而是继续保留在内存中。
|
||||||
|
|
||||||
|
2)用static修饰全局变量:使其只在本文件内部有效,而其他文件不可连接或引用该变量。
|
||||||
|
|
||||||
|
3)用static修饰函数:对函数的连接方式产生影响,使得函数只在本文件内部有效,对其他文件是不可见的(这一点在大工程中很重要很重要,避免很多麻烦,很常见)。这样的函数又叫作静态函数。使用静态函数的好处是,不用担心与其他文件的同名函数产生干扰,另外也是对函数本身的一种保护机制。
|
||||||
|
|
||||||
|
## 9
|
||||||
|
|
||||||
|
### 题目
|
||||||
|
|
||||||
|
const的用法(定义和用途)
|
||||||
|
|
||||||
|
### 答案
|
||||||
|
|
||||||
|
const主要用来修饰变量、函数形参和类成员函数:
|
||||||
|
|
||||||
|
1)用const修饰常量:定义时就初始化,以后不能更改。
|
||||||
|
|
||||||
|
2)用const修饰形参:func(const int a){};该形参在函数里不能改变。
|
||||||
|
|
||||||
|
3)用const修饰类成员函数:该函数对成员变量只能进行只读操作,就是const类成员函数是不能修改成员变量的数值的。
|
||||||
|
|
||||||
|
被const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。
|
||||||
|
|
||||||
|
## 10
|
||||||
|
|
||||||
|
### 题目
|
||||||
|
|
||||||
|
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
|
||||||
|
|
||||||
|
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
|
||||||
|
|
||||||
|
问总共有多少条不同的路径?
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
```
|
||||||
|
输入:m = 3, n = 7
|
||||||
|
输出:28
|
||||||
|
```
|
||||||
|
|
||||||
|
初始代码
|
||||||
|
|
||||||
|
```c++
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int uniquePaths(int m, int n) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 答案
|
||||||
|
|
||||||
|
```c++
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int uniquePaths(int m, int n) {
|
||||||
|
vector<vector<int>> f(m, vector<int>(n));
|
||||||
|
for (int i = 0; i < m; ++i) {
|
||||||
|
f[i][0] = 1;
|
||||||
|
}
|
||||||
|
for (int j = 0; j < n; ++j) {
|
||||||
|
f[0][j] = 1;
|
||||||
|
}
|
||||||
|
for (int i = 1; i < m; ++i) {
|
||||||
|
for (int j = 1; j < n; ++j) {
|
||||||
|
f[i][j] = f[i - 1][j] + f[i][j - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return f[m - 1][n - 1];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
10
高通无人机会议记录.md
Normal file
10
高通无人机会议记录.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# 高通无人机会议记录
|
||||||
|
|
||||||
|
* 计算能力较弱,只能进行简单的slam代码
|
||||||
|
* 网络连接不够稳定大概100M带宽,延时挺高几百毫秒
|
||||||
|
* 只用到相机和通信部分
|
||||||
|
* 用的mavros
|
||||||
|
* 飞控部分存在问题
|
||||||
|
* 没考虑过搭飞机实际测试
|
||||||
|
* 使用phenix mini 连接高通平台,高通平台充当通信链路和图像数据采集,本地计算机做slam计算,使用ros通信。
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user