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.
Please post your code - hard to help otherwise. Use code tags - # button above
You also need to give a better description of the serial spew you are sending from the computer.
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
@zoomkat and wildbill
heres the c code for serial communication:
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:
#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)
arGetTransMat3.c (16.5 KB)
simpleTest.h (72 Bytes)
sketch_sep07a.pde (2.17 KB)
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
if (Serial.available () >= 6)
{
....
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!
@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
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).
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.