Arduino blog

Arduino blog

Arduino thinkering

This blog is about things I come by related to Arduino which I feel are inspiring/important/funny enough to write about.

Controlling Arduino over the web: Blinking a led the cool way.

Arduino sketch experiancesPosted by Jan Wed, September 11, 2013 20:37:35
In the previous article I talked about how to get sentences over the serial line to arduino with the aim to control a Arduino sketch via the internet.
If we want a sketch to control I need a sketch. (I know you are eager to get on the internet but we have to do this step by step. Bear with me)

I took the sample sketch "Blink without delay" made a c++ class for it and made a sketch "may way" (read with loop and setup methods).
(OK; I modded quite a bit but it all started from the blink without delay and I added functionality to have a different on than off time.)

Then I extended the Serial string example we used before with a blinking led.

#include "SerialStringReader.h"
#include "BlinkLed.h"
SerialStringReader mySerialReader;
BlinkLed led13(LED_BUILTIN,500,2000);


//The setup function is called once at startup of the sketch
void setup()
{
Serial.begin(9600);
led13.setup();
mySerialReader.setup();
}

// The loop function is called in an endless loop
void loop()
{
mySerialReader.loop();
led13.loop();
if (mySerialReader.messageReceived())
{
Serial.println("You have send a message to Arduino.");
Serial.println("And the message is:");
Serial.println(mySerialReader.getMessage());
}
}


Lets look at the important parts:
BlinkLed led13(LED_BUILTIN,500,2000);
States the led is connected to pin LED_BUILTIN (13 on most arduinos) and is 500 millis on and 2000 millis off.
led13.setup();
Is to initialize the class. And
led13.loop();
Makes sure the led blinks.
If you want more leds blinking just add more leds to your Arduino and add more classes, setups and loops. You can use a different timing for each led.

If you download the BlinkLed library from github you can compile and upload the sketch to your Arduino.

Now that we have a sketch to change values; we can finally think about changing values. With this sketch we want to be able to change the on and the off time of the blinking led via the serial monitor. But we also want to be able to see the status, know the pin. In other words all the variables of the class must be visible.
Remember I talked about "Kind of memory dump". What we need to do is tell Arduino what the kind of memory dump looks like.
We do this by creating a new class that is derived from BlinkLed and from SerialDataInterface.
SerialDataInterface is a helper class that allows you to easily create the "kind of memory dump" for a class.

The myBlink header looks like this
#ifndef MYBLINKLED_H_
#define MYBLINKLED_H_

#include <BlinkLed.h>
#include <SerialDataInterface.h>

class MyBlinkLed: public BlinkLed, public SerialDataInterface
{
private:
//For SerialDataInterface
static const uint8_t NUMFields = 5;
static const uint8_t NUMChildren = 0;
FieldData myDataFields[NUMFields];
SerialDataInterface * myDataChildren[NUMChildren];
public:
MyBlinkLed(const char* name,uint8_t ledPin,uint32_t onInterval ,uint32_t offInterval);
};

#endif /* MYBLINKLED_H_ */

NUMFields = 5 states there are 5 fields I want in the "kind of memory dump". We are talking about integers, floats, strings ...
NUMChildren = 0; states there are nu children. Children are object derived from SerialDataInterface.
The rest of the private section is always the same is is used to correctly allocate memory.
MyBlinkLed(const char* name,uint8_t ledPin,uint32_t onInterval ,uint32_t offInterval);
Is exactly the same as
BlinkLed(uint8_t ledPin,uint32_t onInterval ,uint32_t offInterval);
Except for I added a name we can use in the serial monitor to reference this particular instance of the class.

If we look at MyBlinkLed source we get

#include "MyBlinkLed.h"

