---
title: Scaffold
format:
  html:
    code-line-numbers: true
    css: Arduino_prompts.css
execute:
  enabled: false
---

```{C++}
// ===================== INCLUDES =====================
#include "Seeed_AMG8833_driver.h"
#include <Grove_I2C_Motor_Driver.h>
#include <Wire.h>
#include <stdint.h>
#include <math.h>

// ===================== CONSTANTS / GLOBALS =====================

// Motor driver settings
#define I2C_ADDRESS 0x0f

// --- CALIBRATION VALUES ---
// Replace these only after validation
float ambientTempC = AMBIENT_TEMP_C;
float boardSideCm = BOARD_SIDE_CM;
char prototypePlacement[] = PLACEMENT; // CORNER or BORDER

// --- MOTOR CONFIGURATION ---
// Keep this style similar to the original sketch
const int START_OFFSET_STEPS = 0;
int SWEEP_STEPS = 128; // update according to placement
int currentMotorPosition = 0;

// Approximate conversion between steps and angle
// AI may adjust this if needed but should keep the same idea
float stepsPerDegree = 128.0 / 90.0;

// Ultrasonic sensor pin (Grove)
const int ultrasonicPin = 5;

// Thermal camera
AMG8833 sensor;

#define ROWS 8
#define COLS 8
#define TOTAL_PIXELS 64

// ===================== HELPER FUNCTIONS =====================

// --- REQUIRED THRESHOLD FUNCTION ---
float getHotThreshold(float distanceCm, float boardSideLength, float ambientTempC) {
  if (distanceCm <= 0.45 * boardSideLength) {
    return 30.0;
  } else if (distanceCm < 0.9 * boardSideLength) {
    return ambientTempC + 38.72 * exp(-0.04661 * distanceCm);
  } else {
    return max(24.5, ambientTempC + 1.0);
  }
}

// --- MOTOR / ANGLE HELPERS ---
// TODO:
// - set SWEEP_STEPS from placement
// - convert motor position to angle
// - keep 0° -> X° -> 0° sweep behavior

// --- ULTRASONIC HELPERS ---
long readUltrasonicDuration() {
  pinMode(ultrasonicPin, OUTPUT);
  digitalWrite(ultrasonicPin, LOW);
  delayMicroseconds(2);
  digitalWrite(ultrasonicPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(ultrasonicPin, LOW);

  pinMode(ultrasonicPin, INPUT);
  return pulseIn(ultrasonicPin, HIGH, 30000);
}

float microsecondsToCentimeters(long duration) {
  if (duration == 0) return -1.0;
  return (duration * 0.0343) / 2.0;
}

// TODO:
// - optionally average multiple readings
// - return distance in cm
// - apply valid-range rule 5 < x < d in detection logic

// --- THERMAL HELPERS ---
// TODO:
// - read all 64 pixels
// - compute max temperature over the full matrix
// - do not use only middle columns

// --- DETECTION / REPORTING HELPERS ---
// TODO:
// - combine valid distance + thermal threshold condition
// - print:
//   current distance
//   current motor angle
//   maximum temperature
//   detection status

// ===================== SETUP =====================
void setup() {
  Serial.begin(115200);

  Wire.begin();
  Motor.begin(I2C_ADDRESS);

  Motor.stop(MOTOR1);
  Motor.stop(MOTOR2);

  sensor.init();

  delay(1000);

  // TODO:
  // - choose SWEEP_STEPS based on placement
  // - optionally move to starting offset
  if (START_OFFSET_STEPS != 0) {
    int direction = (START_OFFSET_STEPS > 0) ? 1 : -1;
    int stepsToMove = abs(START_OFFSET_STEPS);

    for (int i = 0; i < stepsToMove; i++) {
      Motor.StepperRun(direction, 0, 0);
      delay(10);
    }
    currentMotorPosition = START_OFFSET_STEPS;
  }
}

// ===================== MAIN LOOP =====================
void loop() {
  currentMotorPosition = 0;

  delay(500);

  // ---------- Sweep Forward 0 -> X ----------
  for (int i = 0; i < SWEEP_STEPS; i++) {
    Motor.StepperRun(1, 0, 0);
    currentMotorPosition++;

    // TODO:
    // - compute current angle in degrees
    // - read ultrasonic sensor
    // - read all thermal pixels and max temperature
    // - compute threshold
    // - detect only if:
    //   valid distance AND maxTemp > threshold
    // - print serial status

    delayMicroseconds(5000);
  }

  delay(2000);

  // ---------- Sweep Backward X -> 0 ----------
  for (int i = 0; i < SWEEP_STEPS; i++) {
    Motor.StepperRun(-1, 0, 0);
    currentMotorPosition--;

    // TODO:
    // - same logic as forward sweep
    // - keep angle tracking consistent

    delayMicroseconds(5000);
  }

  delay(2000);
}
```

