简体   繁体   中英

Raspberry Pi Python loop stop to work

i manipulate a sensor : HC SR04 to capture a distance. I'm a newbie in Python and RPI. My code work, I capture distance during a time but one moment the script stop...

My code :

GPIO.setmode(GPIO.BCM)

GPIO_TRIGGER = 23
GPIO_ECHO = 24

GPIO.setup(GPIO_TRIGGER, GPIO.OUT)
GPIO.setup(GPIO_ECHO, GPIO.IN)

def main():
    global state
    print("ultrasonic")
    while True:
        print "1s second refresh.."
        time.sleep(1)

        i = 0
        datas = []
        average = 0

        while i< 1:
            GPIO.output(GPIO_TRIGGER, False)

            time.sleep(C.time['count'])
            GPIO.output(GPIO_TRIGGER, True)
            time.sleep(0.00001)
            GPIO.output(GPIO_TRIGGER, False)

            while GPIO.input(GPIO_ECHO) == 0:
                start = time.time()

            while GPIO.input(GPIO_ECHO) == 1:
                stop = time.time()

            distance = (stop-start) * 17000

            print "Distance : %.1f" % distance

        average = F.getAverage(datas)
        print "Average: %.1f" % average

    GPIO.cleanup()

The code stop here

while GPIO.input(GPIO_ECHO) == 0:
                start = time.time()

THE SOLUTION : with a sample timeout :

now = time()

while GPIO.input(self.gpio_echo) == 0 and time()-now<waitTime:
    pass

I am also mucking about with this sensor. My code executes similar to yours and I need no timeout for it to work. The one difference I can find is this:

while i< 1:
        GPIO.output(GPIO_TRIGGER, False)

        time.sleep(C.time['count'])

I don't know how long the sleep time is here, but it might be that that's causing the problem. If it would be similar to mine setting the Trigger to false would be directly after the setup of the in/out pins instead, and then there's a two second wait to eliminate noise. Your wait time might be lower, I can't tell. There should be no need to set the trigger to false again just before you send the pulse and, I don't know, but it might be causing a false start. I would change it to this to work similarly to mine and then remove the setting to false in the while loop.

GPIO.setup(GPIO_TRIGGER, GPIO.OUT)
GPIO.setup(GPIO_ECHO, GPIO.IN)
GPIO.output(GPIO_TRIGGER, False)
print("Waiting for sensor to settle\n")
time.sleep(2)

I'm not sure if this will solve the issue without the need for a timeout, but I don't seem to need one.


I've written a module for making an object of the sensor which then allows for some more readable scripting. I'm also quite new to python and not at all an experienced programmer so fun errors might be there somewhere, but it's here below if you want to use it or just compare code:

#! /usr/bin/python3

# dist.py this is a module for objectifying an ultrasonic distance sensor.

import RPi.GPIO as GPIO
import time


