高德导航、路径规划运用在单片机及APP上,快速开发导航应用【代码均开源】

科技   2024-11-01 08:02   广东  

前言
(一)在当今这个瞬息万变的数字化时代,导航技术已经深入到我们生活的方方面面,从日常出行到物流配送,再到应急救援,无不彰显其重要性。
随着智能手机和物联网技术的飞速发展,对于导航系统的需求不再仅仅局限于简单的路线指引,而是更加追求精准性、实时性和智能化。在此背景下,将高德导航的路径规划算法高效应用于单片机系统及移动APP中,不仅是对传统导航技术的一次革新,更是推动智慧城市、智能交通系统建设的关键一环。
(二)单片机,作为嵌入式系统的核心,凭借其体积小、功耗低、集成度高等特点,在车载设备、智能家居、工业自动化等领域发挥着不可替代的作用。
将高德导航的路径规划功能集成到单片机上,意味着可以实现更为紧凑、低功耗的导航解决方案,为车辆自主导航、无人机路径规划等应用场景提供强有力的技术支持。这不仅要求算法在保持高精度的同时,还需进行深度优化以适应单片机有限的计算资源和存储能力。
(三)所以本文将给大家分享一下,我将高德开放平台的导航、路径规划功能运用到单片机及APP上,从而可以快速开发导航类、规划类的项目。当然方法有非常多种,我本次分享的仅仅是高德的冰山一角,高德提供的API,甚至可以让单片机不需要APP支持,独立运行导航、路径规划等项目。
本文末尾,有项目所有代码的下载地址

效果展示
(一)APP展示
由于是快速开发,所以没有任何美化,仅是实现功能。APP开发平台:App Inventor
图:设定目的地后,会自动规划最近的路线,然后实时定位导航
(二)单片机展示
单片机:ESP32
图:APP开始导航后,将导航信息发送到ESP32

