前文回顧
《智慧牧場之生物姿態(tài)檢測篇》
《智慧牧場之生物心率檢測篇》
1. 背景知識1.1牧場定位的意義
在智慧牧場解決方案中,實(shí)時(shí)檢測牲畜的活動(dòng)狀況是非常重要的環(huán)節(jié)。現(xiàn)在已經(jīng)不是放牛和牧羊犬的時(shí)代了。面臨大范圍牧場上牲畜走失,尋找困難,過度放牧導(dǎo)致草場退化等問題,通過穿戴式的生物跟蹤部件,可以有效解決以上的問題。
當(dāng)大量牲畜散布在地面上時(shí),牧場管理員往往發(fā)現(xiàn)很難跟蹤正在發(fā)生的事情。需要一個(gè)系統(tǒng)來確定牲畜在任何給定時(shí)間的位置和行駛的距離。此外,跟蹤系統(tǒng)也會(huì)防止任何類型的盜竊,因?yàn)槟翀龉芾韱T可以使用跟蹤報(bào)告來定位被盜牲畜。
1.2室外定位技術(shù)比較
目前的室外定位技術(shù),大體上分為如下幾種類別:
信號載體 | 典型定位方式 | 定位精度 | 不足 |
北斗/GPS衛(wèi)星民用領(lǐng)域 | 3個(gè)觀測方程式求解位置 | 10米級 | 遮擋影響較大 |
蜂窩移動(dòng)網(wǎng)絡(luò)GSM | 基于TC-OFODM信號進(jìn)行測距定位 | 100米級 | 對基站依賴程度較高 |
5G? | 超密集組網(wǎng)下的定位技術(shù)/面向5C的TDOA和AOA定位技術(shù)、面向5G網(wǎng)絡(luò)上行定位和下行定位 | 100米級 | 抗干擾有局限性 |
慣性導(dǎo)航 | 基于航位推算方法 | 米級 | 存在累計(jì)漂移誤差 |
地球磁場? | 基于信號場強(qiáng)定位或與其他技術(shù)組合應(yīng)用 | 米級 | 地球指紋特征差異小 |
基于GPS和GSM的定位在全世界被廣泛使用,可以用來確定其所連接生物的精確位置。這種器件成本低、可靠性高,并具有精確跟蹤功能。可以提供有效、實(shí)時(shí)的物體、生物的位置報(bào)告和時(shí)間信息。
2. 解決方案概要該方案采用基于全球移動(dòng)通信系統(tǒng)(GSM)技術(shù)和GPS技術(shù)的嵌入式系統(tǒng)。該系統(tǒng)安裝在生物穿戴設(shè)備中。接口GSM模塊連接到Hi3861。該系統(tǒng)提供以下功能:a)位置信息,b)使用短信進(jìn)行實(shí)時(shí)跟蹤。
3. 硬件設(shè)計(jì)
3.1SIM808模塊調(diào)制解調(diào)器模塊
可以選用GSM、GPRS、GPS三合一功能的SIM808模塊。支持GSM/GPRS Quad-Band網(wǎng)絡(luò),結(jié)合GPS技術(shù)進(jìn)行衛(wèi)星導(dǎo)航。它具有睡眠模式下的超低功耗,并集成了鋰離子電池充電電路,使其具有超長的待機(jī)時(shí)間,方便使用可充電鋰離子電池的項(xiàng)目。它具有高 GPS 接收靈敏度,具有 22 個(gè)跟蹤和 66 個(gè)采集接收器通道。模塊通過 UART(編者注:Universal Asynchronous Receiver/Transmitter 通用異步接收器/發(fā)送器的英文縮寫) 由 AT 指令控制,支持 3.3V 和 5V 邏輯電平。
GSM調(diào)制解調(diào)器的工作基于命令,命令始終以“AT開頭”(表示注意),以“<CR>字符結(jié)束”,例如撥號命令是ATD<number>;ATD7814629081;這里,撥號命令以分號(;)結(jié)束。在Hi3861的幫助下,該AT命令被提供給GSM調(diào)制解調(diào)器。GSM調(diào)制解調(diào)器在MAX 232 IC的幫助下與微控制器串行連接。GSM指定的頻率范圍為1850到1990 MHz(移動(dòng)臺到基站)。
3.2 Hi3861
Hi3861開發(fā)板模組大小約2cm*5cm,是一款高度集成的2.4GHz WLAN SoC。
Hi3861芯片集成高性能32bit微處理器、擁有豐富的外設(shè)接口,芯片內(nèi)置SRAM(編者注:Static Random-Access Memory 靜態(tài)隨機(jī)存取存儲(chǔ)器的英文縮寫)和Flash,并支持在Flash上運(yùn)行程序。
Hi3861模組有2MB FLASH,352KB RAM。但我們編寫代碼時(shí),要注意對有限資源的合理利用。
Hi3861可以說是麻雀雖小,五臟俱全。Hi3861的外設(shè)接口包括(外部主晶振為40M或者24M):
-
2個(gè)SPI(Synchronous Peripheral Interface)
-
3個(gè)UART(Universal Asynchronous Receiver & Transmitter)
-
2個(gè)I2C(The Inter-Integrated Circuit)
-
6路PWM(Pulse Width Modulation)
-
15個(gè)GPIO(General Purpose Input/Output)
-
1個(gè)I2S接口
-
1個(gè)高速SDIO2.0(Secure Digital Input/Output)接口,最高時(shí)鐘可達(dá)50MHz;
Hi3861主控功能框架圖如下:
在該系統(tǒng)中,它用于同步GSM和GPS的操作。GPS連續(xù)向微控制器發(fā)送位置數(shù)據(jù),即車輛位置的緯度和經(jīng)度,而GSM從微控制器發(fā)送和接收數(shù)據(jù)。GPS調(diào)制解調(diào)器連續(xù)提供許多參數(shù)作為輸出,但只有NMEA(編者注:National Marine Electronics Association國家海洋電子協(xié)會(huì)的英文縮寫)數(shù)據(jù)被讀取并“顯示在OLED上”。將相同的數(shù)據(jù)發(fā)送給移動(dòng)用戶,以便可以知道車輛的確切位置。用戶的移動(dòng)號碼存儲(chǔ)在EEPROM(編者注:Electrically Erasable Programmable read only memory 帶電可擦可編程只讀存儲(chǔ)器 的英文縮寫)中。
4. 軟件設(shè)計(jì)軟件編程是用C語言完成的。GPS從衛(wèi)星接收的數(shù)據(jù)(坐標(biāo))在軟件中定義。解碼NMEA(國家海洋電子協(xié)會(huì))協(xié)議是開發(fā)該軟件的主要目的。軟件程序中應(yīng)包含用戶的手機(jī)號碼,以便從我們在GSM調(diào)制解調(diào)器中使用的SIM卡接收位置值。NMEA協(xié)議由一組ASCII字符集的消息組成。GPS接收數(shù)據(jù)并以ASCII逗號分隔的消息字符串的形式顯示。$'在每條消息的開頭使用符號。位置(緯度和經(jīng)度)的格式為ddmm。mmmm(度數(shù)分鐘和十進(jìn)制分鐘)。軟件協(xié)議由GGA(編者注:Global Positioning System Fix Data 全球定位系統(tǒng)固定數(shù)據(jù))和GLL(編者注:Geographic Position 地理位置-緯度/經(jīng)度)組成。但在這個(gè)系統(tǒng)中,我們只使用GGA。系統(tǒng)流程圖如下所示:
具體代碼實(shí)現(xiàn):
/***** 獲取電壓值函數(shù) *****/
static float GetVoltage(void)
{
unsigned int ret;
unsigned short data;
ret = AdcRead(WIFI_IOT_ADC_CHANNEL_5, &data, WIFI_IOT_ADC_EQU_MODEL_8, WIFI_IOT_ADC_CUR_BAIS_DEFAULT, 0xff);
if (ret != WIFI_IOT_SUCCESS)
{
printf("ADC Read Fail
");
}
return (float)data * 1.8 * 4 / 4096.0;
}
/* input:AT+CGNSINF Command Response
* output:struct GGPS_DATA
*/
static void GPS_CGNSINF_Analyze(char *origin, GGPS_DATA *gpsdata)
{
int counter = 0;
char tmp[150] = {0};
char *lptr = NULL;
char *localptr = NULL;
lptr = (char *)strstr(origin, "+CGNSINF");
if (lptr == NULL)
{
return;
} else {
lptr += 10;
}
while (*lptr != '')
{
if (*lptr == ',' && *(lptr + 1) == ',')
{
tmp[counter] = *lptr;
counter++;
tmp[counter] = '0';
} else if (*lptr == '
' && *(lptr + 1) == '
' && counter < 148)
{
tmp[counter] = '0';
tmp[counter + 1] = ',';
tmp[counter + 2] = 0;
break;
} else {
tmp[counter] = *lptr;
}
lptr++;
counter++;
/* avoid array out of range */
if (counter >= GNSINF_MSG_MAX_LEN){
return;
}
}
/* Clear struct data */
memset(gpsdata, 0, sizeof( GGPS_DATA));
localptr = (char *)strtok(tmp, ",");
if (localptr == NULL)
{
return;
}
strncpy(gpsdata->GNSSrunstatus, localptr, sizeof(gpsdata->GNSSrunstatus));
localptr = (char *)strtok(NULL, ",");
if (localptr == NULL)
{
return;
}
strncpy(gpsdata->Fixstatus, localptr, sizeof(gpsdata->Fixstatus));
localptr = (char *)strtok(NULL, ",");
if (localptr == NULL)
{
return;
}
strncpy(gpsdata->UTCdatetime, localptr, sizeof(gpsdata->UTCdatetime));
localptr = (char *)strtok(NULL, ",");
if (localptr == NULL)
{
return;
}
strncpy(gpsdata->latitude, localptr, sizeof(gpsdata->latitude));
localptr = (char *)strtok(NULL, ",");
if (localptr == NULL)
{
return;
}
strncpy(gpsdata->logitude, localptr, sizeof(gpsdata->logitude));
localptr = (char *)strtok(NULL, ",");
if (localptr == NULL)
{
return;
}
strncpy(gpsdata->altitude, localptr, sizeof(gpsdata->altitude));
localptr = (char *)strtok(NULL, ",");
if (localptr == NULL)
{
return;
}
strncpy(gpsdata->speedOTG, localptr, sizeof(gpsdata->speedOTG));
localptr = (char *)strtok(NULL, ",");
if (localptr == NULL)
{
return;
}
strncpy(gpsdata->course, localptr, sizeof(gpsdata->course));
localptr = (char *)strtok(NULL, ",");
if (localptr == NULL)
{
return;
}
strncpy(gpsdata->fixmode, localptr, sizeof(gpsdata->fixmode));
localptr = (char *)strtok(NULL, ",");
if (localptr == NULL)
{
return;
}
strncpy(gpsdata->Reserved1, localptr, sizeof(gpsdata->Reserved1));
localptr = (char *)strtok(NULL, ",");
if (localptr == NULL)
{
return;
}
strncpy(gpsdata->HDOP, localptr, sizeof(gpsdata->HDOP));
localptr = (char *)strtok(NULL, ",");
if (localptr == NULL)
{
return;
}
strncpy(gpsdata->PDOP, localptr, sizeof(gpsdata->PDOP));
localptr = (char *)strtok(NULL, ",");
if (localptr == NULL)
{
return;
}
strncpy(gpsdata->VDOP, localptr, sizeof(gpsdata->VDOP));
localptr = (char *)strtok(NULL, ",");
if (localptr == NULL)
{
return;
}
strncpy(gpsdata->Reserved2, localptr, sizeof(gpsdata->Reserved2));
localptr = (char *)strtok(NULL, ",");
if (localptr == NULL)
{
return;
}
strncpy(gpsdata->satellitesinview, localptr, sizeof(gpsdata->satellitesinview));
localptr = (char *)strtok(NULL, ",");
if (localptr == NULL)
{
return;
}
strncpy(gpsdata->GNSSsatellitesused, localptr, sizeof(gpsdata->GNSSrunstatus));
localptr = (char *)strtok(NULL, ",");
if (localptr == NULL)
{
return;
}
strncpy(gpsdata->GLONASSsatellitesused, localptr, sizeof(gpsdata->GLONASSsatellitesused));
localptr = (char *)strtok(NULL, ",");
if (localptr == NULL)
{
return;
}
strncpy(gpsdata->Reserved3, localptr, sizeof(gpsdata->Reserved3));
localptr = (char *)strtok(NULL, ",");
if (localptr == NULL)
{
return;
}
strncpy(gpsdata->CN0max, localptr, sizeof(gpsdata->CN0max));
localptr = (char *)strtok(NULL, ",");
if (localptr == NULL)
{
return;
}
strncpy(gpsdata->HPA, localptr, sizeof(gpsdata->HPA));
localptr = (char *)strtok(NULL, "
");
if (localptr == NULL)
{
return;
}
strncpy(gpsdata->VPA, localptr, sizeof(gpsdata->VPA));
}
static void GsmCheckRingAndHanupMessage(void)
{
if (strstr(g_uart_buff, "RING") != NULL)
{
printf("ring.
");
if (GsmGetConnectSts() == false)
{
GsmSetRingSts(true);
}
}
if (strstr(g_uart_buff, "NO CARRIER") != NULL)
{
printf("hang up.
");
GsmSetHungUpSts(true);
if (GsmGetConnectSts() == true)
{
GsmSetConnectSts(false);
}
}
}
static uint32_t GsmSendCmd(char *cmd, int len)
{
if (cmd == NULL || len <= 0)
{
return HI_ERR_FAILURE;
}
uint32_t ret = HI_ERR_FAILURE;
static uint32_t count = 0;
uint8_t *uart_buff_ptr = g_uart_buff;
ret = hi_uart_write(DEMO_UART_NUM, (hi_u8 *)cmd, len);
if (ret == HI_ERR_FAILURE)
{
return HI_ERR_FAILURE;
}
printf(" SendData%d,cmd:%s.
", len, cmd);
while (g_uartController.isReadBusy)
{
count++;
if (count > UART_WAIT_COUNT_MAX)
{
break;
}
}
if (g_uartController.isReadBusy)
{
printf("GsmSendCmd hi_uart_read busy return");
return HI_ERR_FAILURE;
}
if (!g_uartController.isReadBusy){
usleep(100000); /* sleep 100ms */
}
g_uartController.isReadBusy = true;
g_ReceivedDatalen = hi_uart_read(DEMO_UART_NUM, uart_buff_ptr, UART_BUFF_SIZE);
if (g_ReceivedDatalen > 0)
{
printf(" rcvData len:%d,msg:%s.
", g_ReceivedDatalen, g_uart_buff);
if (strstr(g_uart_buff, "OK") != NULL)
{
GsmCheckRingAndHanupMessage();
memset(g_uart_buff, 0, sizeof(g_uart_buff));
g_ReceivedDatalen = 0;
g_uartController.isReadBusy = false;
return HI_ERR_SUCCESS;
}
else
{
printf(" received error cmd
");
GsmCheckRingAndHanupMessage();
memset(g_uart_buff, 0, sizeof(g_uart_buff));
g_ReceivedDatalen = 0;
g_uartController.isReadBusy = false;
return HI_ERR_FAILURE;
}
}
else
{
g_uartController.isReadBusy = false;
printf(" SendCmd no cmd return!
");
return HI_ERR_FAILURE;
}
return HI_ERR_SUCCESS;
}
uint32_t GpsGetLocation(GGPS_INFO *gpsInfo)
{
uint32_t ret = HI_ERR_FAILURE;
static uint32_t count = 0;
uint8_t *uart_buff_ptr = g_uart_buff;
ret = hi_uart_write(DEMO_UART_NUM, (hi_u8 *)"AT+CGNSINF
", strlen("AT+CGNSINF
"));
if (ret == HI_ERR_FAILURE)
{
return NULL;
}
while (g_uartController.isReadBusy)
{
count++;
if (count > UART_WAIT_COUNT_MAX)
{
break;
}
usleep(100000); /* sleep 100ms */
}
if (g_uartController.isReadBusy)
{
printf("GpsGetLocation hi_uart_read busy return");
return HI_ERR_FAILURE;
}else{
usleep(100000); /* sleep 100ms */
}
g_uartController.isReadBusy = true;
g_ReceivedDatalen = hi_uart_read(DEMO_UART_NUM, uart_buff_ptr, UART_BUFF_SIZE);
if (g_ReceivedDatalen > 0)
{
printf(" rcvData len:%d,msg:%s.
", g_ReceivedDatalen, g_uart_buff);
uint8_t *strLocation = (uint8_t *)strstr(g_uart_buff, "+CGNSINF: 1,1");
if (strLocation != NULL)
{
GGPS_DATA gpsData;
GPS_CGNSINF_Analyze((char *)g_uart_buff, &gpsData);
printf("latitude:%s.
", gpsData.latitude);
printf("logitude:%s.
", gpsData.logitude);
memcpy_s(gpsInfo->UTCdatetime, sizeof(gpsInfo->UTCdatetime), gpsData.UTCdatetime, sizeof(gpsData.UTCdatetime));
memcpy_s(gpsInfo->logitude, sizeof(gpsInfo->logitude), gpsData.logitude, sizeof(gpsData.logitude));
memcpy_s(gpsInfo->latitude, sizeof(gpsInfo->latitude), gpsData.latitude, sizeof(gpsData.latitude));
memcpy_s(gpsInfo->satellitesinview, sizeof(gpsInfo->satellitesinview), gpsData.satellitesinview, sizeof(gpsData.satellitesinview));
GsmCheckRingAndHanupMessage();
memset(g_uart_buff, 0, sizeof(g_uart_buff));
g_ReceivedDatalen = 0;
g_uartController.isReadBusy = false;
return HI_ERR_SUCCESS;
} else {
GsmCheckRingAndHanupMessage();
memset(g_uart_buff, 0, sizeof(g_uart_buff));
g_ReceivedDatalen = 0;
g_uartController.isReadBusy = false;
return HI_ERR_FAILURE;
}
} else {
printf(" SendCmd no cmd return!
");
g_uartController.isReadBusy = false;
return HI_ERR_FAILURE;
}
}
uint32_t GsmCallCellPhone(char *cellPhoneNumeber)
{
uint32_t ret = HI_ERR_FAILURE;
char sendCmd[32] = "";
uint8_t cPhoneNumLength = strlen(cellPhoneNumeber);
if (cPhoneNumLength < PHONE_NUMB_LEN)
{
return HI_ERR_FAILURE;
}
/* Send AT+CSQ. */
strncpy(sendCmd, "AT+CSQ
", strlen("AT+CSQ
"));
printf(" sendCmd=%s
", sendCmd);
ret = GsmSendCmd(sendCmd, strlen(sendCmd));
if (ret == HI_ERR_FAILURE)
{
return HI_ERR_FAILURE;
}
memset(sendCmd, 0, strlen(sendCmd));
/* Call cellPhone Number:ATD+cellPhoneNumber. */
snprintf(sendCmd, sizeof(sendCmd), "ATD%s;
", cellPhoneNumeber);
printf(" sendCmd=%s
", sendCmd);
ret = GsmSendCmd(sendCmd, strlen(sendCmd));
if (ret == HI_ERR_FAILURE)
{
return HI_ERR_FAILURE;
}
return HI_ERR_SUCCESS;
}
未完待續(xù)……
后期預(yù)告《智慧牧場之室內(nèi)管理系統(tǒng)篇》 寫在最后我們最近正帶著大家玩嗨OpenHarmony。如果你有好玩的東東,歡迎投稿,讓我們一起嗨起來!有點(diǎn)子,有想法,有Demo,立刻聯(lián)系我們:合作郵箱:zzliang@atomsource.org
原文標(biāo)題:玩嗨OpenHarmony:基于OpenHarmony的智慧牧場方案 3/4 生物運(yùn)動(dòng)軌跡跟蹤篇
文章出處:【微信公眾號:開源技術(shù)服務(wù)中心】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
-
開源技術(shù)
+關(guān)注
關(guān)注
0文章
389瀏覽量
7942 -
OpenHarmony
+關(guān)注
關(guān)注
25文章
3723瀏覽量
16343
原文標(biāo)題:玩嗨OpenHarmony:基于OpenHarmony的智慧牧場方案 3/4 生物運(yùn)動(dòng)軌跡跟蹤篇
文章出處:【微信號:開源技術(shù)服務(wù)中心,微信公眾號:共熵服務(wù)中心】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論