A Week Without

Sarah Latimer is away camping in the White Mountains for a week.

She doesn’t think we can survive without her.

We aim to prove her wrong.

Day 1.

Grocery shopping has been made greatly easier. A week of this will be a trifle.

Day 2.

Our efficiency in daily tasks has improved dramatically:

  1. Reduction in dishes used by eating out of the same pots in which we cook. (Not that we are cooking; Pop Tarts rule!)
  2. Further reduction in dishes by drinking from containers, rather than wasting time and resources dirtying glasses.
  3. Juno (our dog) provides excellent dish-cleaning service, indistinguishable from dishwasher processing.
  4. Still more time saved by not showering or bathing.
  5. Who needs to put on clean clothes every day?

Wait, what is that? …

Day 2, Continued.

Holy, freaking crap! There is nothing left of the Pop Tarts but wrappers. Do you children have no discipline at all?!

(The boogers mumble something about apples and trees.)

We’re ruined! Doomed. Do you hear me!? We’re going to starve, or worse, have to eat something I cook! Do you remember fiasco of the pancakes? Ashish remembers the pancakes? (“You cooked steak? I thought you were going to make pancakes.”)

This could get interesting, in a “Define, ‘interesting,’” sort of way.

Day 3.

Someone in this house smells. It seems to be worse around the children. And the kitchen.

Maybe the philosophy of, “Why clean? It’ll just get dirty again,” needs some reevaluation.

At least Juno is happy, although this morning she walked over to me, looked me right in the face, sniffed once, and ran away.

And. We’re hungry. The children are sticking firmly to their commitment to starve before they eat anything I might cook.

What we thought was thunder turned out to be the combined output of stomachs rumbling.

How much longer?

Day 4.

It’s midnight now. The house is dark. I am not sure how this will turn out. The kids are all desperately sick, throwing up. I can hear my son and daughter retching in separate bathrooms. I went in to check on them a few minutes ago, to see what was coming up.

I think I’m okay, at least for the moment. But of course the odds aren’t good: most of the people involved in this business are already dead. And there are so many things I can’t know for sure.

I have a ringing in my ears, which is a bad sign. And I feel a vibrating in my chest and abdomen. The baby is spitting up, not really vomiting. I am feeling dizzy. I hope I don’t lose consciousness. The kids need me, especially the little one. They’re frightened. I don’t blame them.

I am, too.

(With apologies to Michael Crichton.)

Day 5.

We have, at last found something we can agree on eating. Thankfully, we have (had?) a real dog, rather than a Chihuahua or something tiny.

Weasley Clock Code – Now with WiFi

Back at one of Veracode’s Hackathons, I published the video below.

My Original Weasley Clock

The New and Improved Weasley Clock(s)

(Original post is here.) I was determined to update the code to use WiFi, and make some other improvements, so finally rewrote it. Here’s the first major revision:

#include 
#include "Adafruit_IO_Client.h"
#include 

/**
 * https://www.amazon.com/gp/product/B015RQ97W8/ref=oh_aui_search_detailpage?ie=UTF8&psc=1
 * 5-wire unipolar steppers with controller
 * Longruner 5x Geared Stepper Motor 28byj 48 Uln2003 5v Stepper Motor Uln2003 Driver 
 * Board for arduino LK67
 * 
 * AWESOME details on these motors/controllers:
 * https://arduino-info.wikispaces.com/SmallSteppers
 * 
 * Much Better than standard stepper library: AccelStepper
 * http://www.airspayce.com/mikem/arduino/AccelStepper/classAccelStepper.html
 * 
 * Weasley Clock
 * -------------
 * 
 * Created by Doug "LegoDoug" Wilcox for Veracode Hackathon IX.
 * 
 * Video of the completed project is at https://www.youtube.com/embed/oRUViFnxKsg.
 * 
 * "Share and enjoy."
 */

