做定位系统第一步就是选对硬件。STM32F103C8T6这款芯片我用了不下50次,性价比高、资料丰富,特别适合新手入门。搭配Air780EG 4G模块,既能实现基站定位又能联网传输数据,整套硬件成本控制在200元以内。
STM32驱动Air780EG的关键在于串口配置。我习惯用USART1,波特率设115200,记得开启DMA接收节省CPU资源。硬件连接时最容易踩的坑是RST复位引脚,一定要接10K上拉电阻,否则模块会频繁重启。实测中发现如果电源供电不足,模块会间歇性掉线,建议单独给4G模块配个1000μF的电容。
初始化代码里有个细节要注意:AT指令交互必须加延时。比如发送"AT+MCONNECT"后至少要等200ms再发下条指令,否则模块响应不过来。我封装了几个常用函数:
c复制// 带超时和重试的AT指令发送
uint8_t sendATCommand(const char* cmd, const char* expect, uint32_t timeout) {
for(int i=0; i<3; i++) { // 重试3次
HAL_UART_Transmit(&huart1, (uint8_t*)cmd, strlen(cmd), 1000);
if(waitForResponse(expect, timeout)) {
return 0; // 成功
}
}
return 1; // 失败
}
基站定位精度虽然不如GPS,但在室内场景反而更实用。Air780EG的AT+CIPGSMLOC指令返回的是WGS84坐标,直接给百度地图用会有偏移,需要做坐标系转换。我实测在市区精度大概50-300米,足够共享单车这类应用。
获取到原始数据后要做有效性校验:
c复制if(latitude < -90 || latitude > 90 ||
longitude < -180 || longitude > 180) {
// 数据异常处理
}
建议每30秒采集一次数据,用移动平均算法平滑轨迹。遇到过基站切换导致坐标跳变的问题,后来加了5点中值滤波就稳定多了。
上传阿里云时要注意数据格式。物模型属性上报有特定JSON格式,我建议先用Postman测试再写代码:
json复制{
"params": {
"Longitude": 116.404,
"Latitude": 39.915
}
}
在阿里云控制台创建产品时,物模型定义很关键。我建议添加以下属性:
设备认证推荐使用一机一密,比一型一密更安全。有个隐藏坑点:MQTT的ClientId必须包含设备名称,格式是deviceName|securemode=3,signmethod=hmacsha1。
数据流转规则要配置两个:
测试时先用MQTT.fx模拟设备,确认能收到数据再写STM32代码。遇到最多的问题是权限配置不对,记住要给设备分配"发布"和"订阅"权限。
百度地图SDK现在必须用AndroidX,老项目要先迁移。申请密钥时注意绑定SHA1指纹,debug和release的要分别申请。我封装了个地图工具类处理常见需求:
java复制public class MapUtils {
// 坐标转换(GCJ02转BD09)
public static LatLng coordConvert(double lat, double lng) {
//...转换算法实现
}
// 绘制实时轨迹
public static void drawPath(MapView map, List<LatLng> points) {
OverlayOptions options = new PolylineOptions()
.points(points)
.color(Color.RED);
map.addOverlay(options);
}
}
定位数据建议用WebSocket实时接收,比轮询省电。收到MQTT消息后要主线程更新UI:
java复制handler.post(() -> {
marker.setPosition(new LatLng(lat, lng));
mapView.getMap().animateMapStatus(
MapStatusUpdateFactory.newLatLng(new LatLng(lat, lng))
);
});
整套系统联调时建议按这个顺序:
功耗优化我试过几个方案:
稳定性方面,建议添加心跳检测机制。我在STM32端每5分钟发一次ping,超时3次就重启模块。Android端用Foreground Service保活,记得加上电量优化白名单。
内存泄漏排查有个技巧:在Application类里注册Activity生命周期回调,检测Activity是否正常销毁。百度地图的MapView一定要在onDestroy里调用destroy()。