Sending String or Multiple Characters from Unity to Arduino

Hello!

In my project, I am trying to communicate from Unity to Arduino to move servo motors to specific angles and adjust the dimness of LEDs. I've found a code to send single characters that work for this purpose, but I have several servos and LEDs and multiple angles and dimness values, and there are only so many characters I can use, so I want to send strings instead.

I looked up many tutorials and found this one that explains how to send multiple characters, so I tried this but couldn't get it working. When I am using Unity and Arduino at the same time the serial monitor does not open, so I can't really check if it actually prints the characters I am sending, so I tried to use the characters directly to move the servo, which didn't work.

(I also send data from Arduino to Unity, but I deleted some of the unrelated parts to avoid confusion. I used some other tutorials for that and I wasn't sure if the OpenConnection function in the Unity code is actually useful or not so I kept it in anyway :D)

Here is the code I am using in Arduino:

#include <Servo.h>
// Example 2 - Receive with an end-marker

Servo myservo;
int val = 0;

const byte numChars = 32;
char receivedChars[numChars];   // an array to store the received data

boolean newData = false;

void setup() {
  
    Serial.begin(9600);
    myservo.attach(10);
    
}

void loop() {
    recvWithEndMarker();
    myservo.write(val); 
    delay(15); 
}

void recvWithEndMarker() {
    static byte ndx = 0;
    char endMarker = '>';
    char rc;
   
    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();

        if (rc != endMarker) {
            receivedChars[ndx] = rc;
            ndx++;
            if (ndx >= numChars) {
                ndx = numChars - 1;
            }
        }
        else {
            receivedChars[ndx] = '\0'; // terminate the string
            ndx = 0;
            newData = true;
        }
    }

    if (receivedChars == 's110'){
      val = 10;
    }
    if (receivedChars == 's120'){
      val = 20;
    }
    if (receivedChars == 's130'){
      val = 30;
    }
    if (receivedChars == 's140'){
      val = 40;
    }
    if (receivedChars == 's150'){
      val = 50;
    }
    if (receivedChars == 's160'){
      val = 60;
    }
    
}

And here is the code for Unity:

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

public class Sending : MonoBehaviour {
    
    public static SerialPort sp = new SerialPort("COM6", 9600);

    int val = 0;

    void Start () {

	OpenConnection();

    }
	
	
    void Update ()  {

        if (sp.IsOpen)
        {
            try
            {
                ReadArduino(sp.ReadByte());
                print(sp.ReadByte());
            }
            catch (System.Exception)
            {

            }
        }

       
        if (Input.GetKeyDown(KeyCode.Alpha1))
        {
            sp.Write("s110>");
        }
        if (Input.GetKeyDown(KeyCode.Alpha2))
        {
            sp.Write("s120>");
        }
        if (Input.GetKeyDown(KeyCode.Alpha3))
        {
            sp.Write("s130>");
        }
        if (Input.GetKeyDown(KeyCode.Alpha4))
        {
            sp.Write("s140>");
        }
        if (Input.GetKeyDown(KeyCode.Alpha5))
        {
            sp.Write("s150>");
        }
        if (Input.GetKeyDown(KeyCode.Alpha6))
        {
            sp.Write("s160>");
        }
        
    }


    public void OpenConnection() 
    {
       if (sp != null) 
       {
         if (sp.IsOpen) 
         {
          sp.Close();
          print("Closing port, because it was already open!");
         }
         else 
         {
          sp.Open();  // opens the connection
          sp.ReadTimeout = 16;  // sets the timeout value before reporting error
          print("Port Opened!");
         }
       }
       else 
       {
         if (sp.IsOpen)
         {
          print("Port is already open");
         }
         else 
         {
          print("Port == null");
         }
       }
    }

}

P.S. I will eventually change how the data is sent instead of using the keycode.

I am pretty sure the main problem is these lines in Arduino:

if (receivedChars == 's110'){
      val = 10;
    }

Any help or advice would be appreciated :slight_smile:

You can't compare strings like this:

  if (receivedChars == 's110') {
    val = 10;
  }

You have to use the strcmp function.

libc string functions.

And, multi-character strings must be enclosed in double, not single, quotes.

dougp:
You have to use the strcmp function.

So it will be like this right?

if(strcmp(receivedChars,"s110")==0){
      val = 10;
}

I tried this but it didn't work either :frowning:

How much control over what is sent from "Unity" (not sure what that is) do you have. It is easiest to send data in a format that is easy to capture and parse.

If Unity is appending any newline and/or carriage return to your string, those comparisons will never work. You should use the receiveWithStartandEndMarker() example with your start being 's' and your end being '>'. That way, you code won't care about extra newlines, etc.

You should also move the parsing out of the receive function and only do it when newData == true. This applies to the servo writes as well. There is no need to continually write the same value to the servo.

blh64:
If Unity is appending any newline and/or carriage return to your string, those comparisons will never work. You should use the receiveWithStartandEndMarker() example with your start being 's' and your end being '>'. That way, you code won't care about extra newlines, etc.

You should also move the parsing out of the receive function and only do it when newData == true. This applies to the servo writes as well. There is no need to continually write the same value to the servo.

Did I do it right? Still does not work

#include <Servo.h>

Servo myservo;
int val = 0;

const byte numChars = 32;
char receivedChars[numChars];   
boolean newData = false;

void setup() {
  
    Serial.begin(9600);
    myservo.attach(10);
    
}

void loop() {
  
    recvWithStartEndMarkers();
    moveServo();
}

void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = 's';
    char endMarker = '>';
    char rc;
 
    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();

        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = '\0'; 
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

        else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
}

void moveServo () {
  if (newData) {
    
    if(strcmp(receivedChars,"s110")==0){
          val = 10;
    }
    if(strcmp(receivedChars,"s120")==0){
          val = 20;
    }
    if(strcmp(receivedChars,"s130")==0){
          val = 30;
    }
    if(strcmp(receivedChars,"s140")==0){
          val = 40;
    }
    if(strcmp(receivedChars,"s150")==0){
          val = 50;
    }
    if(strcmp(receivedChars,"s160")==0){
          val = 60;
    }
    myservo.write(val); 
    delay(15); 
  }
}

zoomkat:
How much control over what is sent from "Unity" (not sure what that is) do you have. It is easiest to send data in a format that is easy to capture and parse.

What would be the easiest format? Sending a character works well enough but I need a ton of characters

irem_s:
Still does not work

recvWithStartEndMarkers will discard the start marker. Remove the 's' from the compares and it should work.