MicroPython makes the ESP32 freeze - python

I wanted to try out MicroPython on my ESP32.
The flashing seems to be working, but even on the first script it fails.
I tried to use this code:
from machine import Pin
import time
i = 0
led = Pin(1, Pin.OUT)
while i < 10:
led.on()
time.sleep(1)
led.off()
time.sleep(1)
i += 1
print("Done!")
and than type ìmport blink in repl. The LED is blinking 11 times (at least that's my counting). After this part is finished, the LED stays on the hole time and you can't do anything. Done isn't printed at all, so there is probably some problem with the loop.
I also tried to enter it in the repl Python-Shell using:
import machine
led = machine.Pin(1, machine.Pin.OUT)
and at this point it freezes.
Do you know any possible fix for this problem?

Did you tried by changing the pin to 4 or 5 because pin 1 is a TX pin

Related

how to prevent python from stopping the code after one integer value is read?

I am making a project where an arduino sends a "1" (49) or "2" (50) based on wether the door of a room is open or closed. There is then a python program that then switches the windows open on the computer. The arduino is running fine but the python project doesent work properly. Here is the code:
import pyautogui as pa
import serial
#import time
ser = serial.Serial("COM4", 9600)
data_raw = ser.read()
int_val = int.from_bytes(data_raw, "big")
print(int_val)
if (int_val == 49):
pa.hotkey('win','d') #will switch one desktop to the left
if (int_val == 50):
pa.hotkey('alt','tab') #will switch one desktop to the left
The code can print the correct number sent by the arduino but doesent perform the correct hotkey press. Only the first number sent is read and applied. The code then stops immediatly with the following message:
Process finished with exit code 0
Any help is appreciated.

Serial stops reading after about 6 hours

When reading the serial port in python, all works fine until after hours where receiving data stops. This happens both on a laptop running Linux and on a Raspberry PI 2. Sending data still works at that point.
The source is still sending data (now and again). Restarting the python script helps.
The source sends small packages (4 - 12 bytes) and interval times may vary from minutes to over 12 hours.
My code, just only the receiving part, extracted from a bigger part, looks like this:
#!/usr/bin/python3
import tkinter
import os
import serial
class Transceiver():
def __init__(self, main):
self.port = serial.Serial(
port = "/dev/ttyUSB0",
baudrate = 38400,
bytesize = serial.EIGHTBITS,
parity = serial.PARITY_NONE,
stopbits = serial.STOPBITS_ONE,
timeout = 0
)
self.ReceivedData = bytearray()
self.Time = 0
def Receiver(self):
while (self.port.in_waiting > 0):
# Receiving data
self.Time = 0 # Reset time elapsed to 0
self.ReceivedData += self.port.read(1) # Add data to bytearray
if (self.Time == 20): # Some time elapsed, packet considered complete
print(''.join('{:02x} '.format(x) for x in self.ReceivedData))
self.port.reset_input_buffer()
self.ReceivedData = bytearray()
if (self.Time < 2000): # Just avoid running to 0 again
self.Time += 1 # Increment time elapsed
root.after(5, self.Receiver)
root = tkinter.Tk()
transceiver = Transceiver(root)
transceiver.Receiver()
root.mainloop()
It is just this receiving part that stops working after hours, I am trying to find the root cause.
So the above script is just an extract from a bigger script.
It controls the lights in the house. I want to run it on a raspberry PI, instead of a PC. The R'PI has a little 7" touch screen.
The bigger scripts has some decoding of the received data and updates a very simple GUI, just a bunch of small rectangles with some short name as text in it, indicating which lamps are on and off, and they act as buttons too, to toggle the lamps on and off. All works well, apart from the receiving part, though, in the end it may be possible that some other part disturbs the receiving part.
I have just started running just the above extraction of the script, to see if it keeps working without the GUI updates. I suspect the function Receiver fails to be restarted after some time. I need to have the above script running for a day to see of it keeps receiving though. I will update with the findings.
Update: The above script keeps working. The above is the extraction of a bigger program where only this part stops working after some hours. Receiving stops, but transmitting keeps working, hence I did not include that part.
By now I found the problem. In the receiver function, a decode function is called where above is the print line. Without calling the decode function, there is no problem. The decode function has some conditions, depending on the packet length and some values. Code for one of these conditions contained an error. I always started to run the script again in early evening, and then about 6 hours later a timer (at a fixed time late in the evening) would send the offending packet (a different format) that then caused the problem. The packet was not at fault, but my decoding of that packet.
Strange is that the script kept working, only the reception part stopped. I thought it stopped silently, but I printed quite a lot in this stage, hence I didn't see the error message telling me the problem of the use of an uninitialised variable. It's not in the above code. Hope the above code is useful for other people.

Interrupts in Python

I wrote a simple code to test interrupts in Python:
import RPi.GPIO as GPIO
brakepin = 32
brake_value = 0
GPIO.setmode(GPIO.BCM)
GPIO.setup(brakepin, GPIO.IN, pull_up_down = GPIO.PUD_UP) #Brake
def brake_isr(channel):
global brake_value
print ("Entered interrupt")
brake_value = GPIO.input(brakepin)
GPIO.add_event_detect(brakepin, GPIO.RISING, callback = brake_isr)
while True:
print("Brake_value: %d" % (brake_value))
time.sleep(0.025)
I am using interrupts to capture when the brakes are pressed on a scooter and when they are not. Ofcourse, 1 indicates the brakes are pressed and 0 indicates they are not. I have three questions:
In the line:
GPIO.setup(brakepin, GPIO.IN, pull_up_down = GPIO.PUD_UP) what should I put the value of pull_up_down? UP or DOWN. Actually both are working the same way, there is no difference. The brake's default value is 0 (when not pressed) because it is connected to ground.
In the line: GPIO.add_event_detect(brakepin, GPIO.RISING, callback = brake_isr) should I put GPIO.RISING or FALLING? Since I want to detect brake events (i.e. when a brake is being pressed and when it is not) I think I should use RISING only.
One very weird thing is happening:
When I press the brake I get output as:
Brake_value: 1 -> This is as expected. Great!
When I let go off the brake it still remains 1, i.e.:
Brake_value: 1 -> This should be 0
Why is the brake value not coming back to 0 when I let go of the brake
Edit:
I modified my interrupt code block to this:
def brake_isr(channel):
print ("Entered interrupt")
global brake_value
while GPIO.input(brakepin) == 1:
brake_value = GPIO.input(brakepin)
brake_value = 0
Well this solved the problem that I was facing with Question 3. However another weird thing is happening with the output (which was happening even before):
Brake_value: 0
.
.
.
When I press the brakes:
Entered interrupt
Entered interrupt
Entered interrupt
Brake_value: 1
Brake_value: 1
.
.
.
When I let go of the brakes:
Entered interrupt
Entered interrupt
Brake_value: 0
Brake_value: 0
.
.
.
Why is the code entering the interrupt block several times when I press the brakes (as can be seen with the multiple print statement) and why is it entering the interrupt when I let go off the brakes? This is happening for time.sleep(1) or time.sleep(0.025), deosnt matter what the delay is.
It looks like you have an interrupt set to detect rising edges, so when the value changes from 0 to 1, but you have nothing setup to check falling edges which would be when you release the brakes. So it looks to me like you have an interrupt triggered when you push the brakes, set Brake_value = 1... but then you never setup any way to swap it back to 0 so it just stays as a 1 in your stored variable. if you were to measure the physical voltage at the GPIO pin it would change as you pressed the brake, causing the rising edge which triggers your interrupt, however within that interrupt you're just setting Brake_value = GPIOvalue which during the interrupt will always be 1.
Basically the problem is that you're trying to track the status of your GPIO pin, but instead of just reading it's value and printing that, you are setting an internal variable to be equal to the value of the GPIO pin... except you set it high on your interrupt event and then never change it back.
There are a few ways to fix this, you could set another interrupt event to occur on a falling edge for the same pin, which would make it trigger when you make a change from 1 to 0 (when you release the brakes). Additionally you could get rid of brake_value and just replace everywhere you access it with an actual read to the GPIO pin. You could also poll the GPIO pin after the 0 -> 1 interrupt occurs, essentially just having a
while(GPIO == 1) in your interrupt code block which would exit as soon as the pin is set back to 0. There are probably a few other ways to do this but these are what immediately come to mind.
The above essentially answers your questions 3, question 1 is probably a datasheet question, the microcontrollers i've used needed specific values for the pullups to make the GPIO pins do different things, but I think the pi is much more forgiving and if you're not having any issues with either way you set it I wouldn't worry about it... and for question 2 rising edge will trigger an interrupt when the value at that pin goes from 0 to 1, while falling edge triggers the event when going from 1 to 0, so if you have it normally grounded, and it goes high when you pull the brakes, what you want is a rising edge. However if you normally have it tied to vcc and it goes to ground when you pull the brakes, what you want is a falling edge.
As suggested by #Ryan, this is what I did:
def brake_isr(channel):
print ("Entered interrupt")
global brake_value
while GPIO.input(brakepin) == 1:
brake_value = GPIO.input(brakepin)
brake_value = 0
This solves question 3, but it will be great if someone can answer the edit I posted in my question
Concerning your new issue, you might want to look into "switch debounce". This is something that can happen when you push a button and the simple answer is that cheap buttons/switches can result in multiple REALLY fast 0->1->0->1 changes for each press/release... which is why you are getting print outs when you release the button as well. Your sleeps are only pausing the print out of the current brake value, while the interrupt itself triggers it's own print out which is why the sleep duration has no effect on this message. The software fix is to have your interrupt only trigger a certain amount of time after a rising edge is detected if and only if there is no following falling edge (basically if we go from 0->1, make sure it stays at 1 for .5 seconds or something before you actually trigger the event), and then do the same thing for releasing the brake(when we go 1->0, wait 0.5 seconds to make sure it stays at 0). THAT SAID, a software solution isn't what you really want here. Switch Debouncing can be done very easily with two nand gates and a few resistors. https://electrosome.com/switch-debouncing/ has a better explanation with a few really good pictures and if you have the physical components it's the way to go, but if you don't have the actual parts you can cobble together a software solution. The software solution to this problem is sub ideal because it will introduce lag between pushing the brakes and it registering with the arduino, which in some cases you don't really care about but generally for brakes you want them to be very responsive.

Raspberry Pi input reading through endless while loop

I'm detecting a touch throuth a ttp223b touch sensor via python on a raspberry pi. It works pretty good but i need to wait for a second after a touch detection to prevent more than one execution so i just added a "time.sleep(1)".
The problem is that i also get multiple outputs, they are just time offset to 1 second, it seems that the routine is triggering multiple times at once.
import time
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setup(3, GPIO.IN)
while 1:
if GPIO.input(3) == GPIO.HIGH:
print "touched :3"
time.sleep(1)
Any suggestions how i could solve the issue?
add a sentinal
last_update = 0
while 1:
if time.time() - last_update > 1.5 : #1 and a half seconds
if GPIO.input(3) == GPIO.HIGH:
print "touched :3"
this will allow the GPIO to continue flushing so you dont pick up the old press (at least I think im not entirely sure how GPIO buffers work here)

python - Global name XXX is not defined on RPI interrupt

I am new to python with the Raspberry Pi. Below is a example program to use the GPIO. My problem is that in my conditional I cannot see to have any variables span to other statements in the block
The entire program is included the example of the problem code is as follows:
Turn on GPIO pin 23
print uptime
NameError: global name 'uptime' is not defined
Any suggestions?
Thank in advance
**************************** python code *****************************************
!/usr/bin/env python2.7
import time;
import RPi.GPIO as GPIO
from time import sleep # this lets us have a time delay (see line 12)
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM) # set up BCM GPIO numbering
GPIO.setup(17, GPIO.IN) # set GPIO17 as input (button)
GPIO.setup(23, GPIO.OUT) ## Setup GPIO Pin 23 to OUT
GPIO.output(23,False) ## Turn off GPIO pin 23
Define a threaded callback function to run in another thread when events are detected
def my_callback(channel):
global start_time, uptime
if GPIO.input(17): # if port 17 == 1
end_time = time.time()
#print (end_time)
print "Rising edge detected on 17"
uptime = end_time - start_time
#uptime = int(uptime)
print uptime
GPIO.output(23,False)
## Turn off GPIO pin 2
elif (GPIO.input(17)== 0):
start_time = time.time()
#print (start_time)
print "Falling edge detected on 17"
GPIO.output(23,True)
## Turn on GPIO pin 23
print uptime
when a changing edge is detected on port 17, regardless of whatever
else is happening in the program, the function my_callback will be run
GPIO.add_event_detect(17, GPIO.BOTH, callback=my_callback)
raw_input("Press Enter when ready\n>")
try:
print "When pressed, you'll see: Rising Edge detected on 17"
print "When released, you'll see: Falling Edge detected on 17"
sleep(10) # wait 30 seconds
print "Time's up. Finished!"
print uptime
finally: # this block will run no matter how the try block exits
GPIO.cleanup() # clean up after yourself
If, the first time my_callback gets called, GPIO.input(17) is 1, then you'll set uptime and everything will be fine.
But what happens if the first time it's called, GPIO.input(17) is 0? Then you won't set uptime. And, because this is the first time you've ever called this function, and you don't have any other code that sets uptime, it hasn't been set yet. But you try to print it anyway. So you get a NameError.
You could fix this by, e.g., setting it to an initial value at the start of the problem—e.g.:
def my_callback(channel):
# your existing code
uptime = 0
Of course I'm assuming some reasonable indentation for your code. As pasted, your code is just a mess of IndentationError exceptions and won't do anything, and it's quite possible that your real code has other bugs caused by code not being indented under the right flow control statement.
And, since it looks like you may be mixing tabs and spaces, making indentation errors hard to spot: Get yourself a better text editor, which automatically converts tabs into spaces, auto-indents for you, and/or shows tabs in some visible way. Or at least run your code with the -tt flag to catch tabs as errors so you can fix them.
As a side note, your elif is definitely wasteful, and possibly even broken.
If the if GPIO.input(17): part didn't trigger, then you know the result is 0 (or something else falsey, but since input only returns numbers, it can only be 0). So, why test it again for 0 when it can't be anything else?
But meanwhile, you're not just re-testing a value here unnecessarily, you're actually going out and reading the value again off the hardware. So, if the edge changes from 1 to 0 and back to 1 quickly enough, your first read may return 0, then your second read may return 1, meaning neither of your branches fires. (Plus, by reading, you may have also absorbed the edge trigger so you don't get another callback, although I'm not sure about that.)
You can solve all of these problems by just using else: instead of trying to write an elif that exactly captures the opposite sense of the if.

Categories

Resources