"Chum Dispenser" solution with picaxe - advice needed by noob

hippy

Technical Support
Staff member
I think it would help to produce a clear specification of what is needed and to start with it seems to split between two parts; the primary part which flings fish and a secondary part, an alarm which sounds when a fish hasn't been flung. We can deal with the first without worrying about the second, bolt that on later.

There is a three way switch, a speed pot and a motor. That motor is constant speed, only on or off, so no need for motor speed control; the speed pot controls the rate of delivery not the speed of motor.

Switch position 1: Motor stopped. Easy.

Switch position 2: Motor always on. Also easy.

Switch position 3: The more complicated part. Motor runs until a fish has been flung. Once flung the motor stops for a period set by the pot, then starts again. An additional requirement will probably be that it is responsive to pot changes; if set for a minute then switched to 10 seconds one does not want to wait for the rest of that minute to pass before it changes to a 10 second interval.

That gives us a basic framework for a single task, linear program which could be as follows -

Code:
MainLoop:
  Do
    Gosub DetermineSwitchPosition
    If switchPosition = 1 Then Stopped
    If switchPosition = 2 Then AlwaysOn
    If switchPosition = 3 Then IntervalTiming
  Loop

Stopped:
  Gosub TurnMotorOff
  Do
    Gosub DetermineSwitchPosition
    If switchPosition <> 1 Then MainLoop
  Loop
  
AlwaysOn:
  Gosub TurnMotorOn
  Do
    Gosub DetermineSwitchPosition
    If switchPosition <> 2 Then MainLoop
  Loop

IntervalTiming:
  fishFlung = 0
  Gosub TurnMotorOn
  Do
    Gosub DetermineSwitchPosition
    If switchPosition <> 3 Then MainLoop
  Loop Until fishFlung <> 0
  Gosub TurnMotorOff
  elapsedTime = 0
  Do
    Gosub DetermineSwitchPosition
    If switchPosition <> 3 Then MainLoop
    Pause 10
    elapsedTime = elapsedTime + 10
    Gosub DeterminePotTime
  Loop Until elapsedTime >= potTime    
  Goto IntervalTiming

TurnMotorOn:
  ; Some code here
  Return

TurnMotorOff
  ; Some code here
  Return

DetermineSwitchPosition:
  ; Some code here which sets 'switchPosition' variable
  Return

DeterminePotTime:
  ; Return potTime as 1000ms to 60000ms
  Symbol MAX_SECONDS = 60
  Symbol MIN_SECONDS = 1
  ReadAdc POT_PIN, potTime
  potTime = MAX_SECONDS - MIN_SECONDS * potTime / 255 + MIN_SECONDS * 1000
  Return
The one thing missing in that is there is nothing which sets the 'fishFlung' variable. An interrupt when the opto detector activates as a fish passes through the beam and sets 'fishFlung=1' will solve that.

To add an alarm one needs to add some elapsed timer counting when the motor is on and we are waiting for the fish to be flung, something like ...

Code:
IntervalTiming:
  fishFlung = 0
  [b]elapsedTime = 0[/b]
  Gosub TurnMotorOn
  Do
    Gosub DeterineSwitchPosition
    If switchPosition <> 3 Then MainLoop
    [b]Pause 10
    elapsedTime = elapsedTime + 10
    If elapsedTime >= 60000 Then SoundAlarm[/b]
  Loop Until fishFlung <> 0
All timing is done with millisecond units and 16-bit word variables hold time as millisecond values. That limits things to 65 seconds which is okay here.
 

satrapus

Member
Thanks once more for all the help :)

Before I study you post here is what I came up with last night....
As I'm still waiting for my 18M2 and CHI035 board it's more of a logic test harness.
Undoubtedly there are some ugly things in there but I'm still discovering the language syntax.
I'm using the simulator and looking at the output pins it does what I want it too.
Pin c2 will in theory always be high and only a fish breaking the beam switches it to low temporarily.
I flick it off/on to test the logic of the program.

Code:
#picaxe 18m2
;#define simulating ; compiles but doesn't run?

; VARIABLES
symbol timer_value = b2        ; value read from pot
symbol alarm_delay = b3       ; sound alarm afer so many secs

; INPUTS
symbol cont_mode = pinc.0     ; continuous mode
symbol timer_mode = pinb.7     ; timed mode
symbol timer_pot = c.1         ; timer potentiometer knob
symbol ir_photo_mod = pinc.2     ; ir photo modulator

; OUTPUTS
symbol ir_emitter = b.0     ; ir led
symbol dc_motor = b.1         ; 12v dc motor
symbol piezo = b.2         ; piezo buzzer

init:       
    ;initialize output pins
    low dc_motor;
    low piezo;

    ;initialize variables
    timer_value = 5
    alarm_delay = 10

main:
do

;#ifdef simulating
pause 500
;#endif

if cont_mode = 1 then   
    high dc_motor        ; Activate motor pin
endif

if timer_mode = 1 then
    if pinb.1 = 0 then ; if motor stopped
        ;wait timer_value ; error?
	  wait 5
        high dc_motor
    endif
	if time >= alarm_delay then
    		high piezo
	endif

endif

;break in ir beam indicates fish thrown out - stop motor
if ir_photo_mod = 0 and timer_mode = 1 then
    low dc_motor
    time = 0
    if pinb.2 = 1 then
        low piezo
    endif
endif

loop

end
 
Last edited by a moderator:

Blazemaguire

Senior Member
Satrapus.... glad to see you ended up here! Given up on the 555 timers then? Probably for the best with this project! Rob
 

satrapus

Member
I think it would help to produce a clear specification of what is needed and to start with it seems to split between two parts; the primary part which flings fish and a secondary part, an alarm which sounds when a fish hasn't been flung. We can deal with the first without worrying about the second, bolt that on later.

There is a three way switch, a speed pot and a motor. That motor is constant speed, only on or off, so no need for motor speed control; the speed pot controls the rate of delivery not the speed of motor.

Switch position 1: Motor stopped. Easy.

Switch position 2: Motor always on. Also easy.

Switch position 3: The more complicated part. Motor runs until a fish has been flung. Once flung the motor stops for a period set by the pot, then starts again. An additional requirement will probably be that it is responsive to pot changes; if set for a minute then switched to 10 seconds one does not want to wait for the rest of that minute to pass before it changes to a 10 second interval.

That gives us a basic framework for a single task, linear program which could be as follows -

Code:
MainLoop:
  Do
    Gosub DetermineSwitchPosition
    If switchPosition = 1 Then Stopped
    If switchPosition = 2 Then AlwaysOn
    If switchPosition = 3 Then IntervalTiming
  Loop

Stopped:
  Gosub TurnMotorOff
  Do
    Gosub DetermineSwitchPosition
    If switchPosition <> 1 Then MainLoop
  Loop
  
AlwaysOn:
  Gosub TurnMotorOn
  Do
    Gosub DetermineSwitchPosition
    If switchPosition <> 2 Then MainLoop
  Loop

IntervalTiming:
  fishFlung = 0
  Gosub TurnMotorOn
  Do
    Gosub DetermineSwitchPosition
    If switchPosition <> 3 Then MainLoop
  Loop Until fishFlung <> 0
  Gosub TurnMotorOff
  elapsedTime = 0
  Do
    Gosub DetermineSwitchPosition
    If switchPosition <> 3 Then MainLoop
    Pause 10
    elapsedTime = elapsedTime + 10
    Gosub DeterminePotTime
  Loop Until elapsedTime >= potTime    
  Goto IntervalTiming

TurnMotorOn:
  ; Some code here
  Return

TurnMotorOff
  ; Some code here
  Return

DetermineSwitchPosition:
  ; Some code here which sets 'switchPosition' variable
  Return

DeterminePotTime:
  ; Return potTime as 1000ms to 60000ms
  Symbol MAX_SECONDS = 60
  Symbol MIN_SECONDS = 1
  ReadAdc POT_PIN, potTime
  potTime = MAX_SECONDS - MIN_SECONDS * potTime / 255 + MIN_SECONDS * 1000
  Return
The one thing missing in that is there is nothing which sets the 'fishFlung' variable. An interrupt when the opto detector activates as a fish passes through the beam and sets 'fishFlung=1' will solve that.

To add an alarm one needs to add some elapsed timer counting when the motor is on and we are waiting for the fish to be flung, something like ...

Code:
IntervalTiming:
  fishFlung = 0
  [b]elapsedTime = 0[/b]
  Gosub TurnMotorOn
  Do
    Gosub DeterineSwitchPosition
    If switchPosition <> 3 Then MainLoop
    [b]Pause 10
    elapsedTime = elapsedTime + 10
    If elapsedTime >= 60000 Then SoundAlarm[/b]
  Loop Until fishFlung <> 0
All timing is done with millisecond units and 16-bit word variables hold time as millisecond values. That limits things to 65 seconds which is okay here.
Another daft question...
The code in IntervalTiming is calling subprocedure DeterminePotTime every 10 miliseconds to check if timer pot input knob has been changed.

My ir output beam will be bounced off a reflector meaning the ir input sensor will always be high apart from the time a fish goes overboard.
Is there an advantage to using an interrupt for this event as opposed to continually checking the input on the ir sensor much like the timer pot?

Aftery every DeterminePotTime call I'd also call setFishFlung

setFishFlung:
; reflector keeps ir sensor high until fish breaks beam
if ir_photo_mod = 0 then
fishFlung = 1
else fishFlung = 0
endif
return

I think it would be called often enough to not miss a flung fish but maybe this is where I'm mistaken.

Thanks
 

hippy

Technical Support
Staff member
You could get away with polling and you could probably add a resistor and capacitor to stretch the opto pulse so it is always seen if needed. You can also poll faster than every 10ms.
 

satrapus

Member
I did some testing today.
All is well with the blood n guts dispenser apart from the timing.
The faster I poll the worse it is.

Polling at 10ms in main loop results in what should be 60 seconds actually being 2m 28s
25ms - 1m 35s
50ms - 1m 17s

I don't suppose I can avoid this as code execution takes time too, or is there a way?
 

lbenson

Senior Member
Show your current code. What speed are you running at? What chip? (since it's been 3+ weeks.)

With only 3 pins to check, you should be able to poll hundreds of times a second.
 
Last edited:
Top