Internet Connected Petduino - Part 2, Petduino Setup

Published: 12 December 2015

Now that we have a plan of action, the first step we need to take is to setup the Petduino to work over serial and prepare what we want it to do when it receives commands, whether it’s displaying an animation, playing a sound, or any other notification format supported by the Petduino. For our example, we’ll simply display a number on the Petduino’s LED matrix of how many people are currently in space.

Before we start, make sure that you have run through the install instructions for the standard Petduino and it’s library, as well as the PetduinoSerial installation instructions. Once these are ready, connect your petduino and start with the standard PetduinoSerial code file.

#include <LedControl.h>
#include <Petduino.h>

#include <CmdMessenger.h>
#include <PetduinoSerial.h>

PetduinoSerial pet = PetduinoSerial();

void setup() {

  // Setup Petduino
  pet.begin(9600);

}

void loop() {

  // Update pet
  pet.update();
  
  // Update display based on current state
  switch(pet.getState()){
  
    //TODO: Handle states

  }

}

In our Arduino routine, we’ll want to do two things. Firstly we’ll display a waiting animation while we wait to connect to the web, and secondly display a number on screen based upon a value passed in over serial.

To setup the wait animation, update your Arduino sketch to the following:

#include <LedControl.h>
#include <Petduino.h>

#include <CmdMessenger.h>
#include <PetduinoSerial.h>

#define WAIT_ANIM_FRAMES 4
byte waitAnimF[WAIT_ANIM_FRAMES][8]={
  {0x3c,0x02,0x81,0xc7,0xe3,0x81,0x40,0x3c},
  {0x3c,0x58,0x91,0x81,0x81,0x89,0x1a,0x3c}
};
unsigned long waitAnimD[WAIT_ANIM_FRAMES] = { 1501, 1501 };

#define WAIT_STATE 0
#define DATA_STATE 1

PetduinoSerial pet = PetduinoSerial();

void setup() {

  // Setup Petduino
  pet.begin(9600);
  
  // Draw the default img
  pet.setState(WAIT_STATE);

}

void loop() {

  // Update pet
  pet.update();
  
  // Update display based on current state
  switch(pet.getState()){

    case WAIT_STATE:
      pet.playAnimation(waitAnimF, waitAnimD, WAIT_ANIM_FRAMES, 3);
      pet.setNextState(WAIT_STATE, 9000); // Wait for connection
      break;
      
    case DATA_STATE:
      //TODO: Display number
      pet.wait();
      break;

  }

}

What we have done here is to define the two states of our sketch, and created a two image animation for our wait state. In the wait state, we run the animation in a loop 3 times, and then re-enter the wait state re-playing the animation until we receive an external command to change our display state. The important thing to note is that whenever we enter or re-enter a state, the PetduinoSerial command will actually broadcast a state change event. This is important because what we are going to do is listen for these so that we know once the Petduino is connected, and so we can trigger another action.

The next step is to handle receiving and rendering a number on screen. To receive the number, we’ll make use of a generic event broadcast by PetduinoSerial to allow us to handle arbitrary data values. For this, we need to register a callback to the PetduinoSerials onData action which we do as follows:

#include <LedControl.h>
#include <Petduino.h>

#include <CmdMessenger.h>
#include <PetduinoSerial.h>

#define WAIT_ANIM_FRAMES 4
byte waitAnimF[WAIT_ANIM_FRAMES][8]={
  {0x3c,0x02,0x81,0xc7,0xe3,0x81,0x40,0x3c},
  {0x3c,0x58,0x91,0x81,0x81,0x89,0x1a,0x3c}
};
unsigned long waitAnimD[WAIT_ANIM_FRAMES] = { 1501, 1501 };

unsigned int num;

#define WAIT_STATE 0
#define DATA_STATE 1

PetduinoSerial pet = PetduinoSerial();

void setup() {

  // Setup Petduino
  pet.begin(9600);
  
  // Hookup data callback
  pet.setOnDataCallback(onData);
  
  // Draw the default img
  pet.setState(WAIT_STATE);

}

void loop() {

  // Update pet
  pet.update();
  
  // Update display based on current state
  switch(pet.getState()){

    case WAIT_STATE:
      pet.playAnimation(waitAnimF, waitAnimD, WAIT_ANIM_FRAMES, 3);
      pet.setNextState(WAIT_STATE, 9000); // Wait for connection
      break;
      
    case DATA_STATE:
      //TODO: Display number
      pet.wait();
      break;

  }

}

void onData(char *data) {
  num = atoi(data);
  pet.setState(DATA_STATE);
}

What we have done here is defined an onData function, which accepts a single char array argument, and then registered this with the Petduino in the setup command, by calling pet.setOnDataCallback passing in a reference to our onData function. This effectively tells the Petduino that any time we receive a “data” action notification, call our onData function passing in the data that was bundled with the action payload. In our onData command, we simply convert the value to an integer storing it in a global variable, and then tell the pet to change state to the display state.

Now that we have our number stored, we’ll want to get our display state to actually draw the number to the screen. For this we’ll borrow some code from one of the game examples that comes with Petduino which is usually used to display the final score of the game on screen. Update your sketch as follows:

#include <LedControl.h>
#include <Petduino.h>

#include <CmdMessenger.h>
#include <PetduinoSerial.h>

#define WAIT_ANIM_FRAMES 4
byte waitAnimF[WAIT_ANIM_FRAMES][8]={
  {0x3c,0x02,0x81,0xc7,0xe3,0x81,0x40,0x3c},
  {0x3c,0x58,0x91,0x81,0x81,0x89,0x1a,0x3c}
};
unsigned long waitAnimD[WAIT_ANIM_FRAMES] = { 1501, 1501 };

#define NUMBER_COUNT 10
byte numbers[NUMBER_COUNT][8] = {
  { 0xE0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xE0 },
  { 0x60, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 },
  { 0xE0, 0x20, 0x20, 0xE0, 0x80, 0x80, 0x80, 0xE0 },
  { 0xE0, 0x20, 0x20, 0xE0, 0x20, 0x20, 0x20, 0xE0 },
  { 0xA0, 0xA0, 0xA0, 0xE0, 0x20, 0x20, 0x20, 0x20 },
  { 0xE0, 0x80, 0x80, 0xE0, 0x20, 0x20, 0x20, 0xE0 },
  { 0xE0, 0x80, 0x80, 0xE0, 0xA0, 0xA0, 0xA0, 0xE0 },
  { 0xE0, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 },
  { 0xE0, 0xA0, 0xA0, 0xE0, 0xA0, 0xA0, 0xA0, 0xE0 },
  { 0xE0, 0xA0, 0xA0, 0xE0, 0x20, 0x20, 0x20, 0xE0 }
};

unsigned int num;
unsigned int numOnes;
unsigned int numTens;

#define WAIT_STATE 0
#define DATA_STATE 1

PetduinoSerial pet = PetduinoSerial();

void setup() {

  // Setup Petduino
  pet.begin(9600);
  
  // Hookup data callback
  pet.setOnDataCallback(onData);
  
  // Draw the default img
  pet.setState(WAIT_STATE);

}

void loop() {

  // Update pet
  pet.update();
  
  // Update display based on current state
  switch(pet.getState()){

    case WAIT_STATE:
      pet.playAnimation(waitAnimF, waitAnimD, WAIT_ANIM_FRAMES, 3);
      pet.setNextState(WAIT_STATE, 9000); // Wait for connection
      break;
      
    case DATA_STATE:
      pet.stopAnimation();
      pet.clearScreen();
      
      // Split the number digits
      numTens = num/10;
      numOnes = num-numTens*10;
    
      // Generate & draw number graphic
      for(int b = 0; b < 8; b++){
        pet.drawRow(b, numbers[numTens][b] | numbers[numOnes][b] >> 4);
      }
      
      pet.wait();
      break;
      
  }

}

void onData(char *data) {
  num = atoi(data);
  pet.setState(DATA_STATE);
}

What we have done here is defined a byte array containing graphic information for numbers 0 to 9. Each number will fit on one half of the LED matrix, so will allow us (by generating a merged graphic on the fly) to display any one or two digit number. To do this, we split the number into its component parts, and then use some bit shifting and bitwise operations to merge and render the number graphics to the display. Understanding bit shifting and bitwise operations can be a bit complex, so I won’t go into how this works here, but feel free to google what these do, but for now, all we need to know is that we can now convert a physical number digit, into a graphical representation that we are now rendering to the screen.

With this, our Petduino is now ready for the next step.

To test that everything is setup correctly, we can upload our sketch to the Petduino and open the Arduino IDE’s Serial monitor and issue a serial command manually. The format of the “data” action is 7,n; where n is the number that we want to display, so in the Serial monitor we can type 7,6; which should result in the number 6 being displayed on the Petduino screen. Entering the value 7,12; should update the matrix with the number 12.

 

With that, we are now at an end with our first step. In the next post we’ll setup our Raspberry Pi to connect with our Petduino as well as hook it up to Pubnub and have it proxy our serial commands to the internet, ready for hooking up with NodeRED. Stay tuned.