当前位置:   article > 正文

航迹点导入大疆无人机_大疆无人机 预定航迹飞行

大疆无人机 预定航迹飞行

学习到了如何通过经纬度和海拔设置大疆无人机航迹飞行,记录如下:

1. 使用的软件是:DJI Pilot
2.通过航迹点(经纬度以及海拔)csv文件转为kml文件。(KML文件主要用于描述地球上的地理特征,如点、线、多边形、图层、图标等,以及与这些特征相关的属性信息。KML文件可以包含地理坐标、颜色、高度、图标等元素,使其能够用于在地图上呈现丰富的地理信息。)步骤如下:

参考链接(参考代码)

 准备一些航迹点,保存为csv文件,格式如下:
pointnamelonlatheightheadinggimbalspeedturnmodeactions_sequence
point1114.355730.527968180-13AUTOH1000*SHOOT
point2114.355730.527968160-13AUTOH1000*SHOOT
point3114.355730.527958140-13AUTOH1000*SHOOT
point4114.355830.527948120-13AUTOH1000*SHOOT
point5114.355830.527938100-13AUTOH1000*SHOOT
point6114.355830.52791880-13AUTOH1000*SHOOT
point7114.355830.5279860-13AUTOH1000*SHOOT
point8114.355730.52788840-13AUTOH1000*SHOOT

其中列分别是:点名经度维度海拔高度偏航角(注意所使用的大疆软件偏航角是否可以为小数,DJI Pilot软件不支持偏航角为小数,如果偏航角是小数在DJI Pilot中为0!),云台俯仰角无人机飞行的速度转弯模式(可能的值包括"MANUAL"、"AUTO"),在航迹点执行的动作序列(可以没有任何动作,也可以有一个或多个动作。例如表格中动作为悬停1s并拍照)

  • H1000 => 悬停 1000ms = 1s
  • 拍摄 => 拍照
  • G40 =>万向架 a -40°
  • REC => 开始视频录制
  • STOPREC => 停止录像
  • A-170 => 将飞机转向 -170 。航向的范围为 [-180, 180] 度,其中 0 代表正北。
3. 利用Python脚本将csv转化为kml文件
  1. from string import Template
  2. import csv
  3. import sys
  4. import argparse
  5. import xml.etree.ElementTree as ET
  6. import simplekml
  7. from pyproj import CRS, Transformer
  8. import pandas as pd
  9. # csv to kml
  10. def generate_kml(csv_file, output_file, on_finish='hover'):
  11. CSV_HEADER = False
  12. ON_FINISH = "Hover" if on_finish == 'hover' else "GoHome"
  13. XML_string = """<?xml version="1.0" encoding="UTF-8"?>
  14. <kml xmlns="http://www.opengis.net/kml/2.2">
  15. <Document xmlns="">
  16. <name>chambon_small</name>
  17. <open>1</open>
  18. <ExtendedData xmlns:mis="www.dji.com">
  19. <mis:type>Waypoint</mis:type>
  20. <mis:stationType>0</mis:stationType>
  21. </ExtendedData>
  22. <Style id="waylineGreenPoly">
  23. <LineStyle>
  24. <color>FF0AEE8B</color>
  25. <width>6</width>
  26. </LineStyle>
  27. </Style>
  28. <Style id="waypointStyle">
  29. <IconStyle>
  30. <Icon>
  31. <href>https://cdnen.dji-flighthub.com/static/app/images/point.png</href>
  32. </Icon>
  33. </IconStyle>
  34. </Style>
  35. <Folder>
  36. <name>Waypoints</name>
  37. <description>Waypoints in the Mission.</description>\n"""
  38. all_coordinates = ""
  39. waypoint_number = 1
  40. waypoint_start = Template(""" <Placemark>
  41. <name>Waypoint$waypoint_number</name>
  42. <visibility>1</visibility>
  43. <description>Waypoint</description>
  44. <styleUrl>#waypointStyle</styleUrl>
  45. <ExtendedData xmlns:mis="www.dji.com">
  46. <mis:useWaylineAltitude>false</mis:useWaylineAltitude>
  47. <mis:heading>$heading</mis:heading>
  48. <mis:turnMode>$turnmode</mis:turnMode>
  49. <mis:gimbalPitch>$gimbal</mis:gimbalPitch>
  50. <mis:useWaylineSpeed>false</mis:useWaylineSpeed>
  51. <mis:speed>$speed</mis:speed>
  52. <mis:useWaylineHeadingMode>true</mis:useWaylineHeadingMode>
  53. <mis:useWaylinePointType>true</mis:useWaylinePointType>
  54. <mis:pointType>LineStop</mis:pointType>
  55. <mis:cornerRadius>0.2</mis:cornerRadius>""")
  56. waypoint_end = Template("""
  57. </ExtendedData>
  58. <Point>
  59. <altitudeMode>relativeToGround</altitudeMode>
  60. <coordinates>$lon,$lat,$height</coordinates>
  61. </Point>
  62. </Placemark>""")
  63. hover_template = Template("""
  64. <mis:actions param="$length" accuracy="0" cameraIndex="0" payloadType="0" payloadIndex="0">Hovering</mis:actions>""")
  65. shoot_template = Template("""
  66. <mis:actions param="0" accuracy="0" cameraIndex="0" payloadType="0" payloadIndex="0">ShootPhoto</mis:actions>""")
  67. gimbal_template = Template("""
  68. <mis:actions param="$gimbal_angle" accuracy="1" cameraIndex="0" payloadType="0" payloadIndex="0">GimbalPitch</mis:actions>""")
  69. aircraftyaw_template = Template("""
  70. <mis:actions param="$aircraftyaw" accuracy="0" cameraIndex="0" payloadType="0" payloadIndex="0">AircraftYaw</mis:actions>""")
  71. record_template = Template("""
  72. <mis:actions param="0" accuracy="0" cameraIndex="0" payloadType="0" payloadIndex="0">StartRecording</mis:actions>""")
  73. stoprecord_template = Template("""
  74. <mis:actions param="0" accuracy="0" cameraIndex="0" payloadType="0" payloadIndex="0">StopRecording</mis:actions>""")
  75. all_coordinates_template = Template("$lon,$lat,$height")
  76. xml_end = Template(""" </Folder>
  77. <Placemark>
  78. <name>Wayline</name>
  79. <description>Wayline</description>
  80. <visibility>1</visibility>
  81. <ExtendedData xmlns:mis="www.dji.com">
  82. <mis:altitude>50.0</mis:altitude>
  83. <mis:autoFlightSpeed>5.0</mis:autoFlightSpeed>
  84. <mis:actionOnFinish>$ON_FINISH</mis:actionOnFinish>
  85. <mis:headingMode>UsePointSetting</mis:headingMode>
  86. <mis:gimbalPitchMode>UsePointSetting</mis:gimbalPitchMode>
  87. <mis:powerSaveMode>false</mis:powerSaveMode>
  88. <mis:waypointType>LineStop</mis:waypointType>
  89. <mis:droneInfo>
  90. <mis:droneType>COMMON</mis:droneType>
  91. <mis:advanceSettings>false</mis:advanceSettings>
  92. <mis:droneCameras/>
  93. <mis:droneHeight>
  94. <mis:useAbsolute>false</mis:useAbsolute>
  95. <mis:hasTakeoffHeight>false</mis:hasTakeoffHeight>
  96. <mis:takeoffHeight>0.0</mis:takeoffHeight>
  97. </mis:droneHeight>
  98. </mis:droneInfo>
  99. </ExtendedData>
  100. <styleUrl>#waylineGreenPoly</styleUrl>
  101. <LineString>
  102. <tessellate>1</tessellate>
  103. <altitudeMode>relativeToGround</altitudeMode>
  104. <coordinates>$all_coordinates</coordinates>
  105. </LineString>
  106. </Placemark>
  107. </Document>
  108. </kml>""")
  109. with open(csv_file, newline='') as csvfile:
  110. if csv.Sniffer().has_header(csvfile.read(1024)):
  111. CSV_HEADER = True
  112. csvfile.seek(0)
  113. dialect = csv.Sniffer().sniff(csvfile.read(1024))
  114. csvfile.seek(0)
  115. csv_lines = csv.reader(csvfile, dialect)
  116. if CSV_HEADER:
  117. next(csv_lines, None) # skip the headers
  118. for row in csv_lines:
  119. if row:
  120. name, lon, lat, height, heading, gimbal, speed, turnmode, actions_sequence = row
  121. if lon[0] == '_':
  122. lon = lon[1:]
  123. if lat[0] == '_':
  124. lat = lat[1:]
  125. if (float(speed) > 15) or (float(speed) <= 0):
  126. sys.exit('speed should be >0 or <=15 m/s for {}'.format(name))
  127. if '.' not in speed:
  128. speed = speed+'.0'
  129. if '.' not in gimbal:
  130. gimbal = gimbal+'.0'
  131. if turnmode == 'AUTO':
  132. turnmode = 'Auto'
  133. elif turnmode == 'C':
  134. turnmode = 'Clockwise'
  135. elif turnmode == 'CC':
  136. turnmode = 'Counterclockwise'
  137. else:
  138. sys.exit('turnmode should be AUTO, C, or CC for {}'.format(name))
  139. XML_string += waypoint_start.substitute(
  140. turnmode=turnmode, waypoint_number=waypoint_number, speed=speed, heading=heading, gimbal=gimbal)
  141. # Actions decoding
  142. if actions_sequence:
  143. action_list = actions_sequence.split('*')
  144. for action in action_list:
  145. if action == 'SHOOT':
  146. XML_string += shoot_template.substitute()
  147. elif action == 'REC':
  148. XML_string += record_template.substitute()
  149. elif action == 'STOPREC':
  150. XML_string += stoprecord_template.substitute()
  151. # Gimbal orientation
  152. elif action[0] == 'G':
  153. XML_string += gimbal_template.substitute(
  154. gimbal_angle=action[1:])
  155. # Aircraft orientation
  156. elif action[0] == 'A':
  157. XML_string += aircraftyaw_template.substitute(
  158. aircraftyaw=action[1:])
  159. elif action[0] == 'H':
  160. if float(action[1:]) < 500:
  161. sys.exit(
  162. 'Hover length is in ms and should be >500 for {}'.format(name))
  163. XML_string += hover_template.substitute(
  164. length=action[1:])
  165. XML_string += "\n" + \
  166. waypoint_end.substitute(lon=lon, lat=lat,
  167. height=height,)+"\n"
  168. all_coordinates += all_coordinates_template.substitute(
  169. lon=lon, lat=lat, height=height)+" "
  170. waypoint_number += 1
  171. # remove last space from coordinates string
  172. all_coordinates = all_coordinates[:-1]
  173. XML_string += xml_end.substitute(
  174. all_coordinates=all_coordinates, ON_FINISH=ON_FINISH)
  175. with open(output_file, 'w') as output_file:
  176. output_file.write(XML_string)
  177. #分割csv
  178. def split_csv(input_file, chunk_size=99):
  179. # 读取原始CSV文件
  180. df = pd.read_csv(input_file)
  181. # 获取总行数
  182. total_rows = len(df)
  183. # 计算分割后的文件数
  184. num_files = (total_rows + chunk_size - 1) // chunk_size
  185. filenames = []
  186. # 分割数据并保存为新的CSV文件
  187. for i in range(num_files):
  188. start_idx = i * chunk_size
  189. end_idx = min((i + 1) * chunk_size, total_rows)
  190. # 生成新文件名
  191. output_file = f"{input_file.replace('.csv', '')}_{i + 1}.csv"
  192. filenames.append(output_file)
  193. # 写入分割后的数据到新文件
  194. df.iloc[start_idx:end_idx].to_csv(output_file, index=False)
  195. return filenames
  196. def main():
  197. Split = True
  198. input_csv_filename = 'kml.csv' # 替换为输入 CSV 文件名
  199. output_kml_filename = 'kml.kml' # 替换为输出 KML 文件名
  200. #是否分割
  201. if Split:
  202. filenames = split_csv(input_csv_filename,99)
  203. for i, file in enumerate(filenames, start=1):
  204. generate_kml(file, f"{output_kml_filename.replace('.kml', '')}_{i}.kml")
  205. else:
  206. generate_kml(input_csv_filename, output_kml_filename) #csv转kml
  207. if __name__ == '__main__':
  208. main()

将输入的csv文件进行修改,以及是否进行分割(DJI Pilot中每次飞行不可多于99个点所以我进行了切割)。 

4. kml文件制作完成后可导入到大疆的无人机软件中或者Google Earth中查看,例如:

 导入到大疆无人机控制软件中后即可进行飞行!注意不同软件可能有不同限制,例如DJI Pilot中每次飞行不可多于99个点且相邻航迹点不可过近,并且偏航角只能是整数。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/590184
推荐阅读
相关标签
  

闽ICP备14008679号