Go Down

Topic: PC C# Arduino servo control problem. (Read 842 times) previous topic - next topic

steve_ancell

Hi I'm Steve, I'm new here.

I have created a Winforms (c# 2015) application for experimenting with servo control by communicating via the USB port. The two source codes I have listed below sort of communicate but quite a lot of the time it causes other servos to glitch eratically when I move the slider for any particular channel. Please can anyone tell me where I've messed up!  :smiley-confuse:


Here's the C# Windows code:

Code: [Select]

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;

namespace Control_Application
{
    public partial class Form1 : Form
    {
        SerialPort serialPort;

        public Form1()
        {
            InitializeComponent();
            init();

        }

        private void init()
        {
            int centrePosition = 90;
            trackBarServo_0.Value = centrePosition;
            trackBarServo_1.Value = centrePosition;
            trackBarServo_2.Value = centrePosition;
            trackBarServo_3.Value = centrePosition;

            serialPort = new SerialPort();
            serialPort.PortName = "COM7";
            serialPort.BaudRate = 9600;
            serialPort.DataReceived += new SerialDataReceivedEventHandler(serialPort_DataReceived);
            try
            {
                serialPort.Open();

            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);

            }

        }

        private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            Console.WriteLine(serialPort.ReadLine());

        }

        private void trackBarServo_0_Scroll(object sender, EventArgs e)
        {
            if (serialPort.IsOpen)
            {
                string channel = "0";
                string val = trackBarServo_0.Value.ToString();
                serialPort.WriteLine(channel);
                serialPort.WriteLine(val);
                labelServoPos_0.Text = "Position: " + val;

            }

        }

        private void trackBarServo_1_Scroll(object sender, EventArgs e)
        {
            if (serialPort.IsOpen)
            {
                string channel = "1";
                string val = trackBarServo_1.Value.ToString();
                serialPort.WriteLine(channel);
                serialPort.WriteLine(val);
                labelServoPos_1.Text = "Position: " + val;
               
            }

        }

        private void trackBarServo_2_Scroll(object sender, EventArgs e)
        {
            if (serialPort.IsOpen)
            {
                string channel = "2";
                string val = trackBarServo_2.Value.ToString();
                serialPort.WriteLine(channel);
                serialPort.WriteLine(val);
                labelServoPos_2.Text = "Position: " + val;

            }

        }

        private void trackBarServo_3_Scroll(object sender, EventArgs e)
        {
            if (serialPort.IsOpen)
            {
                string channel = "3";
                string val = trackBarServo_3.Value.ToString();
                serialPort.WriteLine(channel);
                serialPort.WriteLine(val);
                labelServoPos_3.Text = "Position: " + val;

            }

        }

    }

}




And here's the Arduino code:

Code: [Select]

#include <Servo.h>

int servoCount = 4;
int servoPins[] = {2, 3, 4, 5};
Servo servos[4];

void setup() {
  Serial.begin(9600);
  AttachServos();
 
}

void loop() {
 
}

void serialEvent() {
  int channel = Serial.parseInt();
  int val = Serial.parseInt();
 
  if(val != 0) {
    servos[channel].write(val);
   
  }
 
}

void AttachServos() {
  for(int i = 0; i < servoCount; i++) {
    servos[i].attach(servoPins[i]);
   
  }
 
}


PaulS

Think about what you are writing to the Serial port in the C# application. HowistheArduinosupposedtoknowwhereapacketstartsandend?
The art of getting good answers lies in asking good questions.

steve_ancell

Thanks PaulS, I'll look that up later ;)

steve_ancell

I have trawled Google, some examples seem to be using Serial.readString(), which is what I used initially but didn't go to well. I've tried the Serial.parseInt() approach on my previous attemp, this is OK for one servo but seems to be pants when trying to distinguish which channel the incoming data is for.

I've now gone for a single line Serial.readString() approach and coded better functions for cutting up that string. The Arduino code works great when I type values into the serial monitor but is again pants when I send the same kind of data from my Winforms application.

I am most certainly not a noob at coding, but this serial data stuff has stumped me. This is a lot different to game coding.

Here's my revised code that I've done so far, first one is the Winforms stuff and the second is the Arduino. I would have posted the actual Winforms designer form but I have no way of hosting it.


Code: [Select]

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;

namespace Control_Application
{
    public partial class Form1 : Form
    {
        SerialPort serialPort;