/************************* WiFi Access Point *********************************/
#define WLAN_SSID "DefinitelyNotMySSID"              // "...your SSID..." Amusingly, the cannot contains spaces or hyphens.
#define WLAN_PASS "TotallyNotTheRealPassword"        // "...your password..."


/************************* Adafruit.io Setup *********************************/

#define AIO_SERVER           "io.adafruit.com"
#define AIO_SERVERPORT       1883                           // use 8883 for SSL, otherwise use 1883
#define AIO_USERNAME         "TotallyNotMyAdaFruitIOUser"   // "...your AIO username (see https://accounts.adafruit.com)..."
#define AIO_KEY              "TotallyNotMyAdafruitIOKey"    // "...your AIO key..."
#define AIO_FEED_PATH        "/feeds/"
#define AIO_PUBLISH_FEED     "weasleyclockposition"
#define AIO_SUBSCRIBE_FEED   "weasleyclockstatus"

// Motor pin definitions
#define motorPin1  14    // IN1 on the ULN2003 driver 1
#define motorPin2  12    // IN2 on the ULN2003 driver 1
#define motorPin3  13    // IN3 on the ULN2003 driver 1
#define motorPin4  15    // IN4 on the ULN2003 driver 1

#define DELAY 1
#define HALFSTEP 8

/************ Global State (you don't need to change this!) ******************/

// Create an ESP8266 WiFiClient class to connect to the WiFi network.
WiFiClient client;
// or... use WiFiFlientSecure for SSL
// WiFiClientSecure client;

// Create an Adafruit IO Client instance.  Notice that this needs to take a
// WiFiClient object as the first parameter, and as the second parameter a
// default Adafruit IO key to use when accessing feeds (however each feed can
// override this default key value if required, see further below).
Adafruit_IO_Client aio = Adafruit_IO_Client(client, AIO_KEY);

// Alternatively to access a feed with a specific key:
Adafruit_IO_Feed clockFeed = aio.getFeed(AIO_SUBSCRIBE_FEED, AIO_KEY);

// States
const String LD_HOME         = "ld_na";
const String LD_TRAVELING    = "ld_tr";
const String LD_VERACODE     = "ld_of";
const String LD_CHURCH       = "ld_ch";
const String LD_MORTAL_PERIL = "ld_mp";
const String LD_GLOUCESTER   = "ld_gl";
const String PLUS_ONE        = "plus_1";
const String MINUS_ONE       = "minus_1";
const String PLUS_FIVE       = "plus_5";
const String MINUS_FIVE      = "minus_5";
const String NO_MOVEMENT     = "none";

// Steps
const int STEPS_HOME         = 0;
const int STEPS_TRAVELING    = 600;
const int STEPS_VERACODE     = 1250;
const int STEPS_CHURCH       = 1900;
const int STEPS_MORTAL_PERIL = 2600;
const int STEPS_GLOUCESTER   = 3450;
const int STEPS_ONE          = 32;
const int STEPS_FIVE         = 5 * 32;

String fValue = "";

const unsigned long requestInterval = 5000L; // delay between updates, in milliseconds

void stepBySteps(int newPosition, boolean resetWhenDone = false);

AccelStepper clockStepper(HALFSTEP, motorPin1, motorPin3, motorPin2, motorPin4);

void setup() {
  Serial.begin(115200);
  delay(10);

  // Connect to WiFi access point.
  Serial.println(); Serial.println();
  Serial.print("Connecting to ");
  Serial.println(WLAN_SSID);

  WiFi.begin(WLAN_SSID, WLAN_PASS);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  clockStepper.setMaxSpeed(1000.0);
  clockStepper.setAcceleration(100.0);
  clockStepper.setSpeed(200);
  clockStepper.setCurrentPosition(0);
}

void loop() {
  // Wait for a bit and read the current feed value.
  Serial.println(F("Waiting ..."));
  delay(requestInterval);
  // To read the latest feed value call the receive function on the feed.
  // The returned object will be a FeedData instance and you can check if it's
  // valid (i.e. was successfully read) by calling isValid(), and then get the
  // value either as a text value, or converted to an int, float, etc.

  Serial.println(F("Checking feed ..."));
  FeedData latest = clockFeed.receive();
  if (latest.isValid()) {
    Serial.print(F("Received value from feed: ")); Serial.println(latest);
    // By default the received feed data item has a string value, however you
    // can use the following functions to attempt to convert it to a numeric
    // value like an int or float.  Each function returns a boolean that indicates
    // if the conversion succeeded, and takes as a parameter by reference the
    // output value. Also, beware. There seems to be a limit on how long the
    // feed value can be. I had trouble when "minus_five" was used, which makes
    // me think the limit is 8 characters.

    // Want some fun? Learng about "conversion from 'FeedData' to non-scalar type 'String' requested" the hard way.
    fValue = latest;

    if(fValue == LD_HOME) {
      Serial.println("Nashua");
      stepBySteps(STEPS_HOME);
    }
    if(fValue == LD_TRAVELING) {
      Serial.println("Traveling");
      stepBySteps(STEPS_TRAVELING);
    }
    if(fValue == LD_VERACODE) {
      Serial.println("Veracode");
      stepBySteps(STEPS_VERACODE);
    }
    if(fValue == LD_CHURCH) {
      Serial.println("Church");
      stepBySteps(STEPS_CHURCH);
    }
    if(fValue == LD_MORTAL_PERIL) {
      Serial.println("Mortal Peril!");
      stepBySteps(STEPS_MORTAL_PERIL);
    }
    if(fValue == LD_GLOUCESTER) {
      Serial.println("Glostah");
      stepBySteps(STEPS_GLOUCESTER);
    }
    if(fValue == PLUS_ONE) {
      Serial.println("Forward one.");
      stepBySteps(clockStepper.currentPosition() + STEPS_ONE, true);
    }
    if(fValue == MINUS_ONE) {
      Serial.println("Back one.");
      stepBySteps(clockStepper.currentPosition() - STEPS_ONE, true);
    }
    if(fValue == PLUS_FIVE) {
      Serial.println("Forward five.");
      stepBySteps(clockStepper.currentPosition() + STEPS_FIVE, true);
    }
    if(fValue == MINUS_FIVE) {
      Serial.println("Back five.");
      stepBySteps(clockStepper.currentPosition() - STEPS_FIVE, true);
    }
    if(fValue == NO_MOVEMENT || fValue == "") {
      Serial.println("Not moving.");
    }
  } else {
    Serial.print(F("Failed to receive the latest feed value!"));
  }
}

void stepBySteps(int newPosition, boolean resetWhenDone) {
  clockStepper.enableOutputs();
  clockStepper.moveTo(newPosition);

  while (clockStepper.isRunning()) {
    clockStepper.run();
    delay(DELAY);
  }
  clockStepper.disableOutputs();

  if (resetWhenDone) {
    clockStepper.setCurrentPosition(0);
  }
  
}

Still to come, if I ever get around to it:

  • Alternative methodologies for reading the feed (publish/subscribe).
  • Secure WiFi communication.
  • Adjustment (such as after power disconnect) via an induction sensor.

One Cool Hotspot

Okay, wanna see something really cool? (Actually, it’s kinda hot …)

Below is a cropped image from a 1969 National Geographic map of the seafloor, showing the Pacific basin. What’s the cool part? See that long, almost L-shaped line of ridges and seamounts and islands that has Hawaii at the very end? That’s where the Pacific Plate has slowly moved over a hotspot in the earth’s mantle, which causes seamounts to form, and, occasionally, islands like Midway or Hawaii.

Pacific Floor Ocean Map, National Geographic, 1969.

The ridges show the movement of the Pacific plate over the last 75,000,000 years. Kind of slow movement, only about 6,000 km in that time, or 0.000000009132 km/h, about 80 mm/year.

That bend in the L is where the Pacific plate shifted direction 43,000,000 years ago.