# Prompt blocks

## Block A - Includes

```{text}

You are editing an Arduino Uno `.ino` sketch step by step.

RULES
- Keep the code very similar to the provided sketch in structure, naming style, and general style.
- Do not redesign the project architecture.
- Keep the section order:
  1. includes
  2. constants / globals
  3. helper functions
  4. setup
  5. loop
- Keep the sketch compilable after this step.
- Return the full updated sketch.
- Modify only what is needed for this step.

TASK FOR THIS STEP
Review only the INCLUDES section.

Use these includes exactly:
- #include "Seeed_AMG8833_driver.h"
- #include <Grove_I2C_Motor_Driver.h>
- #include <Wire.h>
- #include <stdint.h>

You may add only strictly necessary standard Arduino/math includes if required for compilation.
Do not change the rest of the sketch unless strictly necessary.

SECTION TO REVIEW
// ===================== INCLUDES =====================
#include "Seeed_AMG8833_driver.h"
#include <Grove_I2C_Motor_Driver.h>
#include <Wire.h>
#include <stdint.h>
#include <math.h>

CURRENT FULL CODE
[PASTE THE INITIAL SCAFFOLD HERE]
```

## Block B - Constants / Globals

```{text}
You are editing the next step of the same Arduino Uno sketch.

RULES
- Keep the code very similar to the current version.
- Return the full updated sketch.
- Work mainly on the constants / globals section.
- Make only minimal necessary edits elsewhere.
- Do not invent or replace final calibration values.
- Keep the calibration section parameterized using:
  - AMBIENT_TEMP_C
  - BOARD_SIDE_CM
  - PLACEMENT

TASK FOR THIS STEP
Complete and refine the CONSTANTS / GLOBALS section.

Requirements:
- preserve the current coding style
- keep similar names already present
- keep:
  - float ambientTempC = AMBIENT_TEMP_C;
  - float boardSideCm = BOARD_SIDE_CM;
  - char prototypePlacement[] = PLACEMENT;
- keep currentMotorPosition logic
- keep motor configuration simple
- keep TOTAL_PIXELS = 64
- do not implement the full loop logic yet

SECTION TO REVIEW
// ===================== CONSTANTS / GLOBALS =====================

// Motor driver settings
#define I2C_ADDRESS 0x0f

// --- CALIBRATION VALUES ---
// Replace these only after validation
float ambientTempC = AMBIENT_TEMP_C;
float boardSideCm = BOARD_SIDE_CM;
char prototypePlacement[] = PLACEMENT; // CORNER or BORDER

// --- MOTOR CONFIGURATION ---
// Keep this style similar to the original sketch
const int START_OFFSET_STEPS = 0;
int SWEEP_STEPS = 128; // update according to placement
int currentMotorPosition = 0;

// Approximate conversion between steps and angle
// AI may adjust this if needed but should keep the same idea
float stepsPerDegree = 128.0 / 90.0;

// Ultrasonic sensor pin (Grove)
const int ultrasonicPin = 5;

// Thermal camera
AMG8833 sensor;

#define ROWS 8
#define COLS 8
#define TOTAL_PIXELS 64

CURRENT FULL CODE
[PASTE FULL CODE RETURNED BY BLOCK A HERE]
```

## Block C - Threshold + monitor / angle helpers

```{text}

You are editing the next step of the same Arduino Uno sketch.

RULES
- Keep the code very similar to the current version.
- Return the full updated sketch.
- Work mainly on the threshold function and motor / angle helper section.
- Make only minimal necessary edits elsewhere.
- Do not invent or replace final calibration values.

TASK FOR THIS STEP
Complete the threshold and motor / angle helper logic.

Requirements:
- keep this threshold function exactly as required:
  float getHotThreshold(float distanceCm, float boardSideLength, float ambientTempC) {
    if (distanceCm <= 0.45 * boardSideLength) {
      return 30.0;
    } else if (distanceCm < 0.9 * boardSideLength) {
      return ambientTempC + 38.72 * exp(-0.04661 * distanceCm);
    } else {
      return max(24.5, ambientTempC + 1.0);
    }
  }
- keep the original style simple
- set sweep behavior from placement
- CORNER => 90°
- BORDER => 180°
- track motor angle in degrees
- keep currentMotorPosition logic similar to the original code
- do not redesign the whole project

SECTION TO REVIEW
// --- REQUIRED THRESHOLD FUNCTION ---
float getHotThreshold(float distanceCm, float boardSideLength, float ambientTempC) {
  if (distanceCm <= 0.45 * boardSideLength) {
    return 30.0;
  } else if (distanceCm < 0.9 * boardSideLength) {
    return ambientTempC + 38.72 * exp(-0.04661 * distanceCm);
  } else {
    return max(24.5, ambientTempC + 1.0);
  }
}

// --- MOTOR / ANGLE HELPERS ---
// TODO:
// - set SWEEP_STEPS from placement
// - convert motor position to angle
// - keep 0° -> X° -> 0° sweep behavior

CURRENT FULL CODE
[PASTE FULL CODE RETURNED BY BLOCK B HERE]
```

