mypro334 发表于 2021-12-16 15:20

使用Unity调用派样机技术小结

距离这个开发这个项目已经过去差不多两年时间了,今天我闲来无事清理电脑里项目的时候无意看到了这个项目。已经都过去将近两年时间了,时光荏苒啊!两年前的自己也是一个冲动的年轻人,拼了命的做项目,现在想想自己,年轻人还是真年轻呀。算了,废话不多说,今天在这里总结一下调用派样机的开发流程。
一、需求梳理

当时公司让实现一个什么样的功能呐?就是在派样机(类似于饮料自动购物机那种机器)上的电脑上,开发一款Unity程序,这款程序上有一个二维码,用户用微信扫一扫扫这个二维码,这时用户的手机上就会出现一个互动的小程序,用户互动完成后,服务器判断用户互动完成,给派样机的Unity程序发一个网络指令。Unity程序收到该指令后,使用串口通信给派样机发一个指令,派样机硬件收到该指令后,即调用硬件推出一个小礼物,送给用户。



图1、使用的派样机

这个项目不是什么很复杂的项目,这里面有两个难点。1.获取服务器传过来的信号,进行判断。2.判断完毕服务器的信号后,调用派样机,调用硬件进行派样。只要开发完成这两个功能后,这个项目就算是完成了。
二、开发步骤

1.首先在Unity中创建UI,将二维码贴在Unity的程序里的UI上,UI如下图所示。



图2.程序UI展示

2.开发获取服务器指令功能,并且进行判断,如果获取到正确的信息,即对派样机发送派样指令,代码如下。
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using Newtonsoft.Json;
using UnityEngine.UI;

public class HttpNet : MonoBehaviour
{
    Action callback;
    /// <summary>
    /// 派样机字符类
    /// </summary>
    public ComManager comManager;

    // Start is called before the first frame update
    void Start()
    {
      callback += Dispchater;
      StartCoroutine(GetData(callback));
    }

    private void Dispchater()
    {
      //Debug.Log("掉小样!");
      comManager.DemoMechineSendCom();
    }
    //加载路径图片
    IEnumerator GetData(Action action)//Action action
    {

      while (true)
      {
            yield return new WaitForSeconds(2.0f);
            UnityWebRequest unityWebRequest = UnityWebRequest.Get("https://www.brandxspace.com/development/sendPrototype/getPrototypeState?flag=0");
            //UnityWebRequest unityWebRequest = UnityWebRequest.Get(jsonUrl);
            yield return unityWebRequest.SendWebRequest();
            if (!unityWebRequest.isNetworkError)
            {
                string data = unityWebRequest.downloadHandler.text;
                Data d = JsonConvert.DeserializeObject<Data>(data);
                if (d != null)
                {
                  Debug.Log(data + "------");
                  if (d.status == "1")
                  {
                     
                        //掉小样
                        if (action != null)
                        {
                            action();
                        }
                  }
                }
            }
      }
    }   
}
public class Data
{
    public string status;
    public String message;
    public object data;
}
3.开发调用派样机派样功能,该功能主要使用的是串口通信开发,如果对串口通信开发很熟悉的话这个也是十分简单的功能,主要是通过代码设置派样的顺序和速率,代码如下:
(1)CRC.CS
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

public class CRC
{

    #regionCRC16
    public static byte[] CRC16(byte[] data)
    {
      int len = data.Length;
      if (len > 0)
      {
            ushort crc = 0xFFFF;

            for (int i = 0; i < len; i++)
            {
                crc = (ushort)(crc ^ (data));
                for (int j = 0; j < 8; j++)
                {
                  crc = (crc & 1) != 0 ? (ushort)((crc >> 1) ^ 0xA001) : (ushort)(crc >> 1);
                }
            }
            byte hi = (byte)((crc & 0xFF00) >> 8);//高位置
            byte lo = (byte)(crc & 0x00FF);         //低位置

            return new byte[] { hi, lo };
      }
      return new byte[] { 0, 0 };
    }
    #endregion

    #regionToCRC16
    public static string ToCRC16(string content)
    {
      return ToCRC16(content, Encoding.UTF8);
    }

    public static string ToCRC16(string content, bool isReverse)
    {
      return ToCRC16(content, Encoding.UTF8, isReverse);
    }

    public static string ToCRC16(string content, Encoding encoding)
    {
      return ByteToString(CRC16(encoding.GetBytes(content)), true);
    }

    public static string ToCRC16(string content, Encoding encoding, bool isReverse)
    {
      return ByteToString(CRC16(encoding.GetBytes(content)), isReverse);
    }

    public static string ToCRC16(byte[] data)
    {
      return ByteToString(CRC16(data), true);
    }

    public static string ToCRC16(byte[] data, bool isReverse)
    {
      return ByteToString(CRC16(data), isReverse);
    }
    #endregion

    #regionToModbusCRC16
    public static string ToModbusCRC16(string s)
    {
      return ToModbusCRC16(s, true);
    }

    public static string ToModbusCRC16(string s, bool isReverse)
    {
      return ByteToString(CRC16(StringToHexByte(s)), isReverse);
    }

    public static string ToModbusCRC16(byte[] data)
    {
      return ToModbusCRC16(data, true);
    }

    public static string ToModbusCRC16(byte[] data, bool isReverse)
    {
      return ByteToString(CRC16(data), isReverse);
    }
    #endregion

