Contorl servo from winfrom C# application with Arduino Uno

Hello

It is first time I've checked my Arduino Uno servo control from my starter kit. I need to use Arduino control from winfroms C# desktop application.

I'm not sure what is wrong here. It is same COM6 port, RX led indicates communication, when I'm moving scroll bar, but servo does not moves:

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

namespace Arduino
{
    public partial class Form1 : Form
    {
        private SerialPort myport;
        public Form1()
        {
            InitializeComponent();
            Init();
        }

        private void Init()
        {
            try
            {
                myport = new SerialPort();
                myport.BaudRate = 9600;
                myport.PortName = "COM6";
                myport.Open();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void trackBar1_Scroll(object sender, EventArgs e)
        {
            if (myport.IsOpen)
            {
                myport.WriteLine(trackBar1.Value.ToString());
                label3.Text = "Degree = " + trackBar1.Value.ToString();
            }
        }

    }
}

Here is uploaded code:

 #include <Servo.h>
Servo myservo;
int val;

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

void loop() {  
   val = Serial.parseInt();
  if(val != 0){
    myservo.write(val);
  }
}

Any example, guide or advice would be helpful

I can't see any Arduino code that does anything with any form of communication with a desktop (I'm assuming you mean Winforms not Winfrom?). Certainly that Sweep code you posted doesn't.

Steve

slipstick:
I can't see any Arduino code that does anything with any form of communication with a desktop (I'm assuming you mean Winforms not Winfrom?). Certainly that Sweep code you posted doesn't.

Steve

Hello,

Thanks for feedback

I've edited question with uploaded code

The serial port is a two way street. Make the Arduino say something. Make your C# app read the serial port, and show what it read. Make sure that what the C# app sent is what the Arduino received.

Have a look at the examples in Serial Input Basics - simple reliable ways to receive data. There is also a parse example to illustrate how to extract numbers from the received text.

The technique in the 3rd example will be the most reliable.

You can send data in a compatible format with code like this (or the equivalent in any other language)

Serial.print('<'); // start marker
Serial.print(value1);
Serial.print(','); // comma separator
Serial.print(value2);
Serial.println('>'); // end marker

When your PC opens the Serial port it needs to allow time for the Arduino to reset before the PC sends anything. In my Arduino programs I have Serial.println("Arduino is ready"); in setup() and my PC program waits to receive that to know that the Arduino has completed its reset process and is communicating properly.

...R

This is an expansion of the suggestion PaulS made when he said make the C# app "show what it read". The Arduino sketch has an additional Serial instruction that returns the value of the int variable val, the C# program has been modified to to display the returned value val.

The C# app has a delegate that is invoked in the DataReceived eventhandler, the dataDebug routine which displays the data in a richTextbox.

This C# program is handy to keep for simple tests like this where the Serial Monitor of the Arduino IDE might not be available, a few modifications and it can be used to display various data types. There are only three controls on the Form1, a richTextbox a label and a trackBar.

Arduino

#include <Servo.h>
Servo myservo;
int val;

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

void loop() {  
 
  val = Serial.parseInt();
 if(val != 0){
    myservo.write(val);
  
     Serial.println(val);
   
     val=0;
  }
}

C#

public partial class Form1 : Form
    {
      
 SerialPort myport = new SerialPort();
 public delegate void myDelegate(byte sData);
 
        public Form1()
        {
            InitializeComponent();  
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            myport.PortName = "COM6";
            myport.Open();
            myport.DataReceived += new SerialDataReceivedEventHandler(myport_DataReceived);
            trackBar1.Scroll += new EventHandler(trackBar1_Scroll);
            label1.Text = "Degree = " + trackBar1.Value.ToString();
        }


        private void myport_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)

        {
                    byte myData;
                    myport.ReadTimeout = 20;
                    while (myport.BytesToRead > 0)
                    {
                        try
                        {
                            myData = System.Convert.ToByte(myport.ReadByte());
                            this.BeginInvoke((new myDelegate(dataDebug)), myData);
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show(ex.Message);
                        }

                    }
                }


        private void dataDebug(byte sData)
        {
            string s = Convert.ToString((char)sData);

            if (sData < 32) { richTextBox1.AppendText(" "); }
            else
            {
                richTextBox1.AppendText(s);
            }

        }

        private void trackBar1_Scroll(object sender, EventArgs e)
        {
            if(myport.IsOpen)
            {
               myport.WriteLine(trackBar1.Value.ToString());
               label1.Text = "Degree = " + trackBar1.Value.ToString();
            }
           
        }

      
    }