## Block D - Ultrasonic low-level helpers

```{text}

You are editing the next step of the same Arduino Uno sketch.

RULES
- Keep the code very similar to the current version.
- Return the full updated sketch.
- Work mainly on the low-level ultrasonic helper section.
- Make only minimal necessary edits elsewhere.

TASK FOR THIS STEP
Review and refine the low-level ultrasonic helpers.

Requirements:
- keep the existing style and structure if possible
- keep readUltrasonicDuration()
- keep microsecondsToCentimeters()
- return distance in cm from pulse duration
- keep the code simple and suitable for Arduino Uno
- do not implement full detection logic here

SECTION TO REVIEW
// --- ULTRASONIC HELPERS ---
long readUltrasonicDuration() {
  pinMode(ultrasonicPin, OUTPUT);
  digitalWrite(ultrasonicPin, LOW);
  delayMicroseconds(2);
  digitalWrite(ultrasonicPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(ultrasonicPin, LOW);

  pinMode(ultrasonicPin, INPUT);
  return pulseIn(ultrasonicPin, HIGH, 30000);
}

float microsecondsToCentimeters(long duration) {
  if (duration == 0) return -1.0;
  return (duration * 0.0343) / 2.0;
}

CURRENT FULL CODE
[PASTE FULL CODE RETURNED BY BLOCK C HERE]
```

## Block E - Ultrasonic distance logic

```{text}

You are editing the next step of the same Arduino Uno sketch.

RULES
- Keep the code very similar to the current version.
- Return the full updated sketch.
- Work mainly on the remaining ultrasonic helper logic.
- Make only minimal necessary edits elsewhere.

TASK FOR THIS STEP
Complete the higher-level ultrasonic distance logic.

Requirements:
- you may add a helper to average multiple readings
- valid distance rule is exactly:
  5 < x < d
- out-of-range values must not count as detection later
- use boardSideCm as d
- keep the code simple and readable
- do not implement final detection logic here unless minimally necessary

SECTION TO REVIEW
// TODO:
// - optionally average multiple readings
// - return distance in cm
// - apply valid-range rule 5 < x < d in detection logic

CURRENT FULL CODE
[PASTE FULL CODE RETURNED BY BLOCK D HERE]
```

## Block F - Thermal helpers

```{text}

You are editing the next step of the same Arduino Uno sketch.

RULES
- Keep the code very similar to the current version.
- Return the full updated sketch.
- Work mainly on the thermal helper section.
- Make only minimal necessary edits elsewhere.

TASK FOR THIS STEP
Complete the thermal helper logic.

Requirements:
- read the full 8x8 AMG8833 temperature matrix
- compute the maximum temperature across all 64 pixels
- do not use only middle columns
- keep the code simple and readable
- keep memory usage suitable for Arduino Uno

SECTION TO REVIEW
// --- THERMAL HELPERS ---
// TODO:
// - read all 64 pixels
// - compute max temperature over the full matrix
// - do not use only middle columns

CURRENT FULL CODE
[PASTE FULL CODE RETURNED BY BLOCK E HERE]
```

## Block G - Detection / reporting helpers

```{text}

You are editing the next step of the same Arduino Uno sketch.

RULES
- Keep the code very similar to the current version.
- Return the full updated sketch.
- Work mainly on the detection / reporting helper section.
- Make only minimal necessary edits elsewhere.

TASK FOR THIS STEP
Complete the detection and reporting logic.

Requirements:
- target is detected only if both are true:
  - distance is valid
  - maximum temperature > getHotThreshold(distanceCm, boardSideCm, ambientTempC)
- serial output must show:
  - current distance
  - current motor angle
  - maximum temperature
  - detection status
- keep the style similar to the original sketch
- avoid String and dynamic memory

SECTION TO REVIEW
// --- DETECTION / REPORTING HELPERS ---
// TODO:
// - combine valid distance + thermal threshold condition
// - print:
//   current distance
//   current motor angle
//   maximum temperature
//   detection status

CURRENT FULL CODE
[PASTE FULL CODE RETURNED BY BLOCK F HERE]
```

## Block H - Setup

