Shop OBEX P1 Docs P2 Docs Learn Events
ServoInput watchdog attempt: Not counting transitions as expected — Parallax Forums

ServoInput watchdog attempt: Not counting transitions as expected

mmgoodmmgood Posts: 19
edited 2016-04-02 15:38 in Propeller 1
I'm using David Gregory's ServoInput.spin to read a couple of R/C receiver servo channels, then I'm doing some process control calculations before passing an R/C servo pulse to a motor controller. It's all your typical R/C servo 1 to 2 ms positive pulses, about 20 times a second.

ServoInput.spin runs its innermost loop with a waitpeq() and waitpne(), and I gather those can (will) hang indefinitely waiting for a transition. Anyone reading its output variables will see them frozen at the value of the last valid pulse durations.

My receiver stops sending pulses on loss of signal (LOS); I'd like to stop passing pulses to the motor controller when that happens. My thought was to run a watchdog cog or two (wasteful, but I'm just prototyping here, OK?) to count transitions over a period of, say, a second or so. If the counts of transitions are zero, we know the values that ServoInput has stuffed into its pulseWidths are "stale" and we can stop passing pulses along until we're getting real ones again.

So here's a couple of snippets of what I've tried. The code's ugly, the approach inefficient; I'm stuck. The code below always seems to return 0 for both transition counts (in the variables Pulses01 and Pulses02).

Have I provided enough context and info here? Please advise. Thanks.
VAR
  long  Stack01[24]             'Stack space for new cogs: overkill?
  long  Stack02[24]
  long  Pulses01
  long  Pulses02
  byte  p
  byte  pp

PUB SeenPulse(Pin, Delay, tcountbuffer) | tlimit, transcount
  ' (Attempted) watchdog. Look at pin, xor against last value. 
  ' Every "true" xor, increment transcount.
  ' Every delay's worth of seconds, plug a new value into tcountbuffer.
  ' If no transitions in that period, the zero value should be interpreted
  ' as LOS detection; wdogOK should be set to FALSE.
  pp := 0
  p  := pp
  repeat
    transcount := 0
    tlimit := Delay + cnt
    repeat
      p := ina[Pin]
      if p ^ pp ' Spin's bitwise xor function
        transcount += 1
      ' if change, increment transcount
      pp := p
    until cnt > tlimit
    tcountbuffer := transcount

'...
'...and then in the initialization part of my code, I fire up two cogs like so:

  cogsuccess := cognew(SeenPulse(k#ailepin, 80_000_000, Pulses01), @Stack01)       '1 second wdog
  cogsuccess := cognew(Seenpulse(k#gearpin, 80_000_000, Pulses02), @stack02)     ' 2 cogs is rather wasteful of resources, but "meh" for now

Comments

  • I recently modified Duan Degn's SR04 ultrasonic receiver object to support timeouts and still use waitpne. It uses a second unused pin controlled by a counter for the timeout, and does waitpne on both the target and timeout pin at the same time. The main timer code, which should be pretty similar to what you want, is as follows:
    PUB timepin(pin, timeout, timeoutticks) : timer | pm, tm
      pm := |< pin                  ' calculate pin mask
      tm := |< timeout              ' calculate timer mask
    
      ctra~                         ' disable ctra
      phsa~                         ' reset phase
      frqa := posx / timeoutticks   ' set frequency
    
      ' setup ctra to set outa[timeout] := phsa[31] every cycle
      ' and to accumulate phsa += frqa every cycle
      ctra := %0_00100_000_00000000_000000_000_000000 | timeout
    
      dira[timeout]~~               ' make timeout pin an output
    
      waitpne(0,  pm | tm, 0)       ' Wait for pin to go high, or for timeout
      timer := -cnt                 ' Start timer
      waitpne(pm, pm | tm, 0)       ' Wait pin to go low, or for timeout
      timer += cnt                  ' Stop timer
    
      ctra~                         ' disable ctra
    
      if ina[timeout]               ' if timeout
        timer~~                     ' set time to -1
    
      dira[timeout]~                ' make timeout pin an input
    

    The first argument is the pin you want to time, the second is an extra unused pin used for the timeout, and the third is how long (e.g. clkfreq/10 for 0.1 seconds) the timeout should be. It returns -1 if the entire pulse does not fit within the timeout. It waits for the pin to go high then low - swap the two waitpne lines if this is wrong.
  • I'll look at integrating this into David Gregory's stuff. Thanks.
  • mmgood, I looked at David Gregory's object and it makes sense to me.
    This line of code tells you how many microseconds have elapsed for each servo.
    phsa /(clkfreq/1_000_000)
    
    If you want to read input from your receiver before you send the data to your motor controller you can modify "ServoInput" to read 2 pins from your receiver instead of 4 pins from servos then you can pass those values to your motor controller. The other modification I would make is to change "vga text" to the Propeller serial terminal because I don't have a vga monitor.
    One other thing: "It's all your typical R/C servo 1 to 2 ms positive pulses, about 20 times a second."

    About once every 20 milliseconds a 'position' pulse lasting somewhere between 0.6ms and 2.4ms tells the servo controller what position the servo should hold. That's the pulse you want to read and pass to your motor controller.
    @ 20ms the refresh rate is 50 times/sec
Sign In or Register to comment.