Lynxmotion Tech Support

www.lynxmotion.com
It is currently Thu May 23, 2013 6:41 am

All times are UTC - 6 hours [ DST ]




Post new topic Reply to topic  [ 289 posts ]  Go to page Previous  1 ... 11, 12, 13, 14, 15, 16, 17 ... 20  Next
Author Message
 Post subject:
PostPosted: Fri Jan 02, 2009 6:03 am 
Offline
Superguru of Robotics!!!
User avatar

Joined: Wed Nov 28, 2007 7:48 am
Posts: 1141
Location: Netherlands
Happy New Year guys!

kurte wrote:
1) converted the pulse output functions to assembly language. Hoping to make it very accurate! To facilitate this I have updated some of the code to convert the cha1, cha2... to an array ChaVals, which I ordered from 0-6. I then updated several of the variable names that are used in the generation of the pulses to be zero based instead of 1 based. (buffer, sum...)

This sounds like a good idea! Removing overhead by switching to assembly could improve the accuracy. Sound logic to me :P

kurte wrote:
2) I #ifdef around the keep alive pulse.

Feel free to remove the alive pulse. Writing custom failsafe values sounds like a much better solution.

kurte wrote:
3) I am about to add in some BIND support. What I am thinking of doing is if when you first turn on the Radio, if a keypad key is down it will go into bind mode. In this mode I am going to hardwire the pulse widths for all 7 channels. My thoughts are: 1500, 1500, 1000, 1500, 988, 988, 2000 The idea is ground the binding signal on the receiver and power it up, you then hold a key down when you power up the transmitter (Computer side), which enters this mode, then you power up the transmitter and wait for the bind to complete. Once the bind is done, turn off, unplug bind wire and run. When the receiver loses signal, it should go to a safe value for the channels. On the receiver side I plan to detect that the keypad value is out of range to tell me that I lost my connection.

Good plan! Writing the controller init values will stop the bot and the keypad value will tell us to turn off the bot (free servos in my case). I hope this works because this is way better then my alive idea ;)

Xan

_________________
[b]Share, Use and Improve![/b]
Digging trough: [i]Theory of Applied Robotics: Kinematics, Dynamics, and Control[/i]
Xan's YouTube Channel
http://www.youtube.com/xanore


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 02, 2009 2:16 pm 
Offline
Robot Guru
User avatar

Joined: Sat Apr 15, 2006 1:42 pm
Posts: 4414
Hi Xan,

Sounds good to pull out the keep alive.

I now have the assembly working reasonably well. I ran into a few glitches as I forgot that the Basic command pauseus did not acutually pause a us but instead paused in 1/2 us. SO all of my timings were off.

It also suprised me that if you wanted a pulse of 1500 you have a high pulse of 200 followed by low of 1100 followed by high of 200. I would have expected either the pulse width low for 1500 should either be 1500 or incuding the high pulse (1500-200), but that does not appear to be what it is, so...

Also found that when I generated more or less exact values going into the transmitter, that was not what was coming out... That appears to be where the values ramping different comes in. I have a fudge calculation going in, which keeps it pretty close now.

I implemented the Bind function and I rebound my receiver with the transmitter. I used the values I mentioned earlier. I found that my receive all 7 channels at once is hanging when the transmitter is not there. Looking at the logic analyzer it looks like without the transmitter I am not receiving the first channel. The others come in with my defaults, so I need to add in some simple timeout to my function.

That is all for now.

Kurt


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jan 03, 2009 10:17 am 
Offline
Robot Guru
User avatar

Joined: Sat Apr 15, 2006 1:42 pm
Posts: 4414
Ok, I have done some debugging of the bind values and found some more information in that there are differences of losing signal vs not having one at the begginning.

For example if you turn on the robot without the transmitter, it appears to not pulse the first channel (or throttle). Mine looks like:
Image

Note all of the other channels are outputing my bind values.

Now I power up the transmitter and start doing something. In this case I have full throttle. Something like:
Image

The first channell shows the full throttle. Now I lose the transmitter. All of the channels appear as the same as the last transmission, except for the first one, which appears to be the bind value, like:
Image

So I am thinking of changing my default bind values for the first channel, maybe down to something like 750 or lower so it is out of the default range of 1000+.

Sound reasnable?

Kurt


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jan 03, 2009 7:40 pm 
Offline
Robot Guru
User avatar

Joined: Sat Apr 15, 2006 1:42 pm
Posts: 4414
Ok, it appears like what I described in the previous post is somewhat expected. It is described in the manual:
http://www.spektrumrc.com/ProdInfo/Files/SPM-Air-Module-Manual_LoRes.pdf

I now have the program working with binding, plus a sample test program that prints out the 7 channel values and detects when the receiver is powered up without the transmitter as well as lost the connection later.

In case any one else wants to play with my current code, here first is the updated transmitter code:
Code:
;Description: Lynxmotion costum RC radio
;Software version: V1.1
;Date: 29-12-2008
;Programmer: Jim Frye (aka RobotDude), Kurt (aka Kurte), Jeroen Janssen (aka Xan)
;
;Hardware setup: ABB2 with ATOM 28 Pro, Spectrum DM8, 2 joysticks, 2 sliders, HEX keypath, display
;
;NEW IN V1.0
;   - As released
;
;NEW IN V1.1
;   - Added calibration sub. Calibrates the joysticks at powerup. (Xan)
;      CAUTION: Be sure that the left joystick is in the outer down position by powerup!
;   - Added small offset at the pulses to decrease the send error. (Xan)
;   - Added Alive meganism. Sends 1000 on the buttons channel every 4 cycles
;
;New in V1.2
;   - More use of arrays and zero index variable names (Kurt)
;   - Assembly language output of pulses - should be vary accurate (Kurt)
;   - Removed alive function
;   - calibrate of left joystick up/down has a little validation.
;   - Add Bind function, set pulses to predefined values to bind with,
;            Once bound with this, this is the values will use if it loses connection
;               with transmitter.
;            If Receiver is powered up without transmitter, all channels will go to default
;               except for channel 0 (Throttle - by manual).  If receiver loses contact with
;               receiver channel 0 will go to default.
;
;KNOWN BUGS:
;   - None at the moment ;)
;
;====================================================================

Display con 8
Speaker con 9
Row0    con 10
Row1    con 11
Row2    con 12
Row3    con 13   

DM8PPM   con 15   ; Spectrum DM8 signal
;DO_IN_BASIC con 1
#ifndef DO_IN_BASIC
PULSE_FIX con 20
#else
PULSE_FIX con 20
#endif

Calibrated   var bit
ChaVals      var word(7)
ChaOffset   var word(6)
iFudge      var byte      ; used as an array index in our fudge values code
wButtonPulseWidth  var word
keypress var byte

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

; create variables for averaging code
index var byte
buffer0 var word(8)
buffer1 var word(8)
buffer2 var word(8)
buffer3 var word(8)
buffer4 var word(8)
buffer5 var word(8)
sum0 var word
sum1 var word
sum2 var word
sum3 var word
sum4 var word
sum5 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
  buffer0(index) = 542
  buffer1(index) = 542
  buffer2(index) = 542
  buffer3(index) = 542
  buffer4(index) = 542
  buffer5(index) = 542
next

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


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

; wake up the Matrix Orbital display module
serout Display ,i19200, [254, 66, 0] ;Backlight on, no timeout.
serout Display ,i19200, [254, 64, "The D-I-Y 2.4ghzRobot Radio Set!"] ;startup screen. Do only once...
pause 3000

; Mark for calibration
Calibrated = 0

; initialize the ppm output signal
low DM8PPM

; check to see if we should do a bind operation
gosub CheckKeypad
if wButtonPulseWidth <> 1100 then
   gosub DoRadioBind
endif


;====================================================================
; --- top of main loop ---
start:

gosub CheckKeypad
ChaVals(6) = wButtonPulseWidth

; 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, ChaVals(0) ; right vertical 16
sum0 = sum0 - buffer0(index)
buffer0(index) = ChaVals(0)
sum0 = sum0 + ChaVals(0)
ChaVals(0) = sum0 / 8
ChaVals(0) = (((ChaVals(0)*42)-6500)/10)
ChaVals(0) = ChaVals(0) + chaOffset(0)

adin 3, ChaVals(1) ; right horizontal 17
sum1 = sum1 - buffer1(index)
buffer1(index) = ChaVals(1)
sum1 = sum1 + ChaVals(1)
ChaVals(1) = sum1 / 8
ChaVals(1) = (((ChaVals(1)*42)-6500)/10)
ChaVals(1) = ChaVals(1) + chaOffset(1)

adin 0, ChaVals(2) ; left vertical 18
sum2 = sum2 - buffer2(index)
buffer2(index) = ChaVals(2)
sum2 = sum2 + ChaVals(2)
ChaVals(2) = sum2 / 8
ChaVals(2) = (((ChaVals(2)*42)-6500)/10)
ChaVals(2) = ChaVals(2) + chaOffset(2)

adin 1, ChaVals(3) ; left horizontal 19
sum3 = sum3 - buffer3(index)
buffer3(index) = ChaVals(3)
sum3 = sum3 + ChaVals(3)
ChaVals(3) = sum3 / 8
ChaVals(3) = (((ChaVals(3)*42)-6500)/10)
ChaVals(3) = ChaVals(3) + chaOffset(3)

adin 18, ChaVals(4) ; Left slider
sum4 = sum4 - buffer4(index)
buffer4(index) = ChaVals(4)
sum4 = sum4 + ChaVals(4)
ChaVals(4) = sum4 / 8
ChaVals(4) = ChaVals(4) + 988

adin 19, ChaVals(5) ; Right slider
sum5 = sum5 - buffer5(index)
buffer5(index) = ChaVals(5)
sum5 = sum5 + ChaVals(5)
ChaVals(5) = sum5 / 8
ChaVals(5) = ChaVals(5) + 988

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

if Calibrated=1 then
   ; update the display module
   branch index, [update1,update2,update3,update4,update5,update6,update7,update8]

   update8:
   update7:
   serout Display, i19200, [254, 71, 11, 1, keypress]
   goto makepulses

   update6:
   if ChaVals(5)<1000 then
      serout Display, i19200, [254, 71, 6, 2, " ", dec ChaVals(5)]
   else
      serout Display, i19200, [254, 71, 6, 2, dec ChaVals(5)]
   endif
   goto makepulses

   update5:
   if ChaVals(4)<1000 then
      serout Display, i19200, [254, 71, 6, 1, " ", dec ChaVals(4)]
   else
      serout Display, i19200, [254, 71, 6, 1, dec ChaVals(4)]
   endif
   goto makepulses

   update4:
   if ChaVals(3)<1000 then
      serout Display, i19200, [254, 71, 1, 2, " ", dec ChaVals(3)]
   else
      serout Display, i19200, [254, 71, 1, 2, dec ChaVals(3)]
   endif
   goto makepulses

   update3:
   if ChaVals(2)<1000 then
      serout Display, i19200, [254, 71, 1, 1, " ", dec ChaVals(2)]
   else
      serout Display, i19200, [254, 71, 1, 1, dec ChaVals(2)]
   endif
   goto makepulses

   update2:
   if ChaVals(1)<1000 then
      serout Display, i19200, [254, 71, 13, 2, " ", dec ChaVals(1)]
   else
      serout Display, i19200, [254, 71, 13, 2, dec ChaVals(1)]
   endif
   goto makepulses

   update1:
   if ChaVals(0)<1000 then
      serout Display, i19200, [254, 71, 13, 1, " ", dec ChaVals(0)]
   else
      serout Display, i19200, [254, 71, 13, 1, dec ChaVals(0)]
   endif
   goto makepulses


   ; build and send the ppm output
   makepulses:

   gosub GeneratePulses
endif

if Calibrated=0 & index=0 then
  gosub Calibrate
endif

; do it again ad infinitum
goto start

;------------------------------------------------------------------------------
; Generate Pulse function
;
; Variables used: ChanVals array has the pulse widths in us

GeneratePulses:
#ifndef DO_IN_BASIC
   ; fudge the values.  It looks like the transmitter may not fully accuratly take
   ; the signals in and give them out 100% correctly.  So try to fudge...
   for iFudge = 0 to 6
      ChaVals(iFudge) = chaVals(iFudge) - 3 + (ChaVals(iFudge)-988)/70
   next
   
      output DM8PPM
   ; The DM8PPM pin should already be configured for output...
      ; This is P15 on BAP which is P87 on the underlying H8/3694
      ; transistion to assembly language.
      ; fist setup loop counters and the like before we manipulate the IO port
   mov.l   #CHAVALS:32, er3      ; er3 has pointer to our array of desired values
   mov.b   #7, r2l            ; r2l has count of how many channels we wish to output
   bset.b   #7,@PCR8:8         ; make sure set to output, basic should have done earlier!
   
_MP_LOOP:   
   bset.b   #7,@PDR8:8         ; (L8)set P15 high (Low over head here 26)
   mov.w   #200, r1         ; (H4) - We want to pause 400 .5us (pauseus does .5 us)
   nop                     ; (H2)
   nop                     ; (H2)
   nop                     ; (H2)
   nop                     ; (H2)
   jsr      @_MP_PAUSE:24      ; (H8) - Call our wait function.

   bclr.b   #7,@PDR8:8         ; (H8) Go low again - so high overhead here (26)
   mov.w   @er3+, r1         ; (L6) Get the wait count for current channel from array and increment array pointer
   sub.w   #400, r1         ; (L4) subtract off our high pulse widths..
   jsr      @_MP_PAUSE:24      ; (L8) call our wait function
   dec.b   r2l               ; (L2) decrement our counter for how many items to output
   bne      _MP_LOOP:8         ; (L4) still more channels to output
;  loop is done, need to do trailing pulse
   bset.b   #7,@PDR8:8         ; (8)set P15 high
   mov.w   #200, r1         ; (4) - We want to pause 400
   jsr      @_MP_PAUSE:24      ; (8) - Call our wait function.
   bclr.b   #7,@PDR8:8         ; (8) Go low again
   bra      _MP_DONE:8         ; we are done!
   
; internal assembly function to wait a number of us
; Overhead of setup and call to here: 28 or 30
; setup and return overhead: 20: so total of 48/16 = 3us
; add/subtract some fudge
_MP_PAUSE:
   sub.w   #3, r1            ; (4) - subtract call/setup overhead from counter
   shal.w   r1               ; (2) - will multply by 16 to get clock cycles
   shal.w   r1               ; (2) - Should be safe max value ~2000
   shal.w   r1               ; (2)
   shal.w   r1               ; (2)
   nop                     ; fudge
   nop                     ;
   
_MP_PAUSE_LOOP:
   sub.w   #8, r1            ; (4) - decrement the time per loop cycle from loop
   bne      _MP_PAUSE_LOOP:8   ; (4) - hard spin in the loop. - since round number can simply test for zero

   rts                     ; (8) - return

_MP_DONE:
   ; will fall through to return and transition back into basic
#else
   ChaVals(0) = (((ChaVals(0)-PULSE_FIX)*2)-800) ; right vertical
   ChaVals(1) = (((ChaVals(1)-PULSE_FIX)*2)-800) ; right horizontal
   ChaVals(2) = (((ChaVals(2)-PULSE_FIX)*2)-800) ; left vertical
   ChaVals(3) = (((ChaVals(3)-PULSE_FIX)*2)-800) ; left horizontal
   ChaVals(4) = (((ChaVals(4)-PULSE_FIX)*2)-800)
   ChaVals(5) = (((ChaVals(5)-PULSE_FIX)*2)-800)
   ChaVals(6) = ((ChaVals(6)*2)-800)
   
   high DM8PPM ;pulsout 15,800
   pauseus 400
   low DM8PPM
   pauseus ChaVals(0)
   high DM8PPM ;pulsout 15,800
   pauseus 400
   low DM8PPM
   pauseus ChaVals(1)
   high DM8PPM ;pulsout 15,800
   pauseus 400
   low DM8PPM
   pauseus ChaVals(2)
   high DM8PPM ;pulsout 15,800
   pauseus 400
   low DM8PPM
   pauseus ChaVals(3)
   high DM8PPM ;pulsout 15,800
   pauseus 400
   low DM8PPM
   pauseus ChaVals(4)
   high DM8PPM ;pulsout 15,800
   pauseus 400
   low DM8PPM
   pauseus ChaVals(5)
   high DM8PPM ;pulsout 15,800
   pauseus 400
   low DM8PPM
   pauseus ChaVals(6)
   high DM8PPM ;pulsout 15,800
   pauseus 400
   low DM8PPM
#endif
   return

;------------------------------------------------------------------------------
; CheckKeypad function
;
; Variables updated:
;      wButtonPulseWidth - The pulse width
;      keypress - the ascii value associated with that key.
CheckKeypad:
   low  Row0
   high Row1
   high Row2
   high Row3
   
   col1 = in4
   col2 = in5
   col3 = in6
   col4 = in7

   ;Read buttons
   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 Row0
       low  Row1
       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 Row1
           low  Row2
           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 Row2
               low  Row3
               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


   return
   
;====================================================================
;Calibrates middle positions of the sticks to 1500
;Calibrates left vertical stick to be total down
Calibrate:
   serout Display, i19200, [254, 88] ;clear screen     
   serout Display, i19200, [254, 0, "Calibrating..."]
   pause 1000     
   
   ChaOffset(0) = 1500 - ChaVals(0) ; right vertical 16
   ChaOffset(1) = 1500 - ChaVals(1) ; right horizontal 17

; special care for this one as user(me) may forget to put down to bottom
;   if (chaVals(2) > 975) and (chaVals(2) < 1125) then
      ChaOffset(2) = 1000 - ChaVals(2) ; left vertical 18
;   else
;      ChaOffset(2) = 0
;   endif
   
   ChaOffset(3) = 1500 - ChaVals(3) ; left horizontal 19
   
   serout Display, i19200, [254, 88] ;clear screen
   
   ; Mark as calibrated
     Calibrated=1
return

;------------------------------------------------------------------------------
; DoRadioBind function
;
;      This function will set the 7 channels to fixed values that are transmitted
;       This is used when the user is trying to bind the transmitter to the receiver
;      Once bound, the receiver will use these values whenever it loses contact
;      with the transmitter.  This will allow us to have code on the receiver side
;      that can detect this and put the robot into a safe state.
;
;      TBD: Could allow the values to be set by each user, by where the sticks are, or
;      could use keypad to enter...
;
;      This function does not return.
DoRadioBind:

   serout Display, i19200, [254, 88] ;clear screen     
   serout Display ,i19200, [254, 0, ">>Radio Bind!<<"] ;startup screen. Do only once...

   while 1
      ChaVals = 1500, 1500, 800, 1500, 988, 988, 2000
      gosub GeneratePulses      ; output pulses.
      pause 6               ; not sure
   wend

   return   ; will never happen!
   


Here is my sample test program with the assembly level receive function that reads in all 7 channels regardless of the order. I do have some timeouts working in the code as well now.
Code:
;====================================================================
; DIY - Radio Receiver Test Program
;
; Currently this program assumes all 7 inputs are hooked up to P0-P6
; TBD - Make more general purpose, to allow different input pins.
;       For P1-P7 change mask from 0x7f to 0xfe and make pulse_values word(8)
;       For P8,10-15 change mask to 0xFD, PDR5 to PDR8, and pulse_values to word(8)
; BUGBUG - Need to check how PCR5 and PMR5 are used...

awPulsesIn          var word(7)
bPulseTimeout      var byte

awPulsesPrev      var   word(7)
fPulseChanged      var bit      ; we had a channel change
fNoTransmitter      var bit      ; did we detect no transmitter...
fLostTransmitter   var   bit      ; We lost contact with transmitter

i               var   byte
keypress          var byte
pulse_slop         con 2

;--------------------------------------------------------------------
; Init code
;====================================================================
   ; Make sure all 7 pins are marked for input...
   input p0
   input p1
   input p2
   input p3
   input p4
   input p5
   input p6
   
   fNoTransmitter = 0      ; assume we have a transmitter.
   fLostTransmitter = 0
   
start:
   gosub Pulsein7
   
   

   ; if we get a timeout and it is channel 0 then we now the receiver is not on...
   if (bPulseTimeout) then
      ; we detected no tranmitter at startup...
      if fNoTransmitter = 0 then
         serout s_out, i9600, ["No Transmitter at power up(",hex bPulseTimeout, ")", 13 ]
         fNoTransmitter = 1
      endif
   elseif awPulsesIn(0) < 950
      ; On Bind we set channel 1 to about 800 normal is usually > 1000 so if under 950
      ; we probably lost our connection with the transmitter
      if fLostTransmitter = 0 then
         serout s_out, i9600, ["Lost contact with transmitter", 13]
         fLostTransmitter = 1
      endif
   
   else
      ; Ok we hamve a message so reset our error codes
       fNoTransmitter = 0      ; assume we have a transmitter.
      fLostTransmitter = 0

      fPulseChanged = 0
      for i = 0 to 6
         if (awPulsesIn(i) > (awPulsesPrev(i)+pulse_slop)) or (awPulsesIn(i) < (awPulsesPrev(i)-pulse_slop)) then
            fPulseChanged = 1
            awPulsesPrev(i) = awPulsesIn(i)
         endif
      next
      
      if fPulseChanged or bPulseTimeout  then
         if awPulsesIn(6) < 1135 then 
            keypress = 0xff
         else
            keypress = (awPulsesIn(6)+15 - 1150) / 50  ; add in some slope as we could be slight
         endif
    
         serout s_out, i9600, [hex bPulseTimeout, ":", hex keypress, ":" ]
         for i = 0 to 6
            serout s_out, i9600, [dec awPulsesIn(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
   endif

goto start

;==============================================================================
; Read in all 7 servo values in one pass.
;   
;-------------------------------------------------------------------
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...
   
    ; Ok now lets transisiton to assembly language.
    ;
;    bMask = 0x7f                      ; set a mask of which bits we are needing...
;                                 ; Mask could be 0xFE for pins 1-7, need to make array 8 not 7
    mov.b   #0x7f, r1l                  ; Ok R1l will be our mask for outstanding IO port bytes.

    ; wait until none of the IO lines are high...
;    while PDR5 & bMask
;        ;
;    wend
   mov.l   #250000,er2                  ;(4) - setup timeout counter   
_PI7_WAIT_FOR_ALL_LOW:
   mov.b   @PDR5:8, r0l
   and.b   r1l, r0l         ; see if any of the IO bits is still on...
   beq      _PI7_WAIT_FOR_NEXT_IO_TO_GO_HIGH:8   ; all zero go to wait for one to go high...
   dec.l   #1,er2                     ;(2)   
   bne      _PI7_WAIT_FOR_ALL_LOW:8   ; an IO pin is high and we have not timed out, keep looping until none are high
   ; We timed out waiting for all inputs to be low, so error out...
   bra      _P17_RETURN_STATUS:16         ; will return status that all timed out...

;    while bMask   

_PI7_WAIT_FOR_NEXT_IO_TO_GO_HIGH:
   mov.l   #250000,er2                  ;(4) - setup timeout counter
   
_PI7_WAIT_FOR_NEXT_IO_TO_GO_HIGH2:
        ; we still need some 1 or more of the pulses...
;        while (PDR5 & bMask) = 0          ; waiting for a pulse to go high.
   mov.b   @PDR5:8, r0l               ;(4)
   and.b   r1l, r0l                  ;(*2) see if any of the IO bits is still on...
   bne      _P17_IO_WENT_HIGH:8            ;(*4) One went high so go process
   dec.l   #1,er2                     ;(2)   
   bne      _PI7_WAIT_FOR_NEXT_IO_TO_GO_HIGH2:8   ; (4) Not a timeout go try again.
; we timed out...
   bra      _P17_RETURN_STATUS:16         ; will return status of what timed out...
   
;      wend
;        iPin = ???; TBD: convert which bit is high to IO line number 0-6
;   see which bit is on in the mask
_P17_IO_WENT_HIGH:
   xor.w   r2,r2                     ;(*2)
   xor.b   r0h, r0h                  ;(*2)
   mov.l   #AWPULSESIN,er3               ;(*6)
_P17_WHICH_BIT_LOOP:   
   shlr.b   r0l                        ;(@2)
   bcs      _P17_WHICH_BIT_LOOP_DONE:8      ;(@4)
   inc.b   r0h                        ;(@2)
   inc.l   #2, er3                     ;(@2)  - point to the next place in the array.
   add.w   #18,r2                     ;(@4)  - we do 18 clocks for each pass through this loop
   bra      _P17_WHICH_BIT_LOOP:8         ;(@4)
_P17_WHICH_BIT_LOOP_DONE:
;        bMaskBit = 1 << iPin   ; get the mask for which pin...
   xor.b   r1h,r1h                     ;(*2)
   bset.b   r0h,r1h                     ;(*2) ok we have the mask
   bclr.b   r0h,r1l                     ;(*2) and clear it from our global mask of ones we are waiting for

                                 ; = (22) - count so far of clocks after went high
   
;       iPinLoopCnt = 0          ; This may be replaced with time calculations...
;        while (PDR5 & bMaskBit)
;            iPinLoopCnt = iPinLoopCnt + 1  ; how long until it goes low again
;        wend
_P17_WAIT_FOR_IO_GO_BACK_LOW:
   mov.b   @PDR5:8, r0l               ;(#4)
   and.b   r1h, r0l                  ;(#2)
   beq      _P17_IO_WENT_BACK_LOW:8         ;(#4)
   add.w   #18,r2                     ;(#4) - number of cyles per loop
   bcc      _P17_WAIT_FOR_IO_GO_BACK_LOW:8   ;(#4)
   
   ; we had a timeout return the status.
   bset.b   r0h, r1l                  ; turn back on the bit we were waiting for...
   bra      _P17_RETURN_STATUS:8         ;

_P17_IO_WENT_BACK_LOW:
   ; need to calculate the pulse width in ms... need to divide calculated clocks by 16
   add.w   #22,r2                     ; (4) ; need to add the rest of the overhead(*-1 loop above) in...
   shlr.w   r2                        ; (2)
   shlr.w   r2                        ; (2)
   shlr.w   r2                        ; (2)
   shlr.w   r2                        ; (2) / 16 (for clock speed)
   
;        aPulses(iPin) = iPinLoopCnt ; convert loop count to pulse width...
   mov.w   r2,@er3                     ; Save away the value
   
 ;       bMask = bMask & ~bMaskBit    ; turn off waiting for this one...
    or      r1l,r1l                     ; (2) see if we are done or not
;     wend
   bne      _PI7_WAIT_FOR_NEXT_IO_TO_GO_HIGH:16 ;(6)our mask has not gone to zero so wait for the next one.
   
_P17_RETURN_STATUS:   
   mov.b   r1l,@BPULSETIMEOUT
; finally transisition back to basic and return.
    return


Have fun
Kurt


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jan 03, 2009 8:42 pm 
Offline
Roboteer

Joined: Tue Sep 02, 2008 1:11 pm
Posts: 81
Location: Austin, TX
You are quite the programmer, Kurte. I know ALL the credit isn't yours, but thanks, non the less.

_________________
You don't stop playing because you get old; you get old because you stoped playing!


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jan 04, 2009 12:05 pm 
Offline
Robot Guru
User avatar

Joined: Sat Apr 15, 2006 1:42 pm
Posts: 4414
Core2 wrote:
You are quite the programmer, Kurte. I know ALL the credit isn't yours, but thanks, non the less.

Thanks, but as you said the credit should go out to several people here, including, Jim(Robot Dude) who wrote most of it, Xan who made a lot of nice improvements, Eddie who helped Jim with some of the Algorithyms as well as the electronics, ...

Kurt


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jan 04, 2009 12:13 pm 
Offline
Robot Guru
User avatar

Joined: Sat Apr 15, 2006 1:42 pm
Posts: 4414
I thought I would do a follow up post of some of the things I am considering to do next to see if it may overlap with anyone elses desires.

1) Update my rover code with the new functionality of the test program.

2)Change the Pulsin7 function on the receiver to maybe use the WTIMER values instead of directly computing time. This will hopefully allow me to still have accurate enough values even if I am processing interrupts. This would make it incompatible with HSERVO as hservo uses Wtimer directly.

3) Also considering changing the pulsin function to allow the user to set the Mask of which pins are used to any of the first 16. Would probably keep the code simple by saying that the array awPulseIn size needs to be the index of the largest one used +1. Only those pins that are set in the mask will have their values set in this array... Not sure if any of you would find this functionality useful, but I may experiment as to make it so I can free up some of the Analog pins as well as to not necesarily eat up the HSERIAL pins.

4) Play with XBEE. I would start out simple and hopefully use it as a serial port replacement. Would probably make it conditional and maybe only change the GeneratePulses function to simply send the two byte values for each of the 7 channels. On the receive side may simply use HSERIN to read in the 14 bytes and everything else could be reasonably transparent. If this works out we could then add in bidirectional communication...

That is all for now. What do you think?
Kurt


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jan 05, 2009 6:55 am 
Offline
Superguru of Robotics!!!
User avatar

Joined: Wed Nov 28, 2007 7:48 am
Posts: 1141
Location: Netherlands
Hi Kurt,

Great that you’ve got the binding part working. I didn’t had time to try it but the way you describe it, it should work perfect! Great work with the assembly code to. How did it work out? Is it more accurate then the basic code?

kurte wrote:
I thought I would do a follow up post of some of the things I am considering to do next to see if it may overlap with anyone elses desires.

Thanks for sharing your next plans. This keeps us from inventing things twice. Not that I was thinking of one of your points. (except maybe for point 4 :P)

kurte wrote:
2)Change the Pulsin7 function on the receiver to maybe use the WTIMER values instead of directly computing time. This will hopefully allow me to still have accurate enough values even if I am processing interrupts. This would make it incompatible with HSERVO as hservo uses Wtimer directly.

3) Also considering changing the pulsin function to allow the user to set the Mask of which pins are used to any of the first 16. Would probably keep the code simple by saying that the array awPulseIn size needs to be the index of the largest one used +1. Only those pins that are set in the mask will have their values set in this array... Not sure if any of you would find this functionality useful, but I may experiment as to make it so I can free up some of the Analog pins as well as to not necesarily eat up the HSERIAL pins.

