/*# Revised full code for the Braille embosser simulation (no right-end limit switch)
# Key fixes:
# - Proper actuator direction (starts at right, moves left)
# - Simulated return to start by reversing step count
# - Ensuring all dots in each row pass are embossed
# - Updated dot mapping and pass logic
revised_code = """*/
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
// Wi-Fi credentials
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// URL for Braille data
const char* brailleURL = "https://getpantry.cloud/apiv1/pantry/df2a69e5-e6a2-4e3c-906b-fcb9094eeb2e/basket/newBasket35";
// GPIO Pins
#define X_STEP_PIN 14
#define X_DIR_PIN 12
#define Y_STEP_PIN 27
#define Y_DIR_PIN 26
#define SOLENOID_PIN 25
// Stepper motor parameters
const int stepsPerRevolution = 200;
const int microsteps = 16;
const float pulleyDiameterMM = 12.73;
const float pulleyCircumferenceMM = 3.14159 * pulleyDiameterMM;
const float stepsPerMM = (stepsPerRevolution * microsteps) / pulleyCircumferenceMM;
// Timing
const int stepDelayUs = 2000; // 2ms delay between steps
const int solenoidPulseMs = 50; // solenoid on time
String brailleData = "";
void setup() {
Serial.begin(115200);
delay(1000);
pinMode(X_STEP_PIN, OUTPUT);
pinMode(X_DIR_PIN, OUTPUT);
pinMode(Y_STEP_PIN, OUTPUT);
pinMode(Y_DIR_PIN, OUTPUT);
pinMode(SOLENOID_PIN, OUTPUT);
digitalWrite(SOLENOID_PIN, LOW);
connectWiFi();
fetchBrailleData();
delay(2000);
embossBraille(brailleData);
}
void loop() {
// Nothing in loop
}
void connectWiFi() {
Serial.println("Connecting to Wi-Fi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Still connecting...");
}
Serial.println("Connected to Wi-Fi!");
Serial.println("IP Address: " + WiFi.localIP().toString());
}
void fetchBrailleData() {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
Serial.println("Starting HTTP request...");
http.begin(brailleURL);
int httpCode = http.GET();
if (httpCode == HTTP_CODE_OK) {
String payload = http.getString();
Serial.println("Raw JSON:");
Serial.println(payload);
StaticJsonDocument<512> doc;
DeserializationError error = deserializeJson(doc, payload);
if (error) {
Serial.print("JSON parsing failed: ");
Serial.println(error.c_str());
return;
}
brailleData = doc["text"].as<String>();
Serial.println("Extracted Braille Data:");
Serial.println(brailleData);
} else {
Serial.printf("HTTP GET returned code: %d\\n", httpCode);
}
http.end();
} else {
Serial.println("Wi-Fi disconnected. Cannot fetch data.");
}
}
void unicodeBrailleToDots(uint16_t codepoint, bool dots[6]) {
uint8_t val = codepoint - 0x2800;
dots[0] = val & 0x01;
dots[1] = val & 0x02;
dots[2] = val & 0x04;
dots[3] = val & 0x08;
dots[4] = val & 0x10;
dots[5] = val & 0x20;
}
void moveStepper(int stepPin, int dirPin, float distanceMM, bool direction) {
int stepsToMove = (int)(distanceMM * stepsPerMM);
digitalWrite(dirPin, direction ? HIGH : LOW);
for (int i = 0; i < stepsToMove; i++) {
digitalWrite(stepPin, HIGH);
delayMicroseconds(stepDelayUs);
digitalWrite(stepPin, LOW);
delayMicroseconds(stepDelayUs);
}
}
void embossDot() {
Serial.println("Solenoid triggered.");
digitalWrite(SOLENOID_PIN, HIGH);
delay(solenoidPulseMs);
digitalWrite(SOLENOID_PIN, LOW);
delay(10);
}
void feedPaperLine() {
const float lineHeightMM = 6.0;
digitalWrite(Y_DIR_PIN, LOW); // Assume LOW moves paper up
moveStepper(Y_STEP_PIN, Y_DIR_PIN, lineHeightMM, false);
}
int decodeUTF8Char(String& str, int index, uint32_t* codepoint) {
uint8_t c = (uint8_t)str[index];
if (c < 0x80) {
*codepoint = c;
return 1;
} else if ((c & 0xE0) == 0xC0) {
*codepoint = ((str[index] & 0x1F) << 6) | (str[index + 1] & 0x3F);
return 2;
} else if ((c & 0xF0) == 0xE0) {
*codepoint = ((str[index] & 0x0F) << 12) | ((str[index + 1] & 0x3F) << 6) | (str[index + 2] & 0x3F);
return 3;
} else if ((c & 0xF8) == 0xF0) {
*codepoint = ((str[index] & 0x07) << 18) | ((str[index + 1] & 0x3F) << 12) | ((str[index + 2] & 0x3F) << 6) | (str[index + 3] & 0x3F);
return 4;
}
*codepoint = 0;
return 1;
}
void embossBraille(String brailleStr) {
int totalSteps = 0;
const float charSpacingMM = 6.0;
const float dotSpacingMM = 2.5;
for (int row = 0; row < 3; row++) {
Serial.printf("Starting pass for row %d...\\n", row + 1);
int i = 0;
totalSteps = 0;
while (i < brailleStr.length()) {
uint32_t codepoint;
int charLen = decodeUTF8Char(brailleStr, i, &codepoint);
if (codepoint < 0x2800 || codepoint > 0x28FF) {
Serial.printf("Skipping non-braille char: 0x%04X\\n", codepoint);
i += charLen;
continue;
}
bool dots[6] = {false};
unicodeBrailleToDots(codepoint, dots);
int leftIdx = row;
int rightIdx = row + 3;
if (dots[leftIdx]) embossDot();
moveStepper(X_STEP_PIN, X_DIR_PIN, dotSpacingMM, false);
totalSteps += (int)(dotSpacingMM * stepsPerMM);
if (dots[rightIdx]) embossDot();
moveStepper(X_STEP_PIN, X_DIR_PIN, charSpacingMM - dotSpacingMM, false);
totalSteps += (int)((charSpacingMM - dotSpacingMM) * stepsPerMM);
i += charLen;
}
Serial.println("Returning actuator to start position...");
digitalWrite(X_DIR_PIN, HIGH); // reverse direction
for (int j = 0; j < totalSteps; j++) {
digitalWrite(X_STEP_PIN, HIGH);
delayMicroseconds(stepDelayUs);
digitalWrite(X_STEP_PIN, LOW);
delayMicroseconds(stepDelayUs);
}
feedPaperLine();
}
Serial.println("Embossing complete.");
}