Pages: [1]   Go Down
Author Topic: erratic servo motor behaviour  (Read 1050 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

i am using an arduino decimila to receive data from a serial port which is a character array. i am converting the array to unsigned long and then using these values to control a servo motor.
the values being streamed from the computer are live values and are being constantly updated.
when using these values, the servo motor behaves erratically moving for some time randomly and then stopping altogether.
the only thing that it does right is it sets to 90 degrees as specified at the beginning of the program.
any ideas as to what might be wrong?
any help is appreciated.
thanks.
Logged

New Jersey
Offline Offline
Faraday Member
**
Karma: 48
Posts: 3393
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Please post your code - hard to help otherwise. Use code tags - # button above
Logged

0
Offline Offline
Tesla Member
***
Karma: 114
Posts: 8894
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You also need to give a better description of the serial spew you are sending from the computer.
Logged

Consider the daffodil. And while you're doing that, I'll be over here, looking through your stuff.   smiley-cool

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 331
Posts: 16464
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

How are you powering the servo? If being powered from the arduino +5vdc pin, some servos have been known to draw more current then the board can handle, even one, causing resets. Arduinos are great at controlling stuff, but not so great at powering loads.

Lefty

Logged

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

@zoomkat and wildbill
heres the c code for serial communication:
Code:
HANDLE          h;
DCB             dcb={0};
h=CreateFile("\\\\.\\COM15",GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);

if(h==INVALID_HANDLE_VALUE)
{
if(GetLastError()==ERROR_FILE_NOT_FOUND)
{
printf("Serial port doesnt exist. Rectify and restart");
}
printf("Error opening port. Restart");
}

//FillMemory(&dcb,sizeof(dcb),0);
dcb.DCBlength=sizeof(dcb);
if(!BuildCommDCB("19200,n,8,1", &dcb))
{
printf("Error Building DCB. Rectify and restart");
}
else if(!SetCommState(h,&dcb))
{
printf("Error setting state to port. Rectify and restart");
}

   dcb.BaudRate=19200;
   //dcb.fParity=false;
   dcb.ByteSize=8;
   dcb.Parity=0 ;
   dcb.StopBits=0  ;
   //dcb.fAbortOnError = true;
   //dcb.fOutX=true ;
   dcb.fOutxDsrFlow = 0;
   dcb.fOutxCtsFlow = 0;
   dcb.fRtsControl=0 ;
   dcb.fOutxCtsFlow=0 ;
   dcb.fOutxDsrFlow=0 ;
   dcb.fDtrControl=0 ;
CloseHandle(h);
//the above is the code that is opening and initializing the serial com port
//below is the code for transmission:
char data_buf[6];
DWORD written=0;
HANDLE h;
if(a>0)
{
//data_buf[0]=(unsigned long)((((270-(a*180/MD_PI))*1000)+90+(b*180/MD_PI)));
printf("%f %f %f",(270-(a*180/MD_PI)),90+(b*180/MD_PI),(c*180/MD_PI));
printf("\n");
//printf("%f\n",(((270-(a*180/MD_PI))*1000)+90(b*180/MD_PI)));
sprintf(data_buf,"%u",(unsigned long)((unsigned long)((270-(a*180/MD_PI))*1000)+(unsigned long)(90+(b*180/MD_PI))));//(int)((((270-(a*180/MD_PI))*1000)+90+(b*180/MD_PI)));
WriteFile(h,data_buf,6,&written,NULL);
printf("%s\n",data_buf);
//printf("%d\n",written);
}
else
{
printf("%f %f %f",(-90-(a*180/MD_PI)),90+(b*180/MD_PI),(c*180/MD_PI));
printf("\n");
//printf("%f\n",((((-90-(a*180/MD_PI))*1000)+90+(b*180/MD_PI))));
//data_buf[0]=(unsigned long)((((-90-(a*180/MD_PI))*1000)+90+(b*180/MD_PI)));
sprintf(data_buf,"%u",(unsigned long)((unsigned long)(((-90-(a*180/MD_PI))*1000))+(unsigned long)(90+(b*180/MD_PI))));
WriteFile(h,data_buf,6,&written,NULL);
printf("%s\n",data_buf);
//printf("%d\n",written);
}
//This is the snippet from the code that is doing the actual transmitting.

heres the arduino code:
Code:
            #include <stdlib.h>
            #include <Servo.h>
            #include <math.h>
            Servo x;
            Servo y;
            unsigned long inp,pos,x_pos,y_pos;
                     
            void setup()
            {
            pinMode(13,OUTPUT);
            Serial.begin(19200);//set baud rate 9600
            x.attach(3);
            y.attach(5);   
            //x.write(90); //since servo.write func can take
            //y.write(90);
            //0 to 180 we set at 90 and go from
            //60 to 110 for -30 to +30 range
            }
           
            unsigned long value_read=0,tmp=0;
            void loop()
            {
              value_read=1;
              if(Serial.available()>0)
             {
              //for(int i=0;i<10 ;i++)
              //{
             
               for(int j=0;j<6;j++)
               {
                  inp=Serial.read();
                  //Serial.println(inp);
                  delay(5);
                  pos=convert(inp);
                  value_read*=10;
                  value_read+=pos;
               }
                        //      value_read=(value_read+tmp)/2;
            //    tmp=value_read;
              //  delay(10);
             //} 
     
         
            x_pos=(value_read /1000);
            y_pos=(value_read%1000);
            if(x_pos<120 && x_pos>60)
            x.write(x_pos);
            else if(x_pos<=60)
            x.write(60);
            else if(x_pos>=120)
            x.write(120);
            if(y_pos<120 && y_pos>60)
            y.write(y_pos);
            else if(y_pos<=60)
            y.write(60);
            else if(y_pos>=120)
            y.write(120);
            }}
            unsigned long convert(unsigned long n)//function to convert received char array to unsigned long number
            {
              unsigned long r=0;int ctr=0;unsigned long sum=0;
              unsigned long res;
              long arr[6];
              while(n>0)
              {
               r=n%100;
               r-=48;
               arr[ctr]=r;
               ctr++;
               n=n/100;
              }
              for(int i=0;i<ctr;i++)
             sum+=arr[i]*pow(10,i);
             return sum;
            }
               //this is for moving the motors, the values are being written to the motors roughly 30 times a second, thats 30 values a second and with //filtering its 2 values a second
//neither code seems to work properly
//the sweep code in the arduino examples works perfectly on the servo motor so theres no issue with the motor or the board.
//somethings going wrong with the code

@retroLefty
we are using an external power supply of 2 amp current output


i am also attaching the .c files and the arduino file

* simpleTest.c (5.76 KB - downloaded 7 times.)
* arGetTransMat3.c (16.47 KB - downloaded 11 times.)
* simpleTest.h (0.07 KB - downloaded 4 times.)
* sketch_sep07a.pde (2.17 KB - downloaded 1 times.)
Logged

0
Offline Offline
Shannon Member
****
Karma: 159
Posts: 10409
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You are reading characters that are not available...  You test for 1 or more characters being available and then read 6...  You'll be lucky to get more than the first character as valid.  Try
Code:
  if (Serial.available () >= 6)
  {
    ....

Logged

[ I won't respond to messages, use the forum please ]

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

thanks for that reply!!....will implement and post the result!...we had the problem of getting only one value thats why we used the  for loop to read 6 values!...but this is obviously a way better method!!!

also i added  a Serial.println() with a delay(300) so as  to release control of the port... but its not printing x_pos and y_pos now! even though value_read is being printed properly in the serial monitor!
« Last Edit: September 13, 2011, 08:38:49 am by arindam1993 » Logged

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

@markT
we are getting inputs of 5 and 6 digits
any ideas as to how to get the Serial.available() function to work for 5 as well as six digits?
running serial.availalble() again to check if its either 5 or six digits and then running the loop accordingly is not working as it is giving garbage values for 5 inputs

thanks
Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 220
Posts: 6587
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

If you can get inputs of 5 or 6 characters, then presumably you can determine from the first 5 characters whether a 6th character is expected. If you can't, you need to redesign your communications protocol so that you can (or just make all commands 6 characters long).
Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

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

reworked the mechanism to set the motors initially at 60 degree so the range of motion is from 30 to 90 so now i send four bytes always!..but the behavior of the motor is still very erratic.

it seems to go back to 60 every time.we are using a marker with optical glyph tracking software called ARtoolkit to send these angles to a robotic labyrinth game.When i enter values from the arduino serial monitor the motors respond perfectly now!..but when sending from the C code even if I keep the glyph inclined and dont move it at all the motor keeps oscillating between that angle at which the glyph is set and 60.

Even checked that C is sending values properly ...wrote some data to the EEPROM and cross checked with the feed on the console window of the glyph tracking app and the values are the same.
Logged

Pages: [1]   Go Up
Jump to: