I am using a Zaber linear stage controlled by an Arduino using the Zaber shield. I try to do something similar to this question (Track position of a Zaber device as it moves), but using the Arduino language instead of Labview.
In the answer 3 options were provided: interpolate from the start and end points, poll the position using a timer, or turn on a device mode that reports the position every 250 ms.
The device mode does not seem to exist for my stage (X-LSQ-075B-E01) and I don't want to rely on interpolation. The stage is fitted with an encoder and I can easily get its readback for the exact position; I just don't know how to poll the stage while moving. I came up with the following code (a bit simplified), but it is relatively slow and only gives the readback from 1 stage (we are actually using 2) and sending the command to both does not really work.
#include <ZaberAscii.h>
ZaberShield shield(ZABERSHIELD_ADDRESS_AA);
ZaberAscii za(shield);
void setup() {
shield.begin(115200);
Serial.begin(115200);
za.send(1, 1, "move rel", 20000);
za.receive();
while (za.isIdle(1) == false) {
za.send(1, "get encoder.pos");
ZaberAscii::reply reply = za.receive();
if (!reply.isReply) {
Serial.println("*** Received a non-reply message from device " + String(reply.deviceNumber) + ".");
}
else if (reply.isRejected) {
Serial.println("*** A command was rejected by device " + String(reply.deviceNumber) + ".");
}
else {
Serial.println( String(reply.deviceNumber) + ": " + String(reply.responseData));
}
delay(5);
}
za.pollUntilIdle(1);
Serial.println("1 finished");
za.send(2, 1, "move rel", 20000);
while (za.isIdle(2) == false) {
za.send(2, "get encoder.pos");
Serial.println("Device 2 not idle");
ZaberAscii::reply reply = za.receive();
if (!reply.isReply) {
Serial.println("*** Received a non-reply message from device " + String(reply.deviceNumber) + ".");
}
else if (reply.isRejected) {
Serial.println("*** A command was rejected by device " + String(reply.deviceNumber) + ".");
}
else {
Serial.println( String(reply.deviceNumber) + ": " + String(reply.responseData));
}
//delay(10);
}
Serial.println("2 finished");
}
void loop() {}
To have it work on both devices, you would need to send both movement commands before starting the while loop, and then for the while loop you would want the condition to repeat until both axes are idle. Within the while loop you would read the position of both axes.
On the timing, can you say approximately what frequency you're getting now? The timing per communication is typically about 5-10ms. With the current functions, the isIdle() call takes it's own command, so I'd expect the above loop to be about 20-40ms. You could cut it in half by pulling the .IsBusy information from the 'get encoder.pos' reply.
Mike McDonald
mike#zaber.com
Related
Im trying to send inputs to Arduino MEGA using the monitor. Ive noticed that 1/6 times, the Serial skips 1 or more letters in my input. Ive tried Serial.read() and Serial.readStringUntil() but both skip input. I tried putting delay after the Serial.read() but it does nothing. I also tried doing a Serial.flush in the if(complete){...} code block but to no avail.
In this picture, "A**" was sent correctly (Ive noticed it always has as it is the 1st monitor input). But subsequent commands like the "s**100" was sent as "s*0". Is there misuse of the Serial class here? Is there a misconfiguration maybe in using the Serial monitor? (No line ending). Could it be that using other custom classes interfere with the Serial even if it didnt explicitly interact with it?
//===========================================THE IMPORTANT PART===============================================
void loop() {
digitalWrite(13, HIGH);
while (Serial.available()){
String temp = Serial.readStringUntil(';');
Serial.println(temp);
command = temp.substring(0,3);
param = temp.substring(3).toInt();
complete = true;
Serial.println("temp "+temp);
Serial.println("comm "+command);
Serial.println("para "+command);
}
//=============================================================================================================
if(complete){
Serial.println("complete");
if(command == MODE_SOLID || command == MODE_GRADIENT || command == MODE_OFF){
current_mode = command;
}
else if(command == COMMAND_BRIGHTNESS){
current_brightness = param;
}
else if(command == COMMAND_SATURATION){
current_saturation = param;
}
else if(command == COMMAND_COLOR){
current_color = param;
}
else if(command == COMMAND_RANDOM_BRIGHTNESS_UPPERLIMIT){
current_random_brightness_upper_limit = param;
}
else if(command == COMMAND_RANDOM_BRIGHTNESS_LOWERLIMIT){
current_random_brightness_lower_limit = param;
}
else if(command == COMMAND_RANDOM_SATURATION_UPPERLIMIT){
current_random_saturation_upper_limit = param;
}
else if(command == COMMAND_RANDOM_SATURATION_LOWERLIMIT){
current_random_saturation_lower_limit = param;
}
else if(command == COMMAND_RANDOM_COLOR_UPPERLIMIT){
current_random_color_upper_limit = param;
}
else if(command == COMMAND_RANDOM_COLOR_LOWERLIMIT){
current_random_color_lower_limit = param;
}
else if(command == COMMAND_COLOR){
current_color = param;
}
complete = false;
command = "";
param = 0;
}
if(current_mode == MODE_SOLID){
solid.setBrightness(current_brightness);
solid.setSaturation(current_saturation);
solid.setColor(current_color);
solid.runPattern();
}
else if(current_mode == MODE_GRADIENT){
blinkSolid.setCurrentRandomBrightnessLowerLimit(current_random_brightness_lower_limit);
blinkSolid.setCurrentRandomBrightnessUpperLimit(current_random_brightness_upper_limit);
blinkSolid.setCurrentRandomSaturationLowerLimit(current_random_saturation_lower_limit);
blinkSolid.setCurrentRandomSaturationUpperLimit(current_random_saturation_upper_limit);
blinkSolid.setCurrentRandomColorLowerLimit(current_random_color_lower_limit);
blinkSolid.setCurrentRandomColorUpperLimit(current_random_color_upper_limit);
blinkSolid.runPattern();
}
else if(current_mode == MODE_OFF){
strobePalette.runPattern();
//fill_solid( leds, NUM_LEDS, CRGB::Black);
//FastLED.show();
}
}
I've experienced similar issues with physical devices, most of the times in harsh environments or using defective wiring.
I tested your code using tinkercad with an Arduino Uno, only the communication part. This is the code I tested:
bool complete;
String command;
int param;
void setup()
{
Serial.begin(9600);
}
void loop()
{
digitalWrite(13, HIGH);
while (Serial.available()){
String temp = Serial.readStringUntil(';');
Serial.println(temp);
command = temp.substring(0,3);
param = temp.substring(3).toInt();
complete = true;
Serial.println("temp "+temp);
Serial.println("comm "+command);
Serial.println("para "+ String(param)); //I changed this line in order to see the value of "param" in the serial monitor
}
if(complete){
Serial.println("complete");
complete=false;
command="";
param=0;
}
}
I tested the code sending the string A**100;B**101;C**102;D**103; all of the parts arrived ok and they were well decoded. This is the TinkerCad output:
A**100
temp A**100
comm A**
para 100
B**101
temp B**101
comm B**
para 100
C**102
temp C**102
comm C**
para 100
D**103
temp D**103
comm D**
para 100
I also tested the code using a physical Arduino uno, and It worked as well as in Tinkercad. This is what I would do:
Let the code only with the communication part, as I did, and see how it behaves. If your code behaves ok only with the communication part, then you have something interfering in the rest of the code. It is hard to tell what could be without knowing the code of the custom clases.
If you are connecting a physical arduino to the usb port of PC, change that cable. Some defective cables may work weird and cause that kind of issues.
If you will be installing your device in a harsh environment, try to make your code resistant to those kind of errors, it is most likely that they will be present anyway. In such scenarios, I have used a starting character, an ending character and a fixed length, something like #A**100;#B**101; where # is the starting character, the semicolon (;) is the ending character, and all the commands are eight characters long. I discard all of the commands that does not fulfill those params. Using CRC is another option, but in most cases it is enough with the simple pattern I just described.
I have a processing sketch which needs to set up 2 connections with USB devices. I cannot tell in advance which device is USB0 and which is USB1. (not that I am aware off atleast)
One of the devices awnsers with hello the other one does not answer at all. Therefor I have written code with a simple timeout. In the setup I check continously if there are bytes to read. But both a while and an if statement yield incorrect results
while( dccCentral.available() < 5 ) {
if( dccCentral.available() >= 5) break;
if(millis() > 5000 ) {
println("timeout occured");
println(dccCentral.available());
break;
}
}
These lines are in setup. The text "timeout occured" is always printed. Underneath it, the result of dccCentral.available() is printed. This number is 12 which is correct.
regardless, if dccCentral.available() prints 12 at that time. The first if-statement:
if( dccCentral.available() >= 5) break;
should already have break'ed out of the while loop before this time-out should occur. The while-loop itself should also quit itself when 5 or more bytes are received.
Why do both these lines
while( dccCentral.available() < 5 ) {
if( dccCentral.available() >= 5) break;
fail?
Personally I try to avoid while loops unless there isn't another way (e.g. inside a thread) and that is avoid both logic pitfalls and messing with the lifecycle of other objects that might need a bit of time to initialise.
If you send strings from Arduino and also use println() you could init the port to easily catch that using Serial's bufferUntil() in conjuction with serialEvent() to finally readString().
Once you start getting data in, you could:
use references to the serial ports you're after and a couple of extra ones until you know which port is which
use a boolean "toggle" to only handle the "hello" once
if the hello was received, you can use the serialEvent() Serial argument to assign dccCentral and by process of elimination assign the other port
Here's a commented sketch to illustrate the idea:
import processing.serial.*;
// be sure to set this to the baud rate your device use with Arduino as well
final int BAUD_RATE = 115200;
// reference to Serial port sending "Hello" (when that get's detected)
Serial dccCentral;
// reference to the other Serial port
Serial otherDevice;
// temporary references
Serial usb0;
Serial usb1;
// 'toggle' to keep track where the hello was received and handled or not (by default initialised as false)
boolean wasHelloReceived;
void setup(){
usb0 = initSerial("/dev/ttyUSB0", BAUD_RATE);
usb1 = initSerial("/dev/ttyUSB1", BAUD_RATE);
}
Serial initSerial(String portName, int baudRate){
Serial port = null;
try{
port = new Serial(this, portName, baudRate);
// if sending strings and using println() from Arduino
// you can buffer all chars until the new line ('\n') character is found
port.bufferUntil('\n');
}catch(Exception e){
println("error initialising port: " + portName);
println("double check name, cable connections and close other software using the same port");
e.printStackTrace();
}
return port;
}
void draw(){
background(0);
text("wasHelloReceived: " + wasHelloReceived + "\n"
+"dccCentral: " + dccCentral + "\n"
+"otherDevice: " + otherDevice , 10 ,15);
// do something with the devices once they're ready (e.g. send a message every 3 seconds)
if(millis() % 3000 == 0){
if(dccCentral != null){
dccCentral.write("ping\n");
}
if(otherDevice != null){
otherDevice.write("pong\n");
}
}
}
void serialEvent(Serial port){
try{
String serialString = port.readString();
// if the received string is not null, nor empty
if(serialString != null && !serialString.isEmpty()){
// for debugging purposes display the data received
println("received from serial: " + serialString);
// trim any white space
serialString = serialString.trim();
// check if "hello" was received
if(serialString.equals("hello")){
println("hello detected!");
// if the dccCEntral (hello sending) serial port wasn't assigned yet, assign it
// think of this as debouncing a button: setting the port once "hello" was received should happen only once
if(!wasHelloReceived){
// now what dccCentral is found, assign it to the named reference
dccCentral = port;
// by process elimiation, assign the other port
// (e.g. if dccCentral == usb0, then other is usb1 and vice versa)
otherDevice = (dccCentral == usb0 ? usb1 : usb0);
/*
the above is the same as
if(dccCentral == usb0){
otherDevice = usb1;
}else{
otherDevice = usb0;
}
*/
wasHelloReceived = true;
}
}
}
}catch(Exception e){
println("error processing serial data");
e.printStackTrace();
}
}
Note the above code hasn't been tested so it may include syntax errors, but hopefully the point gets across.
I can't help notice that USB0/USB1 are how serial devices sometimes show up on Linux.
If you're working with a Raspberry Pi I can recommend a slightly easier way if you're comfortable with Python. The PySerial has a few tricks up it's sleeve:
You can simply call: python -m serial.tools.list_ports -v which will list ports with extra information such as serial number of the serial converter chipset. This could be useful to tell which device is which, regardless of the manufacturer and USB port used
Other than the serial port name/location, it supports multiple ways (URLs) of accessing the port with a very clever: hwgrep:// will allow you to filter a device by it's unique serial number
Here's a basic list_ports -v output for two devices with the same chipset:
column 1
/dev/ttyUSB9
desc: TTL232R-3V3
hwid: USB VID:PID=0403:6001 SER=FT94O21P LOCATION=1-2.2
column 2
/dev/ttyUSB8
desc: TTL232R-3V3
hwid: USB VID:PID=0403:6001 SER=FT94MKCI LOCATION=1-2.1.4
To assign the devices using serial you would use something like:
"hwgrep://FT94O21P"
"hwgrep://FT94MKCI"
Update
It might help to step by step debug the system and try one port a time.
The idea is to get the bit of code reading the expected serial string tight.
Here's a basic example that should simply accumulate one char at a time into a string and display it:
import processing.serial.*;
Serial port;
String fromSerial = "";
void setup(){
size(300,300);
port = initSerial("/dev/ttyUSB0", 115200);
}
Serial initSerial(String portName, int baudRate){
Serial port = null;
try{
port = new Serial(this, portName, baudRate);
// if sending strings and using println() from Arduino
// you can buffer all chars until the new line ('\n') character is found
port.bufferUntil('\n');
}catch(Exception e){
println("error initialising port: " + portName);
println("double check name, cable connections and close other software using the same port");
e.printStackTrace();
}
return port;
}
void draw(){
if(port != null){
if(port.available() > 0){
char inChar = port.readChar();
fromSerial += inChar;
if(inChar == '\n'){
println("newline encountered");
println(fromSerial.split("\n"));
}
}
}
background(0);
text("from serial:" + fromSerial, 10,15);
}
If the data from dccCentral comes in a expected: great, the code can be simplfied and right conditions applied to filter the device in the future,
otherwise it should help pin point communication issues getting the "hello" in the first place (which would be 6 bytes ("hello"(5) + '\n') if sent with Serial.println() from Arduino)
Regarding Python, no problem at all. Should the idea help in the future you can check out this answer. (AFAIK Processing Serial uses JSSC behind the scenes)
I have an arduino uno with wifi shield and I want it to be able to go to source of signal.
The rssi that I get is usually -80 dBm above -40 dBm I assume the robot has found the source.
So the robot goes straight and checks every 2 seconds the rssi if the new signal is worse than it was before it turns 90 degrees right and goes straight and keeps doing that until it finds the source.
Void loop() is the logic of the robot.
int angle = 90;
char ssid[]="AndroidAP";
bool sourceFound = false;
long rssi = -100;
long prevRssi = 0;
void setup() {
Serial.begin(9600);
updateRSSI();
servoLeft.attach(8);
servoRight.attach(9);
goStraight();
}
void loop() {
if(!sourceFound){
updateRSSI();
if(prevRssi>rssi){
turnRight();
goStraight();
delay(2500);
}
if(rssi>-41){
stayStill();
detachServos();
sourceFound = true;
Serial.print("Source found.");
Serial.println();
}
}
}
/*MOVEMENT CONTROLS*/
void turnLeft(){
servoLeft.writeMicroseconds(1300);
servoRight.writeMicroseconds(1300);
delay(angle*10.6);
}
void turnRight(){
servoLeft.writeMicroseconds(1700);
servoRight.writeMicroseconds(1700);
delay(angle*10.6);
}
void turnAround(){
if((double)rand() / (double)RAND_MAX==0){
turnLeft();
turnLeft();
}else{
turnRight();
turnRight();
}
}
void stayStill(){
servoLeft.writeMicroseconds(1500);
servoRight.writeMicroseconds(1500);
}
void goStraight(){
servoLeft.writeMicroseconds(1600);
servoRight.writeMicroseconds(1444 );
}
void detachServos(){
servoLeft.detach();
servoRight.detach();
}
/*MOVEMENT CONTROLS*/
/*WIFI SHIELD CONTROLS*/
void updateRSSI(){
prevRssi = rssi;
uint8_t available_networks = WiFi.scanNetworks();
for (uint8_t net = 0; net < available_networks; ++net)
{
if (strcmp(WiFi.SSID(net), ssid) == 0)
{
// ssidFound = true;
rssi = WiFi.RSSI(net);
if(rssi-prevRssi<-10){ //disregard the measurement and try again
rssi = prevRssi;
updateRSSI();
}
Serial.print("Old: ");
Serial.print(prevRssi);
Serial.print(" dBm ");
Serial.print("New: ");
Serial.print(rssi);
Serial.print(" dBm");
Serial.println();
break;
}
}
}
The problem is that the signal varies a lot which will cause robot sometimes to turn right even when it's pretty close to the source and always going right is not the most effective way of getting to router it is quite random. Is there an easier way or more efficient way to find and get to the source?
Basically your robot is doing the localization part of a common task called "wardriving" (sounds illegal but it's not). I was recently doing some research in pretty much exactly what you were doing although some papers found that essentially the signal strength of WiFi stations is to weak and inconsistent for use.
Dartmouth study (Page 14) This study found that using typical war driving methods they were only able to detect between 40 and 60 % of all WiFi nodes and on average was around 30-40m of error from the actual transmitter.
Another study (Page 4) Here you have a plot of 3 base stations being sampled for signal strength at a constant distance away. You will notice a bell curve which looks to have a standard deviation of at least 5 (sadly no table for the data). However that does pretty clearly show how noisy of a signal you should expect.
I'm not saying that your goal is impossible I am saying however you will need to do a lot of filtering and move very slowly (something my project could not do). Contrary to instincts WiFi signal strength is incredibly noisy making accurate wardriving difficult without an extremely large data set. Hope having these papers at least helps curve your expectations.
Here's the big picture:
I'm trying to control a stepper motor by recording a set of positions and then playing them back. To control the steppers I am using AccelStepper.
Since the movement data is large I need to store it on my Mac and send it over to the Arduino using the Serial connection.
Also, I can't afford delays because of the way AccelStepper works.
Here's the issue:
The code below works when I insert a delay of about 60ms or more. However, this screws up AccelStepper.
My understanding of this is that the first while loop "listens" to the serial line. If there is nothing to read, I send an 'A' to the Mac to request some data. This loop breaks when there is data available to read.
The second loop reads the serial line until encountering a newline character. This code works with the delay and does not without a delay.
Does that make sense?
Thank-you.
================================
if (stepper.distanceToGo() == 0)
{
while (Serial.available() <= 0) { // Ask Mac for more data.
Serial.print("A");
delay(60); // Argh line!
stepper.runSpeedToPosition();
}
while(Serial.available() > 0) { // There's info on the serial line
character = Serial.read();
content.concat(character);
if (character == '\n') break; // Keep reading until newline
stepper.runSpeedToPosition();
}
Without delay, the while loop will take "all" your system (CPU) resources, actually delaying the interrupt from the serial line. The 60 is very specific value though.
So an option is to rewrite the loop and test if this helps:
if (stepper.distanceToGo() == 0) {
while (true) {
if(Serial.available() <= 0) { // Ask Mac for more data.
Serial.print("A");
stepper.runSpeedToPosition();
} else {
// the case for (Serial.available() > 0) There's info on the serial line
character = Serial.read();
content.concat(character);
if (character == '\n') break; // Keep reading until newline
stepper.runSpeedToPosition();
}
}
}
So I am using Temboo after recently acquiring a Arduino Yun, however I am having an issue with getting and posting data by combining Choreos.
I am using the Yahoo GetWeatherByAddress Choreo and trying to post the individual values I want to a Xively Feed. I am using the Xively Write Choreo and inputting FeedData in JSON format.
So far I have had some success with posting 2 values (humidity and pressure) at a time. Unfortunately I want to use more than this and have Humidity, Temperature, WeatherConditions(Fair, Windy etc) and a LDR reading from a breadboard. So It loops every 10 seconds, reads all those values and then posts them to Xively. The Temperature value seems to have an issue with even printing to Serial Monitor if I have any more than the Temperature value uncommented. It also doesn't go through with the whole process (returning Http 200 for success) It posts the values and the just goes straight to "waiting" for the next set of values to be retrieved. Where am I going wrong here?
/*
YahooWeather
This example code is in the public domain.
*/
#include <Bridge.h>
#include <Temboo.h>
#include "TembooAccount.h" // contains Temboo account information
// the address for which a weather forecast will be retrieved
String ADDRESS_FOR_FORECAST = "Plymouth, United Kingdom";
int numRuns = 1; // execution count, so that this doesn't run forever
int maxRuns = 10; // max number of times the Yahoo WeatherByAddress Choreo should be run
String pData;
String qData;
String rData;
String tData;
String cData;
void setup() {
Serial.begin(9600);
// for debugging, wait until a serial console is connected
delay(4000);
while(!Serial);
Bridge.begin();
pinMode(A0, INPUT);
pinMode(13, OUTPUT);
}
void loop()
{
if (numRuns <= maxRuns) {
int sensorValue = analogRead(A0);
if (sensorValue < 100) {
digitalWrite(13,HIGH);
delay(1000);
digitalWrite(13,LOW);
}
// while we haven't reached the max number of runs...
Serial.println("Sensor value: " + String(sensorValue)); }
TembooChoreo WriteDataChoreo;
// Invoke the Temboo client
WriteDataChoreo.begin();
// Set Temboo account credentials
WriteDataChoreo.setAccountName(TEMBOO_ACCOUNT);
WriteDataChoreo.setAppKeyName(TEMBOO_APP_KEY_NAME);
WriteDataChoreo.setAppKey(TEMBOO_APP_KEY);
// print status
Serial.println("Running GetWeatherByAddress - Run #" + String(numRuns++) + "...");
// create a TembooChoreo object to send a Choreo request to Temboo
TembooChoreo GetWeatherByAddressChoreo;
// invoke the Temboo client
GetWeatherByAddressChoreo.begin();
// add your temboo account info
GetWeatherByAddressChoreo.setAccountName(TEMBOO_ACCOUNT);
GetWeatherByAddressChoreo.setAppKeyName(TEMBOO_APP_KEY_NAME);
GetWeatherByAddressChoreo.setAppKey(TEMBOO_APP_KEY);
// set the name of the choreo we want to run
GetWeatherByAddressChoreo.setChoreo("/Library/Yahoo/Weather/GetWeatherByAddress");
// set choreo inputs; in this case, the address for which to retrieve weather data
// the Temboo client provides standardized calls to 100+ cloud APIs
GetWeatherByAddressChoreo.addInput("Address", ADDRESS_FOR_FORECAST);
// add an output filter to extract the name of the city.
GetWeatherByAddressChoreo.addOutputFilter("pressure", "/rss/channel/yweather:atmosphere/#pressure", "Response");
GetWeatherByAddressChoreo.addOutputFilter("humidity", "/rss/channel/yweather:atmosphere/#humidity", "Response");
GetWeatherByAddressChoreo.addOutputFilter("text", "/rss/channel/item/yweather:condition/#text", "Response");
// GetWeatherByAddressChoreo.addOutputFilter("temperature", "/rss/channel/item/yweather:condition/#temp", "Response"); //
// add an output filter to extract the current temperature
// add an output filter to extract the date and time of the last report.
// run the choreo
GetWeatherByAddressChoreo.run();
// parse the results and print them to the serial monitor
while(GetWeatherByAddressChoreo.available()) {
// read the name of the next output item
String name = GetWeatherByAddressChoreo.readStringUntil('\x1F');
name.trim(); // use “trim” to get rid of newlines
// read the value of the next output item
String data = GetWeatherByAddressChoreo.readStringUntil('\x1E');
data.trim(); // use “trim” to get rid of newlines
if (name == "humidity") {
qData = data;
Serial.println("The humidity is " + qData);
}
else if (name == "temperature") {
tData = data;
Serial.println("The temperature is " + tData);
}
else if (name == "pressure") {
rData = data;
Serial.println("The pressure is " + rData);
}
else if (name == "text") {
cData = data;
Serial.println("The code is " + cData);
}
}
WriteDataChoreo.addInput("FeedID", "1508368369");
WriteDataChoreo.addInput("APIKey", "6Z4tvi6jUOC0VhFkgngijR3bZWMXr2NNu1PHl4Js0hHGqE6C");
// WriteDataChoreo.addInput("FeedData", "{\"version\":\"1.0.0\",\"datastreams\":[ {\"id\" : \"Pressure\",\"current_value\" : \"" + rData + "\"} ,{\"id\" : \"Humidity\",\"current_value\" : \"" + qData + "\"} ,{\"id\" : \"Conditions\",\"current_value\" : \"" + cData + "\"}]}");
WriteDataChoreo.addInput("FeedData", "{\"version\":\"1.0.0\",\"datastreams\":[{\"id\":\"Humidity\",\"current_value\":\""+qData+"\"},{\"id\":\"Pressure\",\"current_value\":\""+rData+"\"},{\"id\":\"Conditions\",\"current_value\":\""+cData+"\"},{\"id\":\"Temp\",\"current_value\":\""+tData+"\"}]}");
// Identify the Choreo to run
// Identify the Choreo to run
WriteDataChoreo.setChoreo("/Library/Xively/ReadWriteData/WriteData");
// Run the Choreo; when results are available, print them to serial
WriteDataChoreo.run();
while(WriteDataChoreo.available()) {
char c = WriteDataChoreo.read();
//Serial.print(c);
}
while(GetWeatherByAddressChoreo.available()) {
char c = GetWeatherByAddressChoreo.read();
//Serial.print(c);
}
WriteDataChoreo.close();
GetWeatherByAddressChoreo.close();
Serial.println("");
Serial.println("Waiting...");
Serial.println("");
delay(10000); // wait 30 seconds between GetWeatherByAddress calls
}
I work at Temboo. I believe we've resolved this issue already via Temboo support, so I'm answering here for posterity.
Generally, if a sketch is working intermittently and you haven't changed any code, then it's likely that you're running out of RAM (a common issue on resource-constrained devices). When your board is out of RAM it causes Choreo input data to get overwritten and corrupted on the 32U4 side of your Yún. Your sketch is probably right at the RAM limit, which explains why it's working sometimes but not others, dependent on the amount of String data involved.
You can free up some RAM by putting the inputs that don't change (your Temboo creds, your Xively creds, the address you're searching for, any other static strings) into settings files that are stored on the Linino side, as described at the link below:
https://temboo.com/arduino/using-settings-files
If that doesn't free enough memory, you can free some more by eliminating any unnecessary Serial or Console print statements.
Hopefully this will help solve the issue you're seeing. Please let me know if it doesn't and we will continue to investigate.
Finally, here's some info on how you can check on how much memory a sketch is using:
http://jeelabs.org/2011/05/22/atmega-memory-use/
Good luck,
Cormac