I have set up 3 HC-SR04 ultrasonic sensors to operate continuously with raspberry pi. Two of the sensors work perfectly while one is being very inconsistent. I have replaced the wires, sensor, and breadboard multiple times, as well as changing the trig and echo pins associated with the sensor. I have debugged the code and have isolated the problem sensor in the code below:
import RPi.GPIO as GPIO
import time
TRIG1 = 13
ECHO1 = 15
##TRIG2 = 22
##ECHO2 = 18
##
##TRIG3 = 37
##ECHO3 = 40
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
GPIO.setup(TRIG1, GPIO.OUT)
GPIO.output(TRIG1, 0)
##GPIO.setup(TRIG2, GPIO.OUT)
##GPIO.output(TRIG2, 0)
##
##GPIO.setup(TRIG3, GPIO.OUT)
##GPIO.output(TRIG3, 0)
GPIO.setup(ECHO1, GPIO.IN)
##GPIO.setup(ECHO2, GPIO.IN)
##GPIO.setup(ECHO3, GPIO.IN)
while True:
time.sleep(0.1)
GPIO.output(TRIG1, 1)
time.sleep(0.00001)
GPIO.output(TRIG1, 0)
print("anything")
while GPIO.input(ECHO1) == 0:
print("Works")
time.sleep(1)
start1 = time.time()
while GPIO.input(ECHO1) ==1:
stop1 = time.time()
print("sensor 1:")
print (stop1-start1) * 17000
## time.sleep(0.1)
##
## GPIO.output(TRIG2, 1)
## time.sleep(0.00001)
## GPIO.output(TRIG2, 0)
##
## while GPIO.input(ECHO2) == 0:
## start2 = time.time()
##
## while GPIO.input(ECHO2) == 1:
## stop2 = time.time()
## print("sensor 2:")
## print (stop2-start2) * 17000
##
## time.sleep(0.1)
##
## GPIO.output(TRIG3, 1)
## time.sleep(0.00001)
## GPIO.output(TRIG3, 0)
##
## while GPIO.input(ECHO3) == 0:
## start3 = time.time()
##
## while GPIO.input(ECHO3) == 1:
## stop3 = time.time()
## print("sensor 3:")
## print (stop3-start3) * 17000
GPIO.cleanup()
The line that reads "print("anything")" allows the code to compile, but take no distance reading and will continue to print "Works" indicating that it is running continuously in the first while loop. Unexpectedly when the "print("anything")" line is removed, the error:
print (stop1-start1) * 17000
NameError: name 'start1' is not defined
prints to the terminal. The code that is commented out above, which is identical to the code for the functioning sensors works without error when isolated from the code that is currently uncommented. Any thoughts or suggestions would be greatly appreciated.
Thanks.
I think you have a timing issue, that causes your code to run differently depending on "small" timing changes.
Your code fails due to not having initialized start1.
When you have a delay in your code (print "anything") is a significant delay, the while loop will run and initialize start1
When you do not have the delay,
GPIO.input(ECHO1)
will not equal zero, the while loop will not run and you get the error.
I think you should initialie your variables and you should check if there are timing requirements you are not aware of.
Also please note running python on a raspberry pi, will not be a real time system, so please be aware of real time constraints and be careful of making code that is timing sensitive.
I think you have declaration issue. At first you need to declare then declare global. I changed line number 6,7,40 and 44. you see
import RPi.GPIO as GPIO
import time
TRIG1 = 13
ECHO1 = 15
start1=0.00
stop1=0.00
##TRIG2 = 22
##ECHO2 = 18
##
##TRIG3 = 37
##ECHO3 = 40
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
GPIO.setup(TRIG1, GPIO.OUT)
GPIO.output(TRIG1, 0)
##GPIO.setup(TRIG2, GPIO.OUT)
##GPIO.output(TRIG2, 0)
##
##GPIO.setup(TRIG3, GPIO.OUT)
##GPIO.output(TRIG3, 0)
GPIO.setup(ECHO1, GPIO.IN)
##GPIO.setup(ECHO2, GPIO.IN)
##GPIO.setup(ECHO3, GPIO.IN)
while True:
time.sleep(0.1)
GPIO.output(TRIG1, 1)
time.sleep(0.00001)
GPIO.output(TRIG1, 0)
print("anything")
while GPIO.input(ECHO1) == 0:
print("Works")
time.sleep(1)
global start1
start1 = time.time()
while GPIO.input(ECHO1) == 1:
global stop1
stop1 = time.time()
print("sensor 1:")
print (stop1 - start1) * 17000
## time.sleep(0.1)
##
## GPIO.output(TRIG2, 1)
## time.sleep(0.00001)
## GPIO.output(TRIG2, 0)
##
## while GPIO.input(ECHO2) == 0:
## start2 = time.time()
##
## while GPIO.input(ECHO2) == 1:
## stop2 = time.time()
## print("sensor 2:")
## print (stop2-start2) * 17000
##
## time.sleep(0.1)
##
## GPIO.output(TRIG3, 1)
## time.sleep(0.00001)
## GPIO.output(TRIG3, 0)
##
## while GPIO.input(ECHO3) == 0:
## start3 = time.time()
##
## while GPIO.input(ECHO3) == 1:
## stop3 = time.time()
## print("sensor 3:")
## print (stop3-start3) * 17000
GPIO.cleanup()
Related
I am using a simple code from PiMyLife tutorial to read from a Light Dependant Resistor using a capacitor. This works great..
I then added a 2nd LDR and capacitor, added it to pin 31 and then duplicated the code (the rc_time function and the fuction call) to add an additional Light Dependant Resistor but for some reason the second function call never happens.
#!/usr/local/bin/python
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
#define the pin that goes to the circuit
pin_ldr_one = 29
pin_ldr_two = 31
def rc_time_one (pin_ldr_one):
count_one = 0
#Output on the pin for
GPIO.setup(pin_ldr_one, GPIO.OUT)
GPIO.output(pin_ldr_one, GPIO.LOW)
time.sleep(0.1)
#Change the pin back to input
GPIO.setup(pin_ldr_one, GPIO.IN)
#Count until the pin goes high
while (GPIO.input(pin_ldr_one) == GPIO.LOW):
count_one += 1
return count_one
def rc_time_two (pin_ldr_two):
count_two = 0
#Output on the pin for
GPIO.setup(pin_ldr_two, GPIO.OUT)
GPIO.output(pin_ldr_two, GPIO.LOW)
time.sleep(0.1)
#Change the pin back to input
GPIO.setup(pin_ldr_two, GPIO.IN)
#Count until the pin goes high
while (GPIO.input(pin_ldr_two) == GPIO.LOW):
count_two += 1
return count_two
#Catch when script is interrupted, cleanup correctly
try:
# Main loop
while True:
print("LDR 1: ",rc_time_one(pin_ldr_one))
print("LDR 2: ",rc_time_two(pin_ldr_two))
except KeyboardInterrupt:
pass
finally:
GPIO.cleanup()
So I thought I would try threading instead thinking that the 2 function calls were having issues.
So this is the threading code I came up with however this too fails to run the second (in this cask 2nd thread). Any ideas where I am going wrong. Thanks for all your help
#!/usr/local/bin/python
import RPi.GPIO as GPIO
import time
from time import sleep, perf_counter
from threading import Thread
GPIO.setmode(GPIO.BOARD)
#define the pin that goes to the circuit
pin_ldr_one = 29
pin_ldr_two = 31
def rc_time_one (pin_ldr_one = 29):
count_one = 0
#Output on the pin for
GPIO.setup(pin_ldr_one, GPIO.OUT)
GPIO.output(pin_ldr_one, GPIO.LOW)
time.sleep(0.1)
#Change the pin back to input
GPIO.setup(pin_ldr_one, GPIO.IN)
#Count until the pin goes high
while (GPIO.input(pin_ldr_one) == GPIO.LOW):
count_one += 1
print("LDR 1: ",count_one)
return count_one
def rc_time_two (pin_ldr_two = 31):
count_two = 0
#Output on the pin for
GPIO.setup(pin_ldr_two, GPIO.OUT)
GPIO.output(pin_ldr_two, GPIO.LOW)
time.sleep(0.1)
#Change the pin back to input
GPIO.setup(pin_ldr_two, GPIO.IN)
#Count until the pin goes high
while (GPIO.input(pin_ldr_two) == GPIO.LOW):
count_two += 1
print("LDR 2: ",count_two)
return count_two
#Catch when script is interrupted, cleanup correctly
try:
# Main loop
while True:
# create two new threads
t1 = Thread(target=rc_time_one)
t2 = Thread(target=rc_time_two)
# start the threads
t1.start()
t2.start()
t1.join()
t2.join()
#print("LDR 1: ",rc_time_one(pin_ldr_one))
#print("LDR 2: ",rc_time_two(pin_ldr_two))
except KeyboardInterrupt:
pass
finally:
GPIO.cleanup()
Peter
I have a problem with the Jsn-sr04t water proof ultrasonic sensor, knowing that the connection in the raspberry pi zero W1 is well made becouse it is activated but the readings of this are totally wrong, the pins were entered correctly but this one seems to have a data entry error. I tried several programs in python that were used on this same sensor model
PD: I'm aware that this works, because I tested it on an arduino mega and the sensor worked correctly
import RPi.GPIO as GPIO
import os
import time
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO_TRIGGER = 10
GPIO_ECHO = 8
TRIGGER_TIME = 0.00001
MAX_TIME = 0.004 # max time waiting for response in case something is missed
GPIO.setup(GPIO_TRIGGER, GPIO.OUT) # Trigger
GPIO.setup(GPIO_ECHO, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Echo
GPIO.output(GPIO_TRIGGER, False)
def measure():
# Pulse the trigger/echo line to initiate a measurement
GPIO.output(GPIO_TRIGGER, True)
time.sleep(TRIGGER_TIME)
GPIO.output(GPIO_TRIGGER, False)
# ensure start time is set in case of very quick return
start = time.time()
timeout = start + MAX_TIME
while GPIO.input(GPIO_ECHO) == 0 and start <= timeout:
start = time.time()
if(start > timeout):
return -1
stop = time.time()
timeout = stop + MAX_TIME
# Wait for end of echo response
while GPIO.input(GPIO_ECHO) == 1 and stop <= timeout:
stop = time.time()
if(stop <= timeout):
elapsed = stop-start
distance = float(elapsed * 34300)/2.0
else:
return -1
return distance
if __name__ == '__main__':
try:
while True:
distance = measure()
if(distance > -1):
print("Measured Distance = %.1f cm" % distance)
else:
print("#")
time.sleep(0.5)
except KeyboardInterrupt:
print("Measurement stopped by User")
GPIO.cleanup()
constantly OUTPUT: "#"
Seems like an issue with the GPIO settings or a timing issue as the same setup works with an Arduino.
Try with higher trigger on time (maybe 20us)
After elapsed calculation, print the elapsed time on the screen and check the actual value
If it still doesn't work, then you can also checkout the alternate output options like serial UART, PWM, etc. You can get more details here -
https://tutorials.probots.co.in/communicating-with-a-waterproof-ultrasonic-sensor-aj-sr04m-jsn-sr04t/
I have a attached a rotary encoder to a DC motor shaft in hopes of creating a python script on a PI4 in which one could set a desired angle, motor will move CW at a 10 - duty cycle, and motor will stop and hold position on desired angle that once set angle is read back into code from rotary encoder (# 800 pulses per revolution - reading out 0.45 deg increments).
The PI controller will ideally then hold the set angle (set in code but later GUI) and will not move regardless of outside force on the shaft.
Lastly i am using if statments after my PI control signal 'PI' into a duty cycle ouput thus controlling the speed of the motor as it reaches the set point (either slowing down or speeding up tp get to the set point) with error PI polarity governing directional output....if this could be done better i'd appreciate any suggestions
I am only getting 1 error i cant figure out and cant find a solution online...but i feel i am close to getting this code right. Any criticism is welcome. The error is regarding the "PI" output of the Pi equation:
"Value of type "int" is not indexable"
from RPi import GPIO
import time
import threading
#Encoder GPIO Pins
clk = 15 # GRN/YLW Z+
dt = 11 # BLU/GRN Z-
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
GPIO.setup(clk, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(dt, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
#Motor GPIO Pins
PWMPin = 18 # PWM Pin connected to ENA.
Motor1 = 16 # Connected to Input 1.
Motor2 = 18 # Connected to Input 2.
GPIO.setup(PWMPin, GPIO.OUT) # We have set our pin mode to output
GPIO.setup(Motor1, GPIO.OUT)
GPIO.setup(Motor2, GPIO.OUT)
GPIO.output(Motor1, GPIO.LOW)# When program start then all Pins will be LOW.
GPIO.output(Motor2, GPIO.LOW)
def MotorClockwise():
GPIO.output(Motor1, GPIO.LOW) # Motor will move in clockwise direction.
GPIO.output(Motor2, GPIO.HIGH)
def MotorAntiClockwise():
GPIO.output(Motor1, GPIO.HIGH) # Motor will move in anti-clockwise direction.
GPIO.output(Motor2, GPIO.LOW)
#Sim Values
duty_c = 10 #duty Cycle
PwmValue = GPIO.PWM(PWMPin, 10000) # We have set our PWM frequency to 5000.
PwmValue.start(duty_c) # That's the maximum value 100 %.
error = 0
Set_point = 1.8
encoder_counter = 0
encoder_angle = 0
Kp = 2
Ki = 1
PI = 0
#Sim Parameters
Ts = .1 #sampling time
Tstop = 200 #end simulation time
N = int(Tstop/Ts)#simulation length
def ReadEncoder():
global encoder_counter
global encoder_angle
clkLastState = GPIO.input(clk)
while True:
clkState = GPIO.input(clk)
dtState = GPIO.input(dt)
encoder_angle = float(encoder_counter/800)*360
if clkState != clkLastState:
if dtState != clkState:
encoder_counter += 1
else:
encoder_counter -= 1
#print("encoder_counter", encoder_counter )
print("encoder_angle", encoder_angle )
time.sleep(1)
clkState = clkLastState
# some delay needed in order to prevent too much CPU load,
# however this will limit the max rotation speed detected
time.sleep(.001)
def PI_function():
global PI
global duty_c
global error
global Kp
global Ki
global encoder_angle
for k in range(N+1):
error = int(Set_point) - encoder_angle
print (f"{error} Error Detected")
PI = PI[k-1] + Kp*(error[k] - error[k-1]) + (Kp/Ki)*error[k] #PI equation
print (f"{PI} PI value")
if (PI > 0):
MotorClockwise()
else:
MotorAntiClockwise()
if ((PI > duty_c) & (duty_c <100)):
duty_c += 1
if ((PI < duty_c) & (duty_c > 10)):
duty_c -= 1
return()
def main_function():
if (N != 0):
encoder_thread = threading.Thread( target=ReadEncoder)
encoder_thread.start()
encoder_thread.join()
PI_thread = threading.Thread( target=PI_function)
PI_thread.start()
PI_thread.join()
PwmValue.ChangeDutyCycle(duty_c)
else:
PwmValue.ChangeDutyCycle(0)
print(f"Motor Stopped & Holding at {encoder_angle} Degrees")
I'm on Raspberry Pi, using Python.
I would like to receive continuous input from a distance sensor and have the distance value determine whether or not to send output.
I have a output function, gogo, and a sense function, sense, which updates the distance value.
I'd like to have the output start when below 20 distance and the output stop when the distance reaches threshold of 20, but the only solution that I can see is another loop.
My code is not working and I'm thinking that there's a nice solution, but I am not well-versed in loops.
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
distance = 40.0
TRIG = 4
ECHO = 18
GPIO.setup(TRIG,GPIO.OUT)
GPIO.setup(ECHO,GPIO.IN)
GPIO.setup(23, GPIO.OUT)
GPIO.setup(24, GPIO.OUT)
GPIO.setup(25, GPIO.OUT)
def gogo():
Motor1A = 23
Motor1B = 24
Motor1E = 25
GPIO.setup(Motor1A,GPIO.OUT)
GPIO.setup(Motor1B,GPIO.OUT)
GPIO.setup(Motor1E,GPIO.OUT)
print "Turning motor on"
GPIO.output(Motor1A,GPIO.HIGH)
GPIO.output(Motor1B,GPIO.LOW)
GPIO.output(Motor1E,GPIO.HIGH)
def sense():
GPIO.output(TRIG, True)
time.sleep(0.00001)
GPIO.output(TRIG, False)
while GPIO.input(ECHO) == False:
start = time.time()
while GPIO.input(ECHO) == True:
end = time.time()
sig_time = end-start
#CM:
distance = sig_time / 0.000058
#inches:
#distance = sig_time / 0.000148
print('Distance: {} centimeters'.format(distance))
while distance > 20.0:
print (distance)
sense()
else:
print (distance)
gogo()
sense()
GPIO.cleanup()
The problem is scope; distance is constantly in your 40 main code. It gets updated only in sense()
First, let's edit sense to return the value of distance
def sense():
GPIO.output(TRIG, True)
time.sleep(0.00001)
GPIO.output(TRIG, False)
while GPIO.input(ECHO) == False:
start = time.time()
while GPIO.input(ECHO) == True:
end = time.time()
sig_time = end-start
#CM:
distance = sig_time / 0.000058
#inches:
#distance = sig_time / 0.000148
print('Distance: {} centimeters'.format(distance))
return distance
you should also probably create a function that turns the motor off
you need to define distance, also let's make a loop that runs forever. right now, your loop only runs until distance< 20
distance = sense()
while True:
if distance > 20:
<call motor off function here>
print (distance)
else:
print (distance)
gogo()
distance = sense() #now we're checking distance every cycle
So basically we're using raspberry pi for a project and a part of it includes the usage of ultrasonic sensors. We have three, and we've been able to get readings from all of them (I actually came from multi-threading but decided to move to multiprocessing). Here is my code:
#Libraries
from multiprocessing import Process, Lock
import RPi.GPIO as GPIO
import time
#GPIO Mode (BOARD / BCM)
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
#set GPIO Pins
GPIO_TRIGGER1 = 23
GPIO_ECHO1 = 24
GPIO_TRIGGER2 = 27
GPIO_ECHO2 = 22
GPIO_TRIGGER3 = 25
GPIO_ECHO3 = 17
#set GPIO direction (IN / OUT)
GPIO.setup(GPIO_TRIGGER1, GPIO.OUT)
GPIO.setup(GPIO_ECHO1, GPIO.IN)
GPIO.setup(GPIO_TRIGGER2, GPIO.OUT)
GPIO.setup(GPIO_ECHO2, GPIO.IN)
GPIO.setup(GPIO_TRIGGER3, GPIO.OUT)
GPIO.setup(GPIO_ECHO3, GPIO.IN)
def sense_distance(lock, processName):
#lock.acquire()
gpio_echo_var = ''
gpio_trigger_var = ''
if processName == "Sensor-1":
gpio_echo_var = GPIO_ECHO1
gpio_trigger_var = GPIO_TRIGGER1
elif processName == "Sensor-2":
gpio_echo_var = GPIO_ECHO2
gpio_trigger_var = GPIO_TRIGGER2
elif processName == "Sensor-3":
gpio_echo_var = GPIO_ECHO3
gpio_trigger_var = GPIO_TRIGGER3
print "%s process created." % (processName)
try:
while True:
# set Trigger to HIGH
GPIO.output(gpio_trigger_var, True)
# set Trigger after 0.01ms to LOW
time.sleep(0.00001)
GPIO.output(gpio_trigger_var, False)
StartTime = time.time()
StopTime = time.time()
# save StartTime
while GPIO.input(gpio_echo_var) == 0:
StartTime = time.time()
# save time of arrival
while GPIO.input(gpio_echo_var) == 1:
StopTime = time.time()
# time difference between start and arrival
TimeElapsed = StopTime - StartTime
# multiply with the sonic speed (34300 cm/s)
# and divide by 2, because there and back
distance = (TimeElapsed * 34300) / 2
if distance <= 10:
print "%s has read less than 10 cm." % (processName)
else:
pass
# Reset by pressing CTRL + C
except KeyboardInterrupt:
print("Measurement stopped by User")
GPIO.cleanup()
#lock.release()
if __name__ == '__main__':
lock = Lock()
Process(target=sense_distance, args=(lock, "Sensor-1")).start()
Process(target=sense_distance, args=(lock, "Sensor-2")).start()
Process(target=sense_distance, args=(lock, "Sensor-3")).start()
It successfully reads the input and prints out the text when input goes smaller than 10 cm. However, after some time, they stop. I have run out of ideas and have searched all over only to come up short. Any sort of help will be appreciated.