MyBlinkLed::MyBlinkLed(const char* name, uint8_t ledPin,uint32_t onInterval ,uint32_t offInterval)
:BlinkLed( ledPin, onInterval ,offInterval)
{

myDataFields[0].set(name, F("myOnInterval"),MOD_WRITE|MOD_SAVE,&myOnInterval);
myDataFields[1].set(myDataFields[0].myClassName, F("myOffInterval"),MOD_WRITE|MOD_SAVE,&myOffInterval);
myDataFields[2].set(myDataFields[0].myClassName, F("myLedState"),0,&myLedState);
myDataFields[3].set(myDataFields[0].myClassName, F("myPreviousMillis"),0,&myPreviousMillis);
myDataFields[4].set(myDataFields[0].myClassName, F("myLedPin"),0,&myLedPin);

SerialDataInterface::myFields = myDataFields;
myNumFields = NUMFields;
myNumChildren = NUMChildren;
myChildren = myDataChildren;
}

This is some hocuspocus code that links the variables to the names of the 5 fields and to the activities you can do with them.
The first line states that the string "myOnInterval" refers to the variable myOnInterval.
MOD_WRITE|MOD_SAVE states that this variable can be changed by the SET command and MOD_SAVE states that the current value can be saved in EEPROM with the "SAVE" command.
If we assume that name is "led" we can change the value of myOnInterval by sending the following string followed by CR to Arduino.
SET led.myOnInterval=3456
If we want to save this value so that next time Arduino starts working it will use this value we send
SAVE

The next 4 lines are doing the same for the other fields. Note that if you see lots of garbage in the serial moniotor you probably made a mistake here or NUMFields is wrong.

The last 4 lines are always the same when the class doesn't have children.

Where are we?
We have a class that is able to read line by line from the serial monitor.
We have a class that does what we want to do BlinkLed.
We have a class that describes the "kind of memory dump" of BlinkLed.
What we now need is a class that handles the serial monitor line by line and links it to the memory dump.
This class is called SerialCommunicator.

So lets look at the sketch code:
#include "SerialStringReader.h"
#include "SerialCommunicator.h"
#include "MyBlinkLed.h"
#include "BlinkLed.h"
#include "SerialDataInterface.h"
const char * mySketchName="ssrDemo Part 2";

SerialCommunicator mySerialCommunicator(A5);
MyBlinkLed led13("BuildInLed",LED_BUILTIN,500,2000);


//The setup function is called once at startup of the sketch
void setup()
{
Serial.begin(9600);
led13.setup();
mySerialCommunicator.setup(&led13);
}

// The loop function is called in an endless loop
void loop()
{
mySerialCommunicator.loop();
led13.loop();
}


leds go over it line by line
const char * mySketchName="ssrDemo Part 2";
The SerialCommunicator needs a name for the program. this is just a display name.
SerialCommunicator mySerialCommunicator(A5);
This line replaces SerialStringReader mySerialReader;. With this code you need to connect pin A5 to reset if you want Arduino to reset when you send "RESET".
MyBlinkLed led13("BuildInLed",LED_BUILTIN,500,2000);
Replaces BlinkLed led13(LED_BUILTIN,500,2000);. So we added a name for reference in the serial monitor.
The next difference is
mySerialCommunicator.setup(&led13);
This used to be
mySerialReader.setup();
As there is only one object in the "kind of memory dump" we simply pass this object. Note that his object can have children. Therefore there you can always create 1 object corresponding to the "kind of memory dump".
And finally I deleted the echoing of the serial monitor.

If you downloaded the libraries, compiled the sketch and uploaded the sketch. You will see ..... that the led is not blinking....
open a serial monitor and send the SET command.
SET will show you all the variables that you can change in the command format.
On my board this gives
SET Admin.ResetCount=10
SET Admin.logLevel=255
SET Admin.RestartDelay=65535
SET Admin.DelaybetweenLogs=65535
SET BuildInLed.myOnInterval=4294967295
SET BuildInLed.myOffInterval=4294967295
As you can see BuildInLed.myOnInterval is a huge number. This explains why trhe led is not blinking.
Set it to 2000milis with the following command
SET BuildInLed.myOnInterval=2000
and also give a nice off interval with
SET BuildInLed.myOffInterval=5000

Now the led is blinking again.
You are probably thinking "We have set the intervals in the code. How did they get lost?"
Well we have indeed set the values but we also have overwritten them later on.
Remember we said that myOnInterval was MOD_WRITE|MOD_SAVE.
MOD_WRITE means we enable the SET command on this fields.
MOD_SAVE means we can save the value to EEPROM. It is no use saving the value when you do not read it.
So when we called mySerialCommunicator.setup(&led13); The value was replaced by what is in EEPROM and that will be different based on the history of the board.
Send the SAVE command and reset the board.
Run the SET command again and the values should be OK now.

The Admin stuff is the memory dump of mySerialCommunicator.
ResetCount tells you how many times the board has been reset.
logLevel is a flag telling wether log is on or off. Bit 0 is used for serial monitor logging. So in my case serial monitoring is on.
RestartDelay is a delay time before restart is triggered.
I put this on 850
DelaybetweenLogs tells how many times the serial monitor will get a logging. I mostly start with 1000 meaning every second the serial monitor will get a line with the "kind of memory dump" in a csv line style.
To know what is what dump the header with the LOG HEADER command
LOG VALUE;15;255;65535;65535;730022;0;789;4294967295;4294967295;0;0;13;
>>Send to /dev/ttyUSB0: "LOG HEADER"<<
LOG HEADER;Admin.ResetCount;Admin.logLevel;Admin.RestartDelay;Admin.DelaybetweenLogs;Admin.LoopCounter;Admin.AveragebetweenLoops;Admin.MaxbetweenLoops;BuildInLed.myOnInterval;BuildInLed.myOffInterval;BuildInLed.myLedState;BuildInLed.myPreviousMillis;BuildInLed.myLedPin;

If you understood all this you are up to the next episode: "controlling the serial monitor with an openwrt"


  • Comments(0)//blog.baeyens.it/#post8

Controlling Arduino over the web

Arduino sketch experiancesPosted by Jan Mon, September 09, 2013 03:06:22
I have been working some years now on building my own lawn mowing robot. I know you can buy a lawnmower robot in the shop but after intense market search I didn't find anything suiting my needs.
The main problem is that the inhabitants of my garden like to make piles which makes for a very unflat surface. After some trials to make it flat I gave up and started designing Marvin.
Marvin is a 4by4 frontmower lawnmower robot. He is planned to become fully autonomous but currently still needs to be brought to his charging station. Marvin is currently taking care of around 3000 square meters. But is planned to be able to handle 5000 and probably even more.
you can read more on Marvin in this post on the arduino forum. http://forum.arduino.cc/index.php?topic=186329.0

But here I want to focus a bit on the "communication part"
Having a robot running in your garden is cool. But when you are developing the robot you want to be able to connect to the robot wit the serial monitor and upload a new sketch without having to run around with a laptop and a USB cable.
There are several options to do this. I have opted to hack a linksys router install openwrt and upload from there.
Wait .... did I say openwrt??? Isn't that what yun will be running? Would this way be compatible with the yun? Well likely but it probably will need some tuning.
To explain this all I have to tell you a long story so you can understand how it works.
I want to tell you why you would listen to the whole story first.

What do you get to learn?
How can I upload a sketch remotely (I mean over the internet if needed)
How can I change parameters of my sketch easily (I mean over the internet if needed)
How can I reboot my sketch remotely (I mean over the internet if needed)
How can I program parameters in progmem (I mean over the internet if needed)
First things first. What do I mean with (I mean over the internet if needed).
The entrance point to your arduino becomes the system running openwrt (or any linux for that part). Accessing that system from your local network is easy. Accessing it from the internet requires some more work and it may have a financial impact (a other subscription wih your network provider). This set of articles is not going into this area as I assume you only need to access your arduino from your local network.

