赞
踩
学习到了如何通过经纬度和海拔设置大疆无人机航迹飞行,记录如下:
参考链接(参考代码)
pointname | lon | lat | height | heading | gimbal | speed | turnmode | actions_sequence |
point1 | 114.3557 | 30.52796 | 8 | 180 | -1 | 3 | AUTO | H1000*SHOOT |
point2 | 114.3557 | 30.52796 | 8 | 160 | -1 | 3 | AUTO | H1000*SHOOT |
point3 | 114.3557 | 30.52795 | 8 | 140 | -1 | 3 | AUTO | H1000*SHOOT |
point4 | 114.3558 | 30.52794 | 8 | 120 | -1 | 3 | AUTO | H1000*SHOOT |
point5 | 114.3558 | 30.52793 | 8 | 100 | -1 | 3 | AUTO | H1000*SHOOT |
point6 | 114.3558 | 30.52791 | 8 | 80 | -1 | 3 | AUTO | H1000*SHOOT |
point7 | 114.3558 | 30.5279 | 8 | 60 | -1 | 3 | AUTO | H1000*SHOOT |
point8 | 114.3557 | 30.52788 | 8 | 40 | -1 | 3 | AUTO | H1000*SHOOT |
其中列分别是:点名、经度、维度、海拔高度、偏航角(注意所使用的大疆软件偏航角是否可以为小数,DJI Pilot软件不支持偏航角为小数,如果偏航角是小数在DJI Pilot中为0!),云台俯仰角,无人机飞行的速度,转弯模式(可能的值包括"MANUAL"、"AUTO"),在航迹点执行的动作序列(可以没有任何动作,也可以有一个或多个动作。例如表格中动作为悬停1s并拍照)
- from string import Template
- import csv
- import sys
- import argparse
- import xml.etree.ElementTree as ET
- import simplekml
- from pyproj import CRS, Transformer
- import pandas as pd
-
- # csv to kml
- def generate_kml(csv_file, output_file, on_finish='hover'):
- CSV_HEADER = False
- ON_FINISH = "Hover" if on_finish == 'hover' else "GoHome"
-
- XML_string = """<?xml version="1.0" encoding="UTF-8"?>
- <kml xmlns="http://www.opengis.net/kml/2.2">
- <Document xmlns="">
- <name>chambon_small</name>
- <open>1</open>
- <ExtendedData xmlns:mis="www.dji.com">
- <mis:type>Waypoint</mis:type>
- <mis:stationType>0</mis:stationType>
- </ExtendedData>
- <Style id="waylineGreenPoly">
- <LineStyle>
- <color>FF0AEE8B</color>
- <width>6</width>
- </LineStyle>
- </Style>
- <Style id="waypointStyle">
- <IconStyle>
- <Icon>
- <href>https://cdnen.dji-flighthub.com/static/app/images/point.png</href>
- </Icon>
- </IconStyle>
- </Style>
- <Folder>
- <name>Waypoints</name>
- <description>Waypoints in the Mission.</description>\n"""
-
- all_coordinates = ""
- waypoint_number = 1
-
- waypoint_start = Template(""" <Placemark>
- <name>Waypoint$waypoint_number</name>
- <visibility>1</visibility>
- <description>Waypoint</description>
- <styleUrl>#waypointStyle</styleUrl>
- <ExtendedData xmlns:mis="www.dji.com">
- <mis:useWaylineAltitude>false</mis:useWaylineAltitude>
- <mis:heading>$heading</mis:heading>
- <mis:turnMode>$turnmode</mis:turnMode>
- <mis:gimbalPitch>$gimbal</mis:gimbalPitch>
- <mis:useWaylineSpeed>false</mis:useWaylineSpeed>
- <mis:speed>$speed</mis:speed>
- <mis:useWaylineHeadingMode>true</mis:useWaylineHeadingMode>
- <mis:useWaylinePointType>true</mis:useWaylinePointType>
- <mis:pointType>LineStop</mis:pointType>
- <mis:cornerRadius>0.2</mis:cornerRadius>""")
-
- waypoint_end = Template("""
- </ExtendedData>
- <Point>
- <altitudeMode>relativeToGround</altitudeMode>
- <coordinates>$lon,$lat,$height</coordinates>
- </Point>
- </Placemark>""")
- hover_template = Template("""
- <mis:actions param="$length" accuracy="0" cameraIndex="0" payloadType="0" payloadIndex="0">Hovering</mis:actions>""")
- shoot_template = Template("""
- <mis:actions param="0" accuracy="0" cameraIndex="0" payloadType="0" payloadIndex="0">ShootPhoto</mis:actions>""")
- gimbal_template = Template("""
- <mis:actions param="$gimbal_angle" accuracy="1" cameraIndex="0" payloadType="0" payloadIndex="0">GimbalPitch</mis:actions>""")
- aircraftyaw_template = Template("""
- <mis:actions param="$aircraftyaw" accuracy="0" cameraIndex="0" payloadType="0" payloadIndex="0">AircraftYaw</mis:actions>""")
- record_template = Template("""
- <mis:actions param="0" accuracy="0" cameraIndex="0" payloadType="0" payloadIndex="0">StartRecording</mis:actions>""")
- stoprecord_template = Template("""
- <mis:actions param="0" accuracy="0" cameraIndex="0" payloadType="0" payloadIndex="0">StopRecording</mis:actions>""")
-
- all_coordinates_template = Template("$lon,$lat,$height")
- xml_end = Template(""" </Folder>
- <Placemark>
- <name>Wayline</name>
- <description>Wayline</description>
- <visibility>1</visibility>
- <ExtendedData xmlns:mis="www.dji.com">
- <mis:altitude>50.0</mis:altitude>
- <mis:autoFlightSpeed>5.0</mis:autoFlightSpeed>
- <mis:actionOnFinish>$ON_FINISH</mis:actionOnFinish>
- <mis:headingMode>UsePointSetting</mis:headingMode>
- <mis:gimbalPitchMode>UsePointSetting</mis:gimbalPitchMode>
- <mis:powerSaveMode>false</mis:powerSaveMode>
- <mis:waypointType>LineStop</mis:waypointType>
- <mis:droneInfo>
- <mis:droneType>COMMON</mis:droneType>
- <mis:advanceSettings>false</mis:advanceSettings>
- <mis:droneCameras/>
- <mis:droneHeight>
- <mis:useAbsolute>false</mis:useAbsolute>
- <mis:hasTakeoffHeight>false</mis:hasTakeoffHeight>
- <mis:takeoffHeight>0.0</mis:takeoffHeight>
- </mis:droneHeight>
- </mis:droneInfo>
- </ExtendedData>
- <styleUrl>#waylineGreenPoly</styleUrl>
- <LineString>
- <tessellate>1</tessellate>
- <altitudeMode>relativeToGround</altitudeMode>
- <coordinates>$all_coordinates</coordinates>
- </LineString>
- </Placemark>
- </Document>
- </kml>""")
-
- with open(csv_file, newline='') as csvfile:
- if csv.Sniffer().has_header(csvfile.read(1024)):
- CSV_HEADER = True
- csvfile.seek(0)
- dialect = csv.Sniffer().sniff(csvfile.read(1024))
- csvfile.seek(0)
- csv_lines = csv.reader(csvfile, dialect)
- if CSV_HEADER:
- next(csv_lines, None) # skip the headers
-
- for row in csv_lines:
- if row:
- name, lon, lat, height, heading, gimbal, speed, turnmode, actions_sequence = row
-
- if lon[0] == '_':
- lon = lon[1:]
- if lat[0] == '_':
- lat = lat[1:]
-
- if (float(speed) > 15) or (float(speed) <= 0):
- sys.exit('speed should be >0 or <=15 m/s for {}'.format(name))
- if '.' not in speed:
- speed = speed+'.0'
-
- if '.' not in gimbal:
- gimbal = gimbal+'.0'
-
- if turnmode == 'AUTO':
- turnmode = 'Auto'
- elif turnmode == 'C':
- turnmode = 'Clockwise'
- elif turnmode == 'CC':
- turnmode = 'Counterclockwise'
- else:
- sys.exit('turnmode should be AUTO, C, or CC for {}'.format(name))
-
- XML_string += waypoint_start.substitute(
- turnmode=turnmode, waypoint_number=waypoint_number, speed=speed, heading=heading, gimbal=gimbal)
-
- # Actions decoding
- if actions_sequence:
- action_list = actions_sequence.split('*')
- for action in action_list:
- if action == 'SHOOT':
- XML_string += shoot_template.substitute()
- elif action == 'REC':
- XML_string += record_template.substitute()
- elif action == 'STOPREC':
- XML_string += stoprecord_template.substitute()
- # Gimbal orientation
- elif action[0] == 'G':
- XML_string += gimbal_template.substitute(
- gimbal_angle=action[1:])
- # Aircraft orientation
- elif action[0] == 'A':
- XML_string += aircraftyaw_template.substitute(
- aircraftyaw=action[1:])
- elif action[0] == 'H':
- if float(action[1:]) < 500:
- sys.exit(
- 'Hover length is in ms and should be >500 for {}'.format(name))
- XML_string += hover_template.substitute(
- length=action[1:])
-
- XML_string += "\n" + \
- waypoint_end.substitute(lon=lon, lat=lat,
- height=height,)+"\n"
-
- all_coordinates += all_coordinates_template.substitute(
- lon=lon, lat=lat, height=height)+" "
- waypoint_number += 1
- # remove last space from coordinates string
- all_coordinates = all_coordinates[:-1]
- XML_string += xml_end.substitute(
- all_coordinates=all_coordinates, ON_FINISH=ON_FINISH)
-
- with open(output_file, 'w') as output_file:
- output_file.write(XML_string)
-
- #分割csv
- def split_csv(input_file, chunk_size=99):
- # 读取原始CSV文件
- df = pd.read_csv(input_file)
-
- # 获取总行数
- total_rows = len(df)
-
- # 计算分割后的文件数
- num_files = (total_rows + chunk_size - 1) // chunk_size
-
- filenames = []
- # 分割数据并保存为新的CSV文件
- for i in range(num_files):
- start_idx = i * chunk_size
- end_idx = min((i + 1) * chunk_size, total_rows)
-
- # 生成新文件名
- output_file = f"{input_file.replace('.csv', '')}_{i + 1}.csv"
-
- filenames.append(output_file)
-
- # 写入分割后的数据到新文件
- df.iloc[start_idx:end_idx].to_csv(output_file, index=False)
-
- return filenames
-
-
- def main():
- Split = True
- input_csv_filename = 'kml.csv' # 替换为输入 CSV 文件名
- output_kml_filename = 'kml.kml' # 替换为输出 KML 文件名
-
- #是否分割
- if Split:
- filenames = split_csv(input_csv_filename,99)
- for i, file in enumerate(filenames, start=1):
- generate_kml(file, f"{output_kml_filename.replace('.kml', '')}_{i}.kml")
- else:
- generate_kml(input_csv_filename, output_kml_filename) #csv转kml
-
-
- if __name__ == '__main__':
- main()
-
-
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
将输入的csv文件进行修改,以及是否进行分割(DJI Pilot中每次飞行不可多于99个点所以我进行了切割)。
导入到大疆无人机控制软件中后即可进行飞行!注意不同软件可能有不同限制,例如DJI Pilot中每次飞行不可多于99个点且相邻航迹点不可过近,并且偏航角只能是整数。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。