Thursday, 9 August 2012

Twitr_janus is now speaking data sent from published google spreadsheet (via RSS feed to Processing)

Twitr_janus' brain can detect more data

I have finally managed to work out how to get Processing to respond to data live from a Google spreadsheet. The effect of this is that I can send separate multiple packets of data to Twitr_janus from a single source, to control multiple functions.

This is a significant development, as data can now be sent for different functions such as text to be spoken or positioning information for eyes, or other body movements.

I have made a successful test of sending 3 packets at once to the latest version of the Processing sketch (Twitr_janus' brain), which it can decode. These were:
  • A number that could be sent by Processing to the Arduino, to tell it how to position a control servo for an up/down eyeball movement 
  • A similar number that could be sent by Processing to the Arduino, to tell it how to position a control servo for an left/right eyeball movement 
  • A text string that was successfully received and converted to speech. 
Here is Twitr_janus's current voice, speaking data sent from a Google spreadsheet

download: mp3
"This is Twitr_janus speaking thoughts from a google spreadsheet"

download: mp3
This method of getting data from my master means I can speak much longer lines, and not worry about stop characters

download: mp3
"Oh yes! and the sending of other data from the same google spreadsheet works. This means my eyeballs could be made to move."

How Processing gets the data from a remote Google spreadsheet via RSS

Setting up the spreadsheet

A Google spreadsheet was set up to hold the test data. This had three data fields for ENTERING data:

  • eyeballUpDown (the field name says it all really) - data in A2 in the spreadsheet
  • eyeballLeftRight - data in B2 in the spreadsheet
  • text (this is the piece of text used to make Twitr_janus talk -  data in  C2 in the spreadsheet
It also had three corresponding for SENDING the data:
  • eyeballUpDown_stop (the same field name with _stop appended) -  data in E2 in the spreadsheet
  • eyeballLeftRight_stop -  data in  F2 in the spreadsheet
  • text _stop (this is the piece of text used to make Twitr_janus talk -  data in G2 in the spreadsheet
The difference between them the data in the entry cells A2-C2 and that in the sending cells E2-G2 by prefixing a control character to the contents of each field. The character is the same for each, and is based on the contents of field D2.

This character was there to be used by Processing to know where to parse the data in the RSS feed. The character can be any SINGLE character, but it must be something that is not going to to be present in the RSS feed output or in normal speech.
In this case the following character has been used: ¬ 

Making the spreadsheet publish to the web automatically and obtaining the RSS url

From the file menu, choose the "Publish to the Web" option. This make the data public as read only. You can still edit the original sheet and control share rights for edit, but the data is now available to use.
The checkbox must be checked for "Automatically republish when changes are made". This will force the RSS feed to refresh when you type in new data.

You then need to get the url for the RSS feed. Select RSS from the "Get a link to the published data" option, and copy the url.

What the RSS data looks like

The output of the RSS feed will be read as a string that looks like this:

How Processing extracts the data from the RSS feed

(You can download the entire Processing sketch for this particular version Twitr_janus  on Github:

The Processing sketch uses a function called getGssData (). Here it is, with some notes about the data extraction using parsing. I have not explained the rest of the function, nor the variable initialisations.

void getGssData ()
  // uses Google SpreadSheets API to get public tweets from twitr_janus_eyeballs published spreadsheet
gssTextCheck = gssText;

  println ("@@@");
  println ("[Start Inside printGSS]");
  println ();

  String [] texty = loadStrings(gssApiString);
The line above is using the Processing function 'loadStrings'. 'gssApiString' has been initialised earlier with the RSS feed URL (
and loading the raw XML output as a string into an array (texty[])

  String [] texty2 = split (texty[0], '¬'); //  pulling out data with stop character
The line above is using the Processing function 'split' to break down the feed text based upon the special stop character '¬'. It is creating an array (texty2[]) which will have 5 values in it, because the feed has four of these characters in it, which are splitting the feed string into 5 sections.

The values are:
  • texty2[0] = contents of everything before the '¬' in cell D2
  • texty2[1] = contents of everything after that and before the '¬' in cell E2
  • texty2[2] = contents of everything after that and before the '¬' in cell  F2
  • texty2[3] =  contents of everything after that and before the '¬' in cell  G2
  • texty2[4] =  contents of everything after the '¬' in cell G2

  String [] texty3 = split (texty2[4], '<'); // get rid of trailing text after <
The line above finally gets  texty2[4] (= the contents of everything after the '¬' in cell G2) and splits it based on the '<' tag in XML, which is the character that follow the contents of G2. This leaves the text from cell G2 which is set as the variable gssText in the line below:
  gssText = texty3[0];

  gssTextLength= gssText.length();

The lines below do a similar thing to extract the contents out of E2
  // @@@@@@@@@@@@@@@@
  String [] texty4 = split (texty2[2], ',');
  gssEyeballUpDown = int (texty4 [0]);
  print ("gssEyeballUpDown = ");
  println (gssEyeballUpDown);
  println ();
Finally the lines below do a similar thing to extract the contents out of F2
  // @@@@@@@@@@@@@@@@
  String [] texty5 = split (texty2[3],',');
  gssEyeballLeftRight = int (texty5 [0]);
  print ("gssEyeballLeftRight = ");
  println (gssEyeballLeftRight);
  println ();
  // @@@@@@@@@@@@@@@@
  //print ("texty= ");
  //println (texty);
  println ();
  //print ("texty2[2]= ");
  //println (texty2[2]);
  println ();
  //print ("texty2[3]= ");
  //println (texty2[3]);
  println ();
  print ("gssText = ");
  println (gssText);
  println ();
  println ();
   // following lines return the contents of tweet check (last new tweet)

  println ("[End Inside getGSS]");
  println ("@@@");
  println ();

  if (gssText.equals(gssTextCheck)==false)
    println ("inside GSS checking IF");
    print (gssText);
    println ("");
    print (gssTextCheck);
    println ("@");

Advantages of using Google spreadsheets to send data

Although this is a similar method as having Twitr_janus listen for tweets, using a spreadsheet has advantages, mainly because there is much more control over the RSS feed format than there is the Twitter API. This means:
  • Several fields of data can be changed in a spreadsheet simultaneously, by using multi-cell cut and paste. So if the left/right and up/down position of eyeballs needed to be changed simultaneously, this could be done in one paste action.
  • By prefixing the data in control fields with an unusual stop character, the Processing command that is parsing the text, will not get confused by common punctuation used in tweets. Notably commas and "quote marks", are used by the Twitter API as field delimiters, and these cause parsing issues truncating the message unexpectedly. The Google method eliminates this.
  • The maximum number of calls in a set time to Google spreadsheet RSS feeds appears to be much higher than Twitter's API. This allows Twitr_janus's brain to check much more frequently (an improvement from about every 28 seconds maximum with Twitter API, to every 5 seconds or faster with the Google feed) 
  • It is probably possible to write a javascript gadget that will write to Google spreadsheet cells in a more interactive way (such as an onscreen slider that writes values to the cells)
This took a lot of coffee and about 7 hours of brainache...

Download this version of Twitr_janus Processing sketch on Github:

No comments:

Post a Comment