I’m not totally sure that I understand what your saying but if you can improve the pulsin command it would be great. Can I still use the timer to read the cycle time? (I think this is the WTimer but correct me if I’m wrong). I personally don’t have a problem with loosing the HSERVO command. My SSC32 does that for me. But I don’t know about the other users. I think the mask will be a good idea to keep the code easy to read.

kurte wrote:
4) Play with XBEE. I would start out simple and hopefully use it as a serial port replacement. Would probably make it conditional and maybe only change the GeneratePulses function to simply send the two byte values for each of the 7 channels. On the receive side may simply use HSERIN to read in the 14 bytes and everything else could be reasonably transparent. If this works out we could then add in bidirectional communication...

Bidirectional communication would be great and the single pin serial input would be much faster and uses less pins. I was thinking about Bluetooth but this takes much more current then XBEE. I’m not sure yet but I might try something later on. But make it switchable so I can always use the DM8 as well.

Thanks for all the great work you put in to this!

Xan

_________________
[b]Share, Use and Improve![/b]
Digging trough: [i]Theory of Applied Robotics: Kinematics, Dynamics, and Control[/i]
Xan's YouTube Channel
http://www.youtube.com/xanore


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jan 05, 2009 10:58 am 
Offline
Robot Guru
User avatar

Joined: Sat Apr 15, 2006 1:42 pm
Posts: 4414
Xan wrote:
Hi Kurt,