    #regionByteToString
    public static string ByteToString(byte[] arr, bool isReverse)
    {
      try
      {
            byte hi = arr, lo = arr;
            return Convert.ToString(isReverse ? hi + lo * 0x100 : hi * 0x100 + lo, 16).ToUpper().PadLeft(4, '0');
      }
      catch (Exception ex) { throw (ex); }
    }

    public static string ByteToString(byte[] arr)
    {
      try
      {
            return ByteToString(arr, true);
      }
      catch (Exception ex) { throw (ex); }
    }
    #endregion

    #regionStringToHexString
    public static string StringToHexString(string str)
    {
      StringBuilder s = new StringBuilder();
      foreach (short c in str.ToCharArray())
      {
            s.Append(c.ToString("X4"));
      }
      return s.ToString();
    }
    #endregion

    #regionStringToHexByte
    private static string ConvertChinese(string str)
    {
      StringBuilder s = new StringBuilder();
      foreach (short c in str.ToCharArray())
      {
            if (c <= 0 || c >= 127)
            {
                s.Append(c.ToString("X4"));
            }
            else
            {
                s.Append((char)c);
            }
      }
      return s.ToString();
    }

    private static string FilterChinese(string str)
    {
      StringBuilder s = new StringBuilder();
      foreach (short c in str.ToCharArray())
      {
            if (c > 0 && c < 127)
            {
                s.Append((char)c);
            }
      }
      return s.ToString();
    }

    /// <summary>
    /// 字符串转16进制字符数组
    /// </summary>
    /// <param name="hex"></param>
    /// <returns></returns>
    public static byte[] StringToHexByte(string str)
    {
      return StringToHexByte(str, false);
    }

    /// <summary>
    /// 字符串转16进制字符数组
    /// </summary>
    /// <param name="str"></param>
    /// <param name="isFilterChinese">是否过滤掉中文字符</param>
    /// <returns></returns>
    public static byte[] StringToHexByte(string str, bool isFilterChinese)
    {
      string hex = isFilterChinese ? FilterChinese(str) : ConvertChinese(str);

      //清除所有空格
      hex = hex.Replace(" ", "");
      //若字符个数为奇数,补一个0
      hex += hex.Length % 2 != 0 ? "0" : "";

      byte[] result = new byte;
      for (int i = 0, c = result.Length; i < c; i++)
      {
            result = Convert.ToByte(hex.Substring(i * 2, 2), 16);
      }
      return result;
    }
    #endregion

}
(2)ComManager.cs
using UnityEngine;
using System.Collections;
using System;
using System.Threading;
using System.Collections.Generic;
using System.IO.Ports;

public class ComManager : MonoBehaviour
{
    //public ComManager instance;
    //端口号
    string com2 = "";
    private SerialPort sp2;
    //波特率
    private int baudRate;

    public float timer = 0.1f;
    //private bool isShinning = false;
    //配置文件管理类
    public ConfigTest configTest;

    //private void Awake()
    //{
      //instance = this;
    //}
   
    void Start()
    {
      //string com2 = "COM7";
      com2 = configTest.dic["端口号"]["portName"];
      baudRate = int.Parse(configTest.dic["波特率"]["baudRate"]);
      //row = 8;
      row = int.Parse(configTest.dic["参数"]["row"]);
      //column = 4;
      column = int.Parse(configTest.dic["参数"]["column"]);
      //depth = 5;
      depth = int.Parse(configTest.dic["参数"]["depth"]);
      mainCount = int.Parse(configTest.dic["参数"]["mainCount"]);
      StartCoroutine(StartCom());
      
    }

    IEnumerator StartCom()
    {
      yield return new WaitForSeconds(0.1f);
      sp2 = new SerialPort(com2, baudRate, Parity.None, 8, StopBits.One);
      if (!sp2.IsOpen)
      {
            sp2.Open();
      }
    }

    /// <summary>
    /// 派样机串口
    /// </summary>
    /// <param name="data"></param>
    private void SendDemoMechineData(byte[] data)
    {
      if (sp2.IsOpen)
      {
            sp2.Write(data, 0, data.Length);
      }
    }

    void OnDisable()
    {
      if (sp2.IsOpen)
      {
            sp2.Close();
      }
    }

    private int row;//8
    private int column;//5
    private int depth;//10
    private int mainCount = 40;//总数
    private static int index = 0;
    public void DemoMechineSendCom()
    {
      int tempRow = index % row; //第几个
      int tempColumn = (index / row) % row; //第几行
      int tempdepth = index / (row * column) % depth;

      Debug.Log(index + " row: " + tempRow + "col: " + tempColumn + "depth " + tempdepth);
      string pos = tempColumn.ToString("0") + tempRow.ToString("0");
      string corPos = System.Convert.ToString(int.Parse(pos),16).PadLeft(2,'0');
      string data = "0105"
            + corPos
            + "030000000000000000000000000000";
      byte[] byteData = CRC.StringToHexByte(data);
      byte[] crcByteData = CRC.CRC16(byteData);
      //Debug.Log(CRC.ByteToString(crcByteData));
      data += CRC.ByteToString(crcByteData);
      //Debug.Log(data);
      byte[] byteDatas = CRC.StringToHexByte(data);

      SendDemoMechineData(byteDatas);
      index++;
      if (index >= mainCount)
      {
            index = 0;
      }
    }
}
三、小结

就这样,派样机的功能就基本开发完成了。虽然这个程序的功能十分简单,但是用处很大,创作不易,如果喜欢文章,请点个赞。
页: [1]
查看完整版本: 使用Unity调用派样机技术小结