```{text}

You are editing the next step of the same Arduino Uno sketch.

RULES
- Keep the code very similar to the current version.
- Return the full updated sketch.
- Work mainly on setup().
- Make only minimal necessary edits elsewhere.
- Do not invent or replace final calibration values.

TASK FOR THIS STEP
Complete setup() consistently with the helper logic already created.

Requirements:
- initialize Serial
- initialize Wire
- initialize motor driver
- initialize AMG8833 sensor
- keep optional start offset behavior
- set any sweep configuration needed from placement
- do not redesign the structure

SECTION TO REVIEW
// ===================== SETUP =====================
void setup() {
  Serial.begin(115200);

  Wire.begin();
  Motor.begin(I2C_ADDRESS);

  Motor.stop(MOTOR1);
  Motor.stop(MOTOR2);

  sensor.init();

  delay(1000);

  // TODO:
  // - choose SWEEP_STEPS based on placement
  // - optionally move to starting offset
  if (START_OFFSET_STEPS != 0) {
    int direction = (START_OFFSET_STEPS > 0) ? 1 : -1;
    int stepsToMove = abs(START_OFFSET_STEPS);

    for (int i = 0; i < stepsToMove; i++) {
      Motor.StepperRun(direction, 0, 0);
      delay(10);
    }
    currentMotorPosition = START_OFFSET_STEPS;
  }
}

CURRENT FULL CODE
[PASTE FULL CODE RETURNED BY BLOCK G HERE]
```

## Block I - Main loop

```{text}

You are editing the next step of the same Arduino Uno sketch.

RULES
- Keep the code very similar to the current version.
- Return the full updated sketch.
- Work mainly on loop().
- Make only minimal necessary edits elsewhere.
- Do not invent or replace final calibration values.

TASK FOR THIS STEP
Complete the logic inside the main loop.

Requirements:
- preserve the current forward / backward sweep structure
- forward sweep must go from 0° to X°
- backward sweep must go from X° to 0°
- read sensors at each motor step
- use the already defined detection logic
- keep angle tracking consistent in both directions
- keep serial reporting active

SECTION TO REVIEW
// ===================== MAIN LOOP =====================
void loop() {
  currentMotorPosition = 0;

  delay(500);

  // ---------- Sweep Forward 0 -> X ----------
  for (int i = 0; i < SWEEP_STEPS; i++) {
    Motor.StepperRun(1, 0, 0);
    currentMotorPosition++;

    // TODO:
    // - compute current angle in degrees
    // - read ultrasonic sensor
    // - read all thermal pixels and max temperature
    // - compute threshold
    // - detect only if:
    //   valid distance AND maxTemp > threshold
    // - print serial status

    delayMicroseconds(5000);
  }

  delay(2000);

  // ---------- Sweep Backward X -> 0 ----------
  for (int i = 0; i < SWEEP_STEPS; i++) {
    Motor.StepperRun(-1, 0, 0);
    currentMotorPosition--;

    // TODO:
    // - same logic as forward sweep
    // - keep angle tracking consistent

    delayMicroseconds(5000);
  }

  delay(2000);
}

CURRENT FULL CODE
[PASTE FULL CODE RETURNED BY BLOCK H HERE]
```

## Block J - Final calibration

```{text}

You are editing the final step of the same Arduino Uno `.ino` sketch.

RULES
- Keep the code very similar to the current version.
- This is the final calibration step.
- If one or more required calibration inputs are missing, ask only for the missing ones and do not return code yet.
- If all required calibration inputs are available and valid, update only the calibration-related part of the code and return the full final sketch.
- Make only minimal necessary edits elsewhere.
- Do not redesign the code.

REQUIRED CALIBRATION INPUTS
1. Ambient temperature in °C
2. Square board side length `d` in cm, with `d <= 100`
3. Prototype placement

VALIDATION RULES
- Prototype placement must be either `CORNER` or `BORDER`
- Accept the value case-insensitively and normalize it to uppercase before validation
- If the normalized value is neither `CORNER` nor `BORDER`, ask again only for prototype placement and do not generate code
- Board size must be a numeric value in cm and must be `<= 100`
- Ambient temperature must be a numeric value in °C
- Do not invent missing calibration values

WHAT TO DO IN THIS STEP
- Check whether the required calibration inputs are already available in the conversation
- If one or more are missing, ask only for the missing ones
- If all are valid, update only this calibration section:

// --- CALIBRATION VALUES ---
// Replace these only after validation
float ambientTempC = AMBIENT_TEMP_C;
float boardSideCm = BOARD_SIDE_CM;
char prototypePlacement[] = PLACEMENT; // CORNER or BORDER

- Replace:
  - AMBIENT_TEMP_C
  - BOARD_SIDE_CM
  - PLACEMENT
  with the validated values
- Keep the rest of the sketch as unchanged as possible
- Return the full final updated sketch

CURRENT FULL CODE
[PASTE FULL CODE RETURNED BY BLOCK I HERE]
```