前面說過,我們的架構是這樣
代表著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還要修正,才能讓室內定位更精確


 
 
 
 
 
沒有留言:
張貼留言