项目大纲
APP设定目的地→→地理编码API→→APP定位经纬度→→坐标转换API→→路径规划API→→APP显示静态图→→提交单片机显示
为了不泄露信息,最好对高德API进行封装,然后通过自己的API来操作。同时APP和单片机的通信也用到API。http://api.xemowo.top
(一)获取高德开放平台API
①路径规划API:https://lbs.amap.com/api/webservice/guide/api/direction
对步行、公交路径规划,返回从原地到目的地的信息(方向,距离,时间,步行指示等)
②地理编码API:https://lbs.amap.com/api/webservice/guide/api/georegeo
将地址信息,转化为经纬度等信息。如:中山市港口镇政府,返回信息:"location" :"113.384324,22.584733"
③坐标转换API:https://lbs.amap.com/api/webservice/guide/api/convert
将用户输入的非高德坐标(GPS 坐标、mapbar 坐标、baidu 坐标)转换成高德坐标。
④静态地图:https://lbs.amap.com/api/webservice/guide/api/staticmaps
项目可以不用静态地图,因为路径规划API也会返回带有标记的静态图
(二)封装API(因人而异,后面我会放出PHP源码)
①地址查询经纬度:http://api.xemowo.top/api/gaode/chaxun.php
文档:http://api.xemowo.top/api/chaxun.html
②坐标转换:http://api.xemowo.top/api/gaode/gps.php
文档:http://api.xemowo.top/api/GPS.html
③路径规划:http://api.xemowo.top/api/gaode/walk.php
文档:http://api.xemowo.top/api/walk.html
④单片机接收信息:http://api.xemowo.top/api/gaode/esp_walk.php
文档:http://api.xemowo.top/api/esp_walk.html
(三)制作APP
App Inventor,Android编程工具https://www.17coding.net/
采用图形化积木式的拖放组件,完全在线开发的Android编程环境,无需复杂的软件安装,可以通过浏览器直接访问并进行编程。
(四)单片机编程
Arduino IDE,内置很多库函数,对编程极其方便,速成项目,并且资料很多,对初学者帮助非常大
高德API
(一)注册高德开放平台的账号https://lbs.amap.com/
(二)应用管理----创建新应用
(三)添加key,选择web服务(请勿泄露key)
(四)寻找所需的API,本期项目我们需要4个高德API
注意个人用户调用的限量,企业用户会多一些,超过限量可能被禁止使用
①路径规划API:https://lbs.amap.com/api/webservice/guide/api/direction
对步行、公交路径规划,返回从原地到目的地的信息(方向,距离,时间,步行指示等)
②地理编码API:https://lbs.amap.com/api/webservice/guide/api/georegeo
将地址信息,转化为经纬度等信息。如:中山市港口镇政府,返回信息:"location" :"113.384324,22.584733"
③坐标转换API:https://lbs.amap.com/api/webservice/guide/api/convert
将用户输入的非高德坐标(GPS 坐标、mapbar 坐标、baidu 坐标)转换成高德坐标。
④静态地图:https://lbs.amap.com/api/webservice/guide/api/staticmaps
项目可以不用静态地图,因为路径规划API也会返回带有标记的静态图
制作API
搭建API(网站)需要一台服务器,并且需要开发环境
我这里的环境如下:
系统:Orange Pi 1.0.2 Jammy (aarch64)
WEB平台:OpenResty
PHP:PHP-72
域名:API.XEMOWO.TOP
(一)坐标转换API (http://api.xemowo.top/api/GPS.html)
示例:http://api.xemowo.top/api/gaode/gps.php?gps=113.38472,22.59476&photo=0
phperror_reporting(0);//屏蔽报错
$photo=$_GET["photo"];
$gps=$_GET["gps"];if($gps==""){exit("GPS地址为空");}
$apiKey = 'xxxxxxxxxxxxxxxxxxx'; //高德API密钥
$html = file_get_contents("https://restapi.amap.com/v3/assistant/coordinate/convert?locations=".$gps."&coordsys=gps&output=json&key=".$apiKey.""); //高德坐标转换
$arr = json_decode($html, true); // 将获取到的 JSON 数据解析成数组
$status = $arr["status"];$info = $arr["info"];$infocode = $arr["infocode"];$locations = $arr["locations"];
//https://restapi.amap.com/v3/staticmap?location=".$gps."&zoom=15&size=400*400&markers=mid,,A:".$gps."&key=".$apiKey."
if($photo == 1){ // 构建图片URL $gps=$_GET["gps"];if($gps==""){exit("GPS地址为空");} $apiKey = 'xxxxxxxxxxxxxxxxxxx'; $ip = $location; $savePath = 'gps_map.png'; // 例如 'images/map.png' $imageUrl = "https://restapi.amap.com/v3/staticmap?location=".$locations."&zoom=15&size=400*400&markers=mid,,A:".$locations."&key=".$apiKey.""; // 使用file_get_contents获取图片内容 $imageContent = file_get_contents($imageUrl); // 使用file_put_contents将图片内容保存到文件 $saveResult = file_put_contents($savePath, $imageContent);
$map = file_get_contents("http://api.xemowo.top/api/gaode/gps_map.png"); //保存图片 // 将图像数据转换为 Base64 编码 $base64 = base64_encode($map); // 嵌入到 img 标签中 echo ''" width="400" height="400" />'; //给图片加上base64,让图片刷新 exit();}
$data = array('status' => $status,'info' => $info,'infocode' => $infocode,'locations' => $locations,);

echo json_encode($data, JSON_UNESCAPED_UNICODE); exit();

file_get_contents函数读取API信息,json_decode函数将获取的API转成JSON,然后获取JSON的信息保存在变量内
如果photo=1时,则网页返回图片,图片地址在http://api.xemowo.top/api/gaode/gps_map.png
构建图片采用高德静态图的API:https://lbs.amap.com/api/webservice/guide/api/staticmaps
注意,末尾的echo输出,一定要用到base64编码,否则在输出时,图片可能没有变化
(二)地址查询经纬度 (http://api.xemowo.top/api/chaxun.html)
示例:http://api.xemowo.top/api/gaode/chaxun.php?address=广东省珠海市香洲区中山大学&photo=0
phperror_reporting(0);//屏蔽报错
$photo=$_GET["photo"];$address=$_GET["address"];
$apiKey = 'xxxxxxxxxxxxxxx';


if($address==""){exit("地址为空");}
$html = file_get_contents("https://restapi.amap.com/v3/geocode/geo?address=".$address."&output=json&key=".$apiKey."");
$arr = json_decode($html, true); // 将获取到的 JSON 数据解析成数组

$formatted_address = $arr["geocodes"][0]["formatted_address"];$location = $arr["geocodes"][0]["location"];$level = $arr["geocodes"][0]["level"];
$data = array('level' => $level,'formatted_address' => $formatted_address,'location' => $location,);



if($photo == 1){// 构建图片URL $ip = $location;$savePath = 'chakan_map.png'; // 例如 'images/map.png'
$apiKey = 'xxxxxxxxxxxxxxx'; $imageUrl = "https://restapi.amap.com/v3/staticmap?location=".$location."&zoom=15&size=400*400&markers=mid,,A:".$location."&key=".$apiKey.""; // 使用file_get_contents获取图片内容 $imageContent = file_get_contents($imageUrl); // 使用file_put_contents将图片内容保存到文件 $saveResult = file_put_contents($savePath, $imageContent);
$map = file_get_contents("http://api.xemowo.top/api/gaode/chakan_map.png"); // 将图像数据转换为 Base64 编码 $base64 = base64_encode($map); // 嵌入到 img 标签中 echo ''" width="400" height="400" />'; exit(); }echo json_encode($data, JSON_UNESCAPED_UNICODE); exit();
地址查询和坐标转换的JSON解析数据差不多,但是注意3项数据都在geocodes下,所以JSON取值在["geocodes"][0]
如果photo=1时,则网页返回图片,图片地址在http://api.xemowo.top/api/gaode/chakan_map.png
构建图片采用高德静态图的API:https://lbs.amap.com/api/webservice/guide/api/staticmaps
注意,末尾的echo输出,一定要用到base64编码,否则在输出时,图片可能没有变化
(三)路径规划 (http://api.xemowo.top/api/walk.html)
示例:http://api.xemowo.top/api/gaode/walk.php?origin=113.388247,22.589615&destination=113.388317,22.587233&mark=1&photo=0
phperror_reporting(0);//屏蔽报错$photo=$_GET["photo"];$oled=$_GET["oled"];$all=$_GET["all"];$esp32=$_GET["esp32"];$mark = $_GET["mark"];
if($esp32 == 1){ if (file_exists($filename)) { // 读取文件内容 $content = file_get_contents($filename); $aa = mb_substr("".$instruction."",0,10,'utf-8'); $bb = mb_substr("".$instruction."",10,10,'utf-8'); $cc = mb_substr("".$instruction."",20,10,'utf-8'); $dd = mb_substr("".$instruction."",30,10,'utf-8');
$data = array(
'content' => $content, 'oled_a' => $aa, 'oled_b' => $bb, 'oled_c' => $cc, 'oled_d' => $dd, ); echo json_encode($data, JSON_UNESCAPED_UNICODE); exit(); } }
$origin=$_GET["origin"];if($origin==""){exit("起点origin地址为空");}
$destination=$_GET["destination"];if($destination==""){exit("目的地destination地址为空");}
$apiKey = 'xxxxxxxxxxxxxxx';
if($all == 1){$html = file_get_contents("https://restapi.amap.com/v3/direction/walking?origin=".$origin."&destination=".$destination."&key=".$apiKey."");
echo $html;exit();}
$html = file_get_contents("https://restapi.amap.com/v3/direction/walking?origin=".$origin."&destination=".$destination."&key=".$apiKey."");$arr = json_decode($html, true); // 将获取到的 JSON 数据解析成数组
$distance = $arr["route"]["paths"][0]["distance"];//步行距离$duration = $arr["route"]["paths"][0]["duration"];//步行预计$instruction = $arr["route"]["paths"][0]["steps"][0]["instruction"];//路段步行指示$orientation = $arr["route"]["paths"][0]["steps"][0]["orientation"];//方向$polyline = $arr["route"]["paths"][0]["steps"][0]["polyline"];//坐标点
if($mark == 1){
// 定义文件名 $filename = "walk.txt"; // 使用文件写入模式打开文件。如果文件不存在,会自动创建 $file = fopen($filename, "w"); // 检查文件是否成功打开 if ($file) { // 将文本写入文件 fwrite($file, $instruction); // 关闭文件 fclose($file);
}
}






if($photo == 1){ // 构建图片URL $apiKey = 'xxxxxxxxxxxx'; $ip = $location; $savePath = 'walk_map.png'; $imageUrl = "https://restapi.amap.com/v3/staticmap?zoom=16&size=400*400&paths=10,0x0000ff,1,,:".$polyline."&key=".$apiKey."";
// 使用file_get_contents获取图片内容 $imageContent = file_get_contents($imageUrl); // 使用file_put_contents将图片内容保存到文件 $saveResult = file_put_contents($savePath, $imageContent);
$map = file_get_contents("http://api.xemowo.top/api/gaode/walk_map.png"); // 将图像数据转换为 Base64 编码 $base64 = base64_encode($map); // 嵌入到 img 标签中 echo ''" width="400" height="400" />'; exit();}

//适配oledif($oled == 1){ $aa = mb_substr("".$instruction."",0,10,'utf-8'); $bb = mb_substr("".$instruction."",10,10,'utf-8'); $cc = mb_substr("".$instruction."",20,10,'utf-8'); $dd = mb_substr("".$instruction."",30,10,'utf-8');
$data = array( 'distance' => $distance, 'duration' => $duration, 'instruction' => $instruction, 'orientation' => $orientation, 'polyline' => $polyline,
'oled_a' => $aa, 'oled_b' => $bb, 'oled_c' => $cc, 'oled_d' => $dd,
);

echo json_encode($data, JSON_UNESCAPED_UNICODE);
exit(); }else{

$data = array( 'distance' => $distance, 'duration' => $duration, 'instruction' => $instruction, 'orientation' => $orientation, 'polyline' => $polyline,

);

echo json_encode($data, JSON_UNESCAPED_UNICODE);
exit();

}
此段为测试适配屏幕的代码,用在单片机显示上,在walk_esp的api上
all=1会返回所有高德api的数据,用于测试
如果使用单片机,或者搭配walk_esp使用的话,就需要让make=1,将数据写入到walk.txt文本中
(四)单片机数据 (http://api.xemowo.top/api/esp_walk.html)
示例:http://api.xemowo.top/api/gaode/esp_walk.php?esp32=1
"esp32"];$mark = $_GET["mark"];$filename = "walk.txt";  if($esp32 == 1){  if (file_exists($filename)) {      // 读取文件内容      $content = file_get_contents($filename);      $aa = mb_substr("".$content."",0,10,'utf-8');    $bb = mb_substr("".$content."",10,10,'utf-8');    $cc = mb_substr("".$content."",20,10,'utf-8');    $dd = mb_substr("".$content."",30,10,'utf-8');
$data = array(
'content' => $content, 'oled_a' => $aa, 'oled_b' => $bb, 'oled_c' => $cc, 'oled_d' => $dd, ); echo json_encode($data, JSON_UNESCAPED_UNICODE); exit(); } }
此单片机API,需要walk.php的make=1,然后读取walk写入到wake.txt的内容
并且将数据转换成0.96OLED屏幕适配的数据,oled_a代表屏幕第一行,以此类推
制作APP
如果要速成一个APP,快速实现功能,那么我推荐用app Inventor,使用拖拽式、搭积木式编程,对没开发过APP的师傅,就非常合适
目前app Inventor有几个版本,官方版http://code.appinventor.mit.edu,社区版http://ai2.17coding.net/?locale=zh_CN,各种私人版本(收费)
所以我们用社区版就够了,可以实现大多数功能http://ai2.17coding.net/?locale=zh_CN
(一)做项目前,注意,每做一步大的步骤,就必须导出项目保存,因为内置的保存项目关闭浏览器后就没了!!!
然后继续做的时候,再导入项目,文件名不要中文
(二)建议下载调试软件----AI伴侣
下载地址:https://wwmg.lanzouj.com/iopRp2dlfrih
(三)拖拽组件
按照我的组件列表添加组件,并且按照自己喜欢的位置放置组件
(四)编写程序
①先读取输入框的内容,并且用地址查询经纬度API来将输入的地址转为经纬度信息
②APP读取手机的位置信息,将手机GPS信息转化为高德经纬度信息
③当地址查询经纬度和GPS信息都完成后,汇总一起到路径规划API内,然后访问路径规划API
顺便返回路径规划图,photo=1
此时web浏览款会实时显示导航信息,当手机定位发生变化时,就会改变地图
④软件使用示例
单片机接收导航信息
我这里使用ESP32,因为ESP32具有wifi功能,而且内存和性能也足够强大,可以完全加载中文库,很方便的显示中文路径信息
代码平台使用Arduino IDE,可以直接调用所需的库文件,用少量的代码就能完美的实现功能
屏幕使用0.96OLED,可以显示中文信息,而且API已经适配了此屏幕,显示更加完美
 #include //wifi库#include //json解析库#include //http连接库#include 
#include //u8g2oled库#include
#define BOARD_I2C_SCL 22#define BOARD_I2C_SDA 21 U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ BOARD_I2C_SCL, /* data=*/ BOARD_I2C_SDA, /* reset=*/ U8X8_PIN_NONE); // All Boards without Reset of the Display
const char * ID = "XEMOWO_PC";//wifi账号const char * PASSWORD = "1SUNjiajun";//wifi密码
const char* one;//api第一行内容const char* two;//api第二行内容const char* three;//api第三行内容const char* four;//api第四行内容
String API = "";String url_xinzhi = "";String WeatherURL = "";

HTTPClient http;String GitURL(String api){ url_xinzhi = "http://api.xemowo.top/api/gaode/esp_walk.php?esp32=1";//oled=1则表示使用oled专属格式 return url_xinzhi;}


void ParseWeather(String url){ http.begin(url); int httpGet = http.GET(); if(httpGet > 0) { Serial.printf("HTTPGET is %d",httpGet); if(httpGet == HTTP_CODE_OK) { StaticJsonDocument<500> doc;
String json = http.getString(); Serial.println("解析"); Serial.println(json); deserializeJson(doc, json); one = doc["oled_a"]; // "人生就是一列开往坟墓" two = doc["oled_b"]; // "的列车,路途上会有很" three = doc["oled_c"]; // "多站,很难有人可以至" four = doc["oled_d"]; // "始至终陪着走完。\n" } else { Serial.printf("ERROR1!!"); ParseWeather(WeatherURL); } } else { Serial.printf("ERROR2!!");

ParseWeather(WeatherURL);
} http.end();}





void setup() { // put your setup code here, to run once: u8g2.setFont( u8g2_font_wqy12_t_gb2312 );//设置为中文字体 u8g2.begin(); u8g2.enableUTF8Print();
Serial.begin(115200); Serial.println("Init u8g2 ...."); Serial.println("WiFi:"); Serial.println(ID); Serial.println("PASSWORLD:"); Serial.println(PASSWORD);

WiFi.begin(ID,PASSWORD);
u8g2.setCursor (0, 10); u8g2.println("连接wifi中"); u8g2.sendBuffer(); while(WiFi.status()!=WL_CONNECTED) {
delay(10000);//延迟大一点,不然联网连不上! Serial.println("正在连接...");
u8g2.setCursor (0, 10); u8g2.println("连接wifi中"); u8g2.sendBuffer(); } Serial.println("连接成功!"); //==================wifi连接================== u8g2.clearBuffer(); WeatherURL = GitURL(API);


delay(100);}
void loop() { ParseWeather(WeatherURL); Serial.println(WeatherURL); u8g2.clearBuffer();//清平 delay(10); u8g2.setCursor (0, 10); u8g2.println(one);
u8g2.setCursor (0, 25); u8g2.println(two);
u8g2.setCursor (0, 40); u8g2.println(three);
u8g2.setCursor (0, 55); u8g2.println(four);
u8g2.sendBuffer();//将内容上传到缓存区

delay(5000);}

①下载库文件,项目所需的库,都可以在内置的库文件管理器中找到
②屏幕接口采用硬件IIC引脚,屏幕方向为R0正向
③定义wifi账号以及wifi密码,还有屏幕的显示内容变量
④设置esp_walk的api,此API实时接收导航内容并让屏幕显示导航内容
⑤接收到API返回的内容后,进行JSON解析到变量内
⑥SETUP函数
将屏幕的字库设置为中文字库,并且启用
设置wifi账号密码,若wifi未连接,则一直循环连接直到连接成功
⑦LOOP函数
一直访问API,并且将更新后的API数据显示到屏幕上,每行10字,4行
⑧显示效果
总结
首先感谢您能看到这里,意味着您认真看了我的文章,有不足之处,欢迎指点
(一)项目采用了高德开放平台的多项API,从而完成一个导航的项目,但是高德平台其实针对导航有更完整的API,文章仅为大家呈现多种API配合、多设备实现导航
(二)文章采用的所有代码,包括API源码、APP代码、单片机代码均开源、分享,让大家一起学习、交流
(三)本项目通过高德导航与路径规划技术在单片机及APP上的成功应用,不仅验证了技术融合的可行性,也为未来导航服务在物联网领域的广泛应用奠定了坚实基础。
(四)本项目所有代码下载地址,https://wwmg.lanzouj.com/in1Dl2dlmvkf
作者:小恶魔owo, 来源:面包板社区


END

 免费申请开发板 


投稿/推广/合作/加群 请扫码添加微信

(请备注来意,加群请备注城市-称呼-行业岗位信息)

 


面包板社区
分享电子技术干货,工程师福利!EET电子工程专辑、ESM国际电子商情、EDN电子技术设计官方社区。
 最新文章