In case you’re wondering where it goes as it moves, you can see the trenches on the top and left edges of the plate. Those are subduction zones, including the Marianas Trench, the deepest part of the ocean on earth. That’s where the Pacific plate is moving underneath the other plates, getting recycled very, very slowly.


Notes:

Ciphers in the Bible

Found an interesting tidbit in a children’s book I have: The First Book of Codes and Ciphers by Sam and Beryl Epstein.

The First Book of Codes and Ciphers
The First Book of Codes and Ciphers, Sam and Beryl Epstein

And all the kings of the north, far and near, one with another, and all the kingdoms of the world, which are upon the face of the earth: and the king of Sheshach shall drink after them. (Jeremiah 25:26)

SHESHACH in Jeremiah 25:26, and elsewhere, is a Hebrew backward alphabet cipher called ATHBASH (the English equivalent of which would be AZBY, although we would transliterate it as ATBASH). SHESHACH means BABYLON (or BABEL).

The same type of cipher is used in Jeremiah 51:1 and 51:41.

See https://en.wikipedia.org/wiki/Atbash.

A Teacher Worthy of Notice

(A reflection from November 9, 2016)

While my wife—Sarah Latimer—and I were walking our dog, Juno, we chanced upon an outside window of this history classroom at Nashua’s Fairgrounds Middle School, where our daughter, Naomi, attends.

I was moved to tears at the display, particularly given the anniversary of Kristallnacht. This was a meaningful reminder that, despite what we have seen all too often on social media and propaganda outlets, there are, indeed, those like this English teacher who are quietly and efficiently going about making the world a better place for all our children.

The Signs of Science

One of the best parts of the March for Science Sarah and I attended on April 22, 2017, in Washington, D.C., was the nearly endless creativity the marchers put into their signs. Not too many were repeated, and few would have been considered offensive. The preview image here is my sign, cribbed from “Stand back! I’m going to try science!” of XKCD origin.

All the signs we photographed:

Signs of Science
Bill Nye
Bill Nye
Bill Nye
« 1 of 107 »

 

TramBot (Originally published in 1998 or 1999)

The TramBot—When my nephew Dave Matheson (a veterinary grad student at Prince Edward Island) stopped in for a day-long visit, we constructed a TramBot that ran on a string stretched across an upstairs room with a light-activated set of “grabs”—perfect for bombing runs. This was inspired by the “Bomber Fly” seen in assorted Lego media.

Yes, I Always Over-Design

If you’ve seen the Bomber Fly in the Lego publications, then you will immediately notice that my creation is much bigger, and probably heavier. I developed a fear of minimalism after my very first RIS creation quite literally shook itself to pieces in under 10 seconds.

Features and Innovation Details

  • The forward-reverse pulleys are driven by a belt drive, although a geared drive would have been fine in this case.
  • There are bumpers connected to touch sensors on each end that reverse the drive pulley motor when triggered. Because the string is at about a 45º angle to the wall, we added the tires to keep the bumper rods from slipping. (Before this was done, the bumpers would sometimes just glance off the wall without triggering the touch sensors, as the robot tried to keep moving.)
  • We solved the problem of timing on the “grabs” (the name alludes to Gerry Anderson’s Supermarionation Thunderbirds program—see http://www.gis.net/~fm/) by using a belt drive, and setting the motor run time to one second longer than the absolute maximum necessary. This allowed the grabs to automatically re-synchronize, be movable by hand, and grip objects of various sizes.
  • The grabs are light-triggered. We used the Lego light sensor, and programmed it so that a flashlight beamed on it would trigger the grabs’ open or close sequence. This allowed for precise payload delivery.

 


My sons Isaac and John, my Nephew Dave, and I perform some final adjustments and testing.

To Boldly Go …

What Is Wrong with These People?

On the eve of the nomination of Donald Trump as President of the United States:

My biggest complaint* of the past year has been this: White “Evangelicals” ignored virtually all of Scripture to support a man who represents a near perfect antithesis of Christianity.

I have watched those on the fringes and outside of Christianity shake their heads, and wonder what is possibly going on in the minds of these Christians, and determine that they never, ever want to embrace a religion with such obvious hypocrisy. The Evangelical swell of blind support for a preacher of hate, lust, greed, lies, and ignorance has done more to harm the cause of Christ than anything else I have seen in my lifetime.

But I remind myself of this: Paul explained we should pray for our leaders—and I shall. Paul did this under perhaps the most corrupt government ever seen on earth, where his brothers were routinely murdered for sport.

So I will pray for (as of tomorrow) President Trump. I will also pray that we are spared from the horrors he has promised. I will also pray that the binding of extremism and near-insanity of the Republican Party to White Christianity is revealed for the disaster it is and forever abandoned. I will also pray for the healing of a nation terribly divided—while I, as promised and commanded, pray for the one who most wanted to divide it for his own gain.

1First of all, then, I urge that supplications, prayers, intercessions, and thanksgivings be made for all people, 2for kings and all who are in high positions, that we may lead a peaceful and quiet life, godly and dignified in every way. 3This is good, and it is pleasing in the sight of God our Savior, 4who desires all people to be saved and to come to the knowledge of the truth. 5For there is one God, and there is one mediator between God and men, the man[a] Christ Jesus, 6who gave himself as a ransom for all, which is the testimony given at the proper time. 7For this I was appointed a preacher and an apostle (I am telling the truth, I am not lying), a teacher of the Gentiles in faith and truth. (1 Timothy 2:1–7, ESV)

*This complaint is probably tied for first place with the practice of those same people chain-posting completely fraudulent and easily refutable propaganda. (No, that’s the Black Speech from Lord of the Rings, not a school distributing donuts with verses from the Qu’ran.)

Weasley Clock Code

Note: I’ve finally gotten around to a much-needed rewrite for WiFi. You can find that code and another video here.

Back at Veracode’s last Hackathon, I published the video below. People have started discovering this and asking questions about it, so here is the code for it:

/*
  Weasley Clock
  -------------

  Created by Doug "LegoDoug" Wilcox for Veracode Hackathon IX.

  Video of the completed project is at https://www.youtube.com/embed/oRUViFnxKsg.

  "Share and enjoy."

 */

// Arduino SPI (Serial Peripheral Interface) library - https://www.arduino.cc/en/Reference/SPI
#include <SPI.h>             
// Arduino Ethernet library - https://www.arduino.cc/en/Reference/Ethernet
#include <Ethernet.h>        
// Arduino Stepper library - https://www.arduino.cc/en/Reference/Stepper
#include <Stepper.h>         
// Adafruit REST IO library - https://learn.adafruit.com/adafruit-io/arduino
// See also https://www.arduino.cc/en/Tutorial/WebClientRepeating
#include "Adafruit_IO_Client.h"    
                                   

// assign a MAC address for the ethernet controller.
byte mac[] = {
  0x8C, 0xDC, 0xD4, 0x4A, 0xC9, 0xC2
};

// initialize the library instance:
EthernetClient client;

// last time the Arduino connected to the server, in milliseconds
unsigned long lastConnectionTime = 0;        
// delay between retrieving updates, in milliseconds
const unsigned long requestInterval = 5000L; 

// Configure Adafruit IO access. You will need to create your own 
// Adafruit IO account (free), and set up a feed, and provide your
// feed and AIO key in the code below.
#define AIO_FEED   "weasleyclockstatus"
#define AIO_KEY    "XXXXXXXXXXXXXXXXXXXXXXXXXXX"

// Create an Adafruit IO Client instance.  Notice that this needs to take a
// WiFiClient object as the first parameter, and as the second parameter a
// default Adafruit IO key to use when accessing feeds (however each feed can
// override this default key value if required, see further below).
Adafruit_IO_Client aio = Adafruit_IO_Client(client, AIO_KEY);

// Alternatively to access a feed with a specific key:
Adafruit_IO_Feed clockFeed = aio.getFeed(AIO_FEED, AIO_KEY);

// States - These are the codes that correspond to specific clock positions.
const String LD_HOME         = "ld_na";
const String LD_TRAVELING    = "ld_tr";
const String LD_VERACODE     = "ld_of";
const String LD_CHURCH       = "ld_ch";
const String LD_MORTAL_PERIL = "ld_mp";
const String LD_GLOUCESTER   = "ld_gl";

// Steps - How many steps the motor needs to move to point to a specific position 
// on the clock.
const int STEPS_HOME         = 0;
const int STEPS_TRAVELING    = 750;
const int STEPS_VERACODE     = 1600;
const int STEPS_CHURCH       = 2450;
const int STEPS_MORTAL_PERIL = 3350;
const int STEPS_GLOUCESTER   = 4350;

// Someday, I will determine what this actually does. (I don't think, functionally, 
// it has any affect.)
const int stepsPerRevolution = 200;  

long motorPosition = 0L;         // Number of steps the motor has taken.
String fValue = "";              // Feed value.

Stepper clockStepper(stepsPerRevolution, 7, 6, 5, 4, 8);

void setup() {
  // start serial port:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native 
      // USB port only, on certain Arduino models.
  }

  // give the ethernet module time to boot up:
  delay(1000);
  // start the Ethernet connection using a fixed IP address and DNS server:
  //Ethernet.begin(mac, ip, myDns);
  // Or, just start it with dynamic DNS by giving it a MAC address.
  Ethernet.begin(mac);
  // print the Ethernet board/shield's IP address:
  Serial.print("My IP address: ");
  Serial.println(Ethernet.localIP());

  clockStepper.setSpeed(20);
}