Great that you’ve got the binding part working. I didn’t had time to try it but the way you describe it, it should work perfect! Great work with the assembly code to. How did it work out? Is it more accurate then the basic code?

I think it is more accurate going into the transmitter, but what I found was that the transmitter itself is the thing that was not completely accurate. So if I generated the pulses exactly for 1500 it may output 1495 and for 1000 may output 1003... So I started playing around with a fudge function at the start of the transmit code and then hooked up the logic analyzer to the 7 channels on the receiver and kept playing with the fudge factors until they appeared to be close enough.

Xan wrote:
I’m not totally sure that I understand what your saying but if you can improve the pulsin command it would be great. Can I still use the timer to read the cycle time? (I think this is the WTimer but correct me if I’m wrong). I personally don’t have a problem with loosing the HSERVO command. My SSC32 does that for me. But I don’t know about the other users. I think the mask will be a good idea to keep the code easy to read.

Yes we could setup WTIMER to use common code such that multiple of us can use it's tick. Awhile ago Nathan (AcidTech) was working on an experimental version of the BAP ide and he was proposing supplying a wtimer service. I don't remember what resolution he had it set for (ie counting in tics or ticks/8...), but we can easily settle on one.

Now the reason I am considering comverting the code from using the calculated number of cycles where is very accurate is because we may want to use interrupts for other things like your timer tick. Or maybe on my Rover to to handle the encoder(s). The current code does a good job of counting clock cycles for the main code, but suppose while it is counting tics for a channel to go back low, we get a WTIMER overlow interrupt. My quick calculations are that processing one WTIMER overlow may take (14 cycles to handle intterupt, + 40 cycles in the interrupt handler) or 54 clock cycles, which when divided by 16 implies our pulse width would be off by 3 or 4, and that is for one interrupt.

Does that make sense?


Xan wrote:
kurte wrote:
4) Play with XBEE. I would start out simple and hopefully use it as a serial port replacement. Would probably make it conditional and maybe only change the GeneratePulses function to simply send the two byte values for each of the 7 channels. On the receive side may simply use HSERIN to read in the 14 bytes and everything else could be reasonably transparent. If this works out we could then add in bidirectional communication...

Bidirectional communication would be great and the single pin serial input would be much faster and uses less pins. I was thinking about Bluetooth but this takes much more current then XBEE. I’m not sure yet but I might try something later on. But make it switchable so I can always use the DM8 as well.

That is the idea, although I can imagine that once we have bidirectional communication working, we may diverge some. For example maybe you want the LCD on the transmitter to display other information, like maybe power levels on the robot, or information from a sensor...

Should be fun!

Kurt


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jan 05, 2009 3:55 pm 
Offline
Lynxmotion Founder
User avatar

Joined: Mon Oct 31, 2005 10:46 am
Posts: 9325
Location: my quiet place
kurte wrote:
It also suprised me that if you wanted a pulse of 1500 you have a high pulse of 200 followed by low of 1100 followed by high of 200. I would have expected either the pulse width low for 1500 should either be 1500 or incuding the high pulse (1500-200), but that does not appear to be what it is, so...


You may have already figured this out, and it fooled me at first too. The solution should be pulsout (800) 400uS then pause for the 1100uS. Pulsout is 0.5uS resolution. :)

_________________
Jim Frye, the Robot Guy
http://www.lynxmotion.com
I've always tried to do my best...


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 07, 2009 3:30 am 
Offline
Superguru of Robotics!!!
User avatar

Joined: Wed Nov 28, 2007 7:48 am
Posts: 1141
Location: Netherlands
Hi Kurt,

I’ve tried V1.2 yesterday and to keep it short: Your binding methods rocks! 8)
It took me some time to figure out the steps. I’m the typical technician that always reads the manual after trying to figure it out by itself…Now it works perfect! If the radio is switched off the phoenix easy returns to his rest position and switches off.

I didn’t tried compared your receiver part with mine. Put I’m planning to do that later on…

Xan

_________________
[b]Share, Use and Improve![/b]
Digging trough: [i]Theory of Applied Robotics: Kinematics, Dynamics, and Control[/i]
Xan's YouTube Channel
http://www.youtube.com/xanore


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 07, 2009 3:34 am 
Offline
Superguru of Robotics!!!
User avatar

Joined: Wed Nov 28, 2007 7:48 am
Posts: 1141
Location: Netherlands
Hi Orac,

Orac wrote:
Anyone hazard a guess to the 'all-in' cost of putting one of these together?


I don’t know the exact cost but I can help you make a shopping list ;)
    1 x Bot Board 2
    1 x BASIC Atom pro 28
    1 x DSM2 Airmod
    1 x Keypad
    1 x Display MOS-AL162-A, Maybe somebody can fill me in where you can get them.
    2 x Joystick. Maybe somebody can fill me in where you can get them.
    2 x slider potentiometers I think 10k will do the job but I can check out the once I’ve got.
    1 x 6V Battery pack
    2 x Switches for switching the power to the BAP and DSM2
    1 x Casing, I have to lookup the size of that… Or maybe someone knows the exact type.

Hope I didn’t forget something…

If you are planning to build the same setup you can easy download the program of this topic.
If there are any questions, please let me know.

Xan

_________________
[b]Share, Use and Improve![/b]
Digging trough: [i]Theory of Applied Robotics: Kinematics, Dynamics, and Control[/i]
Xan's YouTube Channel
http://www.youtube.com/xanore


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 07, 2009 10:32 am 
Offline
Robot Guru
User avatar

Joined: Sat Apr 15, 2006 1:42 pm
Posts: 4414
Hi Xan,

Thanks!

As for the parts list. I think you can order the LCD directly from Matrix Orbital. http://www.matrixorbital.com/mosal162abw-p-334.html

Kurt


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 07, 2009 11:33 am 
Offline
Lynxmotion Founder
User avatar

Joined: Mon Oct 31, 2005 10:46 am
Posts: 9325
Location: my quiet place
I can help.

The joysticks were from Hitec Laser 4 radios. Any RC gimbal should work for this.

The slider pots must be linear taper, not audio taper. I got them from Mouser. The pots are 312-9201F-5K, and the 450-3051. The price is $1.38 each.

The keypad is a simple 16 key row and column keypad. I found them at electronix express http://www.elexp.com part number 17KP1604. I like this one because it has the ABCDEF keys instead of the telephone * # stuff... The price is $6.25 each.

The display is from Matrix Orbital.

The case was from Polycase. I paid like $75.00 setup for them to mill the case down to just 1.5" tall. The cases were around $8.00. I doubt they will allow anyone else to buy them with my mill down setup charge even though I don't care. They wouldn't even let me return 2 of the unmodified ones I bought earlier to have them cut them down. The top panels were made by me using my laser. Unfortunately I'm not able to make these parts for sale.

_________________
Jim Frye, the Robot Guy
http://www.lynxmotion.com
I've always tried to do my best...


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jan 12, 2009 4:53 pm 
Offline
Robot Guru
User avatar

Joined: Thu Nov 09, 2006 5:46 am
Posts: 2078
Location: Norway
Hi,

Thanks for your great work with the code Kurt!
The v 1.2 works fine, have not tried the BIND function yet...
I'm just finished sandblasting and remounting the DIY remote. Mounted the antenna in a similar way like Xan did. And also added a serial/com extension plug.

Picture of my precious DIY remote. :twisted: :

Image

Thanks again Jim! 8)
BTW, I just had to replace some of the screws... :roll:

_________________
[b]Kåre Halvorsen, Zenta[/b]
-----------------------------------------
Zenta's blog
http://zentasrobots.com/
Zenta's YouTube channel
http://www.youtube.com/ZentaOlbaid
-----------------------------------------


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 289 posts ]  Go to page Previous  1 ... 11, 12, 13, 14, 15, 16, 17 ... 20  Next

All times are UTC - 6 hours [ DST ]


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group