I have an Arduino sketch running with a wifi shield and a bluetooth module. The problem is that my loop is so long (about 3 seconds) that the program is really laggy in responding to bluetooth command inputs. I will give the details below, but conceptually I want to use either multithreading or interrupt type programming instead of my one big loop and would like any input as to how to accomplish those things.
I will try to describe only as much detail as necessary about my program so that the answer can be more conceptual than specific. My program is roughly like this:
Create WifiClient client
Create Serial Bluetooth and begin
Loop Start
Connect client to APK and get Var1, Stop Client
Connect client to website and get Var2, Stop Client
Check Bluetooth available and get Var 3
Various Processing of Data
Output
Loop End
My problem is that those Wifi clients connections take 3 seconds or more, so my sketch is only responding to the bluetooth remote every three seconds or so. It gives an awkward feel (“Nothing happened, should I press the button again…”). It is just not good programming anyway because I think that the processor is idle during much of those Wifi client connections.
Can I run my Wifi Clients connect blocks in a multithread fashion and keep my main loop running faster while those Wifi Client connections are running in the background? Does Arduino Programming support multithreading?
Or can I use an interrupt somehow to get an immediate reaction to a bluetooth input, even if the code is up in the wifi client section of the code?
Any tips for multithreading, interrupts or other ways to do the above sketch better would be appreciated.
aarg:
Did you write the Wife client connection code, or is it third party?
The Wifi client connection is from the Arduino Example library for WifiWebClient
Robin2:
Or, is it not possible to keep the WiFi connection open ?
Post your code and please post your program using the code button
I have to pole two different websites (one APK and one Website) and I believe that the Wifi shield can handle only one client (the ethernet shield can handle multiple clients). So that's why I am connecting and closing the client within the loop.
I'll post my code here, but it is rather long. And posting the code may open myself up to other comments... but all comments are welcome anyway, so here's my code...
Actually it's really long so I am going to remove a lot of non-relavent stuff. The connecting and closing of the clients and the bluetooth section are here.
#include <SPI.h>
#include <WiFi.h>
// #include <Ethernet.h>
#include <SoftwareSerial.h>
float tIns = 25.0;
float tOuts = 23;
float tSet = 22;
byte abt;
char ssid[] = "twosom2F";
char pass[] = "027421008";
int keyIndex = 0; // your network key Index number (needed only for WEP)
#define DHTTYPE DHT11 // DHT 11
int status = WL_IDLE_STATUS;
char serversck[] = "api.smartcitizen.me"; // name address for SCK API
IPAddress servertweet(192,168,0,64); // IP appress for team 3
SoftwareSerial BT(4, 5); // Bluetooth
WiFiClient client;
void setup()
{
//Initialize serial port and wait to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
BT.begin(9600);
//while (!BT) {
// ; // wait for serial port to connect. Needed for Leonardo only
// }
// check for the presence of the shield:
if (WiFi.status() == WL_NO_SHIELD)
{
Serial.println("WiFi shield not present");
// don't continue:
while(true);
}
// attempt to connect to Wifi network:
while (status != WL_CONNECTED)
{
// Serial.print("Attempting to connect to SSID: ");
// Serial.println(ssid);
// Connect to WPA/WPA2 network. Change this line if using open or WEP network:
status = WiFi.begin(ssid, pass);
// wait 5 seconds for connection:
delay(5000);
}
// Serial.println("Connected to wifi");
printWifiStatus();
} //end setup
void loop()
{
// Serial.println("\nStarting connection to server Smart Citizen Kit");
// if you get a connection, report back via serial:
if (client.connect(serversck, 80))
{
client.println("GET /v0.0.1/f89b2ced0d52f115d98fa2ba2e6ef3c02e1b70fb/lastpost.json HTTP/1.1");
client.println("Host: api.smartcitizen.me");
client.println("Connection: close");
client.println();
} // end if connectd to server
while (client.connected())
{
// if there are incoming bytes available
// from the server, read them and search for important variables
while (client.available())
{
char c = client.read();
Serial.write(c);
} // end of while client.available
// if the server's disconnected, stop the client:
} //end of while client conneted
// Serial.println();
// Serial.println("disconnecting from server Smart Citizen Kit.");
client.stop();
delay (200);
// Connection for Team 3
if (client.connect(servertweet, 80))
{
// Make a HTTP request:
client.println("GET /external/temp.html/ HTTP/1.1");
client.println("Host: 192.168.0.64");
client.println("Connection: close");
client.println();
} // end if connectd to server
// Serial.println("completed connected to server for Temperature Setting team 3");
while (client.connected())
{
// if there are incoming bytes available
// from the server, read them and search for important variables
while (client.available())
{
char c = client.read();
Serial.write(c);
} // end of while client.available
// if the server's disconnected, stop the client:
} //end of while client conneted
// Print Comment Serial.println();
// Serial.println("disconnecting from server for team 3.");
client.stop();
delay (200);
// End of collaboration with Team 3
// Look for Bluetooth button input
if (BT.available())
{
// Serial.println("BLUETOOTH AVAILABLE");
abt =BT.read();
// Serial.println(abt);
if (abt == 0x30) // temperature up
{
// Serial.println("RAISING TEMPERATURE");
tSet=tSet+1;
}
else if (abt == 0x31) // temperature down
{
// Serial.println("LOWERING TEMPERATURE");
tSet=tSet-1;
}
} // end BT available
Serial.print("Outside Temp: ");
Serial.print(tOuts);
Serial.print(" C,");
Serial.print("Inside Temp: ");
Serial.print(tIns);
Serial.print(" C,");
Serial.print("Set Temp: ");
Serial.print(tSet);
Serial.print(" C,");
} // end of loop, go back and connect again
void printWifiStatus()
{
// print the SSID of the network you're attached to:
// Print Comment Serial.print("SSID: ");
// Print Comment Serial.println(WiFi.SSID());
// print your WiFi shield's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
// print the received signal strength:
long rssi = WiFi.RSSI();
Serial.print("signal strength (RSSI):");
Serial.print(rssi);
Serial.println(" dBm");
}
I agree: having multitasking (e.g., like provided by for the Due) makes things LOT easier.
But it wouldn't make much sense on micro-RAM-sized boards <= 2kB, so a MEGA, Zero, Yun, or DUE would fit.
Most useful for programs using also long time-consuming tasks additionally to real-time capable tasks would be time-slice scheduling like feat. by pre-emptive Multitasking (POSIX , C11 , OSEK). This indeed is still missing yet for the DUE, too.
Since there is not even a simple cooperative Scheduler lib available for the Mega I'm using just the DUE for all of my projects, maybe this one (or, uncertain, the Zero in case) will be an option also to you.
From looking (briefly) at the documentation and source code for the WiFi library it looks as if client.connect() is a blocking function and the library does not seem to have a non-blocking alternative.
I know from browsing generally that some requests can take a few seconds to complete and maybe it would make no sense for your code not to wait for a request to complete. There would be no reason to expect it to complete any quicker a short time later.
Maybe you could reorganize your code so that it only calls one website between each call to the bluetooth module.
Maybe you could reorganize your code so that it only calls one website between each call to the bluetooth module.
Robin2 has my vote on this suggestion. Unless you are willing to tear-into the libraries in an attempt to hack the blocking code somewhat, I think the best one can do is to work at the sketch level to ensure that you are being as modular as possible and not creating problems for yourself.
There is another way, however, and that is to use two uC's ... that is move the Bluetooth to a separate chip. Now, you need to build the glue-software to do the hardware interconnects: likely I2C but I have also done this myself with high-speed serial. You can just build a struct to efficiently move the binary data over a bus... I seem to remember some of the RF12 libraries do this rather efficiently.
Thank you for the suggestions. I found that it is possible to make an interrupt based on a bluetooth serial input, but that wouldn't really help if the client.connect() cant be interrupted...
I also found there are ways to do "multitasking" based on keeping an eye on timing, but no real multithreading which would put the clent.connect() on a parrellel processing path.
The idea of looking for my bluetooth input between every client.connect is a great idea. Thanks and I will try that!
rubbish.
pointless overkill is establishing 2 single real processor boards by a real time synced connection to handle just 2 tasks.
ARM cpus have already built-in multitasking abilities, are fast, and powerful.
A DUE clone costs just < 20 US$, that's actually peanuts!
BTW, is the ZERO capable of multitasking e.g., by ?
But I actually doubt it would be cheaper then, though.
provides cooperative multitasking, so you have to care for intermediate task switching by
yield();
For very long lasting tasks you may provide several ylelds in your code, e.g. in repetitive cycles of loops which work as predetermined breaking point, but the task will re-enter just at this command line.
I cannot guarantee for realtime safety but for my tasks it works, both for the long lasting and for the time sensitive ones.
my personal brain is already widely upgraded to a multi-threaded one, since already ~ 15 years using Lego Mindstorms programming which provides this feature already since that time.
Now just Arduino has to be upgraded by this feature actually to be in sync with my brain again as well.
I think this is a case where it make more sense to downgrade the brain to match the limited capability of the Arduino.
Whatever multitasking system you have found it can only be using more code to do the stuff @Nick Gammon has suggested or what is in Several Things at a Time
When something goes wrong I much prefer to use my time on my own program rather than trying to figure out how some library is supposed to work.
Arduino is no longer so much limited to poor capabilities with respect to Due and (maybe) Zero or Yun - or even already the Mega.
As time went by, the cpu abilities arose, including ARM cpus providing multitasking which is a standard for ARM processors.
But already on a Renessas H8 (Lego Mindstorms RCX, 1999-2006, comparable to a Arduino Mega) Multitasking was working fine, not to talk about NXT (ARM7, 2006-2013) and EV3 (ARM9 2013 ff.).
Delta_G:
Kids bikes have had training wheel technology for years.
My kids' bikes had training wheels. They are a PITA because the kids don't need to learn to balance.
Long after they learned to ride I saw a small kid with a little wooden bike with neither pedals nor training wheels. Like a sit-upon scooter, I guess. That seems like a much better way to learn balance on two wheels - and without the pedals battering your shins.