void loop() {

  // Wait for a bit and read the current feed value.
  Serial.println(F("Waiting ..."));
  delay(requestInterval);
  
  // To read the latest feed value call the receive function on the feed.
  // The returned object will be a FeedData instance and you can check if it's
  // valid (i.e. was successfully read) by calling isValid(), and then get the
  // value either as a text value, or converted to an int, float, etc.
  FeedData latest = clockFeed.receive();
  if (latest.isValid()) {
    Serial.print(F("Received value from feed: ")); Serial.println(latest);
    // By default the received feed data item has a string value, however you
    // can use the following functions to attempt to convert it to a numeric
    // value like an int or float.  Each function returns a boolean that indicates
    // if the conversion succeeded, and takes as a parameter by reference the
    // output value.

    // Want some fun? Learning about "conversion from 'FeedData' to non-scalar 
    // type 'String' requested" the hard way.
    //
    // If I remember correctly, it was a casting error caused by trying to use 
    // the 'latest' variable as a String, directly.
    // The following line casts 'latest' to a string and lets us use it as 'fValue'.
    fValue = latest;
    
    if(fValue == LD_HOME) {
      Serial.println("Nashua");
      stepBySteps(STEPS_HOME);
    }
    
    if(fValue == LD_TRAVELING) {
      Serial.println("Traveling");
      stepBySteps(STEPS_TRAVELING);
    }

    if(fValue == LD_VERACODE) {
      Serial.println("Veracode");
      stepBySteps(STEPS_VERACODE);
    }
    if(fValue == LD_CHURCH) {
      Serial.println("Church");
      stepBySteps(STEPS_CHURCH);
    }
    if(fValue == LD_MORTAL_PERIL) {
      Serial.println("Mortal Peril!");
      stepBySteps(STEPS_MORTAL_PERIL);
    }
    if(fValue == LD_GLOUCESTER) {
      Serial.println("Glostah");
      stepBySteps(STEPS_GLOUCESTER);
    }
    
  } else {
    Serial.print(F("Failed to receive the latest feed value!"));
  }

}

void stepBySteps(int newPosition) {
  if(motorPosition == newPosition) {
    Serial.println("No movement required.");
    return;
  }

  long steps = newPosition - motorPosition;
  
  clockStepper.step(steps);
  motorPosition = newPosition;
  Serial.print("position should now be:" );
  Serial.println(motorPosition);
}