Go Down

Topic: problem controlling Servos through C# (Read 1 time) previous topic - next topic

Jul 24, 2012, 03:46 am Last Edit: Jul 24, 2012, 05:18 am by Fullmetal691 Reason: 1
I am starting an autonomous car project. I have all my plans, and the equipment. I am using an old RC truck, and removing the receiver.  I plan to use the Arduino to control the servos that drive the steering and old mechanical throttle. Before I make it fully autonomous, id like to be able to run some tests, controlling the servos not via the Arduino automatically, but by interfacing to the computer, and controlling it via a program.  The part i'm having problems with is sending a numerical value over the serial connection. I have tried just sending the value(I made a slider that was supposed to change the brightness of an LED, with a value of 0-255), but that didn't work at all. The issue I am having is that sending a value of 255 yielded a serial result of 65,65,65,65,65(each on a new line). I'm assuming that's because of the way the serial data transmission works. how do I send over the data(in my case, a value from 0-180 for the servos, and a letter T or S for throttle or steering), and then reassemble it on the other side. I know how to send it in C#, I just don't know how to format the message, or how to translate it back to the number value on the Arduino side.

I attached a snapshot of my program, It doesn't do anything right now, as I haven't figured out how to format my message to the Arduino, but the track bar has a value of 0-180, and its default is 90(center on a servo).


Code: [Select]
#include <Servo.h>

Servo ThrottleServo;          // Define Throttle servo
Servo SteeringServo;         // Define Steering servo


void setup()
{
  ThrottleServo.attach(10); //Throttle is set to digital pin 10
  SteeringServo.attach(9);  //Steering is set to digital pin 09
  ThrottleServo.write(90);  //Center Throttle(stopped)
  SteeringServo.write(90);  //Center Steering(straight)
  Serial.begin(9600); //Open the serial port for debugging.
}
//BEGIN SECTION OF CONTROL FUNCTIONS(used for autonomy);
void forward()
{
  ThrottleServo.write(180);
}

void reverse()
{
   ThrottleServo.write(0);
}

void stopcar()
{
  ThrottleServo.write(90);
}

void SteerLeft()
{
  SteeringServo.write(0);
}

void SteerRight()
{
  SteeringServo.write(180);
}
//END SECTION OF CONTROL FUNCTIONS

void loop()
{
  //For debugging, place control code here.
}


This is what I have so far.

marco_c

Look at this thread "Simple-yet-powerfull - Serial Command input with numbers" as somewhere to start

http://arduino.cc/forum/index.php/topic,115174.0.html

Arduino libraries http://arduinocode.codeplex.com
Parola for Arduino http://parola.codeplex.com

zoomkat

For simple servo testing you can try the below code with the serial monitor.

Code: [Select]

// zoomkat 10-22-11 serial servo test
// type servo position 0 to 180 in serial monitor
// or for writeMicroseconds, use a value like 1500
// for IDE 0022 and later
// Powering a servo from the arduino usually *DOES NOT WORK*.

String readString;
#include <Servo.h>
Servo myservo;  // create servo object to control a servo

void setup() {
  Serial.begin(9600);
  myservo.writeMicroseconds(1500); //set initial servo position if desired
  myservo.attach(7);  //the pin for the servo control
  Serial.println("servo-test-22-dual-input"); // so I can keep track of what is loaded
}

void loop() {
  while (Serial.available()) {
    char c = Serial.read();  //gets one byte from serial buffer
    readString += c; //makes the string readString
    delay(2);  //slow looping to allow buffer to fill with next character
  }

  if (readString.length() >0) {
    Serial.println(readString);  //so you can see the captured string
    int n = readString.toInt();  //convert readString into a number

    // auto select appropriate value, copied from someone elses code.
    if(n >= 500)
    {
      Serial.print("writing Microseconds: ");
      Serial.println(n);
      myservo.writeMicroseconds(n);
    }
    else
    {   
      Serial.print("writing Angle: ");
      Serial.println(n);
      myservo.write(n);
    }

    readString=""; //empty for next input
  }
}

Google forum search: Use Google Advanced Search and use Http://forum.arduino.cc/index in the "site or domain:" box.

PaulS

Quote
The part i'm having problems with is sending a numerical value over the serial connection.

And the code that did that looked like?

Code: [Select]
  while (Serial.available()) {
    char c = Serial.read();  //gets one byte from serial buffer
    readString += c; //makes the string readString
    delay(2);  //slow looping to allow buffer to fill with next character
  }

What a crappy starting point. Relying in Strings and thinking that delay() is a useful way of ensuring that the whole packet is received. Neither is a good idea. Some end-of-packet marker is a MUCH better idea. No delay() needed.

Quote
I have tried just sending the value(I made a slider that was supposed to change the brightness of an LED, with a value of 0-255), but that didn't work at all.

No code == no help;

Quote
The issue I am having is that sending a value of 255 yielded a serial result of 65,65,65,65,65(each on a new line). I'm assuming that's because of the way the serial data transmission works. how do I send over the data(in my case, a value from 0-180 for the servos, and a letter T or S for throttle or steering), and then reassemble it on the other side. I know how to send it in C#, I just don't know how to format the message, or how to translate it back to the number value on the Arduino side.

You've provided no proof that you know how to get the slider value or how to send that value to the Arduino. You;ve provided no output from the sender or the receiver.

What you want to do is very easy. Modifying your code to send/receive that information may or may not be. Without seeing all of your code, there is no way to tell.



Quote
The part i'm having problems with is sending a numerical value over the serial connection.


And the code that did that looked like?

Code: [Select]
private void trackbar1_scroll(object sender,Args e)
          {

               ArduinoPort.Writeline(trackbar1.value); //ArduinoPort is a SerialPort object set to COM4 <-- trackbar 1.value is from 0-255
           }


Quote
I have tried just sending the value(I made a slider that was supposed to change the brightness of an LED, with a value of 0-255), but that didn't work at all.


No code == no help;

see above code

PaulS

A Console.WriteLine() statement following, or preceding the ArduinoPort.WriteLine() call would be useful. Is the slider returning the value that you expect?

On the Arduino, the serial data being sent ends with a carriage return/line feed. You should read serial data until the CR/LF arrives, and do nothing until it does. Given that the value sent is in the range 0 to 255 (or 180), the data being received will consist of no more than 5 characters. Adding one for the trailing NULL, a char array of 6 elements is adequate for reading the data. No String objects required.

The slider returns the value I want it to, as trackbar1.value is an integer. on the Arduino end, I need to figure out how to retrieve the integer, as when 255 is input, the serial monitor returns several lines of "65"
The ultimate goal would be to send a message in the format of "x:n" where x is a letter representing Throttle or Steering(T or S), the colon separates it, and the n is a value between 0 and 255. I can send a message like this, but I don't know how to reassemble the message on the Arduino, and then interpret the parts.

PaulS

Quote
The slider returns the value I want it to, as trackbar1.value is an integer.

Then, you should be sending something like "137<cr><lf>" to the Arduino.

Quote
on the Arduino end, I need to figure out how to retrieve the integer, as when 255 is input, the serial monitor returns several lines of "65"

This is hard to understand, since 65 in no way relates to '2', '5', '\n' or '\r'.

Where are you seeing this "65"? If you are using C#, that means you are on Windows. That means that only one application at a time can use the serial port. You haven't shown any C# code that is receiving serial data, though the Arduino seems to be sending some.

Quote
The ultimate goal would be to send a message in the format of "x:n" where x is a letter representing Throttle or Steering(T or S), the colon separates it, and the n is a value between 0 and 255.

Even better would be to send "<x:n>" where < is an SOP and > is an EOP (start and end of packet).


jraskell

Per http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.writeline.aspx
SerialPort.WriteLine takes a string parameter.  You are not passing in a string.
C# does not provide any implicit conversion from pretty much any type to a string.  You have to handle that explicitly (even if  by just calling the ToString() method of the type you are passing in).  So this line shouldn't even compile for you:
Code: [Select]
ArduinoPort.Writeline(trackbar1.value);

In fact, when I try just a small project that WriteLine()'s an int value, I get the following compile errors:
Error   1 The best overloaded method match for 'System.IO.Ports.SerialPort.WriteLine(string)' has some invalid arguments
Error   2 Argument 1: cannot convert from 'int' to 'string'



SerialPort.WriteLine takes a string parameter.  You are not passing in a string.


My mistake. I mistyped that. I am passing a string to it. Eventually what im trying to do is

Code: [Select]

private void SendDATA()
{
if(ThrottleRDO.checked)
{
ArduinoPort.Writeline("T:"  + trackbar1.value.ToString());
}
else if(SteeringRDO.checked)
{
ArduinoPort.Writeline("S:" + trackbar1.value.ToString());
}
}



I would then need to break down that at the other end, and interpret it.

something along the lines of

Code: [Select]

if "T"
{
ThrottleServo.write(trackbar value)
}
else if "S"
{
SteeringServo.write(trackbar value)
}


That part is just pseudo code. I know I need more to be able to interpret a message, and perform an action.

Go Up