Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions .github/workflows/content-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,64 @@ jobs:

- name: Check per-page SEO front matter (description:)
run: python scripts/check_seo_frontmatter.py

media-a11y:
# Source-level a11y conventions that html-proofer does NOT cover: YouTube
# iframe title=, <video> aria-label, and lazy empty alt (alt=""). See
# scripts/check_a11y.py. Complements the link-check job below.
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.x"

- name: Check media a11y (iframe title, video aria-label, image alt)
run: python scripts/check_a11y.py --ci

link-check:
# Validate the BUILT site with html-proofer: broken internal links, broken
# anchors, missing image alt, and malformed HTML. External links are NOT
# checked here (slow/flaky); a separate non-blocking job can cover those.
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: "3.3.11"
bundler-cache: true
cache-version: 0

- name: Build site (production baseurl)
run: bundle exec jekyll build --baseurl "/physcomp"
env:
JEKYLL_ENV: production

- name: Install html-proofer
run: gem install html-proofer -v 5.0.9

- name: Proof built site (internal links, anchors, image alt, HTML)
# --swap-urls strips the /physcomp baseurl so absolute internal links
# resolve against _site/. External link checking is disabled (slow/flaky).
#
# --ignore-files: each entry is tracked debt, not a silent skip:
# * signals .+/index.html + IntroTo*.html -> stale generated nbconvert
# notebooks (issue #115)
# * /arduino/accel.html -> WIP draft, missing screenshot (issue #115)
# * /esp32/capacitive-touch.html -> WIP lesson, missing diagrams (issue #114)
# Remove an entry once its issue is resolved so the gate covers that page.
# Each --ignore-files pattern must be wrapped in /slashes/ to be treated
# as a regex (a bare string is an exact-path match); internal slashes are
# escaped as \/.
run: |
htmlproofer ./_site \
--disable-external \
--swap-urls "^/physcomp:" \
--no-enforce-https \
--ignore-files "/\/signals\/.+\/index\.html/,/\/signals\/IntroTo[A-Za-z]+\.html/,/\/arduino\/accel\.html/,/\/esp32\/capacitive-touch\.html/"
2 changes: 1 addition & 1 deletion _config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ callouts:
# Aux links for the upper right navigation
aux_links:
"Makeability Lab":
- "//makeabilitylab.cs.washington.edu"
- "https://makeabilitylab.cs.washington.edu"

# Heading anchor links appear on hover over h1-h6 tags in page content
# allowing users to deep link to a particular heading on a page.
Expand Down
Binary file not shown.
2 changes: 1 addition & 1 deletion advancedio/servo.md
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ The Engineering Mindset YouTube channel did this for real with an oscilloscope,

### Activity 3: Sensor-driven servo gauge

For our final activity, let's build a **physical gauge**—a servo-powered pointer that displays sensor data in the real world, like an analog speedometer or a VU meter needle. This is the physical output equivalent of the [OLED analog graph](oled.md#demo-3-basic-real-time-analog-graph) and the [NeoPixel level meter](addressable-leds.md#activity-4-led-level-meter). Where the OLED drew data on screen and the NeoPixels lit up LEDs proportionally, here we'll sweep a physical pointer across a scale.
For our final activity, let's build a **physical gauge**—a servo-powered pointer that displays sensor data in the real world, like an analog speedometer or a VU meter needle. This is the physical output equivalent of the [OLED analog graph](oled.md#demo-3-basic-real-time-analog-graph) and the [NeoPixel level meter](addressable-leds.md). Where the OLED drew data on screen and the NeoPixels lit up LEDs proportionally, here we'll sweep a physical pointer across a scale.

We'll read an analog sensor on `A0` and map it to the servo's range. To make it more interesting, we'll add two buttons: one to "freeze" the gauge at its current reading (like a max-hold feature on a multimeter), and one to reset it.

Expand Down
2 changes: 1 addition & 1 deletion advancedio/smoothing-input.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ You can find our full implementation on GitHub as [MovingAverageFilter.ino](http

#### Simple C++ class

Signal filtering is a perfect opportunity to create a class to hide complexity, avoid code redundancy, and handle data processing. In our [Makeability Lab Arduino Library](https://github.com/makeabilitylab/arduino/tree/master/MakeabilityLab_Arduino_Library/src), we created the [`MovingAveragefilter.hpp`](https://github.com/makeabilitylab/arduino/blob/master/MakeabilityLab_Arduino_Library/src/MovingAverageFilter.hpp) class, which simplifies using a moving average filter. But you could make your own, of course, or use [other libraries](#arduino-filtering-libraries.)
Signal filtering is a perfect opportunity to create a class to hide complexity, avoid code redundancy, and handle data processing. In our [Makeability Lab Arduino Library](https://github.com/makeabilitylab/arduino/tree/master/MakeabilityLab_Arduino_Library/src), we created the [`MovingAveragefilter.hpp`](https://github.com/makeabilitylab/arduino/blob/master/MakeabilityLab_Arduino_Library/src/MovingAverageFilter.hpp) class, which simplifies using a moving average filter. But you could make your own, of course, or use [other libraries](#arduino-filtering-libraries)

Here's a demonstration of how to use [`MovingAveragefilter.hpp`](https://github.com/makeabilitylab/arduino/blob/master/MakeabilityLab_Arduino_Library/src/MovingAverageFilter.hpp):

Expand Down
2 changes: 1 addition & 1 deletion advancedio/vibromotor.md
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,7 @@ In this lesson, you learned about vibration motors and how to safely control the

## Next Lesson

In the [next lesson](../smoothing-input.md), we will switch from output to input and learn how to smooth noisy sensor data using digital signal processing techniques.
In the [next lesson](smoothing-input.md), we will switch from output to input and learn how to smooth noisy sensor data using digital signal processing techniques.

<nav class="lesson-nav" aria-label="Lesson navigation">
<a href="servo.html" class="nav-prev">
Expand Down
2 changes: 1 addition & 1 deletion arduino/buttons.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ However, if you do this, what will the digital input pin read when the switch is
**Figure.** Animation of what happens when you press a button with the simple circuit configuration.
{: .fs-1 }

In fact, try wiring up this configuration yourself and running the following program with the [Serial Monitor](../electronics/serial-print#step-3-open-serial-monitor-in-the-arduino-ide) open. What happens when you press the button? Try touching the button legs with your fingers but not actually pressing the button—what happens to the `digitalRead` value? Are you reliably tracking the button state?
In fact, try wiring up this configuration yourself and running the following program with the [Serial Monitor](serial-print.md#step-3-open-serial-monitor-in-the-arduino-ide) open. What happens when you press the button? Try touching the button legs with your fingers but not actually pressing the button—what happens to the `digitalRead` value? Are you reliably tracking the button state?

{% highlight cpp %}
const int INPUT_BUTTON_PIN = 2;
Expand Down
2 changes: 1 addition & 1 deletion arduino/fast-analog-read.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ usetocbot: true

## Speeding up the Arduino

The Arduino `C` library attempts to provide an easy-to-understand and accessible API to program and use microcontrollers. However, this comes at a cost. There are a number of interesting online discussions and blog posts analyzing Arduino code and providing faster techniques for I/O. Importantly, as Willem Maes—a faculty of engineering in Belgium—notes in his [Speeding Up the Arduino]((http://www.optiloading.be/willem/Arduino/speeding.pdf)) document:
The Arduino `C` library attempts to provide an easy-to-understand and accessible API to program and use microcontrollers. However, this comes at a cost. There are a number of interesting online discussions and blog posts analyzing Arduino code and providing faster techniques for I/O. Importantly, as Willem Maes—a faculty of engineering in Belgium—notes in his [Speeding Up the Arduino](http://www.optiloading.be/willem/Arduino/speeding.pdf) document:
>the programmers who developed Arduino weren't just lousy coders who couldn't write fast code, they consciously made the decision to add validations and safety checks since it benefits their target customers.

## How fast can we read data using analogRead and ATmega328?
Expand Down
2 changes: 1 addition & 1 deletion arduino/force-sensitive-resistors.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ For more details, see the Interlink [FSR 402 datasheet]({{ site.baseurl }}/asset

Let's make something!

To begin, just like we did with the [buttons](buttons.md) and [potentiometers](potentiometers.md) lessons, we'll make a simple LED circuit without a microcontroller. In fact, this circuit will be the exact same as the "rheostat" potentiometer circuit [here](potentiometers.md#build-the-potentiometer-based-led-dimmer) (but we'll replace the rheostat with an FSR).
To begin, just like we did with the [buttons](buttons.md) and [potentiometers](potentiometers.md) lessons, we'll make a simple LED circuit without a microcontroller. In fact, this circuit will be the exact same as the "rheostat" potentiometer circuit [here](potentiometers.md#step-1-build-the-potentiometer-based-led-dimmer) (but we'll replace the rheostat with an FSR).

Below, we show two possible wiring diagrams: the first (preferred) shows the FSR circuit powered by a 9V battery while the second shows power derived from the 5V and GND pins on the Arduino. (Again, we prefer the former just to further emphasize that at this point, we're not using microcontrollers!)

Expand Down
2 changes: 1 addition & 1 deletion arduino/led-blink3.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ On the Arduino, the `unsigned long` data type is 32 bits (4 bytes), which ranges

#### Blinking without delays logic

We then use the same general logic as the "blinking without delays" [covered previously](led-blink#blink-without-using-delays) for each LED:
We then use the same general logic as the "blinking without delays" [covered previously](led-blink.md#blink-without-using-delay) for each LED:

{% highlight C %}
unsigned long currentTimestampMs = millis();
Expand Down
2 changes: 1 addition & 1 deletion arduino/led-on.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ usetocbot: true
1. TOC
{:toc}
---
For our first learning activity, we are going to use Arduino to turn on an [LED]({{ site.baseurl }}/pages/electronics/leds.md). We're **not** going to write any code. Instead, our goal is to build some initial familiarity with Arduino hardware and connecting components to Arduino pins before we introduce programming, which we do in the [next lesson](led-blink.md).
For our first learning activity, we are going to use Arduino to turn on an [LED](../electronics/leds.md). We're **not** going to write any code. Instead, our goal is to build some initial familiarity with Arduino hardware and connecting components to Arduino pins before we introduce programming, which we do in the [next lesson](led-blink.md).

![Animation showing a USB cable plugging into an Arduino Uno to power an LED + resistor hooked up to 5V and GND](assets/movies/Arduino_LEDOn_5VFixed_USBPower.gif)
**Figure.** The movement of **current** in the circuit is illustrated by the animated yellow circles. This visualization is a coarse abstraction designed to emphasize the direction of current flow. A more accurate visualization would show that electrons are already distributed throughout a wire before a voltage is applied. See our [Introduction to Electronics](../electronics/index.md) series, specifically the lesson on [Voltage, Current, and Resistance](../electronics/electricity-basics.md).
Expand Down
2 changes: 1 addition & 1 deletion arduino/potentiometers.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ Analog input!
More formally, just like **analog output** enabled us to write out voltages between 0V and 5V, **analog input** enables us to **read voltages between 0V and 5V**. How does this work? Via an [ADC](https://en.wikipedia.org/wiki/Analog-to-digital_converter).

<video autoplay loop muted playsinline aria-label="Animation comparing digital input which is either HIGH or LOW versus analog input which can be any voltage in between">
<source src="../electronics/assets/videos/AnalogVsDigital.mp4" type="video/mp4" />
<source src="assets/movies/AnalogVsDigital.mp4" type="video/mp4" />
</video>
**Video.** While digital input is simply HIGH (5V) or LOW (0V), analog can be anywhere in between. Our ability to sense gradations in the voltage signal is based on the resolution of the analog-to-digital converter. In the case of the Arduino Uno and Leonardo, this is 10 bits.
{: .fs-1 }
Expand Down
2 changes: 1 addition & 1 deletion cpx/analog-input.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ It's OK if you don't understand exactly how voltage dividers work. The key is in

In the above examples, we showed how to read 3.3V and GND (0V) with the CPX by touching the yellow wire to the red and black respectively and graphing the result. But analog input is far more interesting than just two numbers: 0 and 1023. How can we play with everything in between?

We can do this by dividing the input voltage using resistors, which we cover in great detail in our [Electronics L4: Voltage Divider lesson](series-parallel.md#voltage-dividers) and touch on it a bit in the above video. We need not repeat ourselves here; however, if you want to experiment with manually controlling different input voltages on A1, try adding different resistor combinations like the following.
We can do this by dividing the input voltage using resistors, which we cover in great detail in our [Electronics L4: Voltage Divider lesson](../electronics/series-parallel.md#voltage-dividers) and touch on it a bit in the above video. We need not repeat ourselves here; however, if you want to experiment with manually controlling different input voltages on A1, try adding different resistor combinations like the following.

![Intro to using a voltage divider with two resistors to control the input voltage on CPX pin A1](assets/images/CPX_IntroToVoltageDivider.png)

Expand Down
2 changes: 1 addition & 1 deletion esp32/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ Use the ESP32's 12-bit ADC to read a potentiometer and control an LED's brightne

Learn how to play tones and melodies on the ESP32 using the `tone()` function (now supported in ESP32 Arduino core v3.x!) and the LEDC PWM library.

### [Lesson 6: Capacitive Touch Sensing](capacitive-touch-sensing.md)
### [Lesson 6: Capacitive Touch Sensing](capacitive-touch.md)

The ESP32 has built-in capacitive touch sensing hardware—no external components needed! In this lesson, you'll use a bare wire (or aluminum foil) as a touch sensor to control an LED.

Expand Down
2 changes: 1 addition & 1 deletion esp32/iot.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ Let's build our first IoT project! We'll read a photoresistor (light sensor), dr
We have a photoresistor in a voltage divider with a 10kΩ resistor. The analog input voltage changes with the ambient light level. We also drive an LED via PWM, making it brighter as the room gets darker.

{: .warning }
> **ADC2 + WiFi conflict!** As we covered in the [Analog Input lesson](analog-input.md), the ESP32's ADC2 pins **cannot be used when WiFi is active**—this is a hardware limitation on all ESP32 variants. You must use **ADC1 pins** for any analog input in IoT projects. On the ESP32-S3 Feather, **A5** is the only "A"-labeled pin on ADC1. Pins labeled D5, D6, D9, and D10 are also ADC1 pins and can be used with `analogRead()` by passing their GPIO number. See the [Analog Input lesson](analog-input.md#which-pins-can-i-use) for full details.
> **ADC2 + WiFi conflict!** As we covered in the [Analog Input lesson](analog-input.md), the ESP32's ADC2 pins **cannot be used when WiFi is active**—this is a hardware limitation on all ESP32 variants. You must use **ADC1 pins** for any analog input in IoT projects. On the ESP32-S3 Feather, **A5** is the only "A"-labeled pin on ADC1. Pins labeled D5, D6, D9, and D10 are also ADC1 pins and can be used with `analogRead()` by passing their GPIO number. See the [Analog Input lesson](analog-input.md#adc-pins-chip-vs-board) for full details.

<!-- TODO: Create an updated Fritzing wiring diagram for the ESP32-S3 Feather with photoresistor + LED -->

Expand Down
4 changes: 2 additions & 2 deletions esp32/tone.md
Original file line number Diff line number Diff line change
Expand Up @@ -645,14 +645,14 @@ In this lesson, you added sound to your ESP32 repertoire! Here's what you learne

## Next Lesson

In the [next lesson](capacitive-touch-sensing.md), we'll learn about the ESP32's built-in capacitive touch sensing hardware—no external components needed! You'll use touch inputs to trigger tones and build a simple touch piano.
In the [next lesson](capacitive-touch.md), we'll learn about the ESP32's built-in capacitive touch sensing hardware—no external components needed! You'll use touch inputs to trigger tones and build a simple touch piano.

<nav class="lesson-nav" aria-label="Lesson navigation">
<a href="analog-input.html" class="nav-prev">
<div class="nav-label">&larr; Previous Lesson</div>
<div class="nav-title">Analog input</div>
</a>
<a href="capacitive-touch-sensing.html" class="nav-next">
<a href="capacitive-touch.html" class="nav-next">
<div class="nav-label">Next Lesson &rarr;</div>
<div class="nav-title">Capacitive touch sensing</div>
</a>
Expand Down
Loading
Loading