Once you've finished setting up your QT Py ESP32-S2 with CircuitPython, you can access the code and necessary libraries by downloading the Project Bundle.
To do this, click on the Download Project Bundle button in the window below. It will download as a zipped folder.
# SPDX-FileCopyrightText: 2022 Liz Clark for Adafruit Industries # SPDX-License-Identifier: MIT import time import ssl import board import touchio import pwmio from analogio import AnalogIn import adafruit_requests import socketpool import wifi from adafruit_io.adafruit_io import IO_HTTP, AdafruitIO_RequestError from simpleio import map_range from adafruit_motor import servo # select which display is running the code servo_one = True # servo_two = True try: from secrets import secrets except ImportError: print("WiFi secrets are kept in secrets.py, please add them there!") raise # connect to adafruitio aio_username = secrets["aio_username"] aio_key = secrets["aio_key"] print("Connecting to %s" % secrets["ssid"]) wifi.radio.connect(secrets["ssid"], secrets["password"]) print("Connected to %s!" % secrets["ssid"]) pool = socketpool.SocketPool(wifi.radio) requests = adafruit_requests.Session(pool, ssl.create_default_context()) # Initialize an Adafruit IO HTTP API object io = IO_HTTP(aio_username, aio_key, requests) # pylint: disable=undefined-variable # disabling undefined-variable for ease of comment/uncomment # servo_one or servo_two at top for user # setup for display 1 if servo_one: # servo calibration values CALIB_MIN = 15708 CALIB_MAX = 43968 # create feeds try: # get feed out_feed = io.get_feed("touch-1") in_feed = io.get_feed("touch-2") except AdafruitIO_RequestError: # if no feed exists, create one out_feed = io.create_new_feed("touch-1") in_feed = io.create_new_feed("touch-2") # setup for display 2 if servo_two: CALIB_MIN = 15668 CALIB_MAX = 43550 try: # get feed out_feed = io.get_feed("touch-2") in_feed = io.get_feed("touch-1") except AdafruitIO_RequestError: # if no feed exists, create one out_feed = io.create_new_feed("touch-2") in_feed = io.create_new_feed("touch-1") received_data = io.receive_data(in_feed["key"]) # Pin setup SERVO_PIN = board.A1 FEEDBACK_PIN = board.A2 touch = touchio.TouchIn(board.TX) # angles for servo ANGLE_MIN = 0 ANGLE_MAX = 180 # servo setup pwm = pwmio.PWMOut(SERVO_PIN, duty_cycle=2 ** 15, frequency=50) servo = servo.Servo(pwm) servo.angle = None # setup feedback feedback = AnalogIn(FEEDBACK_PIN) # position finder function for servo def get_position(): return map_range(feedback.value, CALIB_MIN, CALIB_MAX, ANGLE_MIN, ANGLE_MAX) # touch debounce touch_state = False # new_msg value new_msg = None # last_msg value last_msg = None # time.monotonic() holder for pinging IO clock = 5 while True: # check IO for new data every 5 seconds if (time.monotonic() - clock) > 5: # get data received_data = io.receive_data(in_feed["key"]) # reset clock clock = time.monotonic() # if touched... if touch.value and touch_state is False: touch_state = True # when touch is released... if not touch.value and touch_state is True: # get position of servo pos = get_position() # send position to IO io.send_data(out_feed["key"], float(pos)) # delay to settle time.sleep(1) # reset touch state touch_state = False # if a new value is detected if float(received_data["value"]) != last_msg: # assign value to new_msg new_msg = float(received_data["value"]) # set servo angle servo.angle = new_msg # quick delay to settle time.sleep(1) # release servo servo.angle = None # log msg last_msg = new_msg
Upload the Code and Libraries to the QT Py ESP32-S2
After downloading the Project Bundle, plug your QT Py ESP32-S2 into the computer's USB port with a known good USB data+power cable. You should see a new flash drive appear in the computer's File Explorer or Finder (depending on your operating system) called CIRCUITPY. Unzip the folder and copy the following items to the QT Py ESP32-S2's CIRCUITPY drive.
- lib folder
- code.py
Your QT Py ESP32-S2 CIRCUITPY drive should look like this after copying the lib folder and the code.py file.
secrets.py
You will need to create and add a secrets.py file to your CIRCUITPY drive. Your secrets.py file will need to include the following information:
secrets = { 'ssid' : 'YOUR-SSID-HERE', 'password' : 'YOUR-SSID-PASSWORD-HERE', 'aio_username' : 'YOUR-AIO-USERNAME-HERE', 'aio_key' : 'YOUR-AIO-KEY-HERE', }
Your secrets.py file will have your Adafruit IO username and key. Reference this guide page for steps on how to grab this information from your Adafruit IO account.
Analog servo motors make this project possible, but they work best after they've been calibrated. This CircuitPython calibration code from the Analog Feedback Servos Learn Guide will tell you your analog servo's minimum and maximum values.
Run this code with both of your analog servos and record the results for the code.py file for this project as the CALIB_MIN
and CALIB_MAX
values on lines 46 and 47 for the first display and lines 59 and 60 for the second display.
# setup for display 1 if servo_one: # servo calibration values CALIB_MIN = 15708 CALIB_MAX = 43968 ... # setup for display 2 if servo_two: CALIB_MIN = 15668 CALIB_MAX = 43550
After importing the libraries, you'll leave either servo_one = True
or servo_two = True
uncommented, depending on which of the two displays the code is running for.
# select which display is running the code servo_one = True # servo_two = True
Next, depending on which variable is True
, the analog servo's CALIB_MIN
and CALIB_MAX
calibration values are set. Then, the out_feed
and in_feed
are setup. If the feeds do not exist in your Adafruit IO account yet, then they will be created with io.create_new_feed()
.
# setup for display 1 if servo_one: # servo calibration values CALIB_MIN = 15708 CALIB_MAX = 43968 # create feeds try: # get feed out_feed = io.get_feed("touch-1") in_feed = io.get_feed("touch-2") except AdafruitIO_RequestError: # if no feed exists, create one out_feed = io.create_new_feed("touch-1") in_feed = io.create_new_feed("touch-2") # setup for display 2 if servo_two: CALIB_MIN = 15668 CALIB_MAX = 43550 try: # get feed out_feed = io.get_feed("touch-2") in_feed = io.get_feed("touch-1") except AdafruitIO_RequestError: # if no feed exists, create one out_feed = io.create_new_feed("touch-2") in_feed = io.create_new_feed("touch-1")
In the loop, Adafruit IO is polled every 5
seconds to check the current value in the in_feed
. This is the feed that the opposing servo is sending data to.
# check IO for new data every 5 seconds if (time.monotonic() - clock) > 5: # get data received_data = io.receive_data(in_feed["key"]) # reset clock clock = time.monotonic()
If the incoming data has changed from the previous value, then the servo's position updates to the new angle.
# if a new value is detected if float(received_data["value"]) != last_msg: # assign value to new_msg new_msg = float(received_data["value"]) # set servo angle servo.angle = new_msg # quick delay to settle time.sleep(1) # release servo servo.angle = None # log msg last_msg = new_msg
When the telegraph's touch input is released, the position of the servo is sent to the out_feed
and the touch_state
for debouncing is reset. By having two feeds, each telegraph build has one feed it is publishing to and one feed it is listening to.
# if touched... if touch.value and touch_state is False: touch_state = True # when touch is released... if not touch.value and touch_state is True: # get position of servo pos = get_position() # send position to IO io.send_data(out_feed["key"], float(pos)) # delay to settle time.sleep(1) # reset touch state touch_state = False
Text editor powered by tinymce.