DIY custom 2.4ghz RC radio system for robotics

Wow, it looks great! I love the sliders. This controller has evolved into a interesting bot controller.

Several posts backwards, you mentioned the Lexan arms being replaced by aluminum versions, this is a great thing. I still think however, that lexan has a place in the robot world such as the controller panel above, PCB mounting brackets and other special uses. Are the biped Pete chassis parts going to be converted over to aluminum also sometime in the distant future?

Again, great work on this and it’s incredible what comes off the Lynxmotion workbench.

I’ve stepped away from the air pressure hexapod foot thingy long enough to wrap this up. I’ve added another switch so the transmitter can be powered separately. I move things around just a bit to make them fit better. I’m cutting the panels and having them sand blasted. Hopefully I can have these shipped out in a few days.

The I/O pin assignment from before had several errors. Here is an accurate I/O pin assignment.

R=Row C=Column P0 = Joystick 1 (left) Y P1 = Joystick 1 (left) X P2 = Joystick 2 (right) Y P3 = Joystick 2 (right) X P4 = Keypad R1 P5 = Keypad R2 P6 = Keypad R3 P7 = Keypad R4 P8 = LCD out P9 = Speaker P10 = Keypad C1 P11 = Keypad C2 P12 = Keypad C3 P13 = Keypad C4 P14 = Spare P15 = PPM out P16 = Spare analog input (VS battery check) P17 = Spare analog input (VL battery check) P18 = Slider (left) P19 = Slider (right)

Is the control panel going to be in aluminum?

Here is what I know about it.

I create the PPM signal in this order…

cha1 = right vertical joystick (adin2)
cha2 = right horizontal joystick (adin3)
cha3 = left vertical joystick (adin0)
cha4 = left horizontal joystick (adin1)
cha5 = left slider (adin18)
cha6 = right slider (adin19)
cha7 = (keyboard value yet to be implemented)

The RC receiver (AR7000) does not have channel designation, but uses airplane nomenclature. I have found the order is not the same. I found the following results.

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

So I’m not up on my scope-foo. I will try to determine what order the pulses are created in the receiver. I will edit this post if I make any discoveries.

Edit: I think my scope-foo is ok. 8) Anyway, this is as clear as mud, but here it is. The pulses are generated in the receiver in this order. I’m quite certain this is accurate…

output 1 = rudder = left horizontal joystick
output 2 = elevator = right horizontal joystick
output 3 = aileron = right vertical joystick
output 4 = aux1 = right slider
output 5 = throttle = left vertical joystick
output 6 = gear = left slider
output 7 = aux2 = keypad

Edit again: I added that this is for the AR7000 receiver.

Eventually… :wink:

It’s lexan.

here is the code so far. I added a conditional statement to the LCD output to fix if the value is less than 4 digits. Fixed the analog pin assignments. Added the sliders. Made a splash screen. Nothing major.

[code]; declare variables here
cha1 var word
cha2 var word
cha3 var word
cha4 var word
cha5 var word
cha6 var word
cha7 var word
a_key var bit
b_key var bit
c_key var bit

; create variables for averaging code
index var byte
buffer1 var word(8)
buffer2 var word(8)
buffer3 var word(8)
buffer4 var word(8)
buffer5 var word(8)
buffer6 var word(8)
sum1 var word
sum2 var word
sum3 var word
sum4 var word
sum5 var word
sum6 var word

; initialize each buffer element, each sum, and then index to 0
for index = 0 to 7
buffer1(index) = 542
buffer2(index) = 542
buffer3(index) = 542
buffer4(index) = 542
buffer5(index) = 542
buffer6(index) = 542
next

sum1 = 4336
sum2 = 4336
sum3 = 4336
sum4 = 4336
sum5 = 4336
sum6 = 4336
index = 0

; initialize unused channels outside the main loop
cha7=1500

; chirpy squeak kinda thing
sound 9, [100\880, 100\988, 100\1046, 100\1175] ;musical notes, A,B,C,D.

; wake up the Matrix Orbital display module
;serout 8,i19200,[254, 66, 0] ;Backlight on, no timeout.
;serout 8,i19200,[254, 64, “The D-I-Y 2.4ghzRobot Radio Set!”] ;startup screen. Do only once…
pause 5000
serout 8,i19200, [254, 88] ;clear screen

; initialize the ppm output signal
low 15

; — top of main loop —
start:

; averaging expects that the a/d values are < 4096
; for each channel
; read the a/d
; subtract the previous value from 8 samples ago from the sum
; store the new value in the circular buffer
; add the new value to the sum
; divide the sum by 8 to get the average value
; convert joystick values 392 - 692 to servo values 1000uS - 2000uS

