楼主需要买接收前端芯片,自己做定位计算,这个工作有一定难度,以前要FPGA来算,现在技术发达了,可以试试好一点的带DSP核的MCU。现成GPS模块对垂直上升率有限制,火箭上基本会罢工,根本不用考虑。北斗未见论坛上有人试过。
原因:此前也想过使用陀螺仪计算用以获得相对位移以指引回收操作,然而测试的时候发现不仅算法比较困难,而且精度和资源占用方面也不如我意。
因而转而使用卫星定位系统以进行定位。
这里使用的是微型民用定位模块(以下简称模块),由于较为靠近室内,冷启动和热启动耗时都较长,如果在室外,性能会好很多。
也尝试打印了一下数据,结果是这数据量明显不适合直接打印……
——————————————————————————
正文:
材料准备:
网购一个模块(要带陶瓷天线),USB-TTL
(虽然这里用的是外国产品,但是实际测试的效果上来看,我没觉得中科微的和外国的有什么区别)
STCisp或者其他的总之能读串口就行的软件,也可以用正规的解析软件。
调试:
TXD接RXD,反之亦然,如果没有安装串口驱动需要安装。(如不知道串口参见百度)
打开串口,一般不用改:
通电,状态灯点亮,把天线放在尽可能靠近室外的地方,这将会大大提高成功率,此时不需要打开串口,因为此时模块处于冷启动状态,需要较长的时间进行定位,此时收到的数据都是无意义的。
一般几分钟过后,模块可以确认位置后,此时状态灯闪烁,打开串口,用文本模式接收,可以得到一长串数据,例子:
如果使用专业软件这时候一般都可以有图了。(注意软件不要多开)
时间需要+8小时
会飘完全正常,搜索100x100可能有点困难,但是搜个10x10还是比较容易的。
既然确定了模块OK,那么开始分析数据:
都已$起头,其中要用到的如下:
GPVTG:地面速度
GPGSA:卫星信息
GPGGA:定位信息
GPGSV:可见卫星信息
GPRMC:推荐的最小定位信息(!)
解包就可以了。
然而,有一个点需要注意
虽然这里都是以GP开头,但其实我们收到的很多,这分别对应:
北斗,GPS,GLONASS(北斗以BD开头)
我个人是倾向于用GNRMC(双星或多星联合定位)
GPRMC 最小定位信息:
数据详解:$GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>*hh
<1> UTC 时间,hhmmss(时分秒)格式
<2> 定位状态,A=有效定位,V=无效定位
<3>纬度XXXXXXXmm(度分)格式(前面的0也将被传输)
<4> 纬度半球N(北半球)或S(南半球)
<5>经度XXXXXXXXmm(度分)格式(前面的0也将被传输)
<6> 经度半球E(东经)或W(西经)
<7>地面速率(000.0~999.9节,前面的0也将被传输)
<8>地面航向(000.0~359.9度,以真北为参考基准,前面的0也将被传输)
<9> UTC 日期,ddmmyy(日月年)格式
<10>磁偏角(000.0~180.0度,前面的0也将被传输)
<11> 磁偏角方向,E(东)或W(西)
<12>模式指示(仅NMEA01833.00版本输出,A=自主定位,D=差分,E=估算,N=数据无效)
原文参考以下的连接-XXXXXXXXXXXXXXXXXXXXXXX/csMapx/archive/2011/11/02/XXXXXXXXXXml-,故不赘述。
注意速度单位是海里/h,也就是节。
——————————————————
2023/10/08关于加速度的问题,在网友指正后确认如下:
1:发射前冷启动
2:在点火倒计时结束前关闭模块
3:预定的开伞或者着陆
4:热启动模块并通过无线传送数据
相关参数可以参考这个:
——————————————————
main.c
#include "stm32f10x.h" // Device header #include "Delay.h" #include "OLED.h" #include "Serial.h" #include "string.h" int main(void) { OLED_Init(); Serial_Init(); OLED_ShowString(4, 1, "BDS/GPS"); char* REVFORM; char* GNRMCD; char* DRESS[14]; unsigned char count; OLED_ShowString(3, 1, "UNLOCATED"); while (1) { GNRMCD = strstr(Serial_RxPacket,"GNRMC");//GNRMC, if (Serial_RxFlag == 1) { if(GNRMCD!= NULL) { OLED_ShowString(3, 1," "); OLED_ShowString(3, 1, "LOCATED!"); OLED_ShowString(1, 1," "); //OLED_ShowString(1,1,GNRMCD); REVFORM = strtok(GNRMCD,","); count = 0; while(REVFORM!= NULL) { OLED_ShowString(2, 1," "); OLED_ShowString(2, 1, REVFORM); DRESS[count] = REVFORM; count++; /* CRFC = strtok(REVFORM,","); while(CRFC != NULL) { OLED_ShowString(3, 1," "); OLED_ShowString(3, 1, CRFC); CRFC = strtok(NULL,","); }*/ REVFORM = strtok(NULL,","); } //13:校验 //12:可靠性 //9:日期 //8:海拔 //7:海里/h //6:东西经 //5:东西经坐标 //4:半球 //3:南北半球坐标 //1:格林尼治时间 //0 OLED_ShowString(1,1,DRESS[5]); } // OLED_ShowString(4, 1," "); OLED_ShowString(4, 1, Serial_RxPacket); Serial_RxFlag = 0; } } }
__________________________________________________________________________________________________
Serial.c
#include "stm32f10x.h" // Device header #include <stdio.h> #include <stdarg.h> char Serial_RxPacket[100]; //"@MSG\r\n" uint8_t Serial_RxFlag; void Serial_Init(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate = 9600; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_Init(USART2, &USART_InitStructure); USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_Init(&NVIC_InitStructure); USART_Cmd(USART2, ENABLE); } void Serial_SendByte(uint8_t Byte) { USART_SendData(USART2, Byte); while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET); } void Serial_SendArray(uint8_t *Array, uint16_t Length) { uint16_t i; for (i = 0; i < Length; i ++) { Serial_SendByte(Array[i]); } } void Serial_SendString(char *String) { uint8_t i; for (i = 0; String[i] != '\0'; i ++) { Serial_SendByte(String[i]); } } uint32_t Serial_Pow(uint32_t X, uint32_t Y) { uint32_t Result = 1; while (Y --) { Result *= X; } return Result; } void Serial_SendNumber(uint32_t Number, uint8_t Length) { uint8_t i; for (i = 0; i < Length; i ++) { Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0'); } } int fputc(int ch, FILE *f) { Serial_SendByte(ch); return ch; } void Serial_Printf(char *format, ...) { char String[100]; va_list arg; va_start(arg, format); vsprintf(String, format, arg); va_end(arg); Serial_SendString(String); } void USART2_IRQHandler(void) { static uint8_t RxState = 0; static uint8_t pRxPacket = 0; if (USART_GetITStatus(USART2, USART_IT_RXNE) == SET) { uint8_t RxData = USART_ReceiveData(USART2); if (RxState == 0) { if (RxData == '$' && Serial_RxFlag == 0) { RxState = 1; pRxPacket = 0; } } else if (RxState == 1) { if (RxData == '\r') { RxState = 2; } else { Serial_RxPacket[pRxPacket] = RxData; pRxPacket ++; } } else if (RxState == 2) { if (RxData == '\n') { RxState = 0; Serial_RxPacket[pRxPacket] = '\0'; Serial_RxFlag = 1; } } USART_ClearITPendingBit(USART2, USART_IT_RXNE); } }
(串口框架由B站“江科大”编写)
我将其改为了UART2,因而如需要直接复制粘贴需要注意接线方式。
(因为UART1我用来烧录了)
[修改于 1年1个月前 - 2023/10/11 14:07:39]
楼主需要买接收前端芯片,自己做定位计算,这个工作有一定难度,以前要FPGA来算,现在技术发达了,可以试试好一点的带DSP核的MCU。现成GPS模块对垂直上升率有限制,火箭上基本会罢工,根本不用考虑。北斗未见论坛上有人试过。
楼主需要买接收前端芯片,自己做定位计算,这个工作有一定难度,以前要FPGA来算,现在技术发达了,可以...
感谢教导!我之前看到过似乎对加速度有锁,我做这个的原因是用于着陆之后搜寻的,以下是我的想法:箭载飞控不承担距离换算,发射之后开始计时,在开伞后或者着陆后热启动(发射前进行冷启动),只是挑选合格的GNRMC数据发送,避免在数千平米的地方找。
(稍后会同步并补充这部分到文章里)
感谢教导!我之前看到过似乎对加速度有锁,我做这个的原因是用于着陆之后搜寻的,以下是我的想法:箭载飞控...
只是为了回收的话,提前通电等定位成功再发射,然后定期单向广播坐标比较合适——箭在空中,信号覆盖不成问题,地面站可以用高增益天线。中间定位丢失影响不大。
如果降落时间足够长,那么进入降落程序再给模块通电也可以。
如果等到落地再启动,可能会掉进信号盲区/砸坏
只是为了回收的话,提前通电等定位成功再发射,然后定期单向广播坐标比较合适——箭在空中,信号覆盖不成问...
是的,这完全可以,不过我认为有难度。我目前意图制造的火箭最大高度不会超过200m,选用的无线电模块厂家介绍称1km完全没问题,不过到手之后会实测一下,之所以不考虑在着陆前进行信息发送的原因是:卫星定位模块在加速度达到4g时会自锁,目前我还不知道自锁的后果是什么,(参数详见我发的datasheet),以及另一个原因是由于高度小,在合适天气下也不会飘多远,在这种情况下大地曲率我认为可以通过给地面站天线加个杆子解决。
时段 | 个数 |
---|---|
{{f.startingTime}}点 - {{f.endTime}}点 | {{f.fileCount}} |
200字以内,仅用于支线交流,主线讨论请采用回复功能。