DIY custom 2.4ghz RC radio system for robotics

This is actually pretty simple stuff. The switches are simply a grid of 4x4. So when you press one of the switches one pin in the row set will be connected to 1 pin in the column set.

My first attempt earlier on was to simply set one of the 4 rows high and check for one of the pins in the columns to go high. It did not work well as the 4 IO pins were floating and did not give good results. So instead I wanted to drive one of the 4 outputs ow and put pull-up resistors on the input lines and see if any of these were now low. This is what the code currently does. I found that the underlying H8 did have pull-up support on some of the IO lines, so I thought I would try that. A better approach may be to add actual pull-ups to the 4 input lines. I may also need to experiment and add a larger delay to allow the values to stick…

The only slighly different thing I am doing is using INB which reads in the 4 bits at once. I could just as easily do something like:

[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.bit0 = in4
wKeypadButtons.bit1 = in5
wKeypadButtons.bit2 = in6
wKeypadButtons.bit3 = in7
high p13
low p12
pause 1
wKeypadButtons.bit4 = in4
wKeypadButtons.bit5 = in5
wKeypadButtons.bit6 = in6
wKeypadButtons.bit7 = in7

[/code]

Hi Kurte!

I made a very simple program to test the hardware.

[code]aa var bit
bb var bit
cc var bit
dd var bit

input p4
input p5
input p6
input p7
PUCR5.nib1 = %1111

output p10
output p11
output p12
output p13

low 10
low 11
low 12
low 13

start:

aa = in4
bb = in5
cc = in6
dd = in7

serout s_out, i9600, [bin aa, bin bb, bin cc, bin dd, 13]

goto start[/code]

I got the following with no keys pressed.

1100 1100 1100

I knew right then, there was a problem.

The Atom Pro does not have weak pullups available on pins 6 and 7. Ok, Nathan helped me with that knowledge…

The pins with weak pullups are…

P0 PUCR5.bit0
P1 PUCR5.bit1
P2 PUCR5.bit2
P3 PUCR5.bit3
P4 PUCR5.bit4
P5 PUCR5.bit5
P8 PUCR1.bit5
P12 PUCR1.bit0
P16 PUCR1.bit1
P17 PUCR1.bit2
P18 PUCR1.bit7
P19 PUCR1.bit6

I will need to move things around to make it work, but no soldering will be necessary…

Hey Kurte,

Before I make any proposed changes to the pinouts is it important for the four inputs with pullups to be in sequential order? I can do it and loose only one analog input if they are mix and match, P4,5,8,12 or I can loose two analog inputs and make them P2,3,4,5.

It probably does not matter much. We might be able to make slighly faster code with P2-P5 as underlying we could use the underlying IO pins whcih are P52-P55 so we could simply read PDR5 to get all 4 values, but I am not sure how much speed we need here especially if you think you may want the analog pins in the future.

Kurt

Nathan mentioned that there are not pullups on pins 6 and 7 which appear to be working out that way. Looking at the 3694 documention, it appears like there should be unless this is a 3694N processor, in which case these bits should not be set in PUCR5, but likewise they should not be set in PCR5 or PDR5. I think on the 3694N processor these bits are reserved for I2C probably for the onchip memory… Maybe that is why P6 and P7 don’t work well for PS2 controller…

Hi Kurte,

I’ve got some things I need to deal with this morning. Hopefully later today I will be able to work on the controller. I plan to just go ahead and install hardware pullups (10k) and use the existing pin designations. Do you have a preference on using 4-7 or 10-13 as the inputs?

Either way works for me :slight_smile: . At the Basic level having one or the other as a full 4 pin group inplies I can either use INB to read all in one basic instruction or OUTB to set all 4 in one instruction.

At the underlying H8 level it would be easy to do either:
P4-7 -> P54-P57: so to set could:
PDR5 = (PDR5 & 0x0f) | 0xNN (new value)
Could read:
wKeypadButtons.nib0 = PDR5 >> 4

Likewise for P10-P13, no direct basic IO for this 4 pin Group, but on H8 it is P82-P85: So could set:
PDR8 = (PDR8 & 0xC3) | 0xNN
For readability might use: %11000011 instead 0f 0xC3

Could read:
wKeypadButtons.nib0 = (PDR8 >> 2) & 0xf

I may also setting up the pull-ups as well. I will probably dig out a breadboard to do it…

Kurt

Hi again Jim,

For the fun of it before you put on the pull-ups, you might try your keypad to see if we need it.
You can probably just do a simple modification of your earlier program, maybe something like:

[code]aa var bit
bb var bit
cc var bit
dd var bit

input p4
input p5
input p6
input p7

output p10
output p11
output p12
output p13

low 10
low 11
low 12
low 13

start:

high 10
aa = in4
bb = in5
cc = in6
dd = in7
serout s_out, i9600, [bin aa, bin bb, bin cc, bin dd]
low 10
high 11
aa = in4
bb = in5
cc = in6
dd = in7
serout s_out, i9600, " ",bin aa, bin bb, bin cc, bin dd]
low 11
high 12
aa = in4
bb = in5
cc = in6
dd = in7
serout s_out, i9600, " ",bin aa, bin bb, bin cc, bin dd]
low 12
high 13
aa = in4
bb = in5
cc = in6
dd = in7
serout s_out, i9600, " ",bin aa, bin bb, bin cc, bin dd, 13]
low 13