Hello,

thank you for your answer

Works fine, but sometime Servo SM-S2309S produces buzz after reaching limit, in some cases goes quiet, for example, if I turn it from one side to another just this way:

     private void button1_Click(object sender, EventArgs e)
        {
            myport.WriteLine(1.ToString());
        }

        private void button2_Click(object sender, EventArgs e)
        {
            myport.WriteLine(160.ToString());
        }

I'm not sure, but it looks like that motor continues to move against limit. Also it seems like, rotational range less then 180°, visually it is less then half circle for sure, I can use only 160° degree

What is the specification of the servo?
Does it specify 180°?

There a good reasons that servos don't do 180°, if designed for RC.

This version of the servo specification from the manufacturer says it only has 120 degrees travel so that may be part of the problem.

Steve

Robin2:
Have a look at the examples in Serial Input Basics - simple reliable ways to receive data. There is also a parse example to illustrate how to extract numbers from the received text.

AWOL:
What is the specification of the servo?
Does it specify 180°?

There a good reasons that servos don't do 180°, if designed for RC.

slipstick:
This version of the servo specification from the manufacturer says it only has 120 degrees travel so that may be part of the problem.

Steve

Hello,

Thank you for answers

it says 180° here, servo from Arduino starter kit. Anyway, I'm trying to figure out, what can cause buzzing noise when motor must stop without any noise, which appears with same test, from time to time, and seems like with less range of degree also, for example 80°, when physical limit from one side is not reached, if it should have any sense at all

aive:
it says 180° here, servo from Arduino starter kit.

You may find that it can go beyond 0 but not as far as 180 with Servo.write(). You need to experiment to find the limits for your servo

Of course you can't use negative degrees but if you use Servo.writeMicroseconds() you will have a lot more control. 1000 roughly corresponds to 0° and 2000 to 180°

...R

As standard Servo.write() will give you 544 microseconds for 0 and 2400 microseconds for 180. Not all servos are happy with a range that wide so that may also partly explain why it's unhappy at the extremes.

You can either use writeMicroseconds() or set the lower and upper bounds in Servo.attach(pin, min, max) e.g attach(servoPin, 1000,2000) - that will give you a range of 0 = 1000, 180 = 2000, which is what many people seem to expect.

Steve

Noise appears even when Arduino just turned on, without any action from application, seems like it is something wrong there, this is my diagram powered by usb connection from pc, maybe I need use something else here:

With some servos if you write the position too frequently it will buzz, if you don't write frequently enough the position will drift.

In these cases writing every 50mS is usually optimum. Of course you should take care not to exceed the servo limits.

slipstick:
As standard Servo.write() will give you 544 microseconds for 0 and 2400 microseconds for 180. Not all servos are happy with a range that wide so that may also partly explain why it's unhappy at the extremes.

Interesting. I don't think I ever checked that but I did discover recently that some cheap HobbyKing digital servos needed that range with writeMicroseconds()

I'm pretty sure I have several other servos that work fully across the range 1000 to 2000 (roughly).

I thought 1000 to 2000 was the standard, has it changed?

...R

slipstick:
As standard Servo.write() will give you 544 microseconds for 0 and 2400 microseconds for 180. Not all servos are happy with a range that wide so that may also partly explain why it's unhappy at the extremes.

You can either use writeMicroseconds() or set the lower and upper bounds in Servo.attach(pin, min, max) e.g attach(servoPin, 1000,2000) - that will give you a range of 0 = 1000, 180 = 2000, which is what many people seem to expect.

Steve

sumguy:
With some servos if you write the position too frequently it will buzz, if you don't write frequently enough the position will drift.

In these cases writing every 50mS is usually optimum. Of course you should take care not to exceed the servo limits.

I've tried to use myservo.attach(9, 1000, 2000);, in result movement range is shorter, same as if I set it from C#, but motor still produces noise. With using of myservo.writeMicroseconds(val); it just stops control servo after short movement with first attempt:

#include <Servo.h>
Servo myservo;
int val;

void setup() { 
   Serial.begin(9600);
   myservo.attach(9, 1000, 2000);
}

void loop() { 
 val = Serial.parseInt();
 if(val != 0){
   myservo.writeMicroseconds(val); 
   // myservo.write(val);
 }
}

I am not sure if my previous post was clear or even if it is relevant but what I was trying to say was that it is possible that you are sending the position command at too high a frequency, in other words you are sending the position command too many times in too short a period of time. Try a small delay and see if anything improves.

Arduino

void loop() { 
 val = Serial.parseInt();
 if(val != 0){
   myservo.writeMicroseconds(val); 
   // myservo.write(val);

    delay(40);

 }
}

sumguy:
Arduino

void loop() { 

val = Serial.parseInt();
if(val != 0){
  myservo.writeMicroseconds(val);
  // myservo.write(val);

delay(40);

}
}

Same result with 5V. Only solution I found to avoid noise, is a powering of board with 9V adapter.

I'm looking for way to make servo faster if it is possible. Would be good to get advice for device about 11.9 x 21.9 mm and powerful torque to accelerate mass of mechanical parts 53-193 gm for each separate motor including gear element, from 0 to 300 rpm in 0.1 seconds. I have discussed this in terms of implementation with a stepper. I don't know, if it is possible with servos to use it this way.

Robin2:
Interesting. I don't think I ever checked that but I did discover recently that some cheap HobbyKing digital servos needed that range with writeMicroseconds()

I'm pretty sure I have several other servos that work fully across the range 1000 to 2000 (roughly).

I thought 1000 to 2000 was the standard, has it changed?

...R

It's like much of the hobby world, there are no official standards. Years ago most hobby servos only travelled 120 degrees and responded to 1000 to 2000, 1500 centre (except Futaba who at one time used 1020-2020, 1520 centre for no known reason). When the travel range was commonly extended past 120 degrees some manufacturers made 1000-2000 cover the new full range but others extended the pulse length range so 1000-2000 still did roughly 120 degrees and you needed something like 700-2300 for the full range (and the specification rarely tells you).

These days all you can do it test each type of servo yourself. It's all part of the rich tapestry of life!

Steve

Hello,

I'm trying to figure out, how to control two servos separately from winfroms C# desktop application.

In C# initialization:

 myport.PortName = "COM6";
 myport.BaudRate = 9600;
 myport.Open();

Controlled by trackBar1:

private void trackBar1_Scroll(object sender, EventArgs e)
{
     if (myport.IsOpen)
     {
         myport.WriteLine(trackBar1.Value.ToString());
     }
}

Arduino code moves servos with pin 9 and 11, one goes to left, anther to right side synchronously :

#include <Servo.h>
Servo servo1;
Servo servo2;
int val;

void setup() {
    Serial.begin(9600);
    servo1.attach(9);
    servo2.attach(11);
}

void loop() {
  val = Serial.parseInt();
  if(val != 0){
    servo1.write(val);
    servo2.write(val);
  }
}

to control direction, I can create separate function void for servo1 and servo2 with different angle value, but I can't figure out, how to get separate control for each servo from C#, I'm not sure, what I have to add in Arduino uploaded code and C#, for example, if I want control servo from pin 11 with trackBar2 and servo from pin 9 with trackBar1:

private void trackBar2_Scroll(object sender, EventArgs e)
{
    if (myport.IsOpen)
    {
        myport.WriteLine(trackBar2.Value.ToString());
    }
}

Any advice, guide or example would be very helpful