Weather with LEGO™ MINDSTORMS™ NXT
Ever walked outside and realized that it’s cold and you forgot your jacket?
This robot might be able to help. To demonstrate the power of the WIFI Sensor for LEGO™ MINDSTORMS™ NXT, yesterday we showed you how to share data on the internet. Today, we’re showing you how to get some data.
Google provides weather information for free. If you open your web browser and type in http://www.google.com/ig/api?weather=kabul you can see the weather in Kabul (if you don’t live in Kabul, you can change the location by putting a zip code or city name in place of kabul). The data that comes back in your web browser is XML markup, which is a little hard for humans to read. But easy for robots.
This example program downloads the weather for your location and displays it on the NXT screen.
Possible projects you could use this for:
- A weather alert system: if the temperature drops below a certain level, it alerts you to put a coat on.
- A home monitoring system: monitor the temperature of your home and the outside temperature and post it up on the web with Pachube.
More importantly, this is an example of getting and parsing real-time data from a website. There are many sites that provide data, for free, that you can download and use for your LEGO™ MINDSTORMS™ NXT robot.
Weather is but one example and the RobotC code below can be an example for many other programs.
DIWIFI-Pachube.c
[sourcecode language=”cpp”] // Read Google Weather//
// DIWFI Weather uses the Dexter Industries Wifi Sensor to get the weather
// from Google.com
//
// Run this program with the RobotC Debugging Stream On to view any errors.
// Run AFTER connecting to a Wifi network!
// For more information visit http://www.dexterindustries.com/
//
// This program uses HTTP GET examples to retrieve the weather and
// display the current conditions on the NXT.
//
// See more about the Dexter Industries Wifi Sensor for the Lego Mindstorms NXT here: http://www.dexterindustries.com/wifi.html
//////////////////////////////////////////////////////////////////////////////////////////////////////
#include "drivers/common.h"
#include "DIWIFI-Weather.h"
void weather(string location){
closeAllConns(); // Housekeeping: Close any open connections.
clear_read_buffer(); // Housekeeping: Clear out the buffer.
int CID = 0;
CID = start_TCP_client(); // We start the HTTP client here. Now we’re acting as a client, not a server.
wait10Msec(100);
GetWeather(CID, location); // This kicks off the meat of the project. We’re starting to send a tweet through the connection ID.
read_weather_data(); // Load the weather data into an array so we can deal with it.
print_weather();
}
task main()
{
clear_read_buffer();
string location = "Kabul"; // Enter the name of the city or ZIP Code
// You’re looking for.
while(true) weather(location); // Runs over and over again!
}
DIWIFI-Pachube.h
[sourcecode language=”cpp”]string IP_num = "173.194.73.106"; // Google IP Number
ubyte byteStart[] = {27, ‘S’, ‘0’}; // Begin a Transmission
ubyte byteEnd[] = {27, ‘E’}; // End a transmission
ubyte BytesRead[8]; //
char weather_data[2000]; // Weather Data goes into this array.
int index = 0; // This will be the position index in weather_data
////////////////////////////////////////////////////////////////////////////////////////////////////////
// Clear Read Buffer
// Run this to clear out the reading buffer.
// Simply sends a carriage return, then clears the buffer out.
////////////////////////////////////////////////////////////////////////////////////////////////////////
void clear_read_buffer()
{
ubyte nData[] = {13};
nxtWriteRawHS(nData[0], 1); // Send the carriage return
wait10Msec(100);
while(BytesRead[0] < 0){
nxtReadRawHS(BytesRead[0], 1); // Read the response. Probably an error.
}
wait10Msec(100);
}
// This function writes a string to the DebugStream and Port4
// We wrote this out because it is easier to recognize and see
// strings; easier than working with arrays of characters.
void writeStr(string sData)
{
ubyte byteData = 0;
for(int i = 0; i < strlen(sData); i++)
{
byteData = strIndex(sData, i);
nxtWriteRawHS(byteData, 1);
writeDebugStream("%c", byteData); // Critical for debugging. Make sure you’re getting some time in there
// to read what you wrote.
while(nxtHS_Status == HS_SENDING) wait1Msec(1);
wait1Msec(1); // With
}
}
//
// This function just writes a line break to DebugStream and Port4.
// It is necessary to have this in RobotC because strings are limited to 17 characters
// and sometimes you will need to send commands longer than 17 characters.
void writeLineBreak()
{
writeDebugStream("%c", 13);
ubyte newline = 0x0D;
nxtWriteRawHS(newline, 1);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
// Send Carriage Return, New Line
// This is used in the HTTP request
////////////////////////////////////////////////////////////////////////////////////////////////////////
void crln()
{
writeDebugStream("%c", 13);
writeDebugStream("%c", 10); // Display this on the debug for our information.
ubyte newline[] = {0x0D, 0x0A}; // Carriage return and then line feed.
nxtWriteRawHS(newline, 2);
wait1Msec(5); // ABSOLUTELY CRITICAL. We added this because
// we found that in line-feeds, the first bytes of the next transmission get
// dropped. VERY IMPORTANT TO HAVE THIS DELAY IN HERE.
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
// Receive Bytes
// Reads whatever is in the buffer and prints to debug
////////////////////////////////////////////////////////////////////////////////////////////////////////
void Receive(bool wait=false)
{
if (wait)
while (nxtGetAvailHSBytes() == 0) wait1Msec(5);
while (nxtGetAvailHSBytes() > 0) {
nxtReadRawHS(BytesRead[0], 1);
writeDebugStream("%c", BytesRead[0]);
wait1Msec(1);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
// Housekeeping: Close down the Connections
////////////////////////////////////////////////////////////////////////////////////////////////////////
void closeAllConns() {
writeDebugStreamLine("closeAllCons");
clear_read_buffer();
writeStr("at+ncloseall");
writeLineBreak();
wait10Msec(10);
Receive(true);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
// Connect to google via TCP.
// Open up a client connection with the Google Server.
////////////////////////////////////////////////////////////////////////////////////////////////////////
int start_TCP_client() {
int CID = 0;
bool connected = false; // This will tell us if we’re connected or not.
string port = ",80";
while(!connected){ // Do this over and over again until we get a connection.
writeStr("AT+NCTCP=");
writeStr(IP_num);
writeStr(port);
writeLineBreak();
// Don’t replace the following code with a Receive function.
// This code picks out the CID number.
while (nxtGetAvailHSBytes() == 0) wait1Msec(5);
while (nxtGetAvailHSBytes() > 0) {
nxtReadRawHS(BytesRead[0], 1);
writeDebugStream("%c", BytesRead[0]);
if(BytesRead[0] < 58 && BytesRead[0] > 47){ // So if it’s a number . . .
CID = BytesRead[0]-48; // Works for connections 0 through 9.
connected = true;
}
wait1Msec(2);
}
}
return CID;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
// Send information to Google to get weather.
////////////////////////////////////////////////////////////////////////////////////////////////////////
void GetWeather(int CID, string location) {
wait1Msec(1000);
nxtWriteRawHS(byteStart, 3);
writeDebugStream("%c", byteStart, 2);
writeDebugStreamLine("%c", (CID+48));
wait1Msec(200);
writeStr("GET /ig/api?");
writeStr("weather=");
writeStr(location);
writeStr(" HTTP/1.1");
crln();
writeStr("User-Agent: ");
writeStr("DIWifi");
crln();
writeStr("Host: ");
writeStr("www.google.com");
crln();
crln();
wait1Msec(10);
nxtWriteRawHS(byteEnd, 2);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
// Utility: Load up a response into a large array.
////////////////////////////////////////////////////////////////////////////////////////////////////////
void Receive2Array(bool wait=false)
{
if (wait)
while (nxtGetAvailHSBytes() == 0) wait1Msec(5);
while (nxtGetAvailHSBytes() > 0) {
nxtReadRawHS(BytesRead[0], 1);
writeDebugStream("%c", BytesRead[0]);
weather_data[index] = BytesRead[0];
index++;
wait1Msec(1);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
// Read the weather data from Port4.
// Put it into weather_data[].
////////////////////////////////////////////////////////////////////////////////////////////////////////
void read_weather_data(){
/*
int i = 1;
// wait1Msec(1000);
while (nxtGetAvailHSBytes() > 0) {
nxtReadRawHS(BytesRead[0], 1);
weather_data[i] = BytesRead[0];
i++;
writeDebugStream("%c", BytesRead[0]);
wait1Msec(1);
}
while(nxtGetAvailHSBytes() == 0) wait1Msec(1);
// writeDebugStreamLine("%i", nxtGetAvailHSBytes());
while (nxtGetAvailHSBytes() > 0) {
nxtReadRawHS(weather_data[i], 1);
i++;
// writeDebugStream("%c", weather_data[i]);
wait1Msec(2);
// if(((weather_data[i] == 27) && (weather_data[i-1] == 69))) break;
}
*/
/*wait1Msec(1000);
while (nxtGetAvailHSBytes() > 0) {
nxtReadRawHS(weather_data[i], 1);
i++;
// writeDebugStream("%c", weather_data[i]);
wait1Msec(2);
}
*/
while(true){
Receive2Array(true);
if(weather_data[index-1] == 69 && weather_data[index-2] == 27) break; // This looks for the <ESC> E Sequence that signals the end of a transmission.
//writeDebugStreamLine("%i", index);
//writeDebugStreamLine("");
}
/*
writeDebugStreamLine("PRINT WEATHER");
writeDebugStreamLine("PRINT WEATHER");
int j = 0;
while(j < index){
writeDebugStream("%c", weather_data[j]);
j++;
}
*/
// return(true);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
// Find the the position of the string.
// Returns the postion in the weather_data
// array of the string of characters we’re looking for
////////////////////////////////////////////////////////////////////////////////////////////////////////
int find_string_posn(string stringIN, int start_posn){
for(int i = start_posn; i < (sizeof(weather_data)-20); i++){
if(weather_data[i] == 0) break;
byte array_holder[20];
memset(array_holder, 0, 20);
// Load up an array subsection of weather.
for(int j = 0; j< (strlen(stringIN)); j++){
array_holder[j] = weather_data[j+i];
}
string posn;
StringFromChars(posn, array_holder);
if(strcmp(posn, stringIN) == 0){
return i;
}
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
// Find the incoming string, pring it on the particular line.
// Print also on the Debug screen.
////////////////////////////////////////////////////////////////////////////////////////////////////////
void find_and_print(string findme, string Header, int DispLine){
int start_posn = find_string_posn(findme, 0);
string findend = "/";
int end_posn = find_string_posn(findend, start_posn);
start_posn = start_posn+strlen(findme)+1; // Points to the beggining of the string
end_posn = end_posn-1; // Points to the end of the string.
int strLength = end_posn-start_posn; // Length of the string we’re looking for.
byte condition[20];
memset(condition, 0, sizeof(condition));
if(strLength > 0){
for(int i=0; i < strLength; i++){
condition[i] = weather_data[start_posn+i];
}
string strCond;
StringFromChars(strCond, condition);
writeDebugStream(Header);
writeDebugStreamLine(strCond);
string combined = Header+strCond;
nxtDisplayString(DispLine, combined);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
// Print the weather.
////////////////////////////////////////////////////////////////////////////////////////////////////////
void print_weather(){
find_and_print("condition data=", "Condition: ", 1); // General Conditions
find_and_print("temp_f data=", "Temp (f): ", 2); // Temp in F
find_and_print("temp_c data=", "Temp (c): ", 3); // Temp in C
find_and_print("_condition data=", "", 4); // WIND!
index = 0; // Reset the count so we can do this over and over again.
memset(weather_data, 0, sizeof(weather_data)); // Reset the array to zeros. Good housekeeping.
}
[/sourcecode]
0 Comments
Leave a reply
You must be logged in to post a comment.