goto start[/code]

Then see what you get as you press different buttons…
Just an idea to see if you need pull-ups. Hopefully one digit will go to a 1 as you press different buttons. If it does not look stable, then add pull-ups, change highs to lows and lows to highs and try again…

Kurt

Hi Kurte,

No go on the no pullup code. I had James solder the pullups in, changed low’s to high’s and it’s good and solid!

123A 456B 789C 0FED

Just confirming the status of pullups on P6 (H8 pin P56) and P7 (H8 pin 57).

The Difference between the 3694 and the 3694N is that P56 and P57 are not available at all on the N part. They are strictly SDA and SCL for the internal eeprom or an external i2c device.

However in BOTH cases(N and non-N 3694s) the PUCR register has bits 6 and 7 always set to 0 so no internal pullups available on those pins ever.

Great, it sounds like you now have some solid values. Should be easy now to code it up to generate to do the pulse out on channel 7. It could be written as simply as something like:

wButtonPulseWidth  var word

input p4 
input p5 
input p6 
input p7 

output p10 
output p11 
output p12 
output p13 
    
start: 

high 11 
high 12 
high 13 
low  10 
if in4 = 0 then
    wButtonPulseWidth  = 1200;   1
else if in5 = 0 
    wButtonPulseWidth  = 1250;   2
else if in6 = 0 
    wButtonPulseWidth  = 1300;   3
else if in7 = 0 
    wButtonPulseWidth  = 1650;   A
else
    high 10
    low 11
    if in4 = 0 then
        wButtonPulseWidth  = 1350;   4
    else if in5 = 0 
        wButtonPulseWidth  = 1400;   5
    else if in6 = 0 
        wButtonPulseWidth  = 1450;   6
    else if in7 = 0 
        wButtonPulseWidth  = 1700;   b
    else
        high 11
        low 12
        if in4 = 0 then
            wButtonPulseWidth  = 1500;   7
        else if in5 = 0 
            wButtonPulseWidth  = 1550;   8
        else if in6 = 0 
            wButtonPulseWidth  = 1600;    9
        else if in7 = 0 
            wButtonPulseWidth  = 1750;   c
        else
            high 12
            low 13
            if in4 = 0 then
                wButtonPulseWidth  = 1150;   0
            else if in5 = 0 
                wButtonPulseWidth  = 1800;   D
            else if in6 = 0 
                wButtonPulseWidth  = 1850 ;   E
            else if in7 = 0 
                wButtonPulseWidth  = 1900;   F
            else
                wButtonPulseWidth = 1100;   None is pushed
            endif
        endif
    endif
endif

serout s_out, i9600, [dec wButtonPulseWidth, 13]    

goto main

Note, is this was typed in on the fly so probably has compile issues and obviously could be written more compact…

Kurt

Thanks,

Kurt

Hey Kurt,

I didn’t have to change much in your code to get it to work! Good job for off the top if your head. The pins can’t be tested in an if then command. So I scanned the 4 pins, stuffed them into variables, then made decisions based on the variables. It worked so well I went ahead and wrapped it into my other program. The radio is fully functional now! 8) It actually works very well. It won’t take much longer for me to get the others finished Thanks for your help with this! Thanks to EddieB as well! :smiley:

I know there will be many improvements. Here is the code.

[code]; declare variables here
wButtonPulseWidth var word
keypress var byte

col1 var bit
col2 var bit
col3 var bit
col4 var bit

cha1 var word
cha2 var word
cha3 var word
cha4 var word
cha5 var word
cha6 var word
cha7 var word

; 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

input p4
input p5
input p6
input p7

output p10
output p11
output p12
output p13

; 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:

high 11
high 12
high 13
low 10

col1 = in4
col2 = in5
col3 = in6
col4 = in7

if col1 = 0 then
wButtonPulseWidth = 1200; 1
keypress = “1”
elseif col2 = 0
wButtonPulseWidth = 1250; 2
keypress = “2”
elseif col3 = 0
wButtonPulseWidth = 1300; 3
keypress = “3”
elseif col4 = 0
wButtonPulseWidth = 1650; A
keypress = “A”
else
high 10
low 11
col1 = in4
col2 = in5
col3 = in6
col4 = in7
if col1 = 0 then
wButtonPulseWidth = 1350; 4
keypress = “4”
elseif col2 = 0
wButtonPulseWidth = 1400; 5
keypress = “5”
elseif col3 = 0
wButtonPulseWidth = 1450; 6
keypress = “6”
elseif col4 = 0
wButtonPulseWidth = 1700; B
keypress = “B”
else
high 11
low 12
col1 = in4
col2 = in5
col3 = in6
col4 = in7
if col1 = 0 then
wButtonPulseWidth = 1500; 7
keypress = “7”
elseif col2 = 0
wButtonPulseWidth = 1550; 8
keypress = “8”
elseif col3 = 0
wButtonPulseWidth = 1600; 9
keypress = “9”
elseif col4 = 0
wButtonPulseWidth = 1750; C
keypress = “C”
else
high 12
low 13
col1 = in4
col2 = in5
col3 = in6
col4 = in7
if col1 = 0 then
wButtonPulseWidth = 1150; 0
keypress = “0”
elseif col2 = 0
wButtonPulseWidth = 1900; F
keypress = “F”
elseif col3 = 0
wButtonPulseWidth = 1850 ; E
keypress = “E”
elseif col4 = 0
wButtonPulseWidth = 1800; D
keypress = “D”
else
wButtonPulseWidth = 1100; None is pushed
keypress = " "
endif
endif
endif
endif

; 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 16
sum1 = sum1 - buffer1(index)
buffer1(index) = cha1
sum1 = sum1 + cha1
cha1 = sum1 / 8
cha1 = (((cha1*42)-6500)/10)

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

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

adin 1, cha4 ; left horizontal 19
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:
update7:
serout 8, i19200, [254, 71, 11, 1, keypress]
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 ((wButtonPulseWidth*2)-800)
pulsout 15,800

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

That is good news! :smiley:

You are very welcome. It is a fun project!

Kurt

Nice work Kurt and Jim!

This project is so great since it gives us endless possibilities to customize the controller just the way we want it. About the keypad, I think using the A-F buttons as mode selection and the 0-9 button as function buttons would be an idea. This would give us a total of 60 different functions! 8)

Ex.
Mode A = Normal walking
Mode B = Terrain mode
Mode C = Single leg movement
Mode D = GP player

and so on…

Anyway, since the code are so easy to change this must be the ultimate robot controller!

Great project!

Hi Jim and Kurt,

You guys really made a great Robot controller! And because it is really open source I think it will get just better and better! Just think of the endless posibilities… :unamused:
I can’t wait to try it out!

Do we have a terrain mode? Cool! :wink:

Xan

Ehm :blush: well, not yet… :wink:
But it is our future plans though!

I have been carrying a big box of parts back ad forth from work and home. Not making much progress due to little free time. I asked James to help me get them finished. It’s been too cold to get the sand blasting done but remain hopeful. Just so you know progress is being made.

Man that raidio looks like a serious piece of hardare. I love the flat black look!

Are you going to hand build them all? or offer them as kits? If they are offered as kits you don’t have to hand build each one. I’m not even sure if you’re planing to add them to your line of radios or not. :laughing:

Hi Mike,

The radio is very much a prototype. I have 3 separate “entities” that are very interested in making it a real product. Because it’s a transmitter I’m limited by the FCC in what I can do. It will probably never be a kit though. No way to tell what will come of it, but I’m more interested in making the concept available to the general public to advance the hobby robotics industry as I am in making it a product. Legally anyone can do this on their own as a hobby project, I.e. not selling them…