Escher — The world’s first cloud-controlled Etch-a-Sketch

The Escher web interface.

Design considerations

Hardware design

The Adafruit HUZZAH32 — Image from https://www.adafruit.com/product/3405
The custom power distribution board for Escher. Totally not necessary if you want to use two power supplies instead.

3D printed base

Designing the Escher base in FreeCAD.
Rear view, showing electronics.

The software

The web client and the HUZZAH32 communicate via Firebase.

Web client design

G-code support

Arduino firmware

Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_StepperMotor *myStepper1 = AFMS.getStepper(200, 1);
Adafruit_StepperMotor *myStepper2 = AFMS.getStepper(200, 2);
void forwardstep1() {
myStepper1->onestep(BACKWARD, SINGLE);
}
void backwardstep1() {
myStepper1->onestep(FORWARD, SINGLE);
}
void forwardstep2() {
myStepper2->onestep(BACKWARD, DOUBLE);
}
void backwardstep2() {
myStepper2->onestep(FORWARD, DOUBLE);
}
AccelStepper stepper1(forwardstep1, backwardstep1);
AccelStepper stepper2(forwardstep2, backwardstep2);
stepper1.setMaxSpeed(50);
stepper2.setMaxSpeed(50);
MultiStepper mstepper;
mstepper.addStepper(stepper1);
mstepper.addStepper(stepper2);
AFMS.begin();
#define BACKLASH_X 10
#define BACKLASH_Y 15
// Move to the given position, specified in stepper units.
void EscherStepper::moveTo(long x, long y) {
// Figure out if we're reversing direction in x or y axes.
long dirx = x - last_x_;
if (dirx > 0) {
dirx = 1;
} else if (dirx < 0) {
dirx = -1;
}
long diry = y - last_y_;
if (diry > 0) {
diry = 1;
} else if (diry < 0) {
diry = -1;
}
if (dirx != dir_x_) {
cur_backlash_x_ += (dirx * BACKLASH_X);
}
if (diry != dir_y_) {
cur_backlash_y_ += (diry * BACKLASH_Y);
}
long target[2] = {x + cur_backlash_x_, y + cur_backlash_y_};
last_x_ = x;
last_y_ = y;
// Don't want to add backlash when transitioning from x -> 0 -> x
if (dirx != 0) {
dir_x_ = dirx;
}
if (diry != 0) {
dir_y_ = diry;
}
mstepper_.moveTo(target);
}
// Download the given URL and save it to flash storage.
// Returns true if successful, false otherwise.
bool downloadGcode(const char* url) {
http.setTimeout(10000);
http.begin(url);
int responseCode = http.GET();
if (responseCode <= 0) {
Serial.printf("[downloadGcode] failed, error: %s\n",
http.errorToString(responseCode).c_str());
return false;
}
File outFile = SPIFFS.open("/data.gcd", FILE_WRITE);
int bytesRead = http.writeToStream(&outFile);
http.end();
outFile.close();
if (bytesRead < 0) {
return false;
} else {
return true;
}
}

Stuff that worked, stuff that didn’t

--

--

--

VP of Engineering at OctoML.ai, building compilers for fast AI. Ex-Google engineering director, Ex-Apple. Systems hacker and drinker of beer.

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Front-end and Back-end Explained In Layman’s Terms

A group of people building the front end for a mobile application

Predicting Personality Traits from Content Using IBM Watson

C OPERATORS-9 TYPES WITH DETAILED EXPLANATION

Reduce Cost and Increase Productivity with Value Added IT Services from buzinessware — {link} -

Arth_Task-22

Writing Rego for all the things

Packaging your Spring Boot and Angular 2+ projects together

Create and Run Dart Program in Windows using cmd

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Matt Welsh

Matt Welsh

VP of Engineering at OctoML.ai, building compilers for fast AI. Ex-Google engineering director, Ex-Apple. Systems hacker and drinker of beer.

More from Medium

How to Disable Search Web Results on Windows 11/10–2 Methods

Shells, Computer mouses, and 3D Forms

DEMYSTIFYING COLOR AND LAYOUT.

HTML — 2.Text Formats