Pages: [1]   Go Down
Author Topic: Sending Multiple Values over Serial  (Read 1071 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello World!  Me and a friend are working on an arduino project where we're sending multiple values over serial (13 to be specific (14 if you count the carriage return)).  We're sending it with SerialPort and byte arrays through C# .Net 4.0 and then receiving it on an arduino mega which uses the messenger library.  We're having some problems receiving the data on the arduino side.  It receives the data, but it appears to be in the wrong order (i.e. values will be in different places each time).  I checked and it appears we're reading the same amount as we're receiving, so I don't see how it could get scrambled.

Thank you very much for the help.

Here's the code for arduino and C# respectively:

Code:
#include <Messenger.h>

Messenger message = Messenger();
//int pins[] = { 2,3,4,5,6,7,8,9,10,11 };

void setup() {
  Serial.begin(115200);
  message.attach(messageReady);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
 
  //for (int i = 0; i <11; i++)
    //pinMode(pins[i], OUTPUT);
}

void messageReady(){
  int xspeed = message.readInt();
  int xstrafe = message.readInt();
  int xhandvert = message.readInt();
  int xhandopen = message.readInt();
  byte xupdown = message.readChar();
  byte xsyringe = message.readChar();
  byte xdrill = message.readChar();
  byte xrotate = message.readChar();
  byte xdrillio = message.readChar();
  byte derp = message.readChar();
 
  Serial.println(xspeed);
 
 
  analogWrite(2, abs(xspeed));
}

void loop() {
  digitalWrite(3, HIGH);
  if (!Serial.available()) {
    return;
  }
  if (Serial.available()) {
    message.process(Serial.read());
  }
}

(Here's the C# program.  Sorry that it's so long.)
Code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;

namespace ROV
{
    public partial class Form1 : Form
    {
        Controller controller;
        SerialPort port = null;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            controller = new Controller();
            controller.InputChanged += new Controller.ControllerHandler(controller_InputChanged);
            port = new SerialPort("COM15", 115200);
            if (!port.IsOpen)
            {
                port.Open();
            }
        }

        void controller_InputChanged(ControllerEventArgs e)
        {
            byte[] data = new byte[14]; //the data to send over the port

            float speedMap = map(controller.LS.Y, -1, 1, -255, 255);
            //byte speedTEST = (byte)speedMap;
            byte[] portSpeed = BitConverter.GetBytes((short)speedMap);
            lspeed.Invoke((Action)delegate { lspeed.Text = ((short)speedMap).ToString(); });
            data[0] = portSpeed[0];
            data[1] = portSpeed[1];
            //0-1

            #region Old Code
            //come back to this later
            //differentiate motor speeds
            //if negative, value will be added (subtracted) from left motor and subtracted (added) to right motor = net left rotation
            //if positive, inverse ^________________________________________________________________________________________________^
            //c# side.  do later

            //rotation changed to pulsing rotation with select/start
            //float rotationMap = map(controller.LS.X, -1, 1, -255, 255);
            //byte[] portRotation = BitConverter.GetBytes((short)rotationMap);
            //lrotation.Invoke((Action)delegate { lrotation.Text = ((short)rotationMap).ToString(); });
            #endregion

            float strafeMap = map(controller.LS.X, -1, 1, -255, 255);
            byte[] portStrafe = BitConverter.GetBytes((short)strafeMap);
            lstrafe.Invoke((Action)delegate { lstrafe.Text = ((short)strafeMap).ToString(); });
            data[2] = portStrafe[0];
            data[3] = portStrafe[1];
            //2-3

            float handVerticalMap = map(controller.RS.Y, -1, 1, -255, 255);
            handVerticalMap = -handVerticalMap; //this is to invert the value like flight simulation
            byte[] portHandVertical = BitConverter.GetBytes((short)handVerticalMap);
            larmVert.Invoke((Action)delegate { larmVert.Text = ((short)handVerticalMap).ToString(); });
            data[4] = portHandVertical[0];
            data[5] = portHandVertical[1];
            //4-5

            #region Old Code
            //phased out rs x usage on 3/19
            //float handExtensionMap = map(controller.RS.X, -1, 1, -255, 255);
            //byte[] portHandExtension = BitConverter.GetBytes((short)handExtensionMap);
            //larmExt.Invoke((Action)delegate { larmExt.Text = ((short)handExtensionMap).ToString(); });
            #endregion

            float handOpenCloseMap = controller.RT - controller.LT; //lt = open, rt = close
            handOpenCloseMap = map(handOpenCloseMap, -1, 1, -255, 255);
            byte[] portHandOpenClose = BitConverter.GetBytes((short)handOpenCloseMap);
            lhand.Invoke((Action)delegate { lhand.Text = ((short)handOpenCloseMap).ToString(); });
            data[6] = portHandOpenClose[0];
            data[7] = portHandOpenClose[1];
            //6-7

            byte portUpDown = controller.LB == Microsoft.Xna.Framework.Input.ButtonState.Pressed ? (byte)1 : (byte)0;
            portUpDown = controller.RB == Microsoft.Xna.Framework.Input.ButtonState.Pressed ? (byte)2 : portUpDown;
            lvertical.Invoke((Action)delegate { lvertical.Text = portUpDown == (byte)0 ? "Vertically Still." : (portUpDown == (byte)1 ? "Going up!" : "Going down!"); });
            data[8] = portUpDown;
            //8

            byte portSyringe = controller.B == Microsoft.Xna.Framework.Input.ButtonState.Pressed ? (byte)2 : (byte)0;
            portSyringe = controller.A == Microsoft.Xna.Framework.Input.ButtonState.Pressed ? (byte)1 : portSyringe;
            lsyringe.Invoke((Action)delegate { lsyringe.Text = portSyringe == (byte)0 ? "Syringe Inactive." : (portSyringe == (byte)1 ? "Filling!" : "Emptying!"); });
            data[9] = portSyringe;
            //9

            byte portDrill = controller.X == Microsoft.Xna.Framework.Input.ButtonState.Pressed ? (byte)1 : (byte)0;
            ldrill.Invoke((Action)delegate { ldrill.Text = portDrill == (byte)0 ? "Drill inactive." : "Drill active"; });
            data[10] = portDrill;
            //10

            byte portRotate = controller.Select == Microsoft.Xna.Framework.Input.ButtonState.Pressed ? (byte)1 : (byte)0;
            portRotate = controller.Start == Microsoft.Xna.Framework.Input.ButtonState.Pressed ? (byte)2 : portRotate;
            lrotation.Invoke((Action)delegate { lrotation.Text = portRotate == (byte)0 ? "Not rotating." : (portRotate == (byte)1 ? "Rotating left." : "Rotating right."); });
            data[11] = portRotate;
            //11
            //those are the mappable buttons so we need to map them to something for them to work.
            //I suggest mapping lb2 to select and rb2 to start

            byte portDrillIO = controller.Up == Microsoft.Xna.Framework.Input.ButtonState.Pressed ? (byte)1 : (byte)0;
            portDrillIO = controller.Down == Microsoft.Xna.Framework.Input.ButtonState.Pressed ? (byte)2 : portDrillIO;
            lDrillIO.Invoke((Action)delegate { lDrillIO.Text = portDrillIO == (byte)0 ? "Not moving." : (portDrillIO == (byte)1 ? "Extending." : "Retracting."); });
            data[12] = portDrillIO;
            //12

            data[13] = ASCIIEncoding.ASCII.GetBytes("\r")[0];

            //port.Write(new byte[] { speedTEST }, 0, 1);
            port.Write(data, 0, 14);
            port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
            //ldata.Invoke((Action)delegate { ldata.Text = BitConverter.ToString(data); });
            //char[] buffer = new char[13];
            //if (port.BytesToRead > 0)
            //{
            //    ldata.Invoke((Action)delegate
            //    {
            //        port.Read(buffer, 0, 13);
            //        ldata.Text = new string(buffer); //this is to stop epic, hardcore, vomit-inducing lag
            //    });
            //}
        }

        void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            ldata.Invoke((Action)delegate
            {
                ldata.Text = port.ReadExisting();
            });
        }

        float map(float x, float in_min, float in_max, float out_min, float out_max)
        {
            return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            //because of the polling thread, app doesn't close when exit button is hit.
            //this fixes that
            controller.ExitPollingThread();
            Application.Exit();
        }
    }
}
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48556
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
  if (!Serial.available()) {
    return;
  }
Useless code. Get rid of it.

The Messenger library expects ASCII data. You are not sending ASCII data from the C# program to the Arduino. Why do you think that you can then use the Messenger library?
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok, thanks for the advice. What would be a better way of receiving the data?
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48556
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
What would be a better way of receiving the data?
Use Serial.read() to collect the bytes. Re-assemble as ints as required.
Logged

Pages: [1]   Go Up
Jump to: