前面說過,我們的架構是這樣
代表著MCU掌握了所有溝通技能,一步錯就會導致系統崩潰
PM腦說:哦哦哦! 那不就跟我的角色一樣嗎?
RD腦皺著眉回覆:這有難回答,我先去抽根菸
PM腦接著說:醒醒吧! 你根本不會抽菸,還想多出這一句拖稿! 你是不是不把我奔雷手文泰放在眼裡!?
RD腦指著PM腦說:你…
查了幾家做Lora的廠商,台灣有正文、群登和iFROG
LAB,國外有Pycom出的LoPy
而群登是Cortex M4 + Lora,這…我從來沒試過這麼清新脫俗的感覺,就猶如強大MCU的鮮、與Lora遠距離的甜,混在一起的味道竟然比AlphaGo橫空出世有過之而無不及
又這麼剛好有2組UART可以搭上WiFi和BLE
也難怪PM腦會說:爭什麼呀! 摻在一起做不只是智能燈座功能的智能燈座啊!笨蛋!
PM腦平常都在看市場,很注重客戶的使用狀態回覆,也難怪他程式學不好,我錯怪他了 RD腦心想著
我們使用Acsip的AI127x來做主系統,SDK可以看github上面的
https://github.com/AcSiP/AI127x_SDK
這裡就不寫貼整程式碼了,只寫概念,設計流程如下
1、UART1給WiFi使用,UART2給BLE使用
2、UART1和UART2要在最後一個byte為]才會進判斷式
3、進入判斷式後,用\做分割,所以進來的數據會長這樣
UART1 RXà\Smart phone以MQTT傳來的訊息判斷\]
UART1 TXà\上傳BLE的訊號到Cloud中\]
UART2 RXà\自身的UD\掃瞄到的BLE
ID\BLE ID的RSSI\RSSI轉為距離\]
UART2 TXà\GO\] - 這是告訴BLE可以開始掃瞄
4、在main()內寫UART1及UART2的流程
所以先著手UART設計
void USART2_IRQHandler(void) {
if(USART_GetITStatus(USART2,
USART_IT_RXNE) != RESET) {
/*
Read one byte from the receive data register */
uartReceBuffer[uartReceIndex]
= USART_ReceiveData(USART2);
/*
Clear the USART2 Receive interrupt */
USART_ClearITPendingBit(USART2,
USART_IT_RXNE);
uartReceIndex++;
if(uartReceIndex >= 50 ) //讓buffer只有50個
uartReceIndex =0;
uartReceCount++; //count+1
}
}
再新增一個readRxBuffer
void readRxBuffer(void)
{
if(uartReceCount == 0)
return;
uartReceCount--; //???ring????byte
myData[myDataCount] =
uartReceBuffer[uartReadIndex];
uartReadIndex++;
if(uartReadIndex >= 50)
uartReadIndex = 0;
if(myData[myDataCount] == 0x5D) //只要最後一個為]就進判斷式
{
myData[myDataCount]
= NULL; //把]設為空值
myDataCount
= 0;
uartReceComplete = 1;
j=0;
return;
}
if(myData[myDataCount]== 0x5c) //只要是反斜線就分割
{
split[j] = main_count;
j++;
return;
}
myDataCount++;
main_count++;
}
Uart架構完成後,回到main()內做設定
while(1)
{
readRxBuffer_uart1();
//讀wifi的輸入
if(uartReceComplete_uart1 == 1)
{
uartReceComplete_uart1 = 0;
if(myData_uart1[0] == 'G' &&
myData_uart1[1] == 'O') //如果傳來的是GO,就叫BLE開始Scan
{
WiFi_RX_Flag = 1;
wifi_coming_flag=1;
main_count_uart1=0;
USART2_UartWrite((uint8_t
*)"AT+GO", strlen("AT+GO")); //送AT+GO給BLE
USB_OTG_BSP_mDelay (3000);
}
if(wifi_coming_flag==1)//讀WIFI的回傳,也就是ESP8266的subscribe
{
//還沒開始寫 但預計這裡是手機控制燈座的狀態
//例如開關燈、保全功能的設徹防以及配件如人體感應器或門磁的狀態
//MQTT的架構應該是這樣 à
UID/Bulb/Status 與 UID/Accessory/Status
}
}
readRxBuffer();
//讀BLE的輸入
if(uartReceComplete == 1)
{
uartReceComplete = 0;
if(CentralID_flag==1)//取得BLE的唯一碼當燈座的唯一碼
{
CentralID_flag=0;
USART1_UartWrite((uint8_t *)"\\",
strlen("\\"));
for(i=split[0];i<=split[1]-1;i++)
{
CentralID[i] = myData[i];
sprintf(str1,
"%c", CentralID[i]);
USART1_UartWrite((char *)str1, strlen((char
*)str1));
}
USART1_UartWrite((uint8_t *)"\\",
strlen("\\"));
main_count=0;
}
else{
if(
WiFi_RX_Flag == 1)//把BLE掃瞄到的資料全往上傳
{
USART1_UartWrite((uint8_t
*)"\\", strlen("\\"));
for(i=split[0];i<=split[1]-1;i++)
{
sprintf(str1, "%c", myData[i]);
USART1_UartWrite((char
*)str1, strlen((char *)str1));
}
USART1_UartWrite((uint8_t
*)"\\", strlen("\\"));
for(i=split[1];i<=split[2]-1;i++)
{
sprintf(str1, "%c", myData[i]);
USART1_UartWrite((char
*)str1, strlen((char *)str1));
}
USART1_UartWrite((uint8_t
*)"\\", strlen("\\"));
for(i=split[2];i<=split[3]-1;i++)
{
sprintf(str1, "%c", myData[i]);
USART1_UartWrite((char
*)str1, strlen((char *)str1));
}
//由於RSSI用UART收進來是ASCII,要轉為數字
char
string1[5];
int
l=0;
for(i=split[2];i<=split[3]-1;i++)
{
string1[l]
= myData[i];// 把收到的放到string1內
l++;
}
float
bb = atoi ( string1 ); // 將string1轉為數字
float
cc = calculateAccuracy( -54.0, bb ); //計算有多少米距離
USART1_UartWrite((uint8_t
*)"\\", strlen("\\"));
sprintf(str1,
"%.5f", cc); //取到小數點第五位
USART1_UartWrite((float
*)str1, strlen((float *)str1));
USART1_UartWrite((uint8_t
*)"\r\n", strlen("\r\n"));
USB_OTG_BSP_mDelay
(50);
main_count_uart1=0;
main_count=0;
}
}
}
}
再加下計算距離的公式
float calculateAccuracy(
float txPower, float rssi )
{
if (rssi == 0) {
return -2.0; // if we cannot determine accuracy, return -1.
}
float ratio = rssi * 1.0 / txPower;
if (ratio < 1.0) {
return pow(ratio, 10);
} else {
float accuracy = (0.42093) * pow(ratio, 6.9476) + 0.54992;
return accuracy;
}
}
如此就完成MCU的寫法了
簡單說明一下,calculateAccuracy裡頭有個txPower
這裡我們在mian()是寫-54,Beacon為了計算距離,會有個txPower
指的是一公尺的RSSI值,而Beacon會帶這個值
但我們用的是小米及Fitbit這種常見的產品,它不是Beacon
經測試後,通常會在-54至-64之間,而在這個EVT Stage,我們選擇的是-54
但將來做成產品會讓使用者去校正
既然得到了手環與燈座的距離,就由Android去顯示三角定位的圖示
所以雛形大約長這樣,藍點代表定位的那一位,燈泡圖形就代表智能燈座
PM腦說:零分!!!
RD腦回:為什麼??? 我的禾花雀平面圖,設定可說是百中挑一的三角定位演算法,無論速度、解析度,都是一等一的
PM腦說:我指得不是演算法,我指的是禾花雀平面圖設計的太醜了!!!
RD腦回:設計醜?喂! 醜不醜關專案什麼事啊?
PM腦說:有事!挑男女朋友都挑長的帥或漂亮順眼的,使用者在下載APP也選美觀大方的,誰還有胃口來選你這個醜不拉嘰的APP呢?所以我看了一眼就把早餐吐出來了!
RD腦只好先把Android交代完畢,之後再想要怎麼修改這平面圖的設計
RD腦說:ㄜ…其實我看了幾篇文章才寫出來的Code,但時間有點久,貼這2篇文章也許能代表我想說什麼
在Android的寫法如下:
import java.math.BigDecimal;
import java.text.DecimalFormat;
import android.app.Activity;
import android.graphics.Point;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class IndoorLocation extends
Activity{
private SurfaceView sfv;
private SurfaceHolder sfh;
private Point greenXY = new Point(0, -13);
private Point blueXY = new Point(-8, 13);
private Point purpleXY = new Point(8, 13);
public static Point[] beacons;
private int beaconsNum =3 ;
static double locationX = 0;
static double locationY = 0;
private void init(){
beacons = new Point[beaconsNum];
beacons[0] = greenXY;
beacons[1] = blueXY;
beacons[2] = purpleXY;
}
@Override
protected void onCreate(Bundle
savedInstanceState) {
init();
super.onCreate(savedInstanceState);
setContentView(R.layout.indoorsurfaceview);
sfv = (SurfaceView)
findViewById(R.id.surfaceView1);
sfh = sfv.getHolder();
sfh.addCallback(new
MySfvCallback(IndoorLocation.this));
double xypoint[] = getMeetingPoints(4.0, 4.0,
9.0, 7.0, 9.0, 1.0, 0.0025, 1.42, 6.96);
locationX = xypoint[0];
locationY = -xypoint[1];//因為不知道為什麼y的相限剛好是相反的
}
double norm (double x,double y) // get the
norm of a vector
{
return (float)
Math.pow(Math.pow(x,2)+Math.pow(y,2),0.5);
}
private double[] getMeetingPoints(double x1,
double y1, double x2, double y2, double x3, double y3, double r1, double r2,
double r3)
{
double p2p1Distance =
(Math.pow(Math.pow(x2-x1,2) + Math.pow(y2-y1,2),0.5));
double ex[] = {(x2-x1)/p2p1Distance,
(y2-y1)/p2p1Distance};
double aux[] = {x3-x1,y3-y1}; //correct
//signed magnitude of the x component
double i = ex[0] * aux[0] + ex[1] * aux[1];
//correct
double aux2[] = { x3-x1-i*ex[0],
y3-y1-i*ex[1]};//跑了一點
DecimalFormat df = new
DecimalFormat("##.000");//四捨五入小數點第三位
double d1 =
Double.parseDouble(df.format(aux2[0]));
double d2 =
Double.parseDouble(df.format(aux2[1]));
double
ey[] = { d1 / norm (d1,d2), d2 / norm (d1,d2) };
DecimalFormat df1 = new
DecimalFormat("##.000");//四捨五入小數點第三位
double d11 =
Double.parseDouble(df1.format(ey[0]));
double d21 =
Double.parseDouble(df1.format(ey[1]));
double j = d11 * d1 + d21 * d2;
DecimalFormat jj = new DecimalFormat("##.000");//四捨五入小數點第三位
double jj1 =
Double.parseDouble(jj.format(j));
//coordinates
//double x = ((Math.pow(r1,2) -
Math.pow(r2,2) + Math.pow(p2p1Distance,2))/ (2 * p2p1Distance));
//double y = ((Math.pow(r1,2) -
Math.pow(r3,2) + Math.pow(i,2) + Math.pow(j,2))/(2*j) - i*x/j);
double x = ((Math.pow(r1,2) - Math.pow(r2,2)
+ Math.pow(p2p1Distance,2))/ (2 * p2p1Distance));
DecimalFormat xx = new
DecimalFormat("##.000");//四捨五入小數點第三位
double xx1 = Double.parseDouble(xx.format(x));
double y = ((Math.pow(r1,2) - Math.pow(r3,2)
+ Math.pow(i,2) + Math.pow(jj1,2))/((2*jj1) - (i*x/jj1)));
DecimalFormat yy = new
DecimalFormat("##.000");//四捨五入小數點第三位
double yy1 =
Double.parseDouble(yy.format(y));
//result coordinates
double finalXY[] = {x1+ x*ex[0] + y*d11, y1+
x*ex[1] + y*d21};
DecimalFormat xy = new
DecimalFormat("##.000");//四捨五入小數點第三位
double xy1 =
Double.parseDouble(xy.format(finalXY[0]));
double xy2 = Double.parseDouble(xy.format(finalXY[1]));
double finalXY_return[]={xy1,xy2};
return finalXY_return;
}
}
而layout的部份如下
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.csform.android.uiapptemplate"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:gravity="center"
>
<SurfaceView
android:id="@+id/surfaceView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
/>
</RelativeLayout>
本體:有沒有高手可以跳出來解釋一下2D及3D室內定位的方法?
忘了之前是在哪裡看到的方法,接下來DVT Stage還要修正,才能讓室內定位更精確
沒有留言:
張貼留言