The Coding Part of TWHPFS.

In this article, I will document the coding part of my TWHPFS.

Source code here.

It’s just a python script. I am a newbie to python, hope you won’t laugh about my messy code, hahaha.

Talk about the logic:

Ok, firstly we need variables representing the physical units, which are, LCD, button, led, servo,

# pin for hardwares
lcd = Adafruit_CharLCD(rs=26, en=19, d4=13, d5=6, d6=5, d7=11, cols=16, lines=2)
led = PWMLED(17)
servo = Servo(22) 
button = Button(4)

# setup
servo.max()

We need a timer, which contains start time and time now. We don’t need to hold time now because it constantly changing, and we can get it from the system at any time. So:

time_start = time()
seconds = 0
minutes = 0
lcdTime = ""

To calculate the RPM, my solution is using a Hall effect sensor. Whenever the sensor triggers, I store the timestamp into an array. So, the last timestamp minus the first time stamp, divided by the intervals, I can have the RPM!

pulsesStamps = []
rpmStartTime = time()
currentRpm = 0

And here is the most important part, the workflow:

  1. Wait to be triggered –
  2. Spinning –
  3. Stoped
  4. showing message1
  5. Showing message2
  6. Wait to be triggered.

We use stages to represent each part so the program would know where it is.

# stage:
# 0 = begining, wait for pushing button
# 1 = spinning, wait for stop
# 2 = is stoped, showing time
# 3 = is stoped, showing message
# 4 = ending, auto matically go to begining
stage = 0

Then, based on the variables needed, let’s import the libraries.

from gpiozero import Button, PWMLED, Servo
from Adafruit_CharLCD import Adafruit_CharLCD
from time import time, sleep
import decimal
import RPi.GPIO as GPIO

Then the functions.

To get the servo triggered, I need two callback functions, one of which being called whenever the button is pressed, another one released.

# what to do when pressing button

def triggerServo1():
  global stage 
  stage = 1 
  servo.mid()
  lcd.clear()
  led.value = 0.8
  print("pressed")
  
def triggerServo2():
  sleep(0.05)
  servo.max()
  led.value = 0.2
  recordStartTime()

Moreover, when I release the button, the start time got reset.

def recordStartTime():
  global time_start, minutes
  time_start = time()
  minutes = 0
  print("startTimeRefreshed")

When it is spinning, we need to:

  1. Run the timer and RPM calculator
  2. Show it on the LCD.

Let’s wrap it inside a function:

# stage 1, spining
def Spin ():
  global currentRpm, stage, pulsesStamps, seconds, minutes, rpmStartTime, time_start, lcdTime
  if stage == 1 :   
    if (time() - rpmStartTime) >= 2 and len(pulsesStamps) >= 2 :
      currentRpm = 60 / ((pulsesStamps[-1] - pulsesStamps[0]) / (len(pulsesStamps)-1))
      rpmStartTime = time()
      del pulsesStamps[0: (len(pulsesStamps)-2)]
      print(currentRpm)
      if currentRpm <= 30 :
        print("RPM < 30, Stopped")
        stage = 2
    
    seconds = int(time() - time_start) - minutes * 60
    try:    
      if (time() - pulsesStamps[-1]) >= 5:
        print("Not detect spin for 5 second, Stopped")
        stage = 2       
    except:
      pass
    if seconds >= 60:
                minutes += 1
                seconds = 0
    if seconds < 10 :
      lcdTime = str(minutes)+ "'0" +str(seconds)+ '"  RPM ' + str(currentRpm)
    else: 
      lcdTime = str(minutes)+ "'" +str(seconds)+ '"  RPM ' + str(currentRpm)
    lcd.clear()
    lcd.message(lcdTime)
    if currentRpm >= 400:
      lcd.message("\n" + "Are You Cheating?")

When it stops:

  1. Blink the timer and RPM 4 times.
  2. Show the equality;
  3. Show the description;
  4. If user press the button now, break.
#stage 2,3,4, stopping
def Stop ():
  global currentRpm, pulsesStamps, stage
  if stage == 2 :
    pulsesStamps = []
    for i in range (0,4):
      lcd.clear()
      sleep(0.2)
      lcd.message(lcdTime)
      sleep(0.2)
    stage = 3
  if stage == 3 :
    congrat1 = str(minutes)+ "'" +str(seconds)+ '"' + " = " + "$" + str(0.07 * (minutes*60 + seconds)) 
    congrat2 = "    $1766/Credit in ITP is $0.7/second, and you just wasted "+ str(minutes)+ "'" +str(seconds)+ '"' +" here.  "
    lcd.clear()
    lcd.message(congrat1)   
    for i in range(0,len(congrat2)-16):
      lcd.message("\n" + congrat2[i:i+16])
      sleep(0.5)
      if stage == 1:
        break
    if stage == 3:
      sleep (3)
      stage = 0

Callback function to save the timestamp in the list.

# setup call back event
GPIO.setmode(GPIO.BCM)
print("Setup GPIO pin as input on GPIO27")
GPIO.setup(27 , GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(27, GPIO.BOTH, callback=sensorCallback,bouncetime=10)
# call this to record the time stamp when hall effect sensor activated
def sensorCallback(channel):
  timestamp = time()
  if stage == 1 and GPIO.input(channel):
  pulsesStamps.append(timestamp)

Set the loop

It’s just like Arduino, but we better wrap it inside a try to deal with errors.

# loop
try:
  while True:
    sleep(0.1)
    button.when_pressed = triggerServo1
    button.when_released = triggerServo2
    WaifForStart()
    Spin()
    Stop()
    print(stage)
except KeyboardInterrupt:
  GPIO.cleanup()

 

That’s pretty much it.

 

 

 

 

 

 

 

 

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *