Thread Tools
May 07, 2012, 10:39 AM
ROFLCOPTER
Iron Savior's Avatar
Thread OP
Discussion

Arduino Library for custom DSM2 TX


I wanted to put this out there in case anyone might benefit from it. I wrote an Arduino library to facilitate projects that incorporate the RF modules taken from some DSM2 transmitters (like MLP4DSM or DX5e/DX4e). I started writing this because I am working on a project where I want to use a microcontroller to control DSM2-compatible receivers with my own choice of custom hardware for control input. You might also use this library where you want to write custom transmitter logic like servo slowing, dual rates, expo, custom throttle/pitch curves, custom mixes, etc, etc, etc.

The example sketch illustrates basic functionality--how to bind and send commands.

The latest version is kept on GitHub: https://github.com/IronSavior/dsm2_tx (direct download link:)

Advanced usage notes:

It is possible to use a single donor RF module to control more than one receiver and thereby gaining more channels of input. This is achieved by alternating between model-match ID's between frames. For example, you place two receivers in the same model and you bind one receiver to model ID 0 and another to model ID 1 and you send channels 1-6 to the receiver with model ID 0 and a separate 6 channels to the receiver with model ID 1.

However, you cannot send more than one frame every 10 milliseconds through the same donor module. Keep this in mind because you can only update one receiver every 1 / (n*100) seconds where n is the number of concurrent receivers. You will lose resolution in terms of update opportunities per second across all receivers. It is unknown to me the minimum rate at which a receiver expects to be updated before assuming the signal has been lost.

assuming 6 channels per receiver:
(based on some parts observation, some parts speculation)
1 Rx; you can update it 100 times per second, 10ms between frames and you get 6 channels
2 Rx; update all receivers up to 50 times per second, 20ms between frames, 12 channels
3 Rx; update only 33 times per second, 30ms between frames, 18 channels
4 Rx; update 25 times per second, each receiver waiting 40ms between frames, but you get 24 channels of control.

Instantiate ONLY ONE DSM2_tx object per physical donor radio! You don't have to worry about limiting requests to one per 10 ms as the library will add delays as necessary. I'm working on a way to remove the delays in a future release.

(This part is speculation; I haven't tested this idea yet) It might be possible to achieve a finer resolution when using more than one receiver by using more than one donor module in combination with a mux/demux (like a 74HC4052) on the arduino's serial tx line (pin 1). In this case, you would want to instantiate a DSM2_tx object for each physical donor radio as the object tracks its own transmission rate.

[update 5/8/2012: Added a sketch to demonstrate the multiple receiver use case.]
[update 10/11/2012: Added test code that runs on PC and updated download link.]
Last edited by Iron Savior; Oct 30, 2012 at 02:56 PM.
Sign up now
to remove ads between posts
May 07, 2012, 06:51 PM
I don't want to "Switch Now"
pmackenzie's Avatar
Hi -
A couple of points/questions.

-Regarding frame rates, some of the receivers are quite picky about them.
The ones that output the servo signals sequentially (eg AR6100) don't like it if the frame width is less than the time to output all 6 pulses. They continue to work, but the servos get twitchy. The faster receivers like the AR8000 work fine at 11msec frames.

- I was unable to get the multiple receiver thing to work. When I tried it alternating between two model match codes both simply stopped working. My test code let me select "A" or "B", or both "A" and "B".
Switching between them took a long time for the receiver to recover, and alternating every frame killed them both till a single one was selected.

It could have been a receiver problem, which ones did you test with? I have only genuine Spektrum ones.

- I was unable to get anything beyond 6 channels with any of the modules I tried (LP4DSM2, LP6DSM2 and DX4e). Can you post some details, including which modules and receivers you have done it with?

All my testing/development was in C for ER9X, so is not Arduino based. It would be great to break the 6 channel barrier in particular.

Thanks,

Pat MacKenzie
May 07, 2012, 09:14 PM
ROFLCOPTER
Iron Savior's Avatar
Thread OP
So far, I have only personally used the module taken from a MLP4DSM. It doesn't give me any feedback digitally regarding how long the frames are taking to transmit. I landed on 10ms through experimentation--it may very well be different for other modules, but I don't think that it is. I have a module from a DX4e that I intend to start working with soon and I understand the serial protocol to be the same, I suppose there's only one way to find out.

I have been doing my testing with the orange DSM2 receivers, so I may need to spend some time with some genuine Spektrum brand to see if makes a difference.

So far, I haven't tried to go beyond 6 channels with a single receiver. I suspect that the low-cost modules from MLP4DSM (et, al) and DX4/5e are the limiting factor (speculation). I only have one DSM2 receiver that gets more than 6 channels and it's also an orange knock-off. I mean to test this idea using this receiver, I just haven't done it yet.

I have experimented with using 2 concurrent receivers with promising results. As long as I never tried to send frames more often than 1 per 10ms (each receiver getting 1 frame per 20ms), I never had any glitching problems and the receivers acted normal on the bench. I will put together a sketch that demonstrates this and add it to the examples.
May 08, 2012, 07:45 AM
ROFLCOPTER
Iron Savior's Avatar
Thread OP
I just added a sketch to demonstrate multiple receiver usage. I might put together a schematic or maybe a video later on. The schematic shouldn't really be necessary, it's a basic setup with 2 buttons and 3 LED's (the error LED might not be necessary, but I like the examples to provide for it). You have to bind each receiver to model ID 0 or 1 before you can send commands to them separately. You bind just like any real DSM2 transmitter--hold down the bind button as you turn on the power. The only difference is there are two bind buttons.

It's important to note that the donor radio module has to be powered off and back on to re-enter bind mode. Since my module was powered by the arduino (the low power RF module draws 20mA max, but a full-range variant should have it's own power source), I entered bind mode by holding the bind button as I plugged in the usb cable and then unplugged it and did it again with the other button until both RX's were bound correctly. Obviously, you can't bind them both at the same time.

I'll see if I can't break the 6 channel barrier or at least test with some genuine Spektrum receivers when I get home later.
May 08, 2012, 04:32 PM
ROFLCOPTER
Iron Savior's Avatar
Thread OP
Good news and bad news.

The good news is that I unless I've gone insane, I did get some response on channel 7 when using the donor radio from a DX4e. It wasn't quite right and I got distracted before I could dial it in (and I'm up way past my bedtime now). Sending more than 6 channels of data makes the LP4DSM not function at all.

The bad news is that I only have one receiver with more than 6 channels and I have discovered that it's not quite right and therefore I cannot trust it. Channel 1 on that Rx is completely dead no matter the circumstances, who knows what else is wrong with it.

So I'm hopeful, but I don't have the requisite equipment to test further for channels higher than 7 for now.
Oct 11, 2012, 10:58 AM
ROFLCOPTER
Iron Savior's Avatar
Thread OP

I needed a testing framework


It occurred to me that the conventional development cycle on arduino is too cumbersome and haphazard. For this project, that meant having all of the hardware and batteries with me and ready to use when I have time to work on this. When those pieces fall into place, I write some code and then I can upload that to the arduino and then the only method I have of verifying that it works the way I expect is to run the code and observe the result. This is a problem because I don't have any finer instrumentation with which to look deeper into discrete sections of my code. All I can do is just see if it does what I expect this time or not--if it does, I conclude that it's working correctly (not a safe assumption even when it seems to behave correctly) and then if it does not, then I just have to guess at what is wrong. I find this cycle has a lot of wasted time and isn't scientific enough for my tastes.

I thought that someone else surely has solved this problem before, but what I found was that some people were using arduino emulators. While that seems like a logical place to go, I didn't care for that option because I don't want to test the functionality of the Arduino--The arduino's behavior is not going to change, so I can pretty much assume that it is going to behave correctly (or at least consistently wrong). I may as well just make assumptions about any contact points between my code and the Arduino because It's really only helpful for me to get feedback on my own project's code.

What I decided to do about this was to implement a testing apparatus that runs on the PC that can isolate and test the code that I write. This will give me feedback that is targeted to any discreet unit of code. The idea here is that my test code checks to make sure behavior matches expectations and my expectations are based on assumptions made about the Arduino. If the tests check out and my assumptions are correct, then the code will behave properly when run on the microcontroller.

Also, this frees me to work on this code whenever I want without actually needing the extra hardware to be with me at the time, which also means I don't have to do the code-upload-observe-repeat cycle which will save a lot of time.
Oct 28, 2012, 08:37 PM
Pilot, Co-pilot, Navagator
nemoskull's Avatar
been looking at your code for a few hours, and i got a few questions.
i noticed a 'set_channel', is this to say you need to manually set the 2.4 ghz channels or is this optional?
how do you send stick data?
Oct 28, 2012, 10:16 PM
ROFLCOPTER
Iron Savior's Avatar
Thread OP
Quote:
Originally Posted by nemoskull
been looking at your code for a few hours, and i got a few questions.
i noticed a 'set_channel', is this to say you need to manually set the 2.4 ghz channels or is this optional?
how do you send stick data?
Have you looked at the example sketch called DSM2_tx_proof? I created that as a bare-bones demonstration of how to use the class. That sketch does binding in the setup() routine if a button is pressed at power-up and then the loop causes the servos on all channels to sway back and forth.

Line 26 creates the object that talks to the radio and tells it that it has 6 channels. Line 70 invokes the bind function of the radio (if the button was pressed at startup). The parameter to the bind function is a callback--it's a function that the sketch writer provides so the the library can call it at various stages of binding (see function starting on line 34)--this allows the sketch writer to handle any user interface business that reflects the state of binding. In this sketch, the callback makes an LED flash during bind as a demonstration.

In the loop() routine, line 77 sets each channel to the value chosen by next_step(). Finally, line 79 tells the radio to transmit the frame. Then the loop() routine starts over again.

The set_channel method sets the value of a specific channel in the buffer. In the sketch, the value is varied between 0 and MAX_VALUE (defined as 200 in the sketch). The set_channel method performs a linear map to size the input to the actual unsigned 10-bit integer format required by the buffer. You can inspect the source code of the library to see how that works.

I intend to change this interface a bit in the near future, but when I do, I will also update the example sketches to illustrate how to use it.
Last edited by Iron Savior; Oct 28, 2012 at 10:26 PM.
Mar 11, 2013, 04:22 PM
Registered User
Hi, I am currently trying your code because I had problems with another implementation I was using before. I am not able to make it bind but have to admit, I made some small changes to your code: As I am owning the MegaADK, I am using Serial for debug output and have therefore switched your initialization and sending code to Serial1.

The state of the bind process switches from 1 to 0, the model Id stays 0 after some seconds.

Here is my HW layout: Switch to initiate binding on Analog 2, AMTX11 on 3.3V with signal connected to TX1, using USB as power-source for now.

Can you give me a hint what I am doing wrong?

Thank you for your efforts in advance,
Greetings from Austria,

Romout


EDIT: Just got it to work - I compared your initialization code with the otherone I had and figured out, the other used 0x080 as bind magic header, not 0x098 - but also didn't work on my first try.
Last edited by Romout; Mar 11, 2013 at 04:29 PM.
Mar 11, 2013, 04:56 PM
ROFLCOPTER
Iron Savior's Avatar
Thread OP
Quote:
Originally Posted by Romout
Hi, I am currently trying your code because I had problems with another implementation I was using before. I am not able to make it bind but have to admit, I made some small changes to your code: As I am owning the MegaADK, I am using Serial for debug output and have therefore switched your initialization and sending code to Serial1.

The state of the bind process switches from 1 to 0, the model Id stays 0 after some seconds.

Here is my HW layout: Switch to initiate binding on Analog 2, AMTX11 on 3.3V with signal connected to TX1, using USB as power-source for now.

Can you give me a hint what I am doing wrong?

Thank you for your efforts in advance,
Greetings from Austria,

Romout


EDIT: Just got it to work - I compared your initialization code with the otherone I had and figured out, the other used 0x080 as bind magic header, not 0x098 - but also didn't work on my first try.
Thanks for trying out my work. I've been meaning to make some changes to my code since my last updates and I've learned some things since I last published an update in this thread (although Github does contain a separate branch that reflects some of those lessons).

There's a lot of things that I need to change with respect to this library and I have some updates in the works to address some of those things. One of them is that I'm not quite satisfied with its flexibility to work with different hardware (both in terms of microcontrollers and in terms of donor radios). I've done a LOT of experimenting with every DSM2/X transmitter type I can put my hands on and I've discovered that there can be quite a lot of variance in the serial protocol spoken by any two radios that might otherwise seem identical. Like the encoding of the channel numbers in the high-order bits of the channel data is not always present on all radios. There even seems to be some special quirks related to the specific model of a donor radio, like the 7th channel of my (pre-DSMX) Dx7 radio only has 8 bits of resolution (256 steps) where all the other channels have 10 bits of resolution (1024 steps).

There's also parts of these protocols that I have since made more sense of--for example, you referred to some "magic numbers" in the bind process undoubtedly because I called them such in the code commentary. I called them that because I didn't really understand them at the time, but it turns out that they're just the channel data and the bind command is signified only by the first byte alone. The channel values don't seem to matter with respect to the bind process in the radios that I have observed.

Ideally, I would want to define either more specialized classes for each unique radio behavior or maybe a single class that can conform to many different configurations. I also want to design a more sophisticated API that allows a programmer to use things like a muxer chip to control several radios from the same hardware UART. Unfortunately, I've been really busy with other things and haven't been able to make headway on this in a while.
Mar 12, 2013, 02:56 AM
Registered User
I think one possible approach would be to abstract the timing loop which ensures that data is transmitted on a regular basis, from the bind and the data processing. Ideally, one would configure the transmitter in use by giving a proper bind-type and the correct transmission type. Saying that, obviously, these types each implements an interface and a factory could take care of configuring communication for known devices.

I still don't get it why the 0x98 didn't work for me but the 0x80 did. Is that also a difference in the protocol? Maybe because the DX4 isn't actually a "computer" remote control?

Nonetheless, I was very happy yesterday night when the server moved according to my input :-)