        public Form1()
        {
            InitializeComponent();
            init();

        }

        private void init()
        {
            int centrePosition = 90;
            trackBarServo_0.Value = centrePosition;
            trackBarServo_1.Value = centrePosition;
            trackBarServo_2.Value = centrePosition;
            trackBarServo_3.Value = centrePosition;

            serialPort = new SerialPort();
            serialPort.PortName = "COM7";
            serialPort.BaudRate = 9600;
            
            try
            {
                serialPort.Open();

            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);

            }

        }
        
        private void trackBarServo_0_Scroll(object sender, EventArgs e)
        {
            int servoPos = trackBarServo_0.Value;

            if (serialPort.IsOpen)
            {
                labelServoPos_0.Text = servoPos.ToString();
                SendServoInfo(0, servoPos);

            }

        }

        private void trackBarServo_1_Scroll(object sender, EventArgs e)
        {
            int servoPos = trackBarServo_1.Value;

            if (serialPort.IsOpen)
            {
                labelServoPos_1.Text = servoPos.ToString();
                SendServoInfo(1, servoPos);

            }

        }

        private void trackBarServo_2_Scroll(object sender, EventArgs e)
        {
            int servoPos = trackBarServo_2.Value;

            if (serialPort.IsOpen)
            {
                labelServoPos_2.Text = servoPos.ToString();
                SendServoInfo(2, servoPos);

            }

        }

        private void trackBarServo_3_Scroll(object sender, EventArgs e)
        {
            int servoPos = trackBarServo_3.Value;

            if (serialPort.IsOpen)
            {
                labelServoPos_3.Text = servoPos.ToString();
                SendServoInfo(3, servoPos);

            }

        }

        private void SendServoInfo(int channel, int pos)
        {
            string outString = channel.ToString() + ':' + pos.ToString();

            try
            {
                serialPort.WriteLine(outString);

            }
            catch
            {

            }

        }
        
    }

}




Code: [Select]

#include <Servo.h>

int servoCount = 4;
int servoPins[] = {5, 4, 3, 2};
Servo servos[4];

void setup() {
  Serial.begin(9600);
  AttachServos();
 
  String s = "2:1500";
  int channel = GetChannel(s);
  int pos = GetPosition(s);
 
}

void loop() {
 
}

void serialEvent() {
  String inString = Serial.readString();
  int channel = GetChannel(inString);
  int pos = GetPosition(inString);
 
  if(channel > -1) {
    servos[channel].write(pos);
   
  }
 
}

void AttachServos() {
  for(int i = 0; i < servoCount; i++) {
    servos[i].attach(servoPins[i]);
   
  }
 
}

int InString(String str, char findChar) {
  int pos = -1;
 
  for(int i = 0; i < str.length(); i++) {
    char c = str[i];
   
    if(c == findChar) {
      pos = i;
      break;
     
    }
   
  }

  return pos;
 
}

int GetChannel(String str) {
  int channel = -1;
  int marker = InString(str, ':');
  String s = "";
 
  for(int i = 0; i < marker; i++) {
    char c = str[i];
    s += c;
   
  }

  if(marker > -1) {
    channel = s.toInt();
   
  }

  return channel;
 
}

int GetPosition(String str) {
  int pos = -1;
  int marker = InString(str, ':');
  String s = "";
 
  for(int i = marker + 1; i < str.length(); i++) {
    char c = str[i];
    s += c;
   
  }

  if(marker > -1) {
    pos = s.toInt();
   
  }

  return pos;
 
}


PaulS

Code: [Select]
  String inString = Serial.readString();
There is a readStringUntil() method that lets you read only until a specific character is received.

You could that to read the data until the : arrived, and convert that String to an int, as the channel.
You could then read the data until the \n arrived, and convert that String to an int, as the position.
You could then read one more character, when it arrives (the \r) and throw it away.

Or, use Write() instead of WriteLine(), but add another delimiter after the position value, and readStringUntil() until the second delimiter arrives.

There is NO reason to write your own function to replace the indexOf() method in the String class. There is no reason to write your own function to replace subString().
The art of getting good answers lies in asking good questions.

TomGeorge

Hi,

How have you got your servos powered?

The Arduino cannot power the servos, as they can draw quit a high peak current when asked to move.
If you are using the Arduino 5V then you will be cause power supply problem to the controller logic.

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Thanks.. Tom... :)
Everything runs on smoke, let the smoke out, it stops running....

