DIY custom 2.4ghz RC radio system for robotics

Back to the timing discrepancy… I changed the code to look like this. It’s no longer switching from pulsout to pauseus. It does run much faster as well. But there still seems to be a shorter delay as the value gets larger. They’re inversely proportional.

[code]; build and send the ppm output
makepulses:
cha1 = ((cha12)-800)
cha2 = ((cha2
2)-800)
cha3 = ((cha32)-800)
cha4 = ((cha4
2)-800)
cha5 = ((cha52)-800)
cha6 = ((cha6
2)-800)
cha7 = ((wButtonPulseWidth*2)-800)

high 15 ;pulsout 15,800
pauseus 400
low 15
pauseus cha1
high 15 ;pulsout 15,800
pauseus 400
low 15
pauseus cha2
high 15 ;pulsout 15,800
pauseus 400
low 15
pauseus cha3
high 15 ;pulsout 15,800
pauseus 400
low 15
pauseus cha4
high 15 ;pulsout 15,800
pauseus 400
low 15
pauseus cha5
high 15 ;pulsout 15,800
pauseus 400
low 15
pauseus cha6
high 15 ;pulsout 15,800
pauseus 400
low 15
pauseus cha7
high 15 ;pulsout 15,800
pauseus 400
low 15

; do it again ad infinitum
goto start [/code]

Here is a comparison.

prog old new N 1100 1144uS 1125uS 0 1150 1193uS 1174uS 1 1200 1243uS 1223uS 2 1250 1292uS 1272uS 3 1300 1340uS 1322uS 4 1350 1390uS 1371uS 5 1400 1439uS 1421uS 6 1450 1490uS 1470uS 7 1500 1538uS 1520uS 8 1550 1589uS 1569uS 9 1600 1637uS 1618uS A 1650 1687uS 1666uS B 1700 1736uS 1717uS C 1750 1786uS 1766uS D 1800 1835uS 1816uS E 1850 1885uS 1865uS F 1900 1934uS 1915uS

So when the program makes a 1100uS pulse it appears as a 1125uS pulse. When it makes a 1900uS pulse it appears as a 1915uS pulse. I consider this the minimum error possible. I am adjusting the values the receiver side code uses as follows.

N 1100 - 1150 0 1150 - 1199 1 1199 - 1248 2 1248 - 1297 3 1297 - 1347 4 1347 - 1396 5 1396 - 1446 6 1446 - 1495 7 1495 - 1545 8 1545 - 1594 9 1594 - 1643 A 1643 - 1691 B 1691 - 1742 C 1742 - 1791 D 1791 - 1841 E 1841 - 1891 F 1891 - 1940

This is a cool project! I’ve been tossing ideas around for something similar that would use wireless between it and a robot. My version would have a small LCD with touch screen in place of the buttons, so everything could be changed easily, for different applications.

8-Dale

I’ve looked at the asm code but don’t see where the inverse proportional delay is coming from. But you can subtract (28000/pulsewidth) to get a more acurate output.

28000/1900= ~15 and 28000/1100= ~25.

The offset seems to be fairly linear so this should do the trick in all cases. I believe you will be within 1us of your goal pulse width.

Also, you could setup a capture compare interrupt to process the data. it takes 23ms but the interrupt would only trigger for the couple dozen asm commands needed to handle each pulse so you could run this whole pulse reader in the background with little processor overhead. if you are using TimerW’s harware for something else(HSERVO perhaps) you can use TimerV’s capture compare hardware instead.

Also we could possibly just simply change the code in the ifs to instead of setting the output value to 1100, set it to 1100-fudge… Probably in the end the receving side would probably need to fudge it anyway.

What I always figured I would do is to simply do something like:

wWhichButton = (pwmButtons + fudge)/50

It looks like fudge could equal zero…

Kurt

EDIT: I meant:
wWhichButton = (pwmButtons -1100 + fudge)/50

Thanks Kurt and Nathan,

Yes we all agree it’s easy to change the program to make it function well. It was a learning experience for me to understand what was causing the error, and how to fix it. 8) I will try the math Nathan suggested. I will apply it to all of the channels to get rid of the offset.

Congrats on getting your Ham license (KE7YUT) :wink:

Thanks! I told Alan I was going to get it this year, and I just made it. :smiley: I am hoping to merge radio and robotics at some point.

8-Dale

I was playing around with some of the test code for the receiver side and here is my current test program:

[code]pulse_values var word(7)
pulse_values_prev var word(7)
keypress var byte
i var byte
changed var byte

pulse_slop con 2

start:

pulsin p0, 0, pulse_values(0)
pulsin p2, 0, pulse_values(2)
pulsin p4, 0, pulse_values(4)
pulsin p6, 0, pulse_values(6)
pulsin p1, 0, pulse_values(1)
pulsin p3, 0, pulse_values(3)

pulsin p5, 0, pulse_values(5)

changed = 0
for i = 0 to 6
	if (pulse_values(i) > (pulse_values_prev(i)+pulse_slop)) or (pulse_values(i) < (pulse_values_prev(i)-pulse_slop)) then
		changed = 0xff
		pulse_values_prev(i) = pulse_values(i)
	endif
next

if changed then
	if pulse_values(6) < 1150 then
		keypress = 0xff
	else
		keypress = (pulse_values(6) - 1150) / 50
	endif

	serout s_out, i9600, [hex keypress, ":"]
	for i = 0 to 6
		serout s_out, i9600, [dec pulse_values(i)," "]
	next
	serout s_out, i9600,[13] 

	if keypress = 0xA then 
	  low 12 
	else 
	  input p12 
	endif 
	
	if keypress = 0xB then 
	  low 13 
	else 
	  input p13 
	endif 
	
	if keypress = 0xC then 
	  low 14 
	else 
	  input p14 
	endif 
endif

goto start[/code]

I believe that the 7 channels are in the following order:
0 = left joystick up/down
1 = right joystick up/down
2 = right joystick left/right
3 = left joystick left/right
4 = left slider
5 = right slider
6 = keypad

The code maps the keypress into the range 0-15 for the key pressed or hex ff if no key is pressed. It also does what Jim’s earlier code did, if you press keys A,B or C on the keypad it lights up one of the LEDS on the BB2.

Happy Holidays!
Kurt

I am hopefull I will get to play with this on the weekend but I will not even get home until Saturday afternoon so… I need time off from my time off it seems lately. :smiley:

I sent kurte, eddieb, xan, and zenta a DIY radio set in appreciation for help I received with a bunch of projects. Thanks guys! Ok, I’m trying to keep up with the forum, but email is more difficult. I see you have questions. I also see none of you waited for Christmas to open your packages. lol :smiley:

All of the radios have the code from my last post. I liked putting the code here because it made it easy to work on it from home. Note I never got around to implementing Nathans fix for the pulse position generation error. Maybe on my break. 8)

I know I documented this, but I can’t find it anywhere. It must be at the office. I remember the pulses were not generated by the receiver in the same order they were generated in the PPM routine, which would have been right vert, right hor, left vert, left hor, left sl, right sl, keypad.

Edit: I found it. Yes you have it right.

throttle = left vertical joystick
aileron = right vertical joystick
elevator = right horizontal joystick
rudder = left horizontal joystick
gear = left slider
aux1 = right slider
aux2 = keypad

Hi all,

I can confirm the channel layout :slight_smile:
I’m using this piece of code to read the inputs. The middle position of the sticks isn’t calibrated yet. So i’m thinking of including some offsets in the remote. But I wanted to know where to get the original source before i messed it all up :wink:

[code] ;Read input pulse lengths
PULSIN RCCh0, 0, RCInput(0) ;Left Stick Up/Down
PULSIN RCCh1, 0, RCInput(1) ;Right Stick Up/Down
PULSIN RCCh2, 0, RCInput(2) ;Right Stick Left/Right
PULSIN RCCh3, 0, RCInput(3) ;Left Stick Left/Right
PULSIN RCCh4, 0, RCInput(4) ;Left Slider
PULSIN RCCh5, 0, RCInput(5) ;Right Slider
PULSIN RCCh6, 0, RCInput(6) ;Buttons

;Read Buttons
Index=0
Buttons = 255
DO
IF RCInput(6) >= (1150+Index50) AND RCInput(6) < (1200+Index50) THEN
Buttons = Index
ENDIF

Index = Index+1

WHILE (Index < 16 AND Buttons=255)[/code]

Thanks!

Xan

Hi Xan,

It will be interesting to time some of this. My guess is that there will not be enought of a gap between Pulsins to be able to process from 0 to 1 on the same RC receiver loop. That is why Zenta on his eariler processing for his receiver (Futaba?) did it sort of in the order that I did.

I will probabaly hook up the logic scope to see it. Also I may start a timer and calculate how long each input order takes…

Depending on what I see on the scope I may see how hard it would be to do it in one pass (probably assembly)…

Merry Christmas.
Kurt

Well I had a few minutes so I hooked up the Logic Analyzer to see the order the channels were received. It was not in the order I expected…
http://i416.photobucket.com/albums/pp245/Kurts_Robots/Spectrumreceiver.png

Note Disregard the signal names, that is still set for my PS2 testing…

Kurt

Congratulations! Welcome to the club. I was thinking of eventually trying to merge the two as well. You know, we have special frequencies in the 6 meter band for just that. And we aren’t limited on TX power.

Duane - W5DMB

Great overview Kurt!

It seems like one order to read all channels are ch04, ch02, ch01, ch07, (then we have a little break for the next round :wink: ), ch03, ch06, ch05.
Not the logical order I expected either… But we’ll manage to read all channels in two rounds (cycles).

I have not had much time to work on this since yesterday. I did put a timer tick in my test program to see how much difference the different cycles might make. My first attempt at this did not take into account that clock rolling over, will play with it later.

What I have been wondering is worst best case would be that you started to do the pulse in just after the start of Channel 4. In this case the whole thing takes almost three rounds (best case ordering).

What I am trying to figure out is how hard it would be to maybe write a function that reads all 7 inputs in worst case slightly over 1 round.

If I write this in assembly language I would probably hard code it to two specific configurations, P0-P6 (or possibly P1-P7 if I want to leave an anolog input…) and P8,P10-P15. In these two configurations all 7 inputs are on the same underlying IO Ports. Given this, it might be reasonable to code it up probably in assembly language that does something like:

Pulsein7:
    ; Make sure all 7 IOs are set to input.
    PMR5 = 0 ; all IO lines are general IO 
    PCR5 = 0 ; All are input  (may want to leave bit 7 alone...
    bMask = 0x7f    ; set a mask of which bits we are needing...

    ; wait until none of the IO lines are high...
    while PDR5 & bMask
        ;
    wend

    while bMask   
        ; we still need some 1 or more of the pulses...
        while (PDR5 & bMask) = 0    ; waiting for a pulse to go high.
            ;
        wend
        iPin = ???; TBD: convert which bit is high to IO line number 0-6
        bMaskBit = 1 << iPin   ; get the mask for which pin...

        iPinLoopCnt = 0    
        while (PDR5 & bMaskBit)
            iPinLoopCnt = iPinLoopCnt + 1  ; how long until it goes low again
        wend

        aPulses(iPin) = iPinLoopCnt ; convert loop count to pulse width...
        bMask = bMask & ~bMaskBit    ; turn off waiting for this one...
    wend
    ; maybe do any conversions we need from loop counts to pulse widths
    return

Note, this is semi psuedo code hard coded for io ports P0-P6, that I entered on the fly in this message so there are probably holes and there should probably be some recovery code to make sure we don’t totally hang the machine. But if an assembly version of this works, it should be able to do it in more or less one cycle.

Does this sound reasonable and/or worthwhile?

Kurt

Hey Kurt,

I’m confused about the order of the pulses from the receiver you are seeing. Can you double check the channel names on the receiver?

I like the idea of using the pins as a port in your assembly program. Too bad there isn’t any way to do it without losing some analog inputs, or the speaker. Getting all 7 channels read into variables updated every 23mS is the best possible scenario. I’d say it’s worthwhile.

I think it is right: Here is a picture showing all of the test leads:
http://i416.photobucket.com/albums/pp245/Kurts_Robots/DSC03173.jpg
I think I counted over the right number of pins on the BAP to where P0 is and it does appear like I am getting 7 valid pulses. Note the names shown on the screen were from the PS2 testing where it renamed the IO ports to make it easier to read. I have not updated them back to Input 1, … but the order does look correct. Also the colors in the windo whould match the colors of the wires that are shown in the picture…

As I mentioned in the psuedo code post it would be easy to save 1 analog input or in the other case the speaker. That is simply not using P9. Personally I would hate losing the TXD/RXD… The code could be written to use any combination of the pins, it just would make it more complicated and a little slower. Could simply have two masks and the like…

Kurt

What I’m not able to tell from the image is what channels from the receiver coralate with the atom pro pins. I measured the pulses being generated in the receiver in this order.

throttle = left vertical joystick
aileron = right vertical joystick
elevator = right horizontal joystick
rudder = left horizontal joystick
gear = left slider
aux1 = right slider
aux2 = keypad

But your saying (I think) they come in this order.

left horizontal
right horizontal
right vertical
right slider
left vertical
left slider
keypad