懒得自己研究的推荐去Git上找

先简单说下A2和A3的区别, 具体参数参照官网配置,解析都一样,主要说下波特率

A2: 115200

A3: 256000

串口板是可以调节的,代码层面也是要对应

串口一般都是COM3,具体看设备管理器

unity 读取 nfc unity 读取蓝牙强度_扫描模式

先看下官方提供的工具frame_grabber

unity 读取 nfc unity 读取蓝牙强度_unity 读取 nfc_02

unity 读取 nfc unity 读取蓝牙强度_数据_03

扫描模式分为5种:

Standard     4k     普通模式

Express       8k     高速模式

Boost          16k   增强模式(高速模式的变种1)

Sensitivity   16k    敏感模式(高速模式的变种2)

Stability      16k    稳定模式(高速模式的变种3)

通过观摩C++SDK只写出了 普通和高速模式, 剩下的3种模式(同一种解析)如果有人研究出来请私信我,十分感谢

下图是各个模式指令/起使应答报文头/ 数据报文

unity 读取 nfc unity 读取蓝牙强度_数据_04

红线标出的是于高速扫描指令不同之处,蓝线标出的是数据起使报文头

启动电机指令 "A5F002C40291"

关闭电机指令 "A5F002000057"

Unity的SerialPort和Winform的SerialPort是有出入的,unity种无法使用DataReceived事件,只能自己建立线程去搞,如下:

public void Connect(int baudrate, string portName)
        {
            m_SerialPort = new SerialPort(portName, baudrate, Parity.None, 8, StopBits.One);
            m_SerialPort.Open();
            m_SerialPort.DiscardInBuffer();
            m_SerialPort.DiscardOutBuffer();
            m_SerialPort.DtrEnable = false;
            m_SerialPort.ReadTimeout = -1;
            m_ThreadReceive = new Thread(ListenSerialPort_RPLidarAX)
            {
                IsBackground = true
            };
            //m_ThreadReceive.SetApartmentState(ApartmentState.STA);
            m_ThreadReceive.Start();
        }
m_SerialPort.DiscardInBuffer();//清除接收缓冲区的数据
 m_SerialPort.DiscardOutBuffer();//清除发送缓冲区的数据
 m_SerialPort.DtrEnable = false;// 默认就是false
 m_SerialPort.ReadTimeout = -1;//调成>=0,接受不到数据,写了-1就有了,别问为什么
public void Disconnect()
        {
            if (m_ThreadReceive != null)
            {
                //关闭线程
                m_ThreadReceive.Abort();
                m_ThreadReceive = null;
                Debug.Log("Close thread");
            }
            //关闭串口
            m_SerialPort.Close();
            //将串口从内存中释放掉,注意如果这里不释放则在同一次运行状态下打不开此关闭的串口
            m_SerialPort.Dispose();
            Debug.Log("Serial Disconnected");
        }

 发送串口消息

/// <summary>
        /// 给串口发消息
        /// </summary>
        /// <param name="byteArray"></param>
        /// <returns></returns>
        public void SendMessage(byte[] byteArray)
        {
            if (m_SerialPort != null && m_SerialPort.IsOpen == true)
            {
                m_SerialPort.Write(byteArray, 0, (int)byteArray.LongLength);
                SerialCom_SerialPortSendMessageReportEvent(byteArray);
            }
            else
            {
                Debug.Log("Message Send Failed!");
            }
        }

最关键的接受数据来了:

/// <summary>
        /// 监听串口,读取串口消息
        /// </summary>
        private void ListenSerialPort_RPLidarAX()
        {
                lock (RevBuffer)
                {
                    while (m_SerialPort != null && m_SerialPort.IsOpen)
                    {
                        Thread.Sleep(10);
                        byte[] buffer = new byte[length];
                        //Debug.Log(RevBuffer.Count);
                        while (NormalScanCommand()) ; 
                        if ((checklen = m_SerialPort.Read(buffer, 0, buffer.Length)) <= length)
                            RevBuffer.AddRange(buffer.Take(checklen));
                    }
                }

                //lock (RevBuffer)
                //{
                //    while (m_SerialPort != null && m_SerialPort.IsOpen)
                //    {
                //        Thread.Sleep(10);
                //        buffer = new byte[length];
                //        while (ExpressScanCommand()) ;
                //        if ((checklen = m_SerialPort.Read(buffer, 0, buffer.Length)) <= length)
                //            RevBuffer.AddRange(buffer.Take(checklen));
                //    }
                //}
            }
           
        }

NormalScanCommand方法是 接受数据,判断头,解析报文

先比对报文头是否是"A55A0500004081",是的话开始写数据进入缓冲区,检查是否写入了1000个字节,都满足,开始解析数据

参考官方手册 : 通讯接口协议与应用手册

private bool NormalScanCommand()
        {
            lock (RevBuffer)
            {
                checklen = 0;
                var len = RevBuffer.Count;
                if (len < length)
                    return false;
                var command = new byte[length + errornumber - 1];
                Array.Copy(RevBuffer.ToArray(), command, length + errornumber - 1);
                if (checkalready || length == 7)
                    RevBuffer.RemoveRange(0, length + errornumber - 1);
                if (length == 1000 && checkalready == false)
                {
                    if (startscan)
                    {
                        if (RevBuffer.Count >= 1 + errornumber)
                        {
                            checkalready = true;
                        }
                    }
                    errornumber++;
                }
                //Debug.Log(MyMath.ByteToHexString(command));
                if (checkalready)
                {
                    RPLidarA3_DataResponseContentProcess_SCAN(command);
                    errornumber = 1;
                }
                if (MyMath.ByteToHexString(command) == "A55A0500004081" && startscan != true)
                {
                    startscan = true;
                    length = 1000;
                }
                return true;    //通知调用程序,收到了一个任务
            }
        }

        private void RPLidarA3_DataResponseContentProcess_SCAN(byte[] responseData)
        {
           
            for (int i = 0; i < responseData.Length; i += 5)
            {
                bool isNewScan = (responseData[i] & 1) != 0;
                bool isNewScan2 = (responseData[i] & 2) != 0;

                // 起始字节的判断和数据校验
                if (isNewScan == isNewScan2)
                {
                    return;
                }

                // 校验位,永远为1
                if ((responseData[i + 1] & 1) != 1)
                {
                   return;
                }

                // 获取角度/距离/云点质量
                float angle = ((responseData[i + 2] << 7) | (responseData[i + 1] >> 1)) / 64.0f;
                float distance = ((responseData[i + 4] << 8) | responseData[i + 3]) / 4.0f;
                int quality = responseData[i] >> 2;

                // 添加一个点
                ...
            }
            // 此处通知绘制层绘制点
            ....
        }

高速扫描也是同样的,检查报文头是不是"A55A5400004082", 长度为84,并重新解析就行了, 点比较散就不放出来了

增强模式也是同样的,检查报文头是不是"A55A8400004084", 长度为132,并重新解析,没搞出来,希望有大佬指点x1

敏感模式也是同样的,检查报文头是不是"A55A8400004084", 长度为132,并重新解析,没搞出来,希望有大佬指点x2

稳定模式也是同样的,检查报文头是不是"A55A8400004084", 长度为132,并重新解析,没搞出来,希望有大佬指点x3

最后放上一张运行效果图,用GL方式画的:

unity 读取 nfc unity 读取蓝牙强度_串口_05