adin 2, cha1 ; right vertical
sum1 = sum1 - buffer1(index)
buffer1(index) = cha1
sum1 = sum1 + cha1
cha1 = sum1 / 8
cha1 = (((cha1*42)-6500)/10)

adin 3, cha2 ; right horizontal
sum2 = sum2 - buffer2(index)
buffer2(index) = cha2
sum2 = sum2 + cha2
cha2 = sum2 / 8
cha2 = (((cha2*42)-6500)/10)

adin 0, cha3 ; left vertical
sum3 = sum3 - buffer3(index)
buffer3(index) = cha3
sum3 = sum3 + cha3
cha3 = sum3 / 8
cha3 = (((cha3*42)-6500)/10)

adin 1, cha4 ; left horizontal
sum4 = sum4 - buffer4(index)
buffer4(index) = cha4
sum4 = sum4 + cha4
cha4 = sum4 / 8
cha4 = (((cha4*42)-6500)/10)

adin 18, cha5 ; Left slider
sum5 = sum5 - buffer5(index)
buffer5(index) = cha5
sum5 = sum5 + cha5
cha5 = sum5 / 8
cha5 = cha5 + 988

adin 19, cha6 ; Right slider
sum6 = sum6 - buffer6(index)
buffer6(index) = cha6
sum6 = sum6 + cha6
cha6 = sum6 / 8
cha6 = cha6 + 988

; finally increment the index and limit its range to 0 to 7.
index = (index + 1) & 7

; update the display module
branch index, [update1,update2,update3,update4,update5,update6,update7,update8]

update8:
serout 8, i19200, [254, 71, 11, 2, “A”]
goto makepulses

update7:
serout 8, i19200, [254, 71, 11, 1, “0”]
goto makepulses

update6:
if cha6<1000 then update62
serout 8, i19200, [254, 71, 6, 2, dec cha6]
goto makepulses
update62:
serout 8, i19200, [254, 71, 6, 2, " ", dec cha6]
goto makepulses

update5:
if cha5<1000 then update52
serout 8, i19200, [254, 71, 6, 1, dec cha5]
goto makepulses
update52:
serout 8, i19200, [254, 71, 6, 1, " ", dec cha5]
goto makepulses

update4:
if cha4<1000 then update42
serout 8, i19200, [254, 71, 1, 2, dec cha4]
goto makepulses
update42:
serout 8, i19200, [254, 71, 1, 2, " ", dec cha4]
goto makepulses

update3:
if cha3<1000 then update32
serout 8, i19200, [254, 71, 1, 1, dec cha3]
goto makepulses
update32:
serout 8, i19200, [254, 71, 1, 1, " ", dec cha2]
goto makepulses

update2:
if cha2<1000 then update22
serout 8, i19200, [254, 71, 13, 2, dec cha2]
goto makepulses
update22:
serout 8, i19200, [254, 71, 13, 2, " ", dec cha2]
goto makepulses

update1:
if cha1<1000 then update12
serout 8, i19200, [254, 71, 13, 1, dec cha1]
goto makepulses
update12:
serout 8, i19200, [254, 71, 13, 1, " ", dec cha1]
goto makepulses

; build and send the ppm output
makepulses:
pulsout 15,800
pauseus ((cha12)-800)
pulsout 15,800
pauseus ((cha2
2)-800)
pulsout 15,800
pauseus ((cha32)-800)
pulsout 15,800
pauseus ((cha4
2)-800)
pulsout 15,800
pauseus ((cha52)-800)
pulsout 15,800
pauseus ((cha6
2)-800)
pulsout 15,800
pauseus ((cha7*2)-800)
pulsout 15,800

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

Great work with your code Jim!

Only the keypad code left… :wink:
Or did someone work with that too?

Kurte is waiting for his radio to write that part of the code. Soon… 8)

I had an earlier version working on a keypad at home using IO pins P0-P3 and P4-P7. I need to find my test setup (as I am in my reall office now). Need to convert to the new IO pin which should not be difficult. I am torn on making it easy for everyone to read and customize (ie use standard basic stuff or to make it easier and faster with some assembly (or at least underlying registers).

Also wondering if I should continue to try to use the internal Pull-up resistors on some of the Atom Pro pins or if you should solder some in on either the rows or columns…

I included a first level Quick and Dirty that tries using the underlying IO register for pins P10-P13 which is P82-P85. I have not tested it as I still need to find my test setup. But maybe later today… Or Jim if you have lots of free time you might try it out…

Kurt

[code]'First a simply program to check the state of the 16 buttons on the keypad.
’ For now the keypad is in the default positions that were proposed for the
’ DIY controller… Pins: 0-3 Rows pins 4-7 do Columns. Will try
’ the Basic variables to read or write 4 IO ports at a time…
’ Variables
fKeypadChanged var bit

wKeypadButtons var word
wKeypadPWM var word

bPDR51 var byte
bPDR52 var byte
bPDR53 var byte
bPDR54 var byte
bPCR5 var byte

'[Init]
wKeypadPWM = 0xffff ’ make sure we will generate a new keypad value…
’ Try going directly to the IO registers
PMR5 = 0x0 ’ all 8 IO pins are standard IO

output p4
output p5
output p6
output p7
input 10
input 11
input 12
input 13
		' The low 4 bits are output the high 4 bits are input
sound 9,[50\3960] 


gosub CheckKeypad
serout s_out, i9600, [hex wKeypadButtons, " ", dec wKeypadPWM, 13]
'serout s_out, i9600, [hex bPDR51, " ", hex bPDR52, " ",hex bPDR53, " ",hex bPDR54, " ",hex PCR5, 13]

Main:
gosub CheckKeypad
if fKeypadChanged then
serout s_out, i9600, [hex wKeypadButtons, " ", dec wKeypadPWM, 13]
'serout s_out, i9600, [hex bPDR51, " ", hex bPDR52, " ",hex bPDR53, " ",hex bPDR54, " ",hex PCR5, 13]
endif
goto main

'=====================================================================
’ function: CheckKeypad
’ This function is currently hard coded to pins 0-7 for the 8 pins. four
’ By BAP manual: DIRA, INA, OUTA (pins 0-3) DIRB, INB, OUTB(4-7)
’ are used as a row and 4 as columns. will parameterize this later
’ private variables used in the checkkeypad.
wKeypadButtonsLast var word
wKeypadMask var word

CheckKeypad:
fKeypadChanged = 0 ’ assume nothing changed.

PUCR5.nib1 = %1111		; set the pull-up registers on P54-P57 which are BAP pins P4-P7

_CKPAgain:
wKeypadButtonsLast = wKeypadButtons ’ save the old value

OutB = %1110
pause 1
wKeypadButtons.nib0 = (PDR8 >> 2) & 0xf ; this code relies on P10-P13 is on underlying pins (P82-P85)
OutB = %1101
pause 1
wKeypadButtons.nib1 = (PDR8 >> 2) & 0xf
OutB = %1011
pause 1
wKeypadButtons.nib2 = (PDR8 >> 2) & 0xf
OutB = %0111
wKeypadButtons.nib3 = (PDR8 >> 2) & 0xf
wKeypadButtons = ~wKeypadButtons
if wKeypadButtons <> wkeypadButtonsLast then
fKeypadChanged = 1 ’ ok something changed

  ' quick and dirty try to handle debounce by pausing 1 and recalcing again until 
  ' we get the same value. 
  pause 10 
  goto _CKPAgain 

endif

’ Ok we are here with a stable keypad state. If it changed we need to calculate a new PWM value
’ to return.
if fKeypadChanged then
’ We will generate a pulsewidth between 1100 and 1900 that will translate to zero or one button
’ pressed. Could easily be sped up with assembly…
if wKeypadButtons = 0 then
wKeypadPWM = 1100
else
wKeypadPWM = 1150
wKeypadMask = 0x1

     while ((wKeypadButtons & wKeypadMask) = 0) 
        wKeypadPWM = wKeypadPWM + 50 
        wKeypadMask = wKeypadMask << 1      ' shift the mask down 
     wend 
  endif 

endif

return [/code]

Hi Kurte!

I may have time later today. I wired the keypad as per the pinout outlined above just last night. 8)

Do I run the program as is, or does it need to be nested into my program? I’m not sure which is row and column as the keypad and it’s spec sheet does not tell you where pin one is, but it could be sorted out later.

I need to get 8.0.1.8 on this machine too.

Thanks! Jim

PS Congrats on the new office. I know you’ve been working on the move for a long time. :wink:

Hi Jim,

You should be able to run the program as is. It simply checks the keypad and generates what the PWM should be and displays it on S_OUT. If it generates reasonable output we should then extract some of it to integrate into the main program. We may need to do some debounce support.

As for which are rows and columns it really does not matter (at least on mine). There are simply two groups of 4 pins. If we reverse it it just means we will get different values for each of the buttons…

None of this relies on the new IDE, but having more people try it out is probably a good thing!

Kurt.

P.S. - It feels great to finally be moved in. We were working on this for two years now. First we built the barn which is lived in for a year and then we built the house. Yesterday was a big day as they finally pulled the portable outhouse from the property! :smiley:

Hi Kurt,

I loaded the program. :slight_smile:

When I press the 1 key I get this.

1 1150 0 1100

When I press the 2 key I get this.

10 1350 1111 1150

Also I am seeing random numbers scrolling… Seems to start and stop at random…

1000 1750 1000 1750 1100 1550 1000 1750 1000 1750 1100 1550 1000 1750 1000 1750

