I am trying to create a code that decodes a pulse sequence into commands for a DC motor (with an L293D driver) and a servo. The signal appears as four "synchronization" pulses of approximately 1500 us in width, followed by a "command" sequence of x number of pulses with a pulse width y (between 500 and 1000 us). The amount of command pulses (pulse count, PC) determine the specific "command mode", and the pulse width determines the angle that the servo will rotate to.
After that brief explanation, the problem I'm having is that, according to the serial monitor, not all of the sync pulses are being recognized, meaning the code cannot properly accept the upcoming command pulse sequence. Even without the check that disallows the ISR from registering the command pulse without recognizing all four sync pulses consecutively, the Arduino only seems to read some of the four sync pulses. Note that with an oscilloscope, I have noted that the signal is being sent properly. If the signal is a problem, then it should only be from the frequency (490 Hz), the voltage spike from the rising side of the pulse before it settles to the standard HIGH-state voltage (5 V), or the pulse widths being too small.
If it is from the above possible hardware problems, then I will just change the frequency of the signal to be lower or get a zener diode to limit the spike. But if it is a code problem, then I would like help in trying to figure out the problem. Below is my receiver code (the transmitter code is also attached for reference):
#include <Servo.h>
Servo RCServo; // create a servo object
int receiverPin = 3;
int servoPin = 11;
int motorPinForward = 12;
int motorPinBackward = 13;
// All previous constants which may be necessary for this code
// Pulse Widths
const int centerPW = 750; // Standard Pulse Width for no turning
const int minPW = 500; // Minimum Pulse Width for turning
const int maxPW = 1000; // Maximum Pulse Width for turning
const int syncPW = 1500; // Synchronization Segment Pulse Width
const int errorPW = 50;
const int maxAngle = 180;
const int restAngle = 90;
const int minAngle = 0;
const int angleRate = 5;
// Pulse Counts for each mode of operation
const int forwardPC = 15;
const int backwardPC = 40;
const int leftPC = 25;
const int rightPC = 30;
const int forwardLeftPC = 10;
const int backwardLeftPC = 20;
const int forwardRightPC = 35;
const int backwardRightPC = 45;
const int syncPC = 4;
const float period_us = 1000000 / 490;
const float remain = period_us - syncPW;
const float angle_min = ((maxPW - minPW) / (maxSig - minSig)) * (minSig - minSig) + minPW;
const float angle_max = ((maxPW - minPW) / (maxSig - minSig)) * (maxSig - minSig) + minPW;
const float angle_rest = ((maxPW - minPW) / (maxSig - minSig)) * (restSig - minSig) + minPW;
int PW = 0;
int i = 0;
int syncCount = 0;
int prevSyncCount = 0;
int PC = 0;
int duration[45];
void setup() {
pinMode(servoPin, OUTPUT);
pinMode(motorPinForward, OUTPUT);
pinMode(motorPinBackward, OUTPUT);
pinMode(receiverPin, INPUT);
RCServo.attach(servoPin);
attachInterrupt(digitalPinToInterrupt(receiverPin), signalCommand, RISING);
Serial.begin(9600);
}
void loop() {
//motorServoCommand(PC, duration);
}
void signalCommand() {
//Serial.println("ISR Active");
PW = pulseIn(receiverPin, HIGH); // May not actually measure as the RISING in the attachinterrupt() may cause
// pulseIn() to not register the HIGH
if (PW >= syncPW - errorPW && PW <= syncPW + errorPW && syncCount < 5) {
syncCount++;
if (syncCount == 5) {
motorServoCommand(PC, duration);
syncCount = 1;
PC = 0;
i = 0;
for (int j = 0; j < 45; j++) {
duration[j] = 0;
}
}
}
else if (PW >= minPW - errorPW && PW <= maxPW + errorPW && syncCount == 4) {
PC++;
duration[i] = PW;
i++;
}
else {
syncCount = 0;
PC = 0;
i = 0;
for (int j = 0; j < 45; j++) {
duration[j] = 0;
}
}
Serial.print(PW); Serial.print(", ");
Serial.print(syncCount); Serial.print(", "); Serial.print(PC); Serial.print(", ");
Serial.print(i); Serial.print(", "); Serial.println(duration[i]);
}
void motorServoCommand(int PC, int duration[]) {
int ave = 0;
int k = 0;
int motorDir = 1; // motorDir: 0 - Back, 1 - None, 2 - Forward
int turnDir = 1; // turnDir: 0 - Left, 1 - None, 2 - Right
//Serial.print("Running Command, ");
switch (PC) {
case 15: // Forward
motorDir = 2;
turnDir = 1;
break;
case 40: // Backward
motorDir = 0;
turnDir = 1;
break;
case 25: // Left
motorDir = 1;
turnDir = 0;
break;
case 30: // Right
motorDir = 1;
turnDir = 2;
break;
case 10: // Forward-Left
motorDir = 2;
turnDir = 0;
break;
case 20: // Backward-Left
motorDir = 0;
turnDir = 0;
break;
case 35: // Forward-Right
motorDir = 2;
turnDir = 2;
break;
case 45: // Backward-Right
motorDir = 0;
turnDir = 2;
break;
default:
motorDir = 1;
turnDir = 1;
break;
}
motorCommand(motorDir);
servoCommand(turnDir, duration);
}
void motorCommand(int motorDir) {
if (motorDir == 2) { // Forward
/*
* Forward Code
*/
//Serial.print("Forward, ");
digitalWrite(motorPinForward, HIGH);
digitalWrite(motorPinBackward, LOW);
}
else if (motorDir == 0) { // Backward
/*
* Backward Code
*/
//Serial.print("Backward, ");
digitalWrite(motorPinForward, LOW);
digitalWrite(motorPinBackward, HIGH);
}
else { // None
/*
* Rest Code
*/
//Serial.print("Motor Off, ");
digitalWrite(motorPinForward, LOW);
digitalWrite(motorPinBackward, LOW);
}
}
void servoCommand(int turnDir, int duration[]) {
float avePW = 0.0;
int k = 0;
for (int j = 0; j < 45 && duration[j] != 0; j++) {
avePW = avePW + duration[j];
k = j;
}
avePW = avePW / k;
if (turnDir == 2) {
//float anglePWM_R = ((pw_max - pw_rest) / (maxSig - (restSig + shiftSig))) * (PW_s - (restSig + shiftSig)) + pw_rest;
int angleR = map(avePW, centerPW, maxPW, restAngle, maxAngle);
Serial.print(angleR); Serial.println(", ");
/*
* Right Code
*/
for (int pos = restAngle; pos <= angleR; pos = pos + angleRate) {
RCServo.write(pos);
}
}
else if (turnDir == 0) {
//float anglePWM_L = ((pw_rest - pw_min) / ((restSig - shiftSig) - minSig)) * (PW_s - minSig) + pw_min;
int angleL = map(avePW, minPW, centerPW, minAngle, restAngle);
Serial.print(angleL); Serial.println(", ");
/*
* Left Code
*/
for (int pos = restAngle; pos >= angleL; pos = pos - angleRate) {
RCServo.write(pos);
}
}
else {
/*
* Rest Code
*/
//Serial.println("No Turning, ");
RCServo.write(restAngle);
}
}
EECE4991TransmitterCode.ino (5.2 KB)