If you want me to test some new code, just let me know.

Thanks,
Romout
Mar 12, 2013, 04:41 AM
ROFLCOPTER
Iron Savior's Avatar
Thread OP
Quote:
Originally Posted by Romout
I still don't get it why the 0x98 didn't work for me but the 0x80 did. Is that also a difference in the protocol? Maybe because the DX4 isn't actually a "computer" remote control?
I don't have my notes here with me, but the command byte is basically a series of bit flags. It's likely that your radio just doesn't respond to the flags represented by 0x98. If I were to guess (since I don't have my notes here), it may have something to do with either DSMX or specifying a reduced band to operate in (aka "France mode")
Mar 12, 2013, 10:28 AM
Registered User
That sounds like a very likely reason. As mentioned, I live in austria where a different communication band range on 2.4ghz is allowed for RC. That would explain why my HF Module refuses to bind if a "wrong" range is requested. I guess manufactors produce differently configured modules for different world regions.
Mar 12, 2013, 08:40 PM
I don't want to "Switch Now"
pmackenzie's Avatar
For the DX4e module 0x98 is DSM2/DSMx bind mode
0x80 is "France" bind mode.

So 0x98 should work with any Spektrum receiver. in my experience if the module does not support a particular mode it simply ignores the corresponding bit.

The whole list is here:

https://www.rcgroups.com/forums/show...&postcount=309

Pat MacKenzie
Mar 13, 2013, 02:43 PM
Registered User
Great info, thank you!


Quick Reply
Message:

Thread Tools

Similar Threads
Category Thread Thread Starter Forum Replies Last Post
Wanted Trade DSM2 tx for Parkzone um brick Brian VT Aircraft - General - Radio Equipment (FS/W) 0 May 04, 2012 02:04 PM
Found Wanted: Spektrum DM9 DSM2 TX Module for JR John Boy Aircraft - General - Radio Equipment (FS/W) 2 Mar 24, 2012 12:16 AM
Wanted TX for blade, walkera, parkzone, etc. DSM2 fregon45 Aircraft - Electric - Helis (FS/W) 2 Oct 12, 2011 12:28 AM
Sold Small TX DSM2 $15 ea. $25 for 2 obo. rodair Aircraft - General - Radio Equipment (FS/W) 0 Sep 07, 2011 08:29 PM