What do you need?
1) A arduino.
2) A machine able to run openwrt (or linux) that has a serial port and an Ethernet connection. If you want to go wireless this needs to be a wireless connection and that rules the pi out (unless you go for pi with wireless dongle) but any wireless router that has been hacked by the openwrt community should do.
I have used a linksys WRT54GL but that one is kind of short on "disk space" I hope the yun (which is in the same price range) will do better.
3) A router your machine running openwrt can connect to. (That is just like the pc you are using is connected to your local network)

That is all the hardware you need.

Look at this (slightly outdated drawing) to get the picture.
Note that the yun promises to be 1 and 2 together.
Also note that I did not succeed to hack the router with a sd card which left me with very little space which again should be solved by the yun.


What needs to be done to setup the same for your system?
1) Adapt your Arduino code so it is compliant.
2) Adapt the Arduino hardware so it is compliant.
3) Install and configure the linux scripts and software.

The first one is needed so that serial commands send to arduino are processed properly. For instance sending "RESET" should make the arduino reset. Some code is needed on Arduino to do so.
The second is needed because a RESET must be a hardware reset. The easiest is to connect a pin to the reset pin of the arduino. That finishes the hardware modifications smiley
The third one is needed to send commands to arduino via the network and to make the output of arduino available on the network. For instance you want to install avrdude to upload your sketch and minicom to have a remote serial monitor.

Step 2 and 3 are easy for a user. Step 1 requires a good understanding on what is going on with Arduino and is what major bulk of this set of articles is about.

Lets end this blog with and start the explanation with :"Sending line commands over the serial monitor"
The big bulk of examples of serial communication towards the arduino are character based commands. This is easy as each character is self containing. You do not need to know what was send before or will be send after each character.
For instance when you send 's' arduino starts. When you send 'p' arduino pauses.
But what if you send "Fast play". Arduino would understand start and then pause.
To be able to give long readable commands like "SET led.pwm=20" we need a line interpreter and not a character interpreter.
The first thing you need for a line interpreter is to agree on the "end of the line character sequence". As you can see in the Arduino serial monitor you have several options to add to the characters you send. Namely "no line ending", "carriage return", "newline" and "both NL & CR".
If you want to do line interpretation "no line ending" is not an option (though default in arduino) you need a special string to mark the end of the line. "carriage return", "newline" and "both NL & CR" are all commonly used (One is popular in linux land the other in windowsland).
Therefore the basis of all the above promises starts with a class that does the line interpretation for you. This class handles "carriage return", "newline" and "both NL & CR" seamlessly so you do not need to bother. This class can be downloaded from github at https://github.com/jantje/libraries/tree/master/SerialStringReader

The example looks like

#include "SerialStringReader.h"
SerialStringReader mySerialReader;


//The setup function is called once at startup of the sketch
void setup()
{
Serial.begin(9600);
mySerialReader.setup();
}

// The loop function is called in an endless loop
void loop()
{
mySerialReader.loop();
if (mySerialReader.messageReceived())
{
Serial.println("You have send a message to Arduino.");
Serial.println("And the message is:");
Serial.println(mySerialReader.getMessage());
}
}


I'll go into some detail as it contains some techniques you will see coming back.
First of all I use C++ classes. this allows me to declare the variable
SerialStringReader mySerialReader;
and then call methods on it.
mySerialReader.setup();
mySerialReader.loop();

All the classes have a setup() and loop(). setup() should be called in the main setup and loop in the main loop.
I do part of the initialization in the constructor and part in the setup. (No need to worry f you do not understand this)
All the repetitive action are in loop.
Upload this example to a Arduino and open the serial monitor. As you will see processing line by line in Arduino was never so easy.

In the next blog I'll build on this to add some commands.










  • Comments(0)//blog.baeyens.it/#post7
« Previous