找回密码
 立即注册
查看: 426|回复: 0

[笔记] 使用Unity调用派样机技术小结

[复制链接]
发表于 2021-12-16 15:20 | 显示全部楼层 |阅读模式
距离这个开发这个项目已经过去差不多两年时间了,今天我闲来无事清理电脑里项目的时候无意看到了这个项目。已经都过去将近两年时间了,时光荏苒啊!两年前的自己也是一个冲动的年轻人,拼了命的做项目,现在想想自己,年轻人还是真年轻呀。算了,废话不多说,今天在这里总结一下调用派样机的开发流程。
一、需求梳理

当时公司让实现一个什么样的功能呐?就是在派样机(类似于饮料自动购物机那种机器)上的电脑上,开发一款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
{

    #region  CRC16
    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

    #region  ToCRC16
    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

    #region  ToModbusCRC16
    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

    #region  ByteToString
    public static string ByteToString(byte[] arr, bool isReverse)
    {
        try
        {
            byte hi = arr[0], lo = arr[1];
            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

    #region  StringToHexString
    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

    #region  StringToHexByte
    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[hex.Length / 2];
        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;
        }
    }
}
三、小结

就这样,派样机的功能就基本开发完成了。虽然这个程序的功能十分简单,但是用处很大,创作不易,如果喜欢文章,请点个赞。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-5-10 22:25 , Processed in 0.124150 second(s), 27 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表