EDIT: On second thought, can this be moved to the programming questions forum? This involves servos but probably not in the way this section meant..
I'm having some issues. I have a foolproof code setup (modified from some example I found ages ago to not use timer1) to read the ppm signal coming from a drone style radio rx.
That part works fine, mostly. Some jitter but that could be the radio.
Then, I want to read this ppm signal, extract all the things, which I can do, and then manipulate, do whatever, and then send it out to two servos. I'm reading the ppm signal and using it to smooth, limit, and control a pan-tilt servo setup on a drone.
My issue is that I seem to be fighting some jitter. What I imagine is going on is that my timer interrupts for the servo library and the interrupts for reading the rising edge change on the ppm signal are hitting each other and causing minute microsecond delays to the servo signal output, causing jitter. Same with the input, could also be causing the jitter.
I know there are arduino based systems that control servos and escs and also read ppm in without issue, so.. How does that happen? What am I missing?
I've resorted to adding a significant 'dead spot' to the pan-tilt inputs to stop the jitter when centered but even when getting a solid manually entered variable, if the ppm system is working, the servo jumps ever so slightly, annoying when there is a camera attached.. Ignore the ADC stuff, haven't worked on that yet.
//plane central controller
//libraries
#include <TaskScheduler.h>
#include <eRCaGuy_Timer2_Counter.h>
#include <Servo.h>
//-----
//ADC stuff
#define SELPIN A6 //Selection Pin
#define DATAOUT 11//MOSI
#define DATAIN 12//MISO
#define SPICLOCK 13//Clock
int readvalue;
//-----
//set pins on stuff
int panservo = 10;
int tiltservo = 9;
//servo vars
Servo pan;
Servo tilt;
int panleftlimit = 900;
int panrightlimit = 2100;
int tiltdownlimit = 1200;
int tiltuplimit = 2200;
int panpwm = 1530;
int tiltpwm = 1530;
//-----
//ppm channel setting
int panchannel = 8;
int tiltchannel = 9;
int navlightchannel = 6;
int gearbrakeschannel = 4;
//-----
//Pin connected to PPM input
const int ppm_pin = 2;
//ppm value array
volatile int ppm[16];
//-----
//scheduler stuff
void servodrivercallback();
void heartbeatcallback();
void navlightflashercallback();
Task servodriver(20, TASK_FOREVER, &servodrivercallback); //servo driver clock
Task heartbeat(500, TASK_FOREVER, &heartbeatcallback); //heartbeat clock
Task navlightflasher(100, TASK_FOREVER, &navlightflashercallback); //nav light flash callback
Scheduler runner; //scheduler object
//-----
//pin vars
int heartled = 4;
int navpsuenable = 8;
int strobeled = 5;
int alarmled = 21;
//-----
//general vars
bool heartbeatflag = false;
bool navledpowersetting = true;
int strobeflashcounter = 0;
int strobeflashdelay = 20;
//-----
void setup() {
timer2.setup();
analogReference(EXTERNAL); //so no booms happen
pinMode(heartled,OUTPUT); //heartbeat led pinmode
pinMode(alarmled,OUTPUT); //alarm led pinmode
pinMode(strobeled,OUTPUT); //strobe led pinmode
pinMode(SELPIN,OUTPUT); //Selection Pin
pinMode(DATAOUT,OUTPUT); //MOSI
pinMode(DATAIN,INPUT); //MISO
pinMode(SPICLOCK,OUTPUT); //Clock
pinMode(tiltservo,OUTPUT); //servo tilt
pinMode(panservo,OUTPUT); //servo pan
Serial.begin(57600);
//inputs
pinMode(ppm_pin, INPUT);
//interrupts
attachInterrupt(ppm_pin - 2, read_ppm, CHANGE);
//servo stuff
pan.attach(panservo);
tilt.attach(tiltservo);
//scheduler stuff
runner.addTask(servodriver); //add task to.. thing
runner.addTask(heartbeat); //add task to.. thing
runner.addTask(navlightflasher);
servodriver.enable(); //enable it
// heartbeat.enable(); //enable this too
navlightflasher.enable();
//pin setting stuff
digitalWrite(navpsuenable, !navledpowersetting);
digitalWrite(alarmled, HIGH);
delay(100);
digitalWrite(alarmled, LOW);
}
void loop() {
runner.execute(); //runs scheduler
}
page 2
void servodrivercallback() {
panpwm = map(ppm[panchannel],1644,1404,panleftlimit,panrightlimit);
tiltpwm = map(ppm[tiltchannel],1380,1644,tiltuplimit,tiltdownlimit);
if(panpwm > 1400 && panpwm < 1600) {
panpwm = 1500;
}
if(tiltpwm > 1585 && tiltpwm < 1785) {
tiltpwm = 1685;
}
pan.write(panpwm);
tilt.write(tiltpwm);
//debug stuff
Serial.print("PAN: ");
Serial.print(panpwm);
Serial.print(" ");
Serial.print("TILT: ");
Serial.print(tiltpwm);
Serial.print(" ");
Serial.print("NAVLED: ");
Serial.print(ppm[navlightchannel]);
Serial.print(" ");
Serial.print("BRAKES: ");
Serial.print(ppm[gearbrakeschannel]);
Serial.print(" ");
Serial.print("PPMPAN: ");
Serial.print(ppm[panchannel]);
Serial.print(" ");
Serial.print("PPMTILT: ");
Serial.print(ppm[tiltchannel]);
Serial.println("");
}
void heartbeatcallback() { //just flash the led to make sure everything is still alive
heartbeatflag = !heartbeatflag;
if(navledpowersetting == true) {
digitalWrite(heartled,heartbeatflag);
}
if(navledpowersetting == false) {
digitalWrite(heartled, LOW);
}
}
void navlightflashercallback() {
navledpowersetting = false; //start at zero
if(ppm[navlightchannel] > 1600) { //check ppm channel for light control
navledpowersetting = true;
}
digitalWrite(navpsuenable, !navledpowersetting); //set psu state
if(navledpowersetting == false) { //check that nav power is on. if its not, just write an off
digitalWrite(strobeled, LOW);
digitalWrite(heartled, LOW);
}
if(navledpowersetting == true) { //if it is on, then do your flashing work
digitalWrite(strobeled, LOW); //default to off
digitalWrite(heartled, LOW);
if(strobeflashcounter == 1 || strobeflashcounter == 4) { //if it is 2 of the delay times, turn on, otherwise its off
digitalWrite(strobeled, HIGH);
digitalWrite(heartled, HIGH);
}
}
strobeflashcounter++;
if(strobeflashcounter >= strobeflashdelay) { //reset timer after a set delay to repeat the sequence
strobeflashcounter = 0;
}
}
void read_ppm(){ //leave this alone
static unsigned int pulse;
static unsigned long counter;
static byte channel;
static unsigned long lastmicros;
counter = timer2.get_count() - lastmicros;
lastmicros = timer2.get_count();
if(counter < 1020){ //must be a pulse if less than 510us
pulse = counter;
}
else if(counter > 3820){ //sync pulses over 1910us
channel = 0;
}
else{ //servo values between 510us and 2420us will end up here
ppm[channel] = (counter + pulse)/2;
channel++;
}
}
int read_adc(int channel){
int adcvalue = 0;
byte commandbits = B11000000; //command bits - start, mode, chn (3), dont care (3)
//allow channel selection
commandbits|=((channel-1)<<3);
digitalWrite(SELPIN,LOW); //Select adc
// setup bits to be written
for (int i=7; i>=3; i--){
digitalWrite(DATAOUT,commandbits&1<<i);
//cycle clock
digitalWrite(SPICLOCK,HIGH);
digitalWrite(SPICLOCK,LOW);
}
digitalWrite(SPICLOCK,HIGH); //ignores 2 null bits
digitalWrite(SPICLOCK,LOW);
digitalWrite(SPICLOCK,HIGH);
digitalWrite(SPICLOCK,LOW);
//read bits from adc
for (int i=11; i>=0; i--){
adcvalue+=digitalRead(DATAIN)<<i;
//cycle clock
digitalWrite(SPICLOCK,HIGH);
digitalWrite(SPICLOCK,LOW);
}
digitalWrite(SELPIN, HIGH); //turn off device
return adcvalue;
}