steve_ancell

@PaulS:
Yeah, I did find the indexOf function earlier this afternoon. Where I haven't used C++ for quite a while I'm quite a bit rusty, I felt a right dong after I realised. I will be trying the Write and indexOf commands this time around.

@TomGeorge:
I am powering the Arduino via PC/USB but the servos are powered by one of those 5 Volt 2.1A mains to USB power supply, the one that Maplin sells.

steve_ancell

@TomGeorge:
This is how I connected it. I know my drawing is a bit crude, I'm not much of an artist. ;)



steve_ancell

#8
Apr 14, 2017, 07:32 pm Last Edit: Apr 14, 2017, 07:38 pm by steve_ancell
@PaulS:

I have got this thing going and it works great now. Thanks for pointing me in the right direction, you're an absolute star mate! ;)


Here's my revised code and also a link to the entire VC# Winforms project.

Link to project: https://drive.google.com/open?id=0BxShBC9w_oHPLVhIRldIemVPWVk

Arduino code:

Code: [Select]

#include <Servo.h>

int servoCount = 4;
int servoPins[] = {5, 4, 3, 2};
Servo servos[4];

void setup() {
  Serial.begin(9600);
  AttachServos();

}

void loop() {
  
}

void serialEvent() {
  int channel;
  int pos;
  
  channel = Serial.readStringUntil(':').toInt();
  pos = Serial.readStringUntil('*').toInt();
  servos[channel].write(pos);
  
}

void AttachServos() {
  for(int i = 0; i < servoCount; i++) {
    servos[i].attach(servoPins[i]);
    
  }
  
}




Visual c# code:

Code: [Select]

using System;
using System.Windows.Forms;
using System.IO.Ports;

namespace Control_Application
{
    public partial class Form1 : Form
    {
        SerialPort serialPort;

        public Form1()
        {
            InitializeComponent();
            init();

        }

        private void init()
        {
            serialPort = new SerialPort();
            serialPort.PortName = "COM7";
            serialPort.BaudRate = 9600;
            
            try
            {
                serialPort.Open();

            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);

            }

            ResetServos();

        }
        
        private void trackBarServo_0_Scroll(object sender, EventArgs e)
        {
            int servoPos = trackBarServo_0.Value;

            if (serialPort.IsOpen)
            {
                labelServoPos_0.Text = "Position: " + servoPos.ToString();
                SendServoInfo(0, servoPos);

            }

        }

        private void trackBarServo_1_Scroll(object sender, EventArgs e)
        {
            int servoPos = trackBarServo_1.Value;

            if (serialPort.IsOpen)
            {
                labelServoPos_1.Text = "Position: " + servoPos.ToString();
                SendServoInfo(1, servoPos);

            }

        }

        private void trackBarServo_2_Scroll(object sender, EventArgs e)
        {
            int servoPos = trackBarServo_2.Value;

            if (serialPort.IsOpen)
            {
                labelServoPos_2.Text = "Position: " + servoPos.ToString();
                SendServoInfo(2, servoPos);

            }

        }

        private void trackBarServo_3_Scroll(object sender, EventArgs e)
        {
            int servoPos = trackBarServo_3.Value;

            if (serialPort.IsOpen)
            {
                labelServoPos_3.Text = "Position: " + servoPos.ToString();
                SendServoInfo(3, servoPos);

            }

        }

        private void SendServoInfo(int channel, int pos)
        {
            string message = channel.ToString() + ':' + pos.ToString() + '*';

            try
            {
                serialPort.Write(message);

            }
            catch
            {

            }

        }

        private void ResetServos()
        {
            int centrePosition = 90;
            trackBarServo_0.Value = centrePosition;
            trackBarServo_1.Value = centrePosition;
            trackBarServo_2.Value = centrePosition;
            trackBarServo_3.Value = centrePosition;

            labelServoPos_0.Text = "Position: " + centrePosition.ToString();
            labelServoPos_1.Text = "Position: " + centrePosition.ToString();
            labelServoPos_2.Text = "Position: " + centrePosition.ToString();
            labelServoPos_3.Text = "Position: " + centrePosition.ToString();

            for (int channel = 0; channel < 4; channel++)
            {
                SendServoInfo(channel, centrePosition);

            }

        }

        private void buttonResetServos_Click(object sender, EventArgs e)
        {
            ResetServos();

        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            ResetServos();

        }

    }

}


steve_ancell


Go Up