Question regarding while loop and variables outside the loop with Circuitpython

Hello all,

I am currently finishing this exercise:

Circuitpython Plant Care

Here the capacitive touch sensor A1 is used to measure changes in capacitance when in contact with moist soil.

What I was trying to do is make my code take the value of the sensor when the microcontroler first starts up and use this as a baseline to measure capacitance against.

My code looks like this:

from adafruit_circuitplayground.express import cpx
import time
import touchio
from board import *

touch = touchio.TouchIn(A1)
touch_init = touch.raw_value #calibrates capacity base value
step_size_capacitance = 20 #how much capacity lies between each capacity step, some trial and error needed
while True:
    if cpx.button_a:
        print(cpx.temperature)
    if cpx.button_b:
        print(cpx.light)

    else:
        if cpx.switch:
            print((touch.raw_value, touch_init))
            if touch.raw_value <= touch_init:
                cpx.pixels.fill((50,0,0))
            if touch.raw_value > touch_init and touch.raw_value < (touch_init+step_size_capacitance):

This are the first 26 lines of my code. As you see I instantiate touchio.touchin in the variable touch and then use touch.raw to get the output.

I afterwards use this instance to save the value as touch_init, which is my baseline capacitance.

Now my question: Why does this work?

You see, later I call touch_init to compare against touch.raw_value. My understanding would be the interpreter would then look for the definition of touch_init, up outside the loop, and use touch.raw_value to get it, which in turn would not be the initial value but the current one.

But this does not happen. The print statement clearly shows touch_init staying constant even when A1 is touched. Now, don’t get me wrong - I am as happy as the next guy when my code works. But it seems I missunterstood how the logic behaves in that case and would love to learn the reason for it for future reference.

Thanks in advance for any input!

If I understand your question correctly, you are referring to this line in your code:

touch_init = touch.raw_value

and wondering why the value of touch_init remains the same throughout the rest of your code that follows.

In this case touch_init is a variable, and on the line above you are assigning the current value of touch.raw_value to the variable touch_init. When you later refer to touch_init, you are not “calling” touch_init, as you describe things. Rather, you are “referencing” touch_init, and the distinction is very important because the terms “call” and “calling”, and the like, have a very specific meaning in Python (or any other programming language, for that matter).

When you define a function, you must call it in order to execute the code it contains. More generally, in Python, anything that is callable must be called in order to execute the code that the callable object contains. A function is a callable object that is familiar to most, but there are other types of callables as well, but don’t worry about that. For now, just think of functions as things you must call in order to do something, and variables as things that simply hold values. (This is a simplification of things, but suffices for this explanation.)

When you assign a value to a variable, the variable does not change until you re-assign some other value to it (again, some simplification here, but it suffices for now). In your case, you assign a value to touch_init only once (on the line above), and never re-assign a value to it, so it never changes. When you later use touch_init to compare it to the current value of touch.raw_value, the interpreter does not “look for the definition of touch_init,” as you describe, meaning that it does not find the line above and rerun that line (which would re-assign the variable).

If that’s still unclear, let’s look at it from another perspective, at a lower level.

When the interpreter gets to the line above (i.e., touch_init = touch.raw_value), here’s what happens (roughly speaking):

  1. Lookup touch, which is a reference to a touch sensor instance (TouchIn).
  2. Allocate space in memory (RAM) to store the property value we’re about to retrieve.
  3. Retrieve the value of the raw_value property from the sensor and store it in the memory location we just allocated. (In this case, the property behaves like a function, meaning that every time you get the value of this property, it will perform the action of allocating a new memory location, reading the touch sensor value, and storing the value in the new memory location.)
  4. Assign the new memory location of the new property value to the variable touch_init, so that we can refer to this specific value later by using the name touch_init. Essentially, an assignment simply puts a label (the variable name) on a memory location, so that you can later refer to that memory location by that label (variable name), rather than having to deal with some numeric memory address.

Later, when you get to the line that contains the following expression:

touch.raw_value <= touch_init

Here’s what happens:

  1. Evaluate the left-hand side of the comparison, touch.raw_value, which performs the same first 3 steps listed above, meaning that we end up with a new sensor value reading in a new memory location, but this time we don’t assign the result to a variable.
  2. Lookup touch_init to find the memory location that it refers to, which is holding the very first sensor value that was read earlier.
  3. Compare the value in memory from step 1 (the current sensor value) to the value in memory from step 2 (the initial sensor value) to see if the current sensor value is <= to the initial sensor value.

Since you never assign a new memory location to touch_init, it will always refer to the memory location that contains the initial sensor reading.

I realize that was rather verbose, so I hope that clarifies rather than confuses.

1 Like

Thanks a ton! That made it very clear. Have to think it through once or twice to really get my head around it, but the broad strokes are easily understandable.

I’m sure this will help me alot in the future! :smiley:

And I don’t mind the answer beeing verbose - makes it less likely to misunderstand what you mean. :slight_smile:

This topic was automatically closed 18 hours after the last reply. New replies are no longer allowed.