Hi,
I'm trying to make an RC with RF link trough serial @2400 (higher speeds seem to be unreliable).
Everything seems to work except that servos jitter horribly. If I comment out serial.read lines jittering stops. I've checked incoming data through serial monitor and there's no jittering in it.
Is there anything I can do or there is some hardware interference between servo and serial?
Serial must be busting your servo pulse-width or timing (refresh) constraint.
Is there anything that can be done to help it?
We need to know how you are doing serial I/O using Serial object? NewSoftSerial? which pins?
We need to know how you are running servos, using Servo library? which pins?
How is everything powered? When you say RF link, how is that connected? Is there a library involved?
MarkT:
We need to know how you are doing serial I/O using Serial object? NewSoftSerial? which pins?We need to know how you are running servos, using Servo library? which pins?
How is everything powered? When you say RF link, how is that connected? Is there a library involved?
Everything is powered from Li-po battery through 5V voltage regulator of ESC. I tried connecting servo directly to Arduino 5V/GND/data with no difference.
Serial communication on pins 0,1 is linked to data-in and data-out of Rf-link transmitter@315MHz and receiver@433MHz for two way communication. (2$ links from e-bay, but with error filtering they do work)
Whole slave Arduino sketch (a bit cleaned):
byte sinc[2]={sinc[0]=B11001010, B00001010/*202, 10*/}, rf_mode=1, MODE=1;
byte v[8]={0,0,0,0,0,0,0,0}, i[8]={0,0,0,0,0,0,0,0}, buttons;
int led=13, a0, a1, a2, a3, a4, a5, a6, a7;
long last_millis;
unsigned long millitime;
byte buffer[150], buffer_pos=0, packet_step=0;
#include <Servo.h>
Servo servo[8];
boolean button_bools[8];
byte ping, ch0=3, ch1=5, ch2=6, ch3=9, ch4=10, ch5=11, ping_request=0;
void setup()
{
pinMode(led, OUTPUT);
digitalWrite(led, 0);
Serial.begin(2400);
pinMode(A0, INPUT);
pinMode(A1, INPUT);
pinMode(A2, INPUT);
pinMode(A3, INPUT);
pinMode(A4, INPUT);
pinMode(A5, INPUT);
pinMode(A6, INPUT);
pinMode(A7, INPUT);
servo[0].attach(ch0);
servo[1].attach(ch1);
servo[2].attach(ch2);
servo[3].attach(ch3);
servo[4].attach(ch4);
servo[5].attach(ch5);
pinMode(2, OUTPUT);
pinMode(4, OUTPUT);
pinMode(7, OUTPUT);
pinMode(8, OUTPUT);
pinMode(12, OUTPUT);
millitime=millis();
}
void loop()
{
if(millis()<millitime)last_millis=millis()+((unsigned long)4294967295-millitime);
else last_millis=millis()-millitime;
millitime=millis();
for(int x=0; x<8; x++)
{ button_bools[x]=buttons&B00000001;
buttons>>1;}
servo[0].write(map(i[0], 0, 255, 0, 180));
servo[1].write(map(i[1], 0, 255, 0, 180));
servo[2].write(map(i[2], 0, 255, 0, 180));
servo[3].write(map(i[3], 0, 255, 0, 180));
servo[4].write(map(i[4], 0, 255, 0, 180));
servo[5].write(map(i[5], 0, 255, 0, 180));
rf_mode++;
if(rf_mode>8){rf_mode=1;digitalWrite(led,1);}
else digitalWrite(led,0);
if(ping_request>0)
{
ping_request--;
/* Serial.write(sinc[0]);
Serial.write(rf_mode);
Serial.write(ping);
switch(rf_mode)
{
case 1:Serial.write(v[0]);break;
case 2:Serial.write(v[1]);break;
case 3:Serial.write(v[2]);break;
case 4:Serial.write(v[3]);break;
case 5:Serial.write(v[4]);break;
case 6:Serial.write(v[5]);break;
case 7:Serial.write(v[6]);break;
case 8:Serial.write(v[7]);break;
}
Serial.write(sinc[1]);*/
}
while(Serial.available()>0)
{
if(packet_step>0)buffer_pos++;
if(buffer_pos>149){buffer_pos=0;packet_step=0;}
buffer[buffer_pos]=Serial.read();
if(buffer[buffer_pos]==sinc[0])
{
packet_step=1;
if(buffer_pos>0)
{
buffer[0]=buffer[buffer_pos];
buffer_pos=0;
}
}
else
if(packet_step==1)
{
if(buffer[buffer_pos]==sinc[1])
{
ping++;
ping_request++;
if(ping_request>254)ping_request=254;
/*receive main x1,x2,y1,y2 thumbsticks from radio*/
i[0]=buffer[2];
i[1]=buffer[3];
i[2]=buffer[4];
i[3]=buffer[5];
/*receive additional selectable analog channel from radio*/
switch(buffer[1])
{
case 1:
i[4]=buffer[6];
break;
case 2:
i[5]=buffer[6];
break;
case 3:
i[6]=buffer[6];
break;
case 4:
i[7]=buffer[6];
break;
case 5:
buttons=buffer[6];
break;
case 7:
switch(buffer[6])
{
case 0:
//custom setting value=buffer[7];
break;
}
break;
}
buffer_pos=0;
packet_step=0;
}
}
}
}
It looks like the servo library uses timer interrupts to pulse the servo, which would be delayed if serial interrupts fired.
It certainly should be possible to do the PWM in hardware (using the timers directly) rather than via interrupts, then it would not be affected by serial comms. Probably someone has already done this, but I don't have a link to hand.
Thanks for replies!
Found "PWMServo", that says to control up to three servos on Mega, not sure about Nano that I'm using though. Anyway it's not really enough for RC.
Guess my project fails here. On the other hand I suppose I could use a few Attiny85 to offload PWM if they support servo library functionality...
Edit: there's servo library for Attiny: ยป ATtiny45/85 Servo Library Cunning Turtle
I have some examples of hardware PWM on this page:
Near the bottom are some small sketches that do PWM using Timer 0. Now if you used that, you lose your millis() counter. You could probably modify it to use Timer 2 with little effort. The Timer 2 "A" output is Digital pin 11, and the Timer 2 "B" output is Digital pin 3.
kivig:
On the other hand I suppose I could use a few Attiny85 to offload PWM if they support servo library functionality...
How are you going to communicate with the Attiny85? Via serial? You haven't really solved the problem.
If you use the hardware timers though it could be OK (hardware PWM). The servo library is designed, as far as I can see, to support any pin, which is why they intervene with an interrupt handler rather than using hardware PWM. You have 6 PWM outputs on the Atmega328, so unless you need more than 6 servos, the main chip should be able to do it, with careful use of timers.
Guess I could write something like really primitive communication "protocol" through digitalWrite - even awfully wasteful transfer of six bytes shouldn't take long compared to how much time is already eaten by serial @2400.
But if it is possible to drive six servos as you say that should be a better solution Guess I'll study it. Thanks!
Maybe you can find a copy of the original arduino servo library that only supported 2 servos connected to two specific pins, to see if they used a hardware timer only method. That version was dropped during some IDE version upgrade to the present version that supports all pins.
Lefty