Hello,
I am currently trying to make a servo filtering system that takes the PWM output of a receiver channel (throttle) and check if it is below the neutral point aka braking and then output that to the servo and anything above neutral isn't sent to the servo. The servo jitters around, however it does the overall function but not very precisely.
I have tried using interrupts for reading the PWM from the receiver to try to get a more accurate reading of the timing and that didn't work either (I originally used pulseIn). I think it is down to the 4us accuracy of the micros() function and that is then amplified when being sent out from the attiny as that also uses the micros() function for the PWM timing.
Here's the code I am currently using, this is currently the most jitter-free code I have. Using the difference filter of 8us.
#include <EEPROM.h>
/************ Pin assignments ************************************************/
/* DIP PRT PCINT EXT SYS TIME ANLG PWM1 PWM0 USI TWI PROG APP
* ----------------------------------------------------------------------------
* 1 PB5 PCINT5 RESET ADC0 dW
* 2 PB3 PCINT3 XTAL1 CLKI ADC3 _OC1B
* 3 PB4 PCINT4 XTAL2 CLKO ADC2 OC1B
* 4 GND
* 5 PB0 PCINT0 AREF AIN0 _OC1A OC0A DI SDA MOSI
* 6 PB1 PCINT1 AIN1 OC1A OC0B DO MISO IR LED
* 7 PB2 PCINT2 INT0 T0 ADC1 USCK SCL SCK Rx in
* 8 VCC
*
*/
#define RecieverIn 0 // physical pin 7
#define ServoOut 1 // physical pin 6
#define Switch A1 // physical pin 5
#define NEUTRAL_ADDRESS 0
unsigned long NeutralPosition = 0;
unsigned long RecieverDuration = 0;
unsigned long LastRecieverDuration = 0;
void setup() {
// put your setup code here, to run once:
pinMode(RecieverIn, INPUT);
pinMode(ServoOut, OUTPUT);
pinMode(Switch, INPUT_PULLUP);
if (ReadLong(0) != (0 || 0xFFFFFFFF)) { // Check if it isn't an unset value.
NeutralPosition = ReadLong(NEUTRAL_ADDRESS); // Read from EEPROM.
} else {
NeutralPosition = 1500; // Rough guess.
}
}
void loop() {
RecieverDuration = pulseIn(RecieverIn, HIGH);
if (RecieverDuration < NeutralPosition && abs(RecieverDuration - LastRecieverDuration) > 8) { // Filter with 8us difference. Will reduce reaction speed of the thing. 4us diff in, 4us diff out
writeServoPulse(ServoOut, RecieverDuration);
}
if (digitalRead(Switch) == LOW) { // Might change this to direct register to speed it up a bit.
NeutralPosition = RecieverDuration;
WriteLong(NEUTRAL_ADDRESS, NeutralPosition);
}
LastRecieverDuration = RecieverDuration;
}
// PINB to read
// PORTB to write
void writeServoPulse(int pin, unsigned long delay) {
PORTB |= (1 << pin);
unsigned long start = micros();
while (micros() - start < delay) {}
PORTB &= !(1 << pin);
}
// Taken from http://playground.arduino.cc/Code/EEPROMReadWriteLong
void WriteLong(int address, unsigned long value) {
//Decomposition from a long to 4 bytes by using bitshift.
//One = Most significant -> Four = Least significant byte
byte four = (value & 0xFF);
byte three = ((value >> 8) & 0xFF);
byte two = ((value >> 16) & 0xFF);
byte one = ((value >> 24) & 0xFF);
//Write the 4 bytes into the eeprom memory.
EEPROM.write(address, four);
EEPROM.write(address + 1, three);
EEPROM.write(address + 2, two);
EEPROM.write(address + 3, one);
}
unsigned long ReadLong(long address) {
//Read the 4 bytes from the eeprom memory.
long four = EEPROM.read(address);
long three = EEPROM.read(address + 1);
long two = EEPROM.read(address + 2);
long one = EEPROM.read(address + 3);
//Return the recomposed long by using bitshift.
return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF);
}