class Distancer(object):
    #init takes an input of one GPIO for trigger and one for echo and creates the object,
    #it searches for a calibration file in the working directory (name)Const.txt, if none
    #is found it will initiate a calibration
    def __init__(self, trig, cho, name):
        self.trigger = trig
        self.echo = cho
        self.name = name
        self.filename = self.name + 'Const.txt'
        GPIO.setup(self.trigger, GPIO.OUT)
        GPIO.setup(self.echo, GPIO.IN)
        GPIO.output(self.trigger, False)
        print("Waiting for sensor to calm down")
        time.sleep(2)

        try:
            with open(self.filename, "r") as inConst:
                self.theConst = int(inConst.read())
        except (OSError, IOError) as e:
            print("Not calibrated, initializing calibration")
            self.calibrate()
            with open(self.filename, "r") as inConst:
                self.theConst = int(inConst.read())


    #Returns the echo time
    def measureTime(self):
        GPIO.output(self.trigger, True)
        time.sleep(0.00001)
        GPIO.output(self.trigger, False)

        while GPIO.input(self.echo) == 0:
            pulse_start = time.time()
        while GPIO.input(self.echo) == 1:
            pulse_end = time.time()

        pulse_duration = pulse_end - pulse_start
        return pulse_duration


    #Returns a distance in cm        
    def measure(self):  
        return self.measureTime() * self.theConst


    #Makes you set up the sensor at 3 different distances in order to find the
    #relation between pulse time and distance, it creates the file (name)Const.txt
    #in the working directory and stores the constant there.
    def calibrate(self):

        ten = []
        thirty = []
        seventy = []

        print("Make distance 10 cm, enter when ready")
        input()
        for i in range(30):
            ten.append(10/self.measureTime())
            time.sleep(0.2)

        print("Make distance 30 cm, enter when ready")
        input()
        for i in range(30):
            thirty.append(30/self.measureTime())
            time.sleep(0.2)

        print("Make distance 70 cm, enter when ready")
        input()
        for i in range(30):
            seventy.append(70/self.measureTime())
            time.sleep(0.2)

        allTime = ten + thirty + seventy
        theOne = 0.0
        for i in range(90):
            theOne = theOne + allTime[i]
        theOne = theOne / 90

        with open(self.filename, "w") as inConst:
                inConst.write(str(round(theOne)))


    #Will continually check distance with a given interval until something reaches the
    #treshold (cm), takes an argument to set wether it should check for something being
    #nearer(near) or farther(far) than the treashold. Returns True when treshold is reached. 
    def distWarn(self, nearfar, treashold):
        if nearfar.lower() == "near":
            while True:
                if self.measure() < treashold:
                    return True
                    break
                time.sleep(0.2)

        if nearfar.lower() == "far":
            while True:
                if self.measure() > treashold:
                    return True
                    break
                time.sleep(0.2)             


    #Will measure with a second interval and print the distance
    def keepGoing(self):
        while True:
            try:
                print(str(round(self.measure())) + ' cm')
                time.sleep(1)
            except KeyboardInterrupt:
                print("Won't keep going")
                break

I've run it with the code below to test it and everything seems to work. First time it's run it will prompt you to calibrate the sensor by putting it at different distances from something.

#! /usr/bin/python3

import RPi.GPIO as GPIO
import time
import dist as distancer

GPIO.setmode(GPIO.BOARD)
TRIG = 16
ECHO = 18

dist = distancer.Distancer(TRIG, ECHO, 'dist')

def main():
    global dist
    print(str(round(dist.measureTime(),5)) + ' s')  
    print(str(round(dist.measure())) + ' cm')

    dist.distWarn('near', 10)
    print('Warning, something nearer than 10 cm at ' + time.asctime( time.localtime(time.time()) ))

    dist.distWarn('far', 10)
    print('Warning, something further than 10 cm at ' + time.asctime( time.localtime(time.time()) ))


    dist.keepGoing()
    GPIO.cleanup()
    print('Fin')


if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        GPIO.cleanup()
        print("Exiting")
        time.sleep(1)

I am pretty sure you want

while GPIO.input(GPIO_ECHO)==GPIO.LOW:
    start = time.time()

while GPIO.input(GPIO_ECHO) == GPIO.HIGH:
    stop = time.time()

I don't think GPIO.input naturally returns zeros or ones, you can test that though.

Not really, I think that i lost the signal, i'll try a timeout in

while GPIO.input(GPIO_ECHO)==GPIO.LOW:
    start = time.time()

I think that my program wait indefinitely a signal but he stay to 0

I know this is an old question. The cause of the problem was described in this question https://raspberrypi.stackexchange.com/questions/41159/...

The solution is to add a timeout, like the OP did, to the while loops similar to this:

# If a reschedule occurs or the object is very close
# the echo may already have been received in which case
# the following will loop continuously.
count=time.time()
while GPIO.input(GPIO_ECHO)==0 and time.time()-count<0.1:
   start = time.time()

...

# if an object is not detected some devices do not
# lower the echo line in which case the following will
# loop continuously.
stop = time.time()
count=time.time()
while GPIO.input(GPIO_ECHO)==1 and time.time()-count<0.1:
   stop = time.time()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM