Thursday, April 21, 2016

My Arduino "Thing"

-->
My latest Arduino project is a sentiment visualization experiment (sort of).  Basically what I wanted to do was to watch twitter (say for a hashtag) and indicate the basic sentiment with a rotating “thumb” – a “thumbs up” means there’s a positive sentiment and a    
 A quick stop in my local art store (Michaels) turned up exactly what I was looking for:  a wooden hand, that could be “posed” any way I wanted (in my case to a “thumbs up”).
“thumb’s down” indicates a negative.


Then I attached a metal dowel to the end and mounted it (horizontally) to two boards so that it could rotate.  You can see in the picture below, I wrapped a rubber band (actually it was a large rubber “o” ring) around a servo motor around the arm.  So now when the servo spins, it will spin the arm.  One thing – initially it wasn’t working exactly as I had wanted: when the servo would spin the rubber “O” ring would “slip” and it wouldn’t rotate the arm.   So if you look close, you’ll see some double sided tape around the wrist.  That provided a sticky surface that would keep the “O” ring from slipping and made for a perfect (cheap) solution

I probably made this project a lot more complicated than I needed to.  Since this project had to get input from Twitter, I had to connect to the Internet.  I didn’t have a WiFi shield for my Arduino, but I wanted to figure out how to connect my ESP8266 to an Arduino UNO (for a “poor man’s” wireless device).   Turns out it’s pretty easy – but it made this project a bit more complicated since I had to maintain code for two devices.

The system looks like this:


Figure 1 System diagram for the "Thing"

All of the actions starts in IBM’s Cloud Service (Bluemix).  I have a Node.red flow defined there that watches Twitter for any mention of a particular string (you can watch for specific Twitter handles or hashtags, etc).   When we “see” a tweet, the node.red flow does a little processing (more on that later) and then publishes the result to mqtt (I use channel “MrG-Thing” – yes, I called this project “Thing” after the character in the Adam’s Family).  My ESP8266 is also running an MQTT client which is subscribed to the same broker and channel.  When it “sees” something published from MQTT it grabs it and then writes it out verbatim the ESP8266’s standard output (serial) connection which is connected to the Arduino.   The Arduino gets the message and moves the servo - either pointing the thumb up or down based on how positive or negative the sentiment is.

Simple right ?




Let’s take it step-by-step

Let’s start with the Node.red application. This is really where all the work happens.   First off, here’s the flow:



Figure 2 Flow for node.red application


The flow starts at the bottom with “Fetch Tweets”.  When a tweet matches my criteria (in this case I’m matching on “sanders” since I want to see the thumbs up/down on tweet related to the presidential race) I pass it onto the next node (compute sentiment).  I do have a number of debugging nodes in there so I can watch what’s happening (ie, the “show tweet received” and the “show sentiment”) but I’ll just ignore those here.

The compute sentiment simply takes the payload from the previous node (the tweet it received) and does a basic dictionary lookup on positive and negative words – it’s code that is included with basic node.red.  At the end of “compute sentiment” the data structure “msg” is modified to include “msg.sentiment” and therefore something called “msg.sentiment.score” that provides a numeric value that represents the overall “tone” or sentiment of the message.  According to the documentation the number will be between +5 (very positive) and -5 (very negative).

A quick look at the json shows:


{ "score": -1, "comparative": -0.058823529411764705, "tokens": [ "rt", "ibmfacts", "ibm", "an", "ugly", "quarter", "but", "a", "beautiful", "future", "awaits", "the", "patient", "investor", "httpstcozj9ldtkgsn", "via", "seekingalpha" ], "words": [ "awaits", "beautiful", "ugly" ], "positive": [ "beautiful" ], "negative": [ "awaits", "ugly" ] }

Figure 3 json addition from the sentiment node
So in this case, the tweet was: 

“IBM an ugly quarter, but a beautiful future awaits the patient investor”

Which produced an overall sentiment score of -1 (negative 1).

Ultimately this score needs to be sent to the Arduino which controls the servo that will rotate the arm.   So once the score is computed, the msg construct is passed to a node which is essentially a “case” statement.  If the sentiment score is greater than zero or less than zero, we want to send the score to the Arduino.  If it’s zero, meaning the tweet had no real sentiment we just want to ignore it.  This is what the node labelled “send only valid sentiments” does.   Really it’s just a way to avoid sending messages to the Arduino that are meaningless (a sentiment score of zero wouldn’t cause the arm to move positively or negatively, so why send it).

Since the Arduino is just a microcontroller, it’s somewhat limited in what it can do.  Rather than send a score of -4 to the Arduino over a serial line and having to convert that ascii representation of the characters “-“ and “4” into a numeric value, I chose a different method.  The node “create string” simply takes the score from msg.sentiment.score and builds a string of characters to represent the number.  So if the score was +2, the “create score” node would build a string of 2 “p’s” (ie, “pp”).  If the score was negative 4 it would build “nnnn”.  The code is pretty straight forward, it looks like:


 
-->
sent = "";

marker = "";



val = msg.sentiment.score;



msg.payload = {};

if (msg.sentiment.score<0) {

                             marker="n"

                           }

else {

       marker='p';

}



for (i=0; i<Math.abs(msg.sentiment.score);i++)

{

    sent=sent+marker;

}

sent = sent +"\n"

msg.payload = sent;



return msg;



So when the Arduino receives a string of “ppp” it simply moves the servo 3 units in the positive direction.  Conversely if the string received was “nn” it would move the servo 2 units in the negative direction.

Once the string is formed, it’s simply published on MQTT (in this case I use a channel name: “MrG-Thing” and we wait for the next tweet.

And that’s it from the node.red side

Looking back at the System Diagram in Figure 1, we have the Arduino and the ESP8266 driving the servo (and therefore the arm).   So let’s look at how they are wired up:



Figure 5 Wiring for ESP8266 (Huzzah) and Arduino Uno

 As I said earlier, the ESP8266 (in this case an Adafuit Huzzah) is used mainly for the wifi connection.  The code running there is pretty straight forward.  It connects to my wifi network (in this case I’m using an SSID of  “ws2” so I don’t need to expose my own SSID/password to the rest of the world).  Then we connect to an MQTT broker (the same one that the node.red node is using) and listen on channel “MrG-Thing”.  If anything is received, we simply send it to the ESP8266’s Serial (with a Serial.print) which is also exposed on the TX/RX pins.  The Arduino on the other side will do a Serial.read() and grab the data for further processing.  Here’s the code:

#define STANDALONE

#include <ESP8266WiFi.h>
#include <PubSubClient.h>

// Update these with values suitable for your network.

const char* ssid = "ws2";
const char* password = "";
const char* mqtt_server = "realtime.ngi.ibm.com";

WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[160];
int value = 0;


void setup_wifi() {

  delay(10);
  // We start by connecting to a WiFi network
  #ifndef STANDALONE
    Serial.println();
    Serial.print("Connecting to ");
    Serial.println(ssid);
  #endif

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    #ifndef STANDALONE
      Serial.print(".");
    #endif
  }
#ifndef STANDALONE
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
#endif
}


void callback(char* topic, byte* payload, unsigned int length) {
#ifndef STANDALONE
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  Serial.println();
#endif

for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
   #ifndef STANDALONE
    Serial.print("Attempting MQTT connection...");
   #endif
    // Attempt to connect
    if (client.connect("MrG")) {
     #ifndef STANDALONE
      Serial.println("connected");
     #endif
      // Once connected, publish a msg saying we're up
      client.publish("MrG-debug", "esp8266 up!");
      // ... and resubscribe
      client.subscribe("MrG-Thing");
    } else {
      #ifndef STANDALONE
        Serial.print("failed, rc=");
        Serial.print(client.state());
        Serial.println(" try again in 5 seconds");
      #endif
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void setup() {
 
  pinMode(BUILTIN_LED, OUTPUT);     // Initialize the BUILTIN_LED pin as an output
  #ifndef STANDALONE
    Serial.begin(115200);
  #endif
    Serial.begin(4800);  // Software Serial to Arduino at 4800
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}

void loop() {

  if (!client.connected()) {
    reconnect();
  }
  client.loop();
  
  }

Note, in the code I have a statement “#define STANDALONE”.  If that’s coded, there are lots of blocks of code not included in the compile that print out debugging information.  Since I’m using the serial connection to talk to the Arduino, the only thing expected out of that connection is representation of the sentiment (ie, “ppp” or “nn”, etc).   If you take out the define for debugging, be sure to put it back or things won’t work when you add the Arduino to the mix.

Finally the Arduino code.   Really all this code needs to do is watch the serial connection (in this case I used a Software Serial library that defines a serial connection on Arduino pins 10 and 11).   Because I do this, I can use the standard Arduino Serial monitor for debugging messages from the Arduino.   Once there is something on the serial line, the code determines how long it is (the number of p’s or n’s in the string) and changes the index into an array of angles that represent the movement of the servo.  If the string has p’s (for positive sentiment) we add the string length to the index and look up the angle for the servo’s motion.  If the string is made up of “n’s” we simply subtract and then look up the angle in the array.

And that’s really it.  Here’s the Arduino code:



/*
  The Arduino code for Thing (driving the servo)


This example is basically one-way communication:

From the ESP8266 (and wifi) to the Arduino.  There is NO
communication the other way.  Note, if we wanted to do that
we would have to use a voltage divider in the input to the
ESP8266 to bring the +5v from the arduino to +3.3v on the ESP8266

 The circuit:

 * TX on the ESP8266 is connected to pin 10 of the Arduino
 * RX on the ESP8266 is NOT connected (would be pin 11)

 */


#include <SoftwareSerial.h>


SoftwareSerial mySerial(10, 11); // RX, TX
String fromMQTT;
byte index=0;

  
  int dir;     // direction to rotate
  int rot=0;   // Where we will want to rotate too

#include <Servo.h>

Servo myservo;  // create servo object to control a servo
                // twelve servo objects can be created on most boards

int thumb[] = {0,22,44,66,88,110,132,154,176};

int pos = 0;    // variable to store the servo position
int thumb_entries = (sizeof(thumb)/sizeof(int *)) - 1; 

void setup() {

  /* This allows us to use the Serial Monitor on the Arduino
   *  to watch what's happening
   * 
   *  Just the standard Serial stuff
   */

  
  Serial.begin(115200);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  Serial.println("Running on the Arduino");

 
  pinMode(13,OUTPUT);
 
  // set the data rate for the SoftwareSerial port
  mySerial.begin(4800);


 
   myservo.attach(2);  // attaches the servo on pin 2 to the servo object
   myservo.write(thumb[thumb_entries]);
   rot = 8; // Start at 180 degrees (thumbs UP)
 
}

void loop() { // run over and over

  char input;
  byte incoming;
  unsigned long currentMillis = millis();

  incoming = 0;
  index = 0;

  while (mySerial.available()==0) {            
 
  }
 
 
       fromMQTT= mySerial.readString();
       Serial.println(fromMQTT);
                             

        if (fromMQTT[0]=='p') {
                                dir = 1;
        }
        else {
               dir = -1;
        }
        
   rot = rot + ((fromMQTT.length() - 1) * dir );
       // note, we have to subtract 1 from the length due to CR
   if (rot > 8) {
                   rot = 8;
   }
   if (rot < 0) {
                   rot = 0;
   }

  
   myservo.write(thumb[rot]);
   Serial.print("rotation at: ");
   Serial.print(rot);
   Serial.print(" or: :");
   Serial.println(thumb[rot]);

        
    }



Nothing special in this code really.  As I said, I used Software Serial to create a RX/TX on Arduino pins 10 and 11 – that was handy for having the Serial monitor window available as thing runs.  What I did was define an array of angles for the thumb to rotate – there are 8 angles – that can be changed for a “finer tuned” rotation – but I like seeing the bigger jumps


Here’s an example of “thing” in action.  For this one, I was watching twitter for mentions of Bernie Sanders – enjoy -

Tuesday, August 25, 2015

On a train again

As I woke up this morning, the first song that went  through my mind was:

 "On a train again, just can't wait to get on a train again..."




Back to New York City today and another customer presentation on the adoption of agile software methods.  I really do love doing this (not thrilled about the early morning trains tho).  Today I'm going to focus on the need to modify a corp culture to really adopt these iterative methods.  The other thing I want to hit pretty hard is that we can use these idea and techniques for things outside of software development - so applying collaborative and team practices to everything we do - hey who couldn't benefit from quick meetings?

So I'm at 590 Madison ave today,  nice location - But WOW it was a very hot and sweaty walk from grand central station.   Now if I could just find a coffee.....
(Have to skip the donut since I'm "training" for a 5K race (more on that later)



Sunday, August 23, 2015

Are you ready for some football

Last night Karen and I went to the ny football giants first home preseason game against the Jacksonville Jaguars   




I t was a perfect night - and with game starting at 730 pm it was perfect for tailgating.  The game was "ok" - 6 or 7 field goals in total - they couldn't buy a touchdown - but like I said, the tailgating was great



On the  menu today:

  • Guacamole
  • Vodka and cranberry for the apps 
  • Steamed clams
  • Mozzarella and tomato with olives
  • Grilled shrimp
  • Flank steak with mozzarella and a horseradish sauce
  • White wine
Win or lose - we ate well ! (Oh the Giants win 22-12)

Friday, August 21, 2015

My favorite day

I was sitting at my desk today trying to figure out why I was in such a good mood!   Sounds silly I know - but for some reason I was in an exceptionally good mood today

Every other Friday I host an early morning meeting (conference call with an online screen sharing) called hellosensors - it's a group of ibm'ers interested in the internet of things and microconrollers.  Every time we have a meeting I find myself walking away energized and Looking for a new IOT project to play around with

As I looked at my desk I realized how many Pi's, arduino's, beans and spark cores I had!  Wow


Today didn't disappoint - lots of fun stuff coming (wish I could talk about it all) / most of the enjoyment was just kicking around so pretty creative ideas

My latest project is going to be working with some of my fellow professors at pace university where we're bringing in about 30 high school girls to build and operate some Sea Perchs - they are educational under water robots (  check them out )

my job is to hook up some arduino's and temperature sensors so they can sense and record temperatures in the pond at the university.  if any has any ideas on how to waterproof arduino's or thing like ping sensors I'd love to hear from you

Thursday, August 20, 2015

Thank god I'm a country boy

Today's work schedule brings me into Manhattan for a few meetings.  I don't mind working in "the city" every once in a while, but I could never do it eveyday.

I'm not in a rush today cause my meetings aren't till later so it gives me time to catch up on the things I always let slide on my schedule, like my writing.  I do love to write and I always have something in the works.  Today while I was waiting for my train I was fine tuning a speech I'm giving at Pace University in September.  It's coming along nicely/ just need to finally say "I'm done" - there's always something to tweak or add


The train ride from home isn't too bad - about 1 hr 10min - then it was a quick subway ride.  Of course I'm lost - can't find the entrance do I'm taking a break in a coffee house - cute place - and with the humidity out there a welcomed (air conditioned) place


Well after walking around like a dazed tourist and asking about 10 different security guards I finally found the place! Whew !!

So today's discussion is on how to merge the language of design thinking with agile methods.  Should be a fun one - anything is better than wandering those streets!

Ps - oh I was asked about the titles of my blogs.  Today is "thank god I'm a country boy" - yesterday when I was in jersey city I got lost trying to find my car!  I was trying to get into the wrong parking garage and was insisting to the guard I was in the right place. Turns out the right garage was across the street!  We both laughed as I told him: "hey I'm just a simple country bumpkin!" And got me pointed in the right direction.

Here's home for today (at least for the next few hours)








Wednesday, August 19, 2015

Talk, talk

Today I'm in Jersey city to speak with TD bank about agile software methods.  I've never been in jersey city before, and I have to say it's pretty nice (clean, well kept and wonderful views)



Like I said, I'm here as a guest of our client teams to talk about agility and some of things we do at ibm as well as some of the issues and pitfalls I've seen teams run into as they move into this space.  I'll talk about how to implement some of the practices, but more about the cultural change for both the "workers" and the management types (I'm speaking to the ceo, cto, etc) so hopefully it's a lively conversation.

Oh as long as I was here, I grabbed a quick geocache (there are a bunch more nearby, but it's so hot out there I felt like I was melting - not a good scene in front of the customer :-)

Monday, August 17, 2015

Weather in Chicago: earth, wind and fire!

Last night we went to see Chicago along with earth, Eind and Fire at Jones beach on Long Island with our good friends Caroline and Jay



Tailgating was great and the weather turned out to be perfect 

The concert was really good.  I wasn't sure how many Earth,wind and fire songs I'd remember - and I while I did remember quite a few - it was their energy on stage that was the most amazing-these guy really worked hard!

They sounded great doing songs like: boogie wonderland, devotion, shining star and After the love is gone

Chicago sounded amazing as well doing classics like Saturday in the park, does anyone know what time it is and ending the show with 25 or 6 to 4.   They all did the last 6 songs together which was crazy with over 20 guys up there!