Yep, I was afraid of that. But then again I think I screwed up. I need the pull-ups on the IO lines I poll not the IO lines I drive. So I need to change the code a little to drive IO lines P10-P13 and check the IO lines P4-P7 as P10-P13 don’t have any underlying pull-up resistor available (They are on IO port 8, where P4-P7 are on the underlying IO port 5 which does…).

Back to you in a bit.

Kurt

I think this may work a little better: I only included part of the one function here…

[code]CheckKeypad:
fKeypadChanged = 0 ’ assume nothing changed.

input p4
input p5
input p6
input p7
output p10
output p11
output p12
output p13
PUCR5.nib1 = %1111		; set the pull-up registers on P54-P57 which are BAP pins P4-P7
high p10
high p11
high p12
high p13

_CKPAgain:
wKeypadButtonsLast = wKeypadButtons ’ save the old value

low p13
pause 1
wKeypadButtons.nib0 = INB ; 

high p13
low p12
pause 1
wKeypadButtons.nib1 = INB 

high p12
low	p11
pause 1
wKeypadButtons.nib2 = INB

high p11
low p10
            pause 1
wKeypadButtons.nib3 = INB 
wKeypadButtons = ~wKeypadButtons

if wKeypadButtons <> wkeypadButtonsLast then [/code]

Note, I did it all with normal code except for setting the pull-up. May still get better results with a reall pull up… Mine is working better, still some flakyness, but some caused by my old wire and connections…

Hi Kurte,

I replaced the CheckKeypad section of the code. It’s still scrolling randomly. The values are different too.

CCCC 1250 CCCC 1250 CCCC 1250 CCCC 1250 CCCC 1250

When I press 1 I get.

DDDD 1150 DDDD 1150 DDDD 1150 CCCC 1250

Which keypad do you have? How is it wired in? I should try to verify that it works like mine. Looking it mine again it looks like it has 9 pins and I am using 8. Need to go back and look at the docs again… Obviously it will be easier when we are using the same ones. Ok The 9th pin is a ground wire…actcomponents.com/index_004.htm

Kurt

Did find a small bug in the code that caused some problems. That is when I noticed a change I branched back up to recheck but did not reset P10 to high…

[code]CheckKeypad:
fKeypadChanged = 0 ’ assume nothing changed.

input p4
input p5
input p6
input p7
output p10
output p11
output p12
output p13
PUCR5.nib1 = %1111		; set the pull-up registers on P54-P57 which are BAP pins P4-P7
high p10
high p11
high p12
high p13

_CKPAgain:
wKeypadButtonsLast = wKeypadButtons ’ save the old value
high p10 ; In case we jump back to again…
low p13
pause 1
wKeypadButtons.nib0 = INB ; this code relies on P10-P13 is on underlying pins (P82-P85)

high p13
low p12
pause 1
wKeypadButtons.nib1 = INB 

high p12
low	p11
pause 1
wKeypadButtons.nib2 = INB

high p11
low p10
pause 1
wKeypadButtons.nib3 = INB 
wKeypadButtons = ~wKeypadButtons

if wKeypadButtons <> wkeypadButtonsLast then
fKeypadChanged = 1 ’ ok something changed

  ' quick and dirty try to handle debounce by pausing 1 and recalcing again until 
  ' we get the same value. 
  pause 10 
  goto _CKPAgain 

endif

’ Ok we are here with a stable keypad state. If it changed we need to calculate a new PWM value
’ to return.
if fKeypadChanged then
’ We will generate a pulsewidth between 1100 and 1900 that will translate to zero or one button
’ pressed. Could easily be sped up with assembly…
if wKeypadButtons = 0 then
wKeypadPWM = 1100
else
wKeypadPWM = 1150
wKeypadMask = 0x1

     while ((wKeypadButtons & wKeypadMask) = 0) 
        wKeypadPWM = wKeypadPWM + 50 
        wKeypadMask = wKeypadMask << 1      ' shift the mask down 
     wend 
  endif 

endif

return
[/code]

I need to check my hardware cache for some new connectors as I am shorting out some of the IO pins

Hi Kurte,

I have this one.
elexp.com/cmp_1604.htm

Here is the data sheet.
elexp.com/a_data/17kp1604.pdf

Maybe some really simple code is needed to test my wiring. I will try… I can do simple, it’s the complicated stuff that gets me.

It only has 8 pins and they are C1,2,3,4,R1,2,3,4. I know it’s right. :wink:

I tried your last code and it sent the following immediately.

CCCC 1250

Then after a couple seconds it just started spitting out…

CCC8 1300 CC88 1300 CC88 1300 CC88 1300 CC88 1300 8C88 1300 CC88 1300 CCC8 1300