Quantcast
Channel: Raspberry Pi Forums
Viewing all articles
Browse latest Browse all 4931

MicroPython • Re: (first project) stupidest code not working (webserver + servo)

$
0
0

Code:

Although 'asyncio' looks difficult at first glance, I'd propose you write your solution using asyncio.
The 'sweep' routine for your servo needs some time (too much time in terms of a web request) and should run in background.
Unfortunately multithreading is not yet stable in micropython.
But in asyncio, you can start a Task 'in parallel'.

Starting point https://gist.github.com/aallan/3d45a062 ... ec9c81e3b6

If you detect that a "sweep" is needed by checking the request, you can start a task asyncio.create_task(sweep())
THANK YOU!!! With your tips I managed to figure it out. It's very stable now. Thank you!

Next step is to connect a battery shield to run also when power is down. If you have any awesome tip on linking all together, I'd appreciate it.

Code:

import networkimport socketimport timefrom picozero import pico_temp_sensor, pico_ledfrom machine import Pin, PWMimport uasyncio as asyncio# led = Pin(15, Pin.OUT)# onboard = Pin("LED", Pin.OUT, value=0)ssid = 'myssid'password = 'mypwd'wlan = network.WLAN(network.STA_IF)servo_state = 'Servo is idle.'servo_running = False # Global flagled_state = 'LED is OFF.'pico_led.off()led_is_on = False # Global flagdef webpage(temperature):        global servo_running    global servo_state    global led_is_on    global led_state        html_top = """<!DOCTYPE html>    <html>    <head>    <title>Lazy Project</title>    <script>        function redirectToRoot(event) {            event.preventDefault(); // Prevent the default form submission            window.location.href = '/'; // Redirect to the root URL        }        // Refresh the page every 5 seconds        setTimeout(function() {            window.location.href = '/';        }, 5000);    </script>    </head>    <body>    <h1>Pico WH </h1>    """    if not servo_running:        html_servo = """<form action="./activateservo" onsubmit="redirectToRoot()">    <input type="submit" value="Activate Servo" />    </form>    """    else:         html_servo = """<form action="./activateservo" onsubmit="redirectToRoot()">    <input type="submit" value="Activate Servo" disabled />    </form>    """           if led_is_on:        html_led = f"""<form action="./lighton" onsubmit="redirectToRoot()">        <input type="submit" value="Light on" disabled />        </form>        <form action="./lightoff" onsubmit="redirectToRoot()">        <input type="submit" value="Light off" />        </form>        """    else:        html_led = f"""<form action="./lighton" onsubmit="redirectToRoot()">        <input type="submit" value="Light on" />        </form>        <form action="./lightoff" onsubmit="redirectToRoot()">        <input type="submit" value="Light off" disabled />        </form>        """        html_bottom = f"""<p>Temperature is {temperature}</p>    <p>{led_state}</p>    <p>{servo_state}</p>    </body>    </html>    """    html = html_top + html_servo + html_led + html_bottom    return (html)def lighton():    global led_is_on    global led_state        print("led on")    pico_led.on()    led_is_on = True    led_state = "LED is ON."    returndef lightoff():    global led_is_on    global led_state        print("led off")    pico_led.off()    led_is_on = False    led_state = "LED is OFF."    returnasync def activate_servo():        global servo_running    global servo_state        if servo_running:        print("Servo is running, further requests discarded.")        return         servo_running = True    servo_state = 'Servo is running, further requests discarded.'    print("Servo is running, further requests discarded.")    print("PWM up")        # Define the servo pin (change the pin number as per your connection)    servo_pin = Pin(0)    # Create a PWM instance    servo = PWM(servo_pin)    # Set the frequency of the PWM signal    servo.freq(50)  # 50 Hz for standard servos (20ms)        # code found https://www.waveshare.com/wiki/Pico-Servo-Driver    # https://files.waveshare.com/upload/3/31/Pico_Servo_Driver_Code.7z    # duty_u16 max 65535    # servo.duty_u16(0)    # for i in range(0,6553,100):      #     servo.duty_u16(i)    #     await asyncio.sleep(0.01)            # for i in range(6553,0,-10):    #     servo.duty_u16(i)    #     await asyncio.sleep(0.01)    # servo.duty_u16(0)    # Define the pulse widths for -90, 0, and +90 degrees    min_pulse = 65535 // 20  # Approximately 1 ms pulse width    mid_pulse = 65535 // 20 + (65535 // 40)  # Approximately 1.5 ms pulse width    max_pulse = 65535 // 10  # Approximately 2 ms pulse width        # Move to -90 degrees    servo.duty_u16(min_pulse)    await asyncio.sleep(2)  # Wait for 2 second    # Move to 0 degrees (neutral)    servo.duty_u16(mid_pulse)    await asyncio.sleep(2)    # Move to +90 degrees    servo.duty_u16(max_pulse)    await asyncio.sleep(2)    # Move back to 0 degrees    servo.duty_u16(mid_pulse)    await asyncio.sleep(2)    print("PWM down")     # Stop the PWM    servo.deinit()    servo_state = 'Servo is idle.'    servo_running = False    return def connect_to_network():    wlan.active(True)    wlan.config(pm = 0xa11140)  # Disable power-save mode    wlan.connect(ssid, password)    max_wait = 10    while max_wait > 0:        if wlan.status() < 0 or wlan.status() >= 3:            break        max_wait -= 1        print('waiting for connection...')        time.sleep(1)    if wlan.status() != 3:        print('wlan.status: ', wlan.status)        raise RuntimeError('network connection failed')    else:        print('connected')        status = wlan.ifconfig()        print('ip = ' + status[0])async def serve_client(reader, writer):    print("Client connected")    temperature = 0    temperature = pico_temp_sensor.temp        request_line = await reader.readline()    print("Request:", request_line)    # Request it's either    # GET /favicon.ico HTTP/1.1\r\n    # or something like    # GET /lighton? HTTP/1.1\r\n    # so by analysing request, we understand what the client requested        # We are not interested in HTTP request headers, skip them    # discard each line of the header until it's only \r\n (last line of HTTP headers)    while await reader.readline() != b"\r\n":         pass    request = str(request_line)        led_on = request.find('/lighton') #search /lighton in the Request    led_off = request.find('/lightoff') #search /lightoff in the Request    servo = request.find('/activateservo')     print( 'led on = ' + str(led_on)) # this is -1 if /lighton was not in the request, else is 6    print( 'led off = ' + str(led_off))    print( 'servo = ' + str(servo))        if led_on == 6:        lighton()        if led_off == 6:        lightoff()            if servo == 6:        asyncio.create_task(activate_servo())        # state = activate_servo()    print('temp: '+str(temperature))    response = webpage(temperature)    # print(str(response))    writer.write('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')    writer.write(response)    await writer.drain()    await writer.wait_closed()    print("Client disconnected")async def main():    print('Connecting to Network...')    connect_to_network()    print('Setting up webserver...')    asyncio.create_task(asyncio.start_server(serve_client, "0.0.0.0", 80))    counter = 0    while True:        # Toggle LED for 250 milliseconds        pico_led.toggle()        await asyncio.sleep(0.25)        # onboard.on()        # print("heartbeat")        counter += 1  # Increment the counter        if counter == 12:            print("heartbeat") # print every 60 secs            counter = 0  # Reset the counter        # onboard.off()        pico_led.toggle()        await asyncio.sleep(5)        try:    asyncio.run(main())finally:    asyncio.new_event_loop()

Statistics: Posted by fiore42 — Mon Jan 22, 2024 11:10 pm



Viewing all articles
Browse latest Browse all 4931

Trending Articles