Welcome to Synthiam!

Program robots using technologies created from industry experts. ARC is our free-to-use robot programming software that makes features like vision recognition, navigation and artificial intelligence easy.

Get Started
Netherlands
Asked — Edited
Resolved Resolved by Jeremie!

Can I Read The Signal From An RC Receiver?

I would like to read the signal incoming from an RC receiver. How do I do that?
Use-case: I drive my robot with radio-control, animations are automatic and controlled by EZ-B. Still want to pass on radio signals to EZ-B to trigger certain animation scripts. How can I read the radio signal I get in the receiver. From a receiver I can steer a servo by just plugging it in, how can I get that signal to EZ-B in an easy way. Maybe I am overlooking something very simple but spend some time searching and still no hint.


Related Hardware EZ-Robot EZ-B v4
PRO
USA
#1   — Edited

Quote:

I would like to read the signal incoming from an RC receiver. How do I do that?
you need extra hardware. If you search the internet there are a few how-tos on how to do this. You will need an arduino controller and customized some c code, compile with Arduino IDE and flash/upload the firmware to the controller. You can instruct your arduino to read the ppm signals and send it through the serial port, then you can connect the arduino to the PC. 

Quote:

Still want to pass on radio signals to EZ-B to trigger certain animation scripts.
EZ-B controller has specific features built-in (firmware), what you want to do is not on the "features menu".  

Quote:

how can I get that signal to EZ-B in an easy way.
the simple answer is not possible. EZ-B can read analog and digital signals.  

Quote:

Maybe I am overlooking something very simple
I believe you are overlooking the full picture.

So let's brainstorm the idea:

1) you want to connect a RC receiver to EZ-B, so EZ-B has digital ports 0/1 values, analog ports can read 0-255, and serial ports (RX). How do you plan to connect this RC signal ? Let's imagine you hook it to an ADC port. 

2) ARC software: you can read ADC port, how frequent you want to read the ADC port ? To start each second, so your ARC logic reads a value (0-255) each second what you plan to do with it ?   

3) Bear in mind you are not streaming the values, you are polling the values from the EZ-B so the reaction time is constrained to specific intervals e.g. 1 second, 1/2 second, 1/4 second or less if you use a wired connection.

Deconstructing a "simple idea" can help you understand the limitations and the possibilities.

If you want to implement your idea you will need extra hardware and/or code/copy-paste some arduino code and then you will need to code your logic on ARC.
PRO
Canada
#2  
What @PTP said is spot on. Just to add to his assessment, is that you will need to decode the signals coming from the RC Receiver in order to use those specific commands to trigger events. There are Arduino projects out there that could do it, all that's required is to decode a PWM servo signal. It's likely that ARC could do this job (with any EZ-B) but it would have to be added as a feature request, as I don't think it exists yet.

ADC is an option too as different PWM servo signals will also be different in their analog voltage representation. 

You could also simply use the EZ-B to trigger events/actions when a certain channel goes high, this would just require a bunch of channels and some scripts running in ARC.
PRO
Netherlands
#3  
Thank you for the quick feedback and time to give an answer. The short summary is: not a simple solution that can be handled in SW currently. Looks like pwm to voltage converter is the best option, will do some internet searching. Thanks!
PRO
Canada
#4   — Edited
ADC pins (EZ-B v4 has 8) do automatic PWM to voltage conversion, give it a shot!
PRO
Netherlands
#5  
That is what I tried first but if I connect RC signal to an ADC pin I didn't detect a signal (eg different voltages) when I operated the remote control?
PRO
Canada
#6  
Hmmm....you are correct @Charel, it seems that the average voltage is quite low and the EZ-B's ADC has a hard time picking it up. The voltage is between 0.16V and 0.4V (0-180 servo signals). You could likely use a DAC chip or an RC Low-pass filter to make this work.
PRO
Netherlands
#7  
I have solved it the following way, I left a note for others to find it and hopefully provide a solution.

I bought a simple Arduino which is reading the  PWM RC signals and sending the results via I2C to EZ-B.
Arduino: Arduino Pro Mini 328 - 5V/16MHz.

I need to read 6 RC channels, 2 channels for a joystick (throttle, rudder) and 4 channels for levers (SC, SF, SA, SD). The levers can have 2 or 3 positions. The joystick I wanted to have a range from -25 to + 25.

Arduino code

Code:

#include 

//
// R2D2 RC conversion to I2C EZ-B interface
//
// October 2010

double pin_read; // read a pin
int out_thro; // output throttle stick temp variable
int out_rud; // output rudder stick temp variable
char out_I2C[7]; // I2C output signal
int ledState = LOW; // ledState used to set the LED


void setup() {
pinMode(2,INPUT); // Setup pin 2 for input throttle = up/down
pinMode(3,INPUT); // Setup pin 3 for input Rudder = left/right
pinMode(4,INPUT); // Setup pin 4 for input Gear / SC = trigger
pinMode(5,INPUT); // Setup pin 5 for input Aux1 / SF = tbd
pinMode(6,INPUT); // Setup pin 6 for input Aux2 / SA = 3*3 script id
pinMode(7,INPUT); // Setup pin 7 for input Aux3 / SD = 3*3 script id
pinMode(LED_BUILTIN, OUTPUT); // Setup led pin for output
Serial.begin(19200); // Setup serial for monitoring
Wire.begin(8); // join i2c bus with address #8
Wire.onRequest(requestEvent); // register event
Serial.println("RC to I2C started.");
}

void loop() {
// Do nothing except waiting for interrupt request for I2C event
delay(100);
};

void requestEvent() {
// Event function that executes whenever data is requested by I2C EZ-B master

//Pin 2 = throttle = up/down
pin_read = pulseIn(2, HIGH);
out_thro = map(pin_read, 990, 2000, 50, 100); //range of 50
out_I2C[0] = (char) out_thro; // use characters in the plain ascii range, to get to correct number substract 75

//Pin 3 = Rudder = left/right
pin_read = pulseIn(3, HIGH);
out_rud = map(pin_read, 990, 2000, 50, 100); //range of 50
out_I2C[1] = (char) out_rud; // use characters in the plain ascii range, to get to correct number substract 75

// Pin 4 = Gear = SC = trigger, 2 positions
pin_read = pulseIn(4, HIGH);
if (pin_read > 1700) {
out_I2C[2]='B';
} else {
out_I2C[2]='A';
};

// Pin 5 = Aux1 / SF = tbd, 2 positions
pin_read = pulseIn(5, HIGH);
if (pin_read > 1700) {
out_I2C[3]='B';
} else {
out_I2C[3]='A';
};

// Pin 6 = Aux2 / SA = 3 positions
pin_read = pulseIn(6, HIGH);
if (pin_read < 1200) {
out_I2C[4]='A';
} else if (pin_read >1700) {
out_I2C[4]='C';
} else {
out_I2C[4]='B';
};

// Pin 7 = Aux3 / SD = 3 positions
pin_read = pulseIn(7, HIGH);
if (pin_read < 1200) {
out_I2C[5]='A';
} else if (pin_read >1700) {
out_I2C[5]='C';
} else {
out_I2C[5]='B';
};

// Very simple control byte to check for garbled signals
out_I2C[6] = 'c';

// Write the I2C signal
Wire.write(out_I2C); // respond with message of 7 bytes as expected by EZ-B master

//Signal I2C request as blinking led signal

// if the LED is off turn it on and vice-versa:
if (ledState == LOW) {
ledState = HIGH;
} else {
ledState = LOW;
}
digitalWrite(LED_BUILTIN, ledState);

// Serial prints handy for debugging
Serial.print(out_I2C);
Serial.print(" [ ");
out_thro = (int) out_I2C[0]-75;
Serial.print(out_thro);
Serial.print(" , ");
out_rud = (int) out_I2C[1]-75;
Serial.print(out_rud);
Serial.println(" ] ");


}


And the follwing code is running in the EZ-B

Code:

#----------------------------------------#
# Script to read RC signals via Arduino #
#----------------------------------------#

#Init
$RC_SC_mem = false
$RC_rud_mem=0
$Input_I2C="error init value"

:Loopforever

#Loop
$Input_I2C=I2CRead(1, 8,7 )
#print($Input_I2C)

# control checks
if (Length($Input_I2C)!=7)
goto(Loopforever)
endif

if (GetCharat($Input_I2C,6)!="c")
# very simple control byte, if not c the data is garbled
goto(Loopforever)
endif

# get the data
$RC_thro=GetByteAt($Input_I2C,0)-75
$RC_rud=GetByteAt($Input_I2C,1)-75
$RC_SC=GetCharAt( $Input_I2C, 2 )
$RC_SF=GetCharAt( $Input_I2C, 3 )
$RC_SA=GetCharAt( $Input_I2C, 4 )
$RC_SD=GetCharAt( $Input_I2C, 5 )
#print($RC_thro + " > " + $RC_rud + " > "+ $RC_SC + " > " + $RC_SF + " > " + $RC_SA + " > " +$RC_SD )

# Process data

#-------------------------------------#
# Trigger Dome movement from RC stick #
#-------------------------------------#

if ($RC_rud=1) or ($RC_rud=-1)
$RC_rud = 0 # dead band
endif
$RC_rud = $RC_rud * -1 # change directions + is move right

if ($RC_rud>25) or ($RC_rud<-25)
# Should not be possible, safety
$RC_rud=0
endif

if ($RC_rud!=0) or ($RC_rud_mem!=0)
# Do not send a signal if two times 0 in a row, that way you can overwrite automated scripts running in parallel and end with 0 but not
# continiously stopping scripts if in neutral position by resending 0 all the time, normal automated scripts can continue to function.
$RC_rud_mem=$RC_rud #Update memory
$Dome_command = "1, s" + $RC_rud *72 + "\r\n"
#print($Dome_command)
SendSerial(1.d0, 9600,$Dome_command) # in my R2D2 the dome motor is controlled by a sabertooth via serial
endif


# todo assign a function to the throttle stick

#--------------------------------#
# Trigger scripts from RC levers #
#--------------------------------#

# SC lever is used to trigger a script identified by SA and SD

if ($RC_SC != "B")
# No trigger, do nothing, reset the memory
$RC_SC_mem = false
goto(Loopforever)
Elseif ($RC_SC="B") and ($RC_SC_mem = true)
# Two trigger in a row, do nothing, no memory reset
goto(Loopforever)
endif

# New Trigger to execute
$RC_SC_mem = true #set the memory to prevent double triggers

# Trigger a script depending on SA and SD setting

if ($RC_SA="A") and ($RC_SD="A")
print(" Ping AA remember vader")
ControlCommand("Script Manager Animations", "ScriptStart", "Remember vader")
endif

if ($RC_SA="A") and ($RC_SD="B")
print(" Ping AB remember cantina")
ControlCommand("Script Manager Animations", "ScriptStart", "Remember cantina")
endif

if ($RC_SA="A") and ($RC_SD="C")
print(" Ping AC disco")
ControlCommand("Script Manager Animations", "ScriptStart", "Disco")
endif

sleep(50)
goto(Loopforever)

Hope it is usefull for you!