Reading Current State of RC Transmitter

Hello all,

I'm currently working on controlling a "multifunction" robot with the use of an RC transmitter, a receiver, and an Arduino. I would like to be able to send commands to the receiver, then have the receiver send a signal to the Arduino. The Arduino should then execute the action corresponding to the received signal. Right now I am beginning to brainstorm a decent way of reading the different states of the RC controller. Depending on the action I want the robot to perform, there could be a large number of active button combinations.

As of now, I have a series of if/elseif statements that check the state of the RC channels to see what commands are being received. I have 14 different state combinations so far that I've thought of. I'm sure more will be discovered later. After checking the button states, I initialize a state integer that I then use in a switch statement. Inside the switch statement is where I will place the functions that will carry out the desired actions.

My question is this: Are there any less cumbersome ways to implement this type of communication? There's always a better way to do things... Whether the proposed way will fit my time constraint (12 days), I do not know. :slight_smile: Below I've posted what I currently have. Please note that this is an outline in the strictest sense. My team members have not yet completed the hardware portion of the project, so I have not even defined input/output pins.

#define DMR_A			// Right Drive Motor dir. 1
#define DMR_B			// Right Drive Motor dir. 2
#define CH1			// Right Drive Motor RC Channel
#define DML_A			// Left Drive Motor dir. 1
#define DML_B			// Left Drive Motor dir. 2
#define CH2			// Left Drive Motor RC Channel

#define AR_A			// Right Actuator dir. 1
#define AR_B			// Right Actuator dir. 2
#define CH3			// Right Actuator RC Channel
#define AL_A			// Left Actuator dir. 1
#define AL_B			// Left Actuator dir. 2
#define CH4			// Left Actuator RC Channel

#define SSMR_A			// Right Slingshot Motor dir. 1
#define SSMR_B			// Right Slingshot Motor dir. 2
#define CH5			// Right Slingshot Motor RC Channel
#define SSML_A			// Left Slingshot Motor dir. 1
#define SSML_B			// Left Slingshot Motor dir. 2 
#define CH6			// Left Slingshot Motor RC Channel

#define GBALL_A			// Golf Ball Piston dir. 1
#define GBALL_B			// Golf Ball Piston dir. 2
#define CH7			// Golf Ball Piston RC Channel
#define LATCH_A			// Latching Piston dir. 1
#define LATCH_B			// Latching Piston dir. 2
#define CH8			// Latching Piston RC Channel

#define COMP			// Compressor Pin 
#define CH9			// Compressor Power RC Channel

int unsigned state = 0;	        // Initialize state integer

void setup()
{
	pinMode(DMR_A, OUTPUT);
	pinMode(DMR_B, OUTPUT);
	pinMode(CH1, INPUT);			// Right Drive Motor Channel
	pinMode(DML_A, OUTPUT);
	pinMode(DML_B, OUTPUT);
	pinMode(CH2, INPUT);			// Left Drive Motor Channel

	pinMode(AR_A, OUTPUT);
	pinMode(AR_B, OUTPUT);
	pinMode(CH3, INPUT);			// Right Actuator Motor Channel
	pinMode(AL_A, OUTPUT);
	pinMode(AL_B, OUTPUT);
	pinMode(CH4, INPUT);			// Left Actuator Motor Channel

	pinMode(SSMR_A, OUTPUT);
	pinMode(SSMR_B, OUTPUT);
	pinMode(CH5, INPUT);			// Right Slingshot Motor Channel
	pinMode(SSML_A, OUTPUT);
	pinMode(SSML_B, OUTPUT);
	pinMode(CH6, INPUT);			// Left Slingshot Motor Channel

	pinMode(GBALL_A, OUTPUT);
	pinMode(GBALL_B, OUTPUT);
	pinMode(CH7, INPUT);			// Golf Ball Piston Channel
	pinMode(LATCH_A, OUTPUT);
	pinMode(LATCH_B, OUTPUT);
	pinMode(CH8, INPUT);			// Slingshot Latching Piston Channel

	pinMode(COMP, OUTPUT);
	pinMode(CH9, INPUT);			// Compressor Channel

}

void loop()
{
	
	// HIGH values correspond to analog values greater than the resting point of the analog sticks. LOW values correspond to analog values lower than the resting point of the analog sticks.
	// OFF means the control is in the resting position

	if (digitalRead(CH1) == HIGH && digitalRead(CH2) == HIGH) {		// Drive Forward
		state = 1;	
	}
	else if (digitalRead(CH1) == LOW && digitalRead(CH2) == LOW) {		// Drive Backward
		state = 2;
	}
	else if (digitalRead(CH1) == HIGH && digitalRead(CH2) == LOW) {		// Turn Left
		state = 3;
	}
	else if (digitalRead(CH1) == LOW && digitalRead(CH2) == HIGH) {		// Turn Right
		state = 4;
	}
	else if (digitalRead(CH1) == HIGH && digitalRead(CH2) == HIGH && digitalRead(CH7) == HIGH) {	
// Drive Forward w/ Piston Down
		state = 5;
	}
	else if (digitalRead(CH1) == OFF && digitalRead(CH2) == OFF && digitalRead(CH7) == HIGH) {	// Golf Ball Piston Extend
		state = 6;
	}
	else if (digitalRead(CH1) == OFF && digitalRead(CH2) == OFF && digitalRead(CH7) == LOW) {	// Golf Ball Piston Retract
		state = 7;
	}
	else if (digitalRead(CH1) == OFF && digitalRead(CH2) == OFF && digitalRead(CH3) == HIGH && digitalRead(CH4) = HIGH) {		// Actuators Extend
		state = 8;
	}
	else if (digitalRead(CH1) == OFF && digitalRead(CH2) == OFF && digitalRead(CH3) == LOW && digitalRead(CH4) == LOW) {		// Actuators Retract
		state = 9;
	}
	else if (digitalRead(CH1) == OFF && digitalRead(CH2) == OFF && digitalRead(CH5) == HIGH && digitalRead(CH6) == HIGH) {		// Retract Slingshot
		state = 10;
	}
	else if (digitalRead(CH1) == OFF && digitalRead(CH2) == OFF && digitalRead(CH5) == OFF && digitalRead(CH6) == OFF && digitalRead(CH8) == HIGH) {	// Latch Slingshot		
		state = 11;
	}
	else if (digitalRead(CH1) == OFF && digitalRead(CH2) == OFF && digitalRead(CH5) == LOW && digitalRead(CH6) == LOW) {	        // Release Slingshot
		state = 12;
	}
	else if (digitalRead(CH1) == OFF && digitalRead(CH2) == OFF && digitalRead(CH5) == OFF && digitalRead(CH6) == OFF && digitalRead(CH8) == LOW) {	        // Unlatch Slingshot
		state = 13;
	}
	else if (digitalRead(CH1) == OFF && digitalRead(CH2) == OFF && digitalRead(CH9) == HIGH) {		// Start Compressor
		state = 14;
	}


	switch (state) {
		case 1: 
			forward();
			break;
		case 2:
			backward();
			break;
		case 3:
			turnRight();
			break;
		case 4:
			turnLeft();
			break;
		case 5:
			forward_pist();
			break;
		case 6:
			gb_piston_ext();
			break;
		case 7:
			gb_piston_retr();
			break;
		case 8:
			lift();
			break;
		case 9:
			lower();
			break;
		case 10:
			ss_retr();
			break;
		case 11:
			latch();
			break;
		case 12:
			ss_release();
			break;
		case 13:
			unlatch();
			break;
		case 14:
			comp_power();
			break;
	}
}

If any of you have any feedback, I'd more than appreciate it. I'd love to discover that my method will not work sooner rather than later. Thank you!

Build up the state variable by setting bits in a byte instead of all those messy if then statements. Make this even shorter by using an array to define the pin numbers so you can do it in a loop.

Aren't the signals on the CHx pins a PPM signal that varies with the servo position commanded?
Also, what is the value of "OFF"?

As 756E6C indicates, you are misunderstanding how RC receivers communicate with servos.

2 ways I know of to read RC receiver output
-pulsein which is easy to implement but wastes lots of processing time waiting for the pulse to complete
-interrupts attached to the rising and falling of the pins connected to the receiver which is a bit harder to set up but uses very little processing time to manage the receiver.

I have several examples on my laptop. I will post links later when I fire that up.

In the mean time, go read up about PPM and servo communication.

Interrupt driven RC receiver reading
http://playground.arduino.cc/Code/ReadReceiver

RCArduino: How To Read an RC Receiver With A Microcontroller - Part 1 This one emphasizes "Don't use pulsein!" :slight_smile:
And part 2

And pulsein driven RC receiver reading
https://www.sparkfun.com/tutorials/348

Read through the interrupt driven links. They will help you understand how the receiver-servo communication works.

Try out the examples with just a few channels, without any of your robot code. Just a sketch to read the receiver and print the values.
The try to expand those examples to all 9 of the channels you intend to use.

After you have chosen which method you want to use and get it running, then you can start trying to tie it in to your logic for the robot control.

Thanks everyone for the replies.

As I mentioned, this is an outline, so there is stuff that definitely does not make sense. The HIGH, LOW and OFF values are pretty much placeholders until I figured out the signal stuff. I know it's not as simple as just doing a digitalRead() on everything. Lol, I will be sure to do some reading up on PPM.

So far, it seems as though the pulseIn() command will work best for me. I do like interrupts, but there are only 6 digital pins that can be configured to be an interrupt and I have 9 channels being used.

Grumpy_Mike:
Build up the state variable by setting bits in a byte instead of all those messy if then statements. Make this even shorter by using an array to define the pin numbers so you can do it in a loop.

Thank you for mentioning this. I haven't really delved too far into programming as I'm a lowly mechE student :slight_smile: This will tidy up my program significantly.

Again, thanks everyone for the help. I will report back once I've done further research and have made a bit of progress!

but there are only 6 digital pins that can be configured to be an interrupt and I have 9 channels being used.

No, any pin can trigger an interrupt using the state change method.

See this project as an example of how to write code like this :- http://www.thebox.myzen.co.uk/Hardware/Crazy_People.html

Just wanted to follow up with everyone. I've managed to getting the robot working with the interrupt method with little to no trouble. Thank you to everyone who replied. I am very appreciative!