Arduino和电机由Unity控制

时间:2016-05-31 08:49:55

标签: c# unity3d arduino serial-port

using UnityEngine;
using System.Collections;
using System.IO.Ports;
using System.Threading;

public class Sending : MonoBehaviour {

    //public static SerialPort sp = new SerialPort("COM4", 9600, Parity.None, 8, StopBits.One);
    public static SerialPort sp = new SerialPort("COM3", 9600);

    void Start () {
        OpenConnection();
    }



    public void OpenConnection() 
    {
        if (sp != null) 
        {
            if (sp.IsOpen) 
            {
                sp.Close();
            }
            else 
            {
                sp.Open();  
            }
        }
    }

    void OnApplicationQuit() 
    {       
        sp.Close();
    }

    public static void Contact(int pos)
    {
        string PosStr = pos.ToString ();
        Debug.Log(PosStr);
        sp.Write(PosStr);
    }
}

/////////////////////////////////////////////// ///////////

using UnityEngine;
using System.Collections;

public class GetPosition : MonoBehaviour
{
    Vector3 dragStartPosition;
    float dragStartDistance;
    float[] Xfloat;

    void OnMouseDown ()
    {
        dragStartPosition = transform.position;
        dragStartDistance = (Camera.main.transform.position - transform.position).magnitude;
    }

    void Update ()
    {
    }

    int OnMouseDrag ()
    {
        Vector3 worldDragTo = Camera.main.ScreenToWorldPoint (new Vector3 (Input.mousePosition.x, Input.mousePosition.y, dragStartDistance));
        transform.position = new Vector3 (worldDragTo.x, dragStartPosition.y, dragStartPosition.z);
        new Vector3 (worldDragTo.x, dragStartPosition.y, dragStartPosition.z);
        int Newpos = (int)worldDragTo.x;
        return (Newpos);
    }

    void OnMouseUp ()
    {
        int NewPos = OnMouseDrag ();
        Sending.Contact (NewPos);
    }

}

/////////////////////////////////////////////// //////////////////

int motorPin1 = 8;
int motorPin2 = 9;
int motorPin3 = 10;
int motorPin4 = 11;
int delayTime = 2;
int i = 0;
char myCol[5];


void setup() {
  Serial.begin (9600);
  pinMode(motorPin1, OUTPUT);
  pinMode(motorPin2, OUTPUT);
  pinMode(motorPin3, OUTPUT);
  pinMode(motorPin4, OUTPUT);
}


void loop()
{
  int lf = 5;
  Serial.readBytesUntil(lf, myCol, 5);
  Serial.setTimeout(0);


  int Angle = atoi(myCol);
  int Tick = ((Angle * 51.2) / 36.0);

  Serial.println(Tick);

  if ( i < Tick)
  {
    Play();
    i++;
  }
  if (i > Tick)
  {
    Reverse();
    i--;
  }
}



void Play()
{
  digitalWrite(motorPin1, HIGH);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin4, HIGH);
  delay(delayTime);
  digitalWrite(motorPin1, LOW);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin3, HIGH);
  digitalWrite(motorPin4, HIGH);
  delay(delayTime);
  digitalWrite(motorPin1, LOW);
  digitalWrite(motorPin2, HIGH);
  digitalWrite(motorPin3, HIGH);
  digitalWrite(motorPin4, LOW);
  delay(delayTime);
  digitalWrite(motorPin1, HIGH);
  digitalWrite(motorPin2, HIGH);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin4, LOW);
  delay(delayTime);
}

void Reverse()
{
  digitalWrite(motorPin1, HIGH);
  digitalWrite(motorPin2, HIGH);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin4, LOW);
  delay(delayTime);
  digitalWrite(motorPin1, LOW);
  digitalWrite(motorPin2, HIGH);
  digitalWrite(motorPin3, HIGH);
  digitalWrite(motorPin4, LOW);
  delay(delayTime);
  digitalWrite(motorPin1, LOW);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin3, HIGH);
  digitalWrite(motorPin4, HIGH);
  delay(delayTime);
  digitalWrite(motorPin1, HIGH);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin4, HIGH);
  delay(delayTime);
}

嗨,我的单位控制马达有问题,我有一个包含立方体的Unity场景,我可以在x轴上滑动这个立方体,我通过COM3发送x值,我在我的Arduino中得到了值将它转换为我的电机的角度。

我的问题是: 当我在Unity中移动立方体时,我的电机旋转但是在我滑动立方体几次之后,团结冻结了15/20秒然后我的电机移动但不是直角。

谁能告诉我问题出在哪里?

1 个答案:

答案 0 :(得分:2)

在您的代码中发现了许多错误,我不知道哪个错误导致了问题。修复了所有这些问题。请阅读下面的内容,看看我修复了什么。

1.团结冻结是因为你没有使用Thread

2.Arduino很可能因为Serial.println(Tick);而冻结。它发送到Unity,但你没有从Unity端读取。也许有缓冲区溢出。评论出来了。

3. OnMouseDrag是一个Unity回调函数。自己从OnMouseUp函数调用它不是一个好主意。

4.单击立方体的一侧将使其跳转到鼠标的位置。通过添加偏移值来修复它。

5.使用拖动回调函数替换OnMouseDownOnMouseDragOnMouseUp

6.改变了Arduino端数据的读取方式。已移除Serial.readBytesUntil(lf, myCol, 5);代码。

7.在致电delay(1);之前添加Serial.available()。不要删除它。一些Arduino板需要或者Serial.available()不能按预期运行。

8.删除代码中的所有静态内容。

9.您的字符串未终止。您必须在阅读myCol[index]= '\0';myCol[index]= 0;

后将其终止

我不明白你的角度转换是如何在Arduino方面完成的,所以我保持原样。将每个脚本替换为下面的新脚本,如果出现问题则发表评论。我没有你的电机所以无法测试电机部件。

<强> Arduino的

int motorPin1 = 8;
int motorPin2 = 9;
int motorPin3 = 10;
int motorPin4 = 11;
int delayTime = 2;
char myCol[10];

enum class READSTAT {NONE, READING, DONEREADING};

READSTAT readStat = READSTAT::NONE;

void setup() {
  Serial.begin (9600);
  pinMode(motorPin1, OUTPUT);
  pinMode(motorPin2, OUTPUT);
  pinMode(motorPin3, OUTPUT);
  pinMode(motorPin4, OUTPUT);
}


void loop()
{
  //Must delay 1 milliseconds to make Serial.available() work properly
  delay(1);

  //Serial.setTimeout(0);
  static int avalData = 0;
  if ( Serial.available() > 0) {
    readStat = READSTAT::READING;
    myCol[avalData] = Serial.read();
    avalData++;
  } else {
    //If we are in READING mode and there are no more available bytes, change mode to DONEREADING
    if (readStat == READSTAT::READING ) {
      readStat = READSTAT::DONEREADING;
      myCol[avalData] = '\0';
    }
  }

  //[CODE INSIDE HERE WILL RUN WHEN EVERY BYTE HAS BEEN RECEIVED FROM UNITY]
  //If we are in DONEREADING mode, change mode to NONE
  if (readStat == READSTAT::DONEREADING ) {

    checkMotor(avalData);

    //SET TO NONE then reset avalData
    readStat = READSTAT::NONE;
    avalData = 0;
  }

}

void checkMotor(int avalData ) {
  int Angle = atoi(myCol);
  int Tick = ((Angle * 51.2) / 36.0);


  if (0 <  Tick) {
    Tick = abs(Tick);
    for ( int i = 0; i < Tick; i++) {
      Play();
    }
  } else if (0 > Tick) {
    Tick = abs(Tick);
    for ( int i = 0; i < Tick; i++) {
      Reverse();
    }
  }
}

void Play()
{
  digitalWrite(motorPin1, HIGH);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin4, HIGH);
  delay(delayTime);
  digitalWrite(motorPin1, LOW);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin3, HIGH);
  digitalWrite(motorPin4, HIGH);
  delay(delayTime);
  digitalWrite(motorPin1, LOW);
  digitalWrite(motorPin2, HIGH);
  digitalWrite(motorPin3, HIGH);
  digitalWrite(motorPin4, LOW);
  delay(delayTime);
  digitalWrite(motorPin1, HIGH);
  digitalWrite(motorPin2, HIGH);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin4, LOW);
  delay(delayTime);
}

void Reverse()
{
  digitalWrite(motorPin1, HIGH);
  digitalWrite(motorPin2, HIGH);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin4, LOW);
  delay(delayTime);
  digitalWrite(motorPin1, LOW);
  digitalWrite(motorPin2, HIGH);
  digitalWrite(motorPin3, HIGH);
  digitalWrite(motorPin4, LOW);
  delay(delayTime);
  digitalWrite(motorPin1, LOW);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin3, HIGH);
  digitalWrite(motorPin4, HIGH);
  delay(delayTime);
  digitalWrite(motorPin1, HIGH);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin4, HIGH);
  delay(delayTime);
}

发送:

using UnityEngine;
using System.Collections;
using System.IO.Ports;
using System.Threading;

public class Sending : MonoBehaviour
{
    public SerialPort sp;
    Thread SerialThread;
    bool stopSerialCom = true;

    bool sendNow = false;
    int posTosend = 0;

    void Start()
    {
        startCommuncation();
    }

    public void startCommuncation()
    {
        SerialThread = new Thread(onConnected);
        SerialThread.IsBackground = true;
        SerialThread.Start();
    }

    private void onConnected()
    {
        //Open Connection
        openCon();
        sp.ReadTimeout = 2;

        //Run forever until stopSerialCom = true
        while (!stopSerialCom)
        {
            //Check if we should send
            if (sendNow)
            {

                Debug.Log("Sent: " + posTosend.ToString());
                //Send
                sendToSerial(posTosend);
                posTosend = 0; //Reset to 0
                sendNow = false;
            }
            Thread.Sleep(1);
        }
    }

    private void openCon(string comPort = "COM3", int port = 9600)
    {
        sp = new SerialPort(comPort, port);

        if (sp != null)
        {
            if (sp.IsOpen)
            {
                sp.Close();
                sp.Open();
                stopSerialCom = false;
                Debug.Log("Opened!");
            }
            else
            {
                sp.Open();
                stopSerialCom = false;
                Debug.Log("Opened!");
            }
        }
    }

    public void closeConnection()
    {
        stopSerialCom = true;

        //stop thread
        if (SerialThread != null && SerialThread.IsAlive)
        {
            Debug.Log("Thread Aborted!");
            SerialThread.Abort();
        }

        if (sp != null && sp.IsOpen)
        {
            sp.Close();
            Debug.Log("Closed!");
        }
    }

    void OnApplicationQuit()
    {
        closeConnection();
    }


    public void Send(int pos)
    {
        posTosend = pos;
        sendNow = true;
    }

    private void sendToSerial(int pos)
    {
        try
        {
            string PosStr = pos.ToString();
            sp.Write(PosStr);
        }
        catch (System.Exception e)
        {
            Debug.Log("Error: " + e.Message);
        }
    }
}

为getPosition:

using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;

public class GetPosition : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
    Vector3 dragStartPosition;
    float dragStartDistance;
    float[] Xfloat;

    Vector3 clickOffset = Vector3.zero;
    Sending sending;

    Camera mainCamera;
    Transform camTransform;

    void Start()
    {
        mainCamera = Camera.main;
        camTransform = mainCamera.transform;
        mainCamera.gameObject.AddComponent<PhysicsRaycaster>();

        sending = GetComponent<Sending>();
    }

    public void OnBeginDrag(PointerEventData eventData)
    {
        dragStartPosition = transform.position;
        dragStartDistance = (camTransform.position - transform.position).magnitude;

        //Get offset
        clickOffset = transform.position - mainCamera.ScreenToWorldPoint(new Vector3(eventData.position.x, eventData.position.y, dragStartDistance));
    }

    public void OnDrag(PointerEventData eventData)
    {
        Vector3 tempPos = mainCamera.ScreenToWorldPoint(new Vector3(eventData.position.x, eventData.position.y, dragStartDistance));

        //Apply Offset to prevent the Cube from Jumping when mouse is clicke on the side/edge
        tempPos = tempPos + clickOffset;

        tempPos.y = dragStartPosition.y;
        tempPos.z = dragStartPosition.z;

        transform.position = tempPos;

    }

    public void OnEndDrag(PointerEventData eventData)
    {
        sending.Send((int)transform.position.x);
    }
}

确保SendingGetPosition附加到相同的GameObject / Cube。仅使用一个立方体进行测试。