Trying to send PPM commands from Arduino Uno to TBS crsfr transmitter help pease?

Hi,
I'm currently trying to send PPM packets from my laptop to my Arduino to a TBS crossfire transmitter to communicate with my drone. Every time I try to communicate the drone does not seem to be able to receive any signal I have it hooked up to beta flight config but I do not see any changes.

Current setup
Laptop to Arduino Uno R3 to tbs crossfire nano to communicates with a tbs crossfire receiver on a drone with betalfight

Any input is greatly appreciated :slight_smile:

Welcome to the forum

You have given very little information to work on. For instance, what sketch is running on the Uno, how are the commands sent to the Uno from the PC, what format are the commands in, how does the Uno communicate with the software on the drone, how is the project powered, does it share a common GND with the PC, does the drone hardware share a common GND with the Uno, do all devices use the same signal voltage level ?

Please post the sketch, using code tags when you do, and a schematic of your project, a photo of a hand drawn circuit is good enough

1 Like

Try to feed the Arduino’s PPM output to an RC receiver or simulator software. This is to test signal integrity.
Check TBS Crossfire Nano TX manual. Update firmware via Agent X to ensure PPM input is enabled.

I too would like to see the code you are using to synthesize the PPM signal.

It's not clear what the laptop says to the Arduino says to the Nano TX. I'll take @ahsrabrifat at her word for the fact that this Nano TX has a PPM input mode…

Post anti code you've written for any part of this setup.Post a link to the exact transmitter to which you are connecting.

a7

Hi sorry about that,
Setup is currently I'm just trying to see if I can send ppm signals to the drone. But the arduino is plugged into my laptop just running a loop for a certain value and I'm trying the view that on beta flight but it's not coming up. the Arduino is than hooked up to a tbs crossfire transmitter connect powered by the Arduino which is hooked up on 5V,GND and port 9.
So the current code is:
#define PPM_PIN 9
#define CHANNEL_VALUE 1900 // in microseconds (can change this value)
#define FRAME_LENGTH 22500 // in microseconds (22.5 ms for one frame)
#define PULSE_LENGTH 300 // in microseconds (spacing between channels)

void setup() {
pinMode(PPM_PIN, OUTPUT);
digitalWrite(PPM_PIN, HIGH); // idle state HIGH
}

void loop() {
// Start frame sync pulse (Low)
digitalWrite(PPM_PIN, LOW);
delayMicroseconds(PULSE_LENGTH); // Sync pulse length

// Channel value: High pulse for the actual signal (variable length)
digitalWrite(PPM_PIN, HIGH);
delayMicroseconds(CHANNEL_VALUE - PULSE_LENGTH); // pulse for channel

// Rest of frame time (idle between channels)
delayMicroseconds(FRAME_LENGTH - CHANNEL_VALUE); // Fill the rest of frame

// Repeat the process
}

I can try and make a sketch later when I have the chance

Thanks again

Did you miss the requst to use code tags when posting your sketch ?

Please edit your post and add them
In my experience the easiest way to tidy up the code and add the code tags is as follows

Start by tidying up your code by using Tools/Auto Format in the IDE to make it easier to read. Then use Edit/Copy for Forum and paste what was copied in a new reply. Code tags will have been added to the code to make it easy to read in the forum thus making it easier to provide help.

It is also helpful to post error messages in code tags as it makes it easier to scroll through them and copy them for examination

Okay hopefully this looks a little better. As well I'm not receiving any errors though its really just failed to run on beta flight config. So I wonder if I did something wrong with the code or hardware wise.

#define PPM_PIN 9
#define CHANNEL_VALUE 1900 // in microseconds (can change this value)
#define FRAME_LENGTH 22500 // in microseconds (22.5 ms for one frame)
#define PULSE_LENGTH 300 // in microseconds (spacing between channels)

void setup() {
pinMode(PPM_PIN, OUTPUT);
digitalWrite(PPM_PIN, HIGH); // idle state HIGH
}

void loop() {
// Start frame sync pulse (Low)
digitalWrite(PPM_PIN, LOW);
delayMicroseconds(PULSE_LENGTH); // Sync pulse length

// Channel value: High pulse for the actual signal (variable length)
digitalWrite(PPM_PIN, HIGH);
delayMicroseconds(CHANNEL_VALUE - PULSE_LENGTH); // pulse for channel

// Rest of frame time (idle between channels)
delayMicroseconds(FRAME_LENGTH - CHANNEL_VALUE); // Fill the rest of frame

// Repeat the process
}

From the comments in the code it would appear to me that you are trying to generate two low going pulses each time you go round loop.

However you only have one

digitalWrite(PPM_PIN, LOW);

and one

digitalWrite(PPM_PIN, HIGH);

Thus you are only actually generating one low going pulse each time round loop().

Another issue is that there is a maximum value for the parameter sent to the function delayMicroseconds().

The largest value that will produce an accurate delay is 16383; larger values can produce an extremely short delay. For delays longer than a few thousand microseconds, you should use delay() instead.

For more details see: delayMicroseconds( ) and delay( ).

Here is an oscilloscope trace showing the result of your code:


That looks wrong to me.
Only the 300µs low going pulse is correct.

Actually, no

I am not sure what you did but you certainly did not follow my suggested method of adding code tags. I am sorry if asking for code tags to be used sounds pedantic but it really does make reading code and copying it for examination easier

@rangerr,
Is this what you were aiming for?

I added a second low going 300µs 'Stop pulse' to show that the Channel pulse has ended.
I split the 'Rest of frame' into two parts, each less than 16383µs.

Here is the revised code:

#define PPM_PIN 9

#define CHANNEL_VALUE 1900  // in microseconds (can change this value)

#define FRAME_LENGTH 22500  // in microseconds (22.5 ms for one frame)

#define PULSE_LENGTH 300    // in microseconds (spacing between channels)

void setup() {
  pinMode(PPM_PIN, OUTPUT);
  digitalWrite(PPM_PIN, HIGH); // idle state HIGH
}

void loop() {
  // Start frame sync pulse (Low)
  digitalWrite(PPM_PIN, LOW);
  delayMicroseconds(PULSE_LENGTH); // Sync pulse length

  // Channel value: High pulse for the actual signal (variable length)
  digitalWrite(PPM_PIN, HIGH);
  delayMicroseconds(CHANNEL_VALUE - PULSE_LENGTH); // pulse for channel

  digitalWrite(PPM_PIN, LOW);   // Added: Stop pulse ends Channel signal
  delayMicroseconds(PULSE_LENGTH);
  digitalWrite(PPM_PIN, HIGH);

  // Rest of frame time (idle between channels)  Now split into two - Each less than 16383µs
  delayMicroseconds(10000);
  delayMicroseconds(FRAME_LENGTH - CHANNEL_VALUE - PULSE_LENGTH - 10000); // Fill the rest of frame

  // Repeat the process
}

It's too soon for me to ask, but is this going for

a PPM signal consists of a long (around 4 - 5 mS) HIGH pulse as sync pulse and then channel pulses of 1 - 2 mS separated by 300 microseconds LOW pulses. Pulse period of a single channel consists of its corresponding HIGH pulse plus 300 microseconds.

?

Sounds like positive pulses, easy enough. The thread that quote came from is issuing one PPM train every 50 milliseconds.

a7