I am trying to build a circuit that reads in a PWM signal from a RC remote then controls the position of a DC motor with a quadrature encoder.
I am building my code off of a tutorial by www.HomoFaciens.de.
The circuit is wired up as shown (plus a variable resistor going to pin A1 and a PWM signal going to pin 8).
I modified the original code to run off input from an analog input from a variable resistor to try and get it working. Using analogRead the entire circuit works great.
However, when i try to read in a PWM pulse from an RC receiver (using either PulseIn or using interrupts), I get some strange behavior. My "actualPoint" variable starts acting all crazy, even though the PWM signal is being read correctly (or so I think) another strange behavior of this code is that if Serial.println() is used, seemingly at all, my actualPoint variable gets broken.
Code is as follows:
//Digital wiper motor servo
//Source & info at: www.HomoFaciens.de/technics-base-circuits-encoder-disc_en_navion.htm
#include <util/delay.h>
int stepStatus = 0;
int sensorStatusA = 0;
int sensorStatusB = 0;
int count = 0;
int stepDone = 0;
int diffTime = 0;
signed long PotPosition = 0;
signed long prevPot = 0;
unsigned long millisStart = 0;
unsigned long millisNow = 0;
unsigned long millisDiff = 0;
int dutyCycle = 0;
signed long setPoint = 0;
signed long actualPoint = 0;
byte readByte = 0;
#define ENABLE_R 10
#define ENABLE_L 9
#define PWM_IN 8
#define SENSOR_A 3
#define SENSOR_B 4
#define ANALOG_IN A1
#define MOTOR_DIRECTION 5
#define MOTOR_PWM 6
#define LED 13 //Status LED of servo
#define P_FRACTION 1 //Proportional factor of control loop 0.001 - 10.0 (1.0)
#define I_FRACTION 0.3 //Integral factor of control loop 0.0 - 10.0 (0.3)
#define SOFT_START 0.0005 //0.0 - 1.0 (0.0005)
#define STEP_MARGIN 22 //10 - 1000 (1)
#define MIN_DUTYCYCLE 125 //0 - 255 (125)
#define MAX_DUTYCYCLE 255 //0 - 255 (255)
void setup() {
//Serial.begin(9600);
pinMode(SENSOR_A, INPUT);
pinMode(SENSOR_B, INPUT);
pinMode(ANALOG_IN, INPUT);
pinMode(PWM_IN, INPUT);
pinMode(LED, OUTPUT);
pinMode(MOTOR_DIRECTION, OUTPUT);
pinMode(MOTOR_PWM, OUTPUT);
analogWrite(MOTOR_PWM, 0);
digitalWrite(LED, 1);
count = 0;
}
void loop() {
PotPosition = pulseIn(PWM_IN, HIGH, 25000); // FirePin
//PotPosition = analogRead(ANALOG_IN);
if ((PotPosition > prevPot+5) || (PotPosition < prevPot-5)) {
//setPoint = map(PotPosition, 0, 1023, 0, 36*22*2);
setPoint = map(PotPosition, 980, 1980, 0, 36*22*2);
prevPot = PotPosition;
}
sensorStatusA = digitalRead(SENSOR_A);
sensorStatusB = digitalRead(SENSOR_B);
diffTime++;
if(sensorStatusB == 0 && sensorStatusA == 0){
if(stepStatus == 1){
actualPoint--;
diffTime = 0;
}
if(stepStatus == 3){
actualPoint++;
diffTime = 0;
}
stepStatus = 0;
}
if(sensorStatusB == 1 && sensorStatusA == 0){
if(stepStatus == 0){
actualPoint++;
diffTime = 0;
}
if(stepStatus == 2){
actualPoint--;
diffTime = 0;
}
stepStatus = 1;
}
if(sensorStatusB == 1 && sensorStatusA == 1){
if(stepStatus == 3){
actualPoint--;
diffTime = 0;
}
if(stepStatus == 1){
actualPoint++;
diffTime = 0;
}
stepStatus = 2;
}
if(sensorStatusB == 0 && sensorStatusA == 1){
if(stepStatus == 2){
actualPoint++;
diffTime = 0;
}
if(stepStatus == 0){
actualPoint--;
diffTime = 0;
}
stepStatus = 3;
}
dutyCycle = (double)(abs(setPoint - actualPoint)) * (double)P_FRACTION;
dutyCycle += (double)(diffTime * I_FRACTION);
if(dutyCycle < MIN_DUTYCYCLE){
dutyCycle = MIN_DUTYCYCLE;
}
if(dutyCycle > MAX_DUTYCYCLE){
dutyCycle = MAX_DUTYCYCLE;
}
if(SOFT_START * (double)(millisNow - millisStart) < 1.0){
dutyCycle = (double)(dutyCycle * SOFT_START * (millisNow - millisStart));
}
if(dutyCycle < MIN_DUTYCYCLE){
dutyCycle = MIN_DUTYCYCLE;
}
if(dutyCycle > MAX_DUTYCYCLE){
dutyCycle = MAX_DUTYCYCLE;
}
if(abs(setPoint - actualPoint) < STEP_MARGIN){
stepDone = 1;
diffTime = 0;
analogWrite(MOTOR_PWM, 0);
digitalWrite(MOTOR_DIRECTION, 0);
digitalWrite(ENABLE_R, 0);
digitalWrite(ENABLE_L, 0);
}
else{
digitalWrite(ENABLE_R, 1);
digitalWrite(ENABLE_L, 1);
if(actualPoint < setPoint){
digitalWrite(MOTOR_DIRECTION, 1);
analogWrite(MOTOR_PWM, 255 - dutyCycle);
}
if(actualPoint > setPoint){
digitalWrite(MOTOR_DIRECTION, 0);
analogWrite(MOTOR_PWM, dutyCycle);
}
}
millisNow = millis();
if(millisStart > millisNow){
millisStart = millisNow;
}
}
Anyone have any ideas? Maybe there is a better way to do this that I didn't find yet.
digital-servo-L298N.pdf (700 KB)