Python新手求助:NMEA日志坐标保存至CSV文件报错解决
解决NMEA数据CSV保存错误并实现KML导出
首先,咱们先拆解你遇到的问题:TypeError: write() argument must be str, not list 是因为你直接把列表传给了文件的write()方法,但它只接受字符串。而且你的CSV处理逻辑还有几个小疏漏:
- 每次循环都创建空的
coord_list,还在for i in message里重复执行写入,这会导致同一行数据被重复写入N次(N是该行字符数) - 每次写入后立刻
f.close(),这会导致后续数据完全无法写入——文件已经被关闭了
接下来咱们一步步修正代码,同时实现KML导出功能:
1. 修正CSV保存逻辑
我们用Python内置的csv.writer来处理CSV写入,它会自动帮我们处理逗号分隔、字符串转义这些细节,比手动拼接字符串靠谱得多。另外用with语句管理文件,不用手动关闭,程序结束时会自动处理文件资源。
2. 实现KML导出功能
KML是基于XML的格式,对于简单的轨迹场景,我们可以用Python的xml.etree.ElementTree构建标准的KML结构,生成的文件可以直接用Google Earth或其他GIS软件打开。
完整修正代码
import serial from pynmea import nmea import csv from xml.etree.ElementTree import Element, SubElement, tostring def create_kml(coords_list): # 创建KML根元素,指定命名空间 kml = Element('kml', xmlns='http://www.opengis.net/kml/2.2') document = SubElement(kml, 'Document') # 创建轨迹线图层 placemark = SubElement(document, 'Placemark') name = SubElement(placemark, 'Name') name.text = 'NMEA GPS轨迹' line_string = SubElement(placemark, 'LineString') # 设置轨迹样式(可选) style_url = SubElement(placemark, 'styleUrl') style_url.text = '#blueLine' # 定义蓝色轨迹样式 style = SubElement(document, 'Style', id='blueLine') line_style = SubElement(style, 'LineStyle') color = SubElement(line_style, 'color') color.text = 'ff0000ff' # 蓝色(KML颜色格式:AARRGGBB) width = SubElement(line_style, 'width') width.text = '3' # 处理坐标:KML格式是 经度,纬度,海拔,这里忽略海拔填0 coordinates = SubElement(line_string, 'coordinates') coords_text = '\n'.join([f"{lon},{lat},0" for lat, lon in coords_list]) coordinates.text = coords_text # 转为带XML声明的字符串 kml_str = '<?xml version="1.0" encoding="UTF-8"?>\n' + tostring(kml, encoding='unicode') return kml_str try: # 初始化串口,直接指定波特率更简洁 ser = serial.Serial('COM4', baudrate=4800) print('Waiting for data') # 存储所有坐标,用于生成KML all_coords = [] # 用with语句管理CSV文件,自动处理关闭 with open('coord_list.csv', 'w', newline='', encoding='utf-8') as csv_file: writer = csv.writer(csv_file) # 写入CSV表头 writer.writerow(['Latitude', 'Longitude']) while True: message = ser.readline().decode().strip() if '$GPGGA' in message: print(message) gpgga = nmea.GPGGA() gpgga.parse(message) # 把NMEA的DDMM.MMMM格式转为通用的十进制DD.DDDDD格式 # 比如5335.6665N → 53 + 35.6665/60 ≈ 53.594442° lat_deg = float(gpgga.latitude[:2]) + float(gpgga.latitude[2:])/60 lon_deg = float(gpgga.longitude[:3]) + float(gpgga.longitude[3:])/60 # 处理南北纬、东西经的正负符号 if gpgga.lat_dir == 'S': lat_deg = -lat_deg if gpgga.lon_dir == 'W': lon_deg = -lon_deg print(f"Lat {lat_deg:.6f} Long {lon_deg:.6f}") # 写入CSV一行数据 writer.writerow([lat_deg, lon_deg]) # 刷新缓冲区,确保数据实时写入文件 csv_file.flush() # 保存坐标到列表,用于后续生成KML all_coords.append((lat_deg, lon_deg)) except KeyboardInterrupt: print("\n程序中断,正在保存KML文件...") # 只有收集到坐标时才生成KML if all_coords: kml_content = create_kml(all_coords) with open('gps轨迹.kml', 'w', encoding='utf-8') as kml_file: kml_file.write(kml_content) print("KML文件已保存") finally: ser.close() print("串口已关闭")
关键改动说明:
CSV处理优化:
- 用
csv.writer替代手动写入,避免格式错误 - 移除了无用的
for i in message循环,避免重复写入 - 把原始的DDMM.MMMM格式坐标转为通用的十进制格式(这是大多数GIS工具需要的格式)
- 用
KML实现细节:
- 新增
create_kml函数构建标准KML结构,包含轨迹样式定义 - 在程序通过Ctrl+C中断时,自动将所有收集到的坐标写入KML文件
- 遵循KML坐标格式要求:
经度,纬度,海拔
- 新增
其他细节优化:
- 串口初始化时直接指定波特率,代码更简洁
- 处理了南北纬、东西经的符号,生成正确的正负坐标
- 每次CSV写入后调用
flush(),避免程序意外退出时丢失数据
现在运行代码,CSV文件会正常保存坐标,程序中断时还会自动生成带样式的KML轨迹文件,直接用Google Earth打开就能看到你的GPS轨迹啦。
内容的提问来源于stack exchange,提问作者fuji_doji
相关产品推荐
相关产品推荐

