MicroPython with the ESP32 guide series

How to debug a MicroPython program

In this lesson, I will show you a few techniques you can use to debug and troubleshoot your MicroPython scripts.

To demonstrate how to debug and troubleshoot MicroPython scripts using the Thonny editor, we'll use the same demo script that your are familiar from the previous few lectures.

Here the script:

from machine import Pin
from utime import sleep

led = Pin(21, Pin.OUT)

while True:
    print(".")
    led.on()
    sleep(0.5)
    led.off()
    sleep(0.5)

Use print statements to help with tracing

If you come from the Arduino world, then you are familiar with how we use print statements there to try and figure out what is happening during runtime.

In the screenshot I provide below, I have added a couple of print statements that contain a value that I am interested in using to evaluate whether my program is working properly or not. The print statement looks like this:

print("LED is ", led.value())

In the screenshot, you can see the output of these print statements in the shell.

Why are print statements (like in this example) useful?

Here's a simple scenario:

Imagine that I had not properly connected the LED to GPIO21, or the LED was damaged.

Even though this program is correct, the LED would not blink. By including the led value in the print statement, I have confirmation in the shell that my program is working properly.

This would prompt me to look at the LED for the source of the problem (i.e. the LED not blinking as expected).

Of course, this is a simple scenario. However, print statements can scale up to much more complicated situations so they comprise of a indispensable debugging tool.

Print statements provide a simple way to trace the execution of your program by printing out debug values in the shell.

MicroPython error messages

The MicroPython interpreter produces error messages that can provide valuable clues for when things go wrong. Even though some times the information they provide can be very broad and generic, in most cases you can use these messages to find and fix a programming bug within seconds.

Example 1: parameter typo bugs

Let's have a look at a simple example.

In line 4 of the demo program, I have introduced an innocent type. It can happen to all of us. Here's the new "buggy" line 4 (bug in bold):

led = Pin(211, Pin.OUT)

This bug results in MicroPython trying to setup a GPIO that does not exist.

When you try to execute this file, you will see a "ValueError" in the shell.

It looks like this:

This typo has generated a very specific and useful error message.

The error message is very useful because it is very specific. It both identifies line 4 as the location of the bug, and even the kind of but that it is ("invalid pin").

Fixing it is quick and easy, just remove the redundant "1".

Let's look at one more bug that involves an incorrect parameter. Here's another buggy line, again in line 4 of the demo program (bug in bold):

led = Pin(21, Pin.OUTs)

Run the program. The interpreter complains an "AttributeError".

Again, this error is very specific, and informs you that the problem is in line 4, and the the object "Pin" does not have an attribute "OUTs":

This error message specifically highlights the incorrect attribute.

With this information, you can easily find the bug and fix it.

Generally, bugs that involve parameters produce accurate and descriptive error messages. But not all error messages are like this. Let's look at an example where a simple typo generates an error message that is not as accurate.

Example 2: Name errors

A "NameError" is an error that relates to using an incorrect keyword. A keyword can be something like a variable or a reserved language keyword.

For example,  in the demo program, I will introduce a bug by making a typo in the "while True:" loop statement. After the bug, the relevant line looks like this (bug in bold):

while Truae:

When you try to execute the program, a "NameError" error message is generated:

The bug is in line 6, but the error message indicates line 13.

This bug is more challenging to fix because it indicates the location of the bug in line 13, even though the actual location is line 6.

However, the clue that is more useful is that the buggy keyword "Truae" is included in the error message. In such cases, you can do a quick text search in your program for the offending keyword so that you can find it, and then fix it.

Lesson to remember: error messages provide clues that you have to consider in their entirety. The line number is just one of these clues, and it may be incorrect.

Example 3: Positional arguments

Let's look at one more bug. In one of the led functions, I have introduced an incorrect parameter, like this (bug in bold):

led.off(3)

As you probably know, the Pin.on() and Pin.off() functions do not take any arguments. When you try to run this program, the interpreter will throw a "TypeError", like this:

This error message identifies the correct bug location, but the description is confusing

This error message identifies the correct location of the bug, line 11.

However, the description is confusing. The description suggests that the function "off" requires one positional argument, but that two arguments were given. As you can clearly see, I have only given a single argument (not two, as the message claims), and I know that the correct number of arguments is zero (not one, as the message claims).

The counting of positional arguments in MicroPython functions relate to the "self" keyword, and I address it in a dedicated lecture in the course. But for now, it is worth taking into account the fact that this specific message can really throw you of and cause confusion, at least for a short time.

To fix it, I would start by not taking much note of the specific number of arguments that the error message indicates. Instead, I would look at the documentation of the specific function in question. This would give me authoritative information about how many arguments the function requires (if at all it requires arguments), and of what kind.

You can find the documentation for the off() function here. As you can see, this function takes no arguments.

The Pin.off() function takes no arguments.

With this information you can reason that the problem is the value "3" in the off() function. You'll be able to fix the bug by removing the "3".

In the course, during the experiments, we'll be bumping into various programming problems. And in many cases, I'll be showing you "live" how I solved those problems.

But for now, keep in mind what you have learned in this lessons as it will help you save a lot of time and spare a lot of frustration as you are programming your ESP32 using MicroPython.

"MicroPython with the ESP32 " series

Learn MicroPython for the ESP32

With this video course, you will learn how to use the
MicroPython programming language with the ESP32 micro-controller.


MicroPython is the perfect language for anyone looking for the easiest (yet still powerful) way to program a micro-controller.

{"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}