Pages: [1] 2   Go Down
Author Topic: Control servo with Visual Basic 2008  (Read 3726 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 18
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello,

I want to control a simple servo with Visual Basic 2008. I want to use a trackbar with 180 points. The servo is attached to digital pin 9. I tried this 2 simple codes:

Visual Basic 2008 code:
Code:
Private Sub TrackBar1_Scroll(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TrackBar1.Scroll
        If RadioButton2.Checked = True Then
            SerialPort1.Write(TrackBar1.Value)
        End If
    End Sub

Arduino code:
Code:
#include <Servo.h>
 
Servo myservo;

int SerialValue = 0;
 
void setup()
{
  myservo.attach(9);
  Serial.begin(9600);
}
 
 
void loop() {
  SerialValue = Serial.read();
    myservo.write(SerialValue);
    delay(15);
  }

...But it doesn't work. The servo moves somewhat, but not to the right angle, not even close. It just moves like it's confused and doesn't know what to do.

Does anyone know a solution to this?

Many thanks,
Deco Aoreste
Logged

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

In the Arduino code, loop executes in an endless loop, potentially millions of times a second. During each iteration, it will (try to) read a byte from the serial port, and send the servo there, then wait 15 milliseconds for the servo to get there.

You are not checking to see if there is serial data to read, nor are you checking that the value read is reasonable.

If there is no data to be read, Serial.read returns -255. That is probably not an angle that the servo can rotate to.

Add a call to Serial.available(), and only read from the serial port if there is data to read. Only move the servo if the value read from the port is reasonable.
Logged

Rural Arizona
Offline Offline
Edison Member
*
Karma: 7
Posts: 1711
Incorrigible tinkerer
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
But it doesn't work.

Sure it does.  It just doesn't work the way you think it does  smiley

The Arduino's read() doesn't work the same way as VB's:  it only gets one character at a time.  You need to accumulate the characters into a string,  and convert that to a number with a function like http://atoi().  Or you can convert the characters "on-the-fly" by translating each digit as it comes in,  and accumulating the value.

The examples on the reference page for the Serial library don't seem to show those,  but you can find examples posted in the forums.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 18
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for replying.

I tried the things that you said, but it still doesn't work. Please note that I'm a beginner, this is one of my first projects.

So this is my code now:
Code:
#include <Servo.h>
 
Servo myservo;

int SerialValue = 0;
char incomingByte;
int outputValue;
 
void setup()
{
  myservo.attach(9);
  Serial.begin(9600);
}
 
 
void loop() {
  if (Serial.available() > 0) {
    SerialValue = Serial.read();
    outputValue = atoi(incomingByte);
    myservo.write(outputValue);
    delay(15);
  }
}

I get an error at this line:
Code:
outputValue = atoi(incomingByte);
I get this error:

error: invalid conversion from 'char' to 'const char*

What should I do to make it work?

Thanks,
Deco Aoreste
Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 291
Posts: 25876
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You're reading a single "char", and passing it to "atoi", which expects a string (char*).

However, a single decimal digit will result in only very limited movement of the servo.
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

0
Offline Offline
Newbie
*
Karma: 0
Posts: 18
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I understand. But what do I need to do to make it work? I made the char 'incomingByte' to a string(char*), and I don't get errors in the code anymore. But it still doesn't work. Does anyone have an example code? I would really appreciate it if you would share it with me.
Logged

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

You'll need to modify the VB application to send more data. Currently it sends the value as a string, apparently. If the VB application sends data as the mouse moves, it might send

'1', '5', '6', 1', '5', '8', '1', '4', 9'...

In that data stream, where does one value begin and end? Is the data supposed to represent 15, 61, 58, 14, 9 or 156, 158, 149?

Change the VB app. to send '<', '1', '5', '6', '>', '<', '1', '5', '8', '>', '<', '1', '4', 9', '>'.... This way, there is no ambiguity.

Then, do something like this on the Arduino:

Code:
int servoValue = 0;
char inData[12];
int index = 0;
bool started = false;
bool ended = false;

void loop()
{
   if(Serial.available() > 0)
  {
     while(Serial.available() > 0)
     {
        char aChar = Serial.read();
        if(aChar == '<')
        {
           index = 0;
           inData[index] = '\0'; // Null out the array
           started = true;
           ended = false;
        }
        if(aChar != '>' && started && !ended)
        {
           inData[index] = aChar;
           index++;
           inData[index] = '\0';
        }
        if(aChar == '>')
        {
            ended = true;
            started = false;
        }

        if(ended && !started)
        {
            servoValue = atoi(inData);
            // Move the servo
            // Wait for it to get there
            ended = false; // Set up for the next packet
        }
     }
  }
}

This code uses two flags, started and ended, to indicate whether we have encountered a start of data marker and and end of data marker.

If the character is a start of data marker, started is set to true, and the array is initialized.

If the character is an end of data marker, started is set to false, and ended is set to true. This means that we can now use the data received, because we know it is complete.

If the character is not an end of data marker, and we have received a start of data marker, the character is added at the end of the string, the pointer is advanced, and the string is (again) properly terminated.

If an end of data marker has been received (ended is true and started is false), we move the servo, and set the flags to false.

Try out various data loss scenarios, and you'll see that a dropped start of data marker is handled properly - the next one starts the process of receiving data again. An end of data marker loss is handled the same way.

The only thing that is not handled is a dropped character between start and end of data markers. That could be handled by making the payload look like:

<numberOfcharacters:validCharacters>

An example:

<3:156>

Then, the received string should look like '3', ':', '1', '5', '6', NULL. You could then convert the value before the : to an integer, 3, and then make sure that there are 3 characters after the smiley-small This is probably more than you really need to deal with, though, for this simple application.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 18
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I changed your code so I thought it would work, but it didn't. This is my Arduino code now:
Code:
int select;
int val;
int val2;
int servoValue = 0;
char inData[12];
int index = 0;
bool started = false;
bool ended = false;
int pos;

#include <Servo.h>
 
Servo myservo;

void setup()
{
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
}

void loop()
{
   if(Serial.available() > 0)
  {
     while(Serial.available() > 0)
     {
        char aChar = Serial.read();
        if(aChar == '<')
        {
           index = 0;
           inData[index] = '\0'; // Null out the array
           started = true;
           ended = false;
        }
        if(aChar != '>' && started && !ended)
        {
           inData[index] = aChar;
           index++;
           inData[index] = '\0';
        }
        if(aChar == '>')
        {
            ended = true;
            started = false;
        }
          if(aChar == ':')
          {
            select = pos;
            pos = 0;
            val = 1;
          }
        if(ended && !started)
        {
            servoValue = atoi(inData);
            myservo.write(pos);
            delay(15);
            ended = false; // Set up for the next packet
        }
          else{
            select = Serial.read();
            val2 = Serial.read();
            if(val = 1){
              val2 = Serial.read();
              val2 * 100;
              pos = val2;
            }
            else if(val = 2){
              val2 = Serial.read();
              val2 * 10;
              pos = pos + val2;
            }
            else if(val = 3){
              val2 = Serial.read();
              pos = pos + val2;
              val = 0;
            }
          }
     }
  }
}

And this is my Visual Basic 2008 code:
Code:
Private Sub TrackBar1_Scroll(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TrackBar1.Scroll
        Dim value As Integer
        SerialPort1.Write("<")
        If TrackBar1.Value.ToString.Count = 1 Then
            SerialPort1.Write("1")
            SerialPort1.Write(":")
            SerialPort1.Write(TrackBar1.Value)
        ElseIf TrackBar1.Value.ToString.Count = 2 Then
            SerialPort1.Write("2")
            SerialPort1.Write(":")
            SerialPort1.Write(TrackBar1.Value.ToString.First)
            SerialPort1.Write(TrackBar1.Value.ToString.Last)
        ElseIf TrackBar1.Value.ToString.Count = 3 Then
            SerialPort1.Write("3")
            SerialPort1.Write(":")
            SerialPort1.Write(TrackBar1.Value.ToString.First)
            value = TrackBar1.Value - 100
            SerialPort1.Write(value - Val(TrackBar1.Value.ToString.Last))
            SerialPort1.Write(TrackBar1.Value.ToString.Last)
        End If
        SerialPort1.Write(">")
    End Sub
Logged

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

Start by getting the VB application to write '<', TrackBar1.Value.ToString, and '>'. If TrackBar1's value is 159. it should write <159> to the serial port.
 
On the Arduino side, remove this stuff:

Code:
         if(aChar == ':')
          {
            select = pos;
            pos = 0;
            val = 1;
          }

and

Code:
         else{
            select = Serial.read();
            val2 = Serial.read();
            if(val = 1){
              val2 = Serial.read();
              val2 * 100;
              pos = val2;
            }
            else if(val = 2){
              val2 = Serial.read();
              val2 * 10;
              pos = pos + val2;
            }
            else if(val = 3){
              val2 = Serial.read();
              pos = pos + val2;
              val = 0;
            }
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 18
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I tried that earlier, but that didn't work. The servo doesn't move. These are my codes now:

Visual Basic 2008
Code:
Private Sub TrackBar1_Scroll(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TrackBar1.Scroll
        SerialPort1.Write("<")
        SerialPort1.Write(TrackBar1.Value.ToString)
        SerialPort1.Write(">")
    End Sub

And this is my Arduino code:
Code:
int servoValue = 0;
char inData[12];
int index = 0;
bool started = false;
bool ended = false;

#include <Servo.h>
 
Servo myservo;

void setup()
{
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
}

void loop()
{
   if(Serial.available() > 0)
  {
     while(Serial.available() > 0)
     {
        char aChar = Serial.read();
        if(aChar == '<')
        {
           index = 0;
           inData[index] = '\0'; // Null out the array
           started = true;
           ended = false;
        }
        if(aChar != '>' && started && !ended)
        {
           inData[index] = aChar;
           index++;
           inData[index] = '\0';
        }
        if(aChar == '>')
        {
            ended = true;
            started = false;
        }
        if(ended && !started)
        {
            servoValue = atoi(inData);
            myservo.write(servoValue);
            delay(15);
            ended = false; // Set up for the next packet
        }
          }
     }
  }
(Almost the same as your code, the only change is 'myservo.write(servoValue)' and 'Delay(15)').

Logged

London
Offline Offline
Tesla Member
***
Karma: 10
Posts: 6251
Have fun!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

you are missing the Serial.begin statement in setup - without this, Serial wont work.

here is a shorter version of your code. Its untested but it may give you some ideas on how to simplify the task of getting serial data.

Code:
#include <Servo.h>

Servo myservo;

int pos=0;

void setup()
{
  Serial.begin(9600);
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
}

void loop()
{
  if(Serial.available() > 0)
  {
    char aChar = Serial.read();
    if(aChar == '<')
    {
      pos = 0;
      do{
          while(Serial.available() <1)
            ; // wait for a character
        aChar = Serial.read();    
        if(aChar >= '0' && aChar <= '9')              // is ch a number?  
          pos = pos * 10 + aChar - '0';           // yes, accumulate the value      
      }
      while(aChar != '>');
      myservo.write(pos);
      pos = 0;
    }
  }
« Last Edit: February 28, 2010, 05:52:32 am by mem » Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 18
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

It works!
Both mem and PaulS; thank you very much!  smiley

It was pretty stupid of me to forget the Serial.begin(9600); command.
I'll post the 2 codes here, just for administration, for other people who want to do this and cannot find it on the internet.

Visual Basic 2008 (my trackbar has 170 points)
Code:
   Private Sub TrackBar1_Scroll(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TrackBar1.Scroll
        SerialPort1.Write("<")
        SerialPort1.Write(TrackBar1.Value.ToString)
        SerialPort1.Write(">")
    End Sub

Arduino code
Code:
#include <Servo.h>

Servo myservo;

int pos=0;

void setup()
{
  Serial.begin(9600);
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
}

void loop()
{
  if(Serial.available() > 0)
  {
    char aChar = Serial.read();
    if(aChar == '<')
    {
      pos = 0;
      do{
          while(Serial.available() <1)
            ; // wait for a character
        aChar = Serial.read();    
        if(aChar >= '0' && aChar <= '9')              // is ch a number?  
          pos = pos * 10 + aChar - '0';           // yes, accumulate the value
      }
      while(aChar != '>');
      myservo.write(pos);
      pos = 0;
    }
  }
}

Again, thank you very much!
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 11
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I know a lot about Visual Basic, but doen't understand this at all...
I'm using Visual Basic 2008 Express Edition and an Arduino UNO and I want to make a GUI with 4 buttons, if you click one of them a LED on a breadboard connected to the Arduino turn On/Off.
How do i code it?

It would be great if you could post the FULL code, for at least one button...

Thank You Very Much
Logged

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 126
Posts: 8475
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

You should be able to do it using the above code as a base.

In VB just send a number (1, 2, 3, 4) according to the button pressed.

On the Arduino read that number and do a digitalWrite() to the appropriate pin.

It's actually a lot easier than the above because you only have to work with one character at a time.

______
Ron

Logged

Rob Gray aka the GRAYnomad www.robgray.com

0
Offline Offline
Newbie
*
Karma: 0
Posts: 11
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Could you give me an example code part for arduino and Visual Basic.

Would be great thanks,
Logged

Pages: [1] 2   Go Up
Jump to: