0

I am writing a script to decode morse inputs using a momentary pushbutton and a piezo buzzer and I've run into an interesting snag. My program will periodically crash without giving me any traceback details. I suspect i might be running into a memory issue, but without any crash or error details, it's hard to say. There are a lot of datetime.now() calls being made in rapid succession which might be the culprit.

Basically you tap a morse character (currently only s (...) or o (---) using a button, the script will evaluate your character to see if it is acceptable, then play either an accept or deny tone, store the character if accepted, and wait for the next input.

This is being run on a Raspberry Pi 3 B

Any help is appreciated.

edit: Code added as requested:

import RPi.GPIO as GPIO
from datetime import datetime
import time, traceback, threading
print('Running button program')
GPIO.setmode(GPIO.BOARD)

b = 37 #button pin

GPIO.setup(b, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

class buzzer():  #piezo buzzer handler
    def __init__(self, pin, freq):
        GPIO.setup(15, GPIO.OUT)
        GPIO.output(15, 1)
        self.p = GPIO.PWM(pin, freq) #15, 50

    def encode(self):
        self.p.start(90)
        self.p.ChangeFrequency(7000)

    def accept(self):
        self.p.start(90)
        self.p.ChangeFrequency(2000)

    def deny(self):
        self.p.start(90)
        self.p.ChangeFrequency(300)

    def stop(self):
        try:
            self.p.stop()
        except:
            pass

class charPart(): #dots and dashes
    def __init__(self):
        self.timeStarted = datetime.now()

class morseChar(): #combination of parts
    def __init__(self):
        self.parts = []
        self.timeCreated = datetime.now()

    def addPart(self, part):
        if len(self.parts) < 5:
            self.parts.append(part)
        else:
            print('Too many parts')

class morseString(): #runnung list of characters
    def __init__(self):
        self.chars = []
        self.mDict = {'s':'...', 'o':'---'}

    def addChar(self, char):
        self.chars.append(char)

    def validateString(self, char):
        ret = False
        for c in self.mDict:
            if self.mDict[c] == char:
                ret = True
        return ret

buz = buzzer(15, 50)

def threadTimer(): #multithreaded timer that modifies a var after a set time
    global stopChar
    stopChar = True

def mainloop(): #main program loop
    global stopChar
    while True:
        try:
            mChar
        except NameError:
            mChar = None
            threadStart = None
            stopChar = False
        if mChar:
            if threadStart:
                print('starting thread')
                threading.Timer(3, threadTimer).start()
                threadStart = False
            if stopChar:
                try:
                    mString
                except NameError:
                    mString = morseString()
                string = ''.join(mChar.parts)
                if mString.validateString(string):
                    mString.addChar(string)
                    print(mString.chars)
                    buz.accept()
                    time.sleep(0.2)
                    buz.stop()
                else:
                    buz.deny()
                    time.sleep(0.2)
                    buz.stop()
                mChar = None
                stopChar = False
        mCharPart = None
        while GPIO.input(b):
            if not mChar:
                mChar = morseChar()
                threadStart = True
            if not mCharPart:
                mCharPart = charPart()
            buz.encode()
        if mCharPart:
            start = mCharPart.timeStarted
            stop = datetime.now()
            buz.stop()
            dur = stop-start
            if .03 < dur.total_seconds() < .2:
                mChar.addPart('.')
            else:
                mChar.addPart('-')
            del mCharPart

##try:
mainloop()
##except KeyboardInterrupt:
##    GPIO.cleanup()
##except:
##    GPIO.cleanup()
##    tb = traceback.print_exc()
##    print(tb)
  • The code you have added doesn't do anything. The lines just containing mChar and mString are incomplete. – joan Nov 2 '16 at 9:05
  • Just based off my testing I can assure it does what it is intended to do - decode morse inputs. It's the crashing that is of concern. – bluefoot Nov 2 '16 at 13:20
  • The code as posted does nothing. – joan Nov 2 '16 at 13:34
  • The lines with just mChar and mString are just tests to see if those variables have been created. The following except block creates them if the try block fails. – bluefoot Nov 2 '16 at 13:52
  • Ah, okay. I was expecting it to work the other way around. Read a character and output the morse. – joan Nov 2 '16 at 13:58
1

There are a number of open issues on PWM with RPi.GPIO.

See https://sourceforge.net/p/raspberry-gpio-python/tickets/

I haven't looked too carefully at your code but you seem to make repeated start and stops of PWM. That seems to crash.

My initial thought is that you should redesign your code to only use one start (at initialisation) and one stop (at termination). Control the rest with the dutycycle method.

  • This seems to have been the problem! I've reworked it so that the PWM is started only when the buzzer is initialized and then just change duty cycles between 100 and 90 to 'turn it on/off'. No crashes since. – bluefoot Nov 2 '16 at 13:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.