Friday, November 26, 2021

ESP Webserver tutorial part 1 - textfields

For an index to all my stories click this line

Most of the time we want to control an ESP8266 or ESP32 remotely. Be it from our work or from a lazy chair. The best way to do this is to use the ESP as a webserver.

A webserver builds a webpage and sends that to your computer or smart-phone or tablet. On the webpage there will be text fields that we can fill in, buttons and sliders. As soon as we have filled in the desired action on the webpage the information is send back to the ESP. The ESP analyses what it receives and acts on it by switching a led on or off, dimming a led, setting the angle of a servo,  or altering the color of an RGB led. 

IN ESP-Basic this is all done in an easy way. And there are numerous pages on this weblog that demonstrate this. Unfortunately ESP-Basic is not available for the ESP32 and more important it is no longer maintained as the developer (Mike) has a company to run nowadays. So back to C++ the Arduino language. However in Arduino language this appears much more difficult to realise.

That is untill you realise how it is done. And once you get the hang of it, it is no longer complicated at all.

Therefore I am going to give you a detailed tutorial on how to achieve this.
The first part is showing how to send text and figures to the ESP from a field on a webpage that you can fill in yourself. The next parts will show you how to put buttons, radio buttons, sliders and color pickers on the webpage.This will lead to building the most fantastic websites that can be used for any IOT purpose.

On a sidenote I want to urge you to study HTML, CSS and Javascript as these are the fundamentals that build a webpage. You can find ample information on these subjects on the following websites:
https://www.w3schools.com/
https://www.tutorialspoint.com/index.htm
https://www.edx.org/

At EDX you can follow complete courses. The other two websites are intended for self-study.

How does it work.

There are 4 steps in this process. I already adressed them brief in the beginning of this story.

As soon as the ESP starts it will make a connection with your router. Then it will tell it's IP adress on the Serial Monitor. You can find the IP adress also in your routers webpages.

The ESP then waits till you adress it with a web-browser. That can be any webbrowser on your computer, smart-phone or tablet.
As soon as you point your browser to the ESP's IP number it will send a webpage to the browser.

The webpage appears on your web-browser and the ESP does nothing until you fill in some text fields, press a button or alter the settings of a slider. The web-browser will then send the information back to the ESP.

The ESP receives the information and analyses it. And your program will act on the information received by switching a led on or of, changing the speed of a motor, altering the colors of a ledstring or whatever you want to happen.

To achieve all this you will need a program that handles all the above actions. And here it is.

The ESP webserver

The information provided here will work on the ESP8266 AND on the ESP32. The only thing you will need to change is the part where the libraries are loaded and initialised.


As this will be a long and fairly complicated program I will do a step by step analyse which will shed some light on how this works.


#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

ESP8266WebServer server(80);

// Your routers credentials
const char* ssid = "YourRoutersName";
const char* password = "YourPassWord";

The first part of the program loads the libraries for the ESP8266 that it will need. Then it will start the webserver on port 80 which is the normal port for HTTP communication.
Do not forget to substitute YourRoutersName and YourPassWord with your credentials.



#include <WiFi.h>
#include <WebServer.h>

WebServer server(80);

// Your routers credentials
const char* ssid = "YourRoutersName";
const char* password = "YourPassWord";


The above code is the code for the ESP32. As you can see the changes are minimal. The names of the libraries are different and therefore the way the library is initiated is different. But that is all. The rest of the program is identical for the ESP8266 and the ESP32.


// ===================================================
// Setup
// ===================================================
void setup()
{
  delay(1000);
  Serial.begin(115200);

  // Connect to Wi-Fi network with SSID and password
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid,password);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  // Print local IP address and start web server
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  server.begin();
  server.on("/", handleRoot);
  server.onNotFound(handleNotFound);

  server.begin();
  delay(500);
}

The Setup starts with opening the Serial Port and making a connection to your router. A series of dots (".") will be printed as long as the connection is not established.
When the connection is established the IP number will be printed in the Serial Monitor.
The webserver is started and two handles are defined. The first one is "/" which is the adress of the Homepage on your website. So if you type the IP adress of the ESP in your browser this will direct you to the main page.
If you adress a non-existing addition to the IP adress like 192.168.1.77/test then the server will active the handleNotFound routine.


// ===================================================

// Loop

// ===================================================

void loop()

{ 

  server.handleClient();

  delay(50);

}

As in any normal program the loop will now start. In this loop nothing happens. It just waits till the server receives anything back from the webpage. In a reallife program you would let all kind of things start from here.


// ==================================================
// Handle for page not found
// ==================================================
void handleNotFound()
{
  server.send(200, "text/html", getPage());

If you enter a non existing webpage for the found IP adress like 192.168.1.77/test then this routine catches that error and the server sends the information which is in the getPage() routine


// ===================================================
// Handle root
// ===================================================
void handleRoot() 
{   
  if (server.args() ) 
    {
    handleSubmit();
    } 
  else 
    {
    server.send(200, "text/html", getPage());  
    }
}

If the webpage sends some information back to the ESP this routine recognizes that there is information received and starts the handleSubmit() routine to analyse what has been received.
If the webpages is refreshed but no valid information is send back the server just sends the webpage anew. The webpage is build in the getPage() routine.



// =========================================
// Here is the HTML page
// =========================================
String getPage()
  {
  String page = "<!DOCTYPE HTML>";
  page += "<html>";
  page += "<head>";
  page += "<meta name = \"viewport\" content = \"width = device-width, initial-scale = 1.0 maximum-scale = 2.5, user-scalable=1\">";
  page += "<title>Luc's tekst test demo</title>";
  page += "<style>";
  page += "body { background-color: powderblue}";
  page += "</style>";
  page += "</head>";
  page += "<body>";
  page += "<h1 style='color:red'>Luc's send text to ESP8266</h1>";

The first part of the getPage() routine is where the body of the webpage is being build. The scale is set to one and a maximum enlargement of 2.5 is defined. These settings are especially for mobile devices. You can alter them if you need to. The background color is defined as Powderblue which I use often. The text of the heading is set to red.


  //Form to put the data in
  page += "<FORM action=\"/\" method=\"post\">";
  page += "Fill in the text you want to send<br><br>";
  page += "<input type=\"text\" name=\"textosend\" id=\"textosend\" value=\"Lucs test\">";
  page += "<br><br>";
  page += "<input type=\"submit\" value=\"Send to ESP\">";
  page += "</form>";
  page += "<br>";
  page += "<br>";
  page += "<br>";
  page += "</body>";
  page += "</html>";
  return page;

This is where the action is. A form is created and the method to send the data from the form to the ESP is the POST method.
Next an input field is created of the type text. In this field you can put the data you want to send to the ESP. The name of the field is 'texttosend' and the ID with which we can identify it is also 'texttosend'. A default value is filled in when the page is opened and that default value is 'Luc's test'. All these things are collected in the string with the name page. The last line returns that string to the function that called this routine.

// ==================================================
// Handle submit form
// ==================================================
void handleSubmit()
{
  //Text to show
  if (server.hasArg("textosend"))
      {
      textosend_string = server.arg("textosend");
      Serial.print("The received text is:             ");
      Serial.println(textosend_string);
      Serial.print("If it is an integer its value is: ");
      Serial.println(textosend_string.toInt());
      }

  server.send(200, "text/html", getPage());       //Response to the HTTP request
} 

When you have entered the text you want to send and push the submit button or press enter in the textfield this routine is called.
The if statement test wether the information comes from the field with the ID 'texttosend' If that is the case the received information is put in the variable textosend_string.
The next to lines are just for demonstration purposes. The Serial Monitor prints which information was receved and the information is converted to an integer. If the received information is indeed a figure it will be print6ed in the second line otherwise the result is 0.

That's it. The variable 'textosend_string' contains te information that you filled in on the webpage and with this variable you can start any action you want the ESP to perform.

Adding an extra field

Undoubtedly you want or need to send more then one text or figure. So let us add a second field.
Start with altering the part where the page is build as follows:

  //Form to put the data in
  page += "<FORM action=\"/\" method=\"post\">";
  page += "Fill in the text you want to send<br><br>";
  page += "<input type=\"text\" name=\"textosend\" id=\"textosend\" value=\"Lucs test\">";
  page += "<br><br>";
  page += "<input type=\"submit\" value=\"Send to ESP\">";
  page += "</form>";
  page += "<br>";
  page += "<br>";
  page += "<br>";

  page += "<FORM action=\"/\" method=\"post\">";
  page += "Fill in the second text you want to send<br><br>";
  page += "<input type=\"text\" name=\"textosend2\" id=\"textosend2\" value=\"Something else\">";
  page += "<br><br>";
  page += "<input type=\"submit\" value=\"Send to ESP\">";
  page += "</form>";
  page += "<br>";
  page += "<br>";
  page += "<br>";
  page += "</body>";
  page += "</html>";

There are now 2 forms. The first one is unaltered and the second one is just a copy of the first one. In the second one all references to 'texttosend' are changed in 'texttosend2' This refers the webserver to link the second text field to the second variable.

Now we only have to change the routine where the information that is returned gets processed:


// ==================================================
// Handle submit form
// ==================================================
void handleSubmit()
{
  //Text to show
  if (server.hasArg("textosend"))
      {
      textosend_string = server.arg("textosend");
      Serial.print("The received text is:             ");
      Serial.println(textosend_string);
      Serial.print("If it is an integer its value is: ");
      Serial.println(textosend_string.toInt());
      }

   if (server.hasArg("textosend2"))
      {
      textosend_string2 = server.arg("textosend2");
      Serial.print("The second received text is:             ");
      Serial.println(textosend_string2);
      Serial.print("If it is an integer its value is: ");
      Serial.println(textosend_string2.toInt());
      } 

As you can see the drill is almost the same as where the webpage gets build. We now have a second routine that tests for the new variable and sends it's data to the Serial monitor.

The complete program


// ======================================================
// Webserver program that sends text to an ESP8266
// so we can send commands from a webpage.
// ======================================================

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

ESP8266WebServer server(80);

// Your routers credentials
const char* ssid = "YOURROUTERSNAME";
const char* password = "YOURPASSWORD";


// ==========================================
// initial variables
// ========================================== 

String textosend_string;
String textosend_string2;

// =========================================
// Here is the HTML page
// =========================================
String getPage()
  {
  String page = "<!DOCTYPE HTML>";
  page += "<html>";
  page += "<head>";
  page += "<meta name = \"viewport\" content = \"width = device-width, initial-scale = 1.0 maximum-scale = 2.5, user-scalable=1\">";
  page += "<title>Luc's text test demo</title>";
  page += "<style>";
  page += "body { background-color: powderblue}";
  page += "</style>";
  page += "</head>";
  page += "<body>";
  page += "<h1 style='color:red'>Luc's send text to ESP8266</h1>";

  //Form to put the data in
  page += "<FORM action=\"/\" method=\"post\">";
  page += "Fill in the text you want to send<br><br>";
  page += "<input type=\"text\" name=\"textosend\" id=\"textosend\" value=\"Lucs test\">";
  page += "<br><br>";
  page += "<input type=\"submit\" value=\"Send to ESP\">";
  page += "</form>";
  page += "<br>";
  page += "<br>";
  page += "<br>";

  page += "<FORM action=\"/\" method=\"post\">";
  page += "Fill in the second text you want to send<br><br>";
  page += "<input type=\"text\" name=\"textosend2\" id=\"textosend2\" value=\"Something else\">";
  page += "<br><br>";
  page += "<input type=\"submit\" value=\"Send to ESP\">";
  page += "</form>";
  page += "<br>";
  page += "<br>";
  page += "<br>";
  page += "</body>";
  page += "</html>";

  
  return page;
  }


// ==================================================
// Handle for page not found
// ==================================================
void handleNotFound()
{
  server.send(200, "text/html", getPage());
}


// ==================================================
// Handle submit form
// ==================================================
void handleSubmit()
{
  //Text to show
  if (server.hasArg("textosend"))
      {
      textosend_string = server.arg("textosend");
      Serial.print("The received text is:             ");
      Serial.println(textosend_string);
      Serial.print("If it is an integer its value is: ");
      Serial.println(textosend_string.toInt());
      }

   if (server.hasArg("textosend2"))
      {
      textosend_string2 = server.arg("textosend2");
      Serial.print("The second received text is:             ");
      Serial.println(textosend_string2);
      Serial.print("If it is an integer its value is:        ");
      Serial.println(textosend_string2.toInt());
      }   

  server.send(200, "text/html", getPage());       //Response to the HTTP request
}  


// ===================================================
// Handle root
// ===================================================
void handleRoot() 
{   
  if (server.args() ) 
    {
    handleSubmit();
    } 
  else 
    {
    server.send(200, "text/html", getPage());  
    }
}


// ===================================================
// Setup
// ===================================================
void setup()
{
  delay(1000);
  Serial.begin(115200);

  // Connect to Wi-Fi network with SSID and password
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid,password);
  while (WiFi.status() != WL_CONNECTED) 
  {
    delay(500);
    Serial.print(".");
  }
  // Print local IP address and start web server
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  server.begin();
  server.on("/", handleRoot);
  server.onNotFound(handleNotFound);

  server.begin();
  delay(500);
}


// ===================================================
// Loop
// ===================================================
void loop()
{  
  server.handleClient(); 
  delay(50);
}


And above is the complete program. just copy it into the Arduino IDE and fill in your routers credentials. And as stated in the beginning of this story: replace the first lines of the program with the appropriate libraries and library calls for the ESP8266 or the ESP32.

The result

 
Here you can see how the webpage looks.



And this is how the information is displayed in the Serial monitor.
I entered the default text in the first field and pressed the send button. Next I entered the figure 155 and again pressed the send button. I did the same in field number 2 however here I only entered text.

Next step.

Before we proceed to the next step play around with this program. Add more fields. Alter HTML code and use different background colors and maybe even change the text appearences.

But above all: study the code so you fully understand whats happening.
If you fully understand how this works you can start building fantastic webistes for your IOT projects.
You could remove the second form creating command on the webpage and see what happens when both text fields are treated as one form.
Hint: do not forget to remove the first -- page += "</form>"; -- line.

This is a base for the next articles in which we are going to add all kind of goodies like buttons, radio buttons, sliders, color pickers, etc etc etc.

Till then
Have fun

Luc Volders

Friday, November 19, 2021

Sinterklaas 2021

 For an index to all my stories click this text

Sorry guys, Dutch only this time and a shameless plug too !!!

Het lijkt nog erg vroeg maar de tijd gaat sneller als je denkt. Over iets meer dan 2 weken is het al weer Sinterklaas.

Als je nog iemand in je naaste omgeving hebt die geïnteresseerd is in electronica in zijn algemeenheid en The Internet of Things specifiek dan kan ik nog steeds (zonder gêne) een van mijn eigen boeken aanbevelen.



ESP32 Uitgelegd bespreekt de populaire ESP32 die ik ook op dit weblog voor veel projecten gebruik. Het boek begint met wat achtergrond informatie en laat vervolgens zien hoe je de (gratis verkrijgbare) software installeert op je computer. Een korte introductie in de C++ programmeertaal ontbreekt natuurlijk niet.
Daarna volgt er uitleg over de vele sensoren die je aan de ESP32 kunt koppelen. Denk bijvoorbeeld aan bewegingssensoren, trillingssensoren, thermometer sensor, licht sensor maar ook de eenvoudige druktoets. Daarnaast komen er ook displays, leds en neopixels aan bod. Er wordt veel aandacht besteed aan hoe je deze sensors hun gegevens op een webpagina kunt laten weergeven, de ESP32 heeft immers Wifi aan boord. Maar ook cloud services als IFTTT en Thingspeak komen aan bod.

Alles op een duidelijk te begrijpen manier uitgelegd. Bedoeld voor beginners, maar ook voor electronica hobbyisten die geen ervaring hebben met microcontrollers en Wifi.

Het boek is bij iedere boekhandel te krijgen of te bestellen. Je kunt het ook direct bij mijn drukker bestellen via onderstaande link:
https://www.boekenbestellen.nl/boek/esp32-uitgelegd/9789463456814

Maar je kunt het ook via Bol bestellen:
https://www.bol.com/nl/nl/p/esp32-uitgelegd/9200000116004013/?bltgh=kxKOW-iIF6vaCc5VqYlCfg.2_9.10.ProductImage

Daarnaast hebben ook electronica webshops zoals Kiwi Electronics en Otronic het boek in hun assortiment.

Kiwi vindt je hier:
https://www.kiwi-electronics.nl/nl/esp32-uitgelegd-4324?search=esp32%20uitge

Otronic vindt je hier:
https://www.otronic.nl/a-61328375/esp32/boek-esp32-uitgelegd-door-luc-volders/


Otronic heeft zelfs een complete starterkit samengesteld met mijn boek en alle se3nsoren en onderdelen die erin besproken worden:
https://www.otronic.nl/a-60815511/esp32/esp32-starter-kit-inclusief-leerboek-van-luc-volders-nl-365-pagina-s/





 


Raspberry is bekend van zijn Linux computers. Maar de Raspberry Pi Pico is een microcontroller net als de Arduino. Hij is alleen veel sneller en heel goedkoop. je hebt al een Pico voor onder de 5 euro !!!
De Raspberry Pi Pico kan met de makkelijk te leren Python taal geprogrammeerd worden. De Pico heeft geen Wifi maar dat hoeft geen belemmering te zijn. De Arduino heeft ook geen Wifi en er kunnen honderden projecten mee gerealiseerd worden.

De opzet van dit boek is gelijk aan de opzet van mijn boek over de ESP32. Het begint met het installeren van de (gratis verkrijgbare) benodigde software en geeft dan een uitleg over de Python programmeertaal. Daarna volgt er uitleg over de meest bekende sensoren die jue aan de Pico kunt koppelen zoals trilling en tilt sensoren, bewegings sensoren, temperatuur sensor, aanraak gevoelige sensor (touch), afstand meter, licht sensor etc.etc.etc. Om de gevens van deze sensoren weer te geven worden led's, neopixels maar ook displays uitgelegd. Van elk onderdeel wordt uitgelegd hoe je het moet aansluiten en hoe je de Pico programmeert om ermee te communiceren. In begrijpelijke taal en voorzien van vele voorbeelden.
Alles kan op een breadboard worden nagebouwd dus er hoeft niets gesoldeerd te worden.

Dit boek is alleen in het Engels verkrijgbaar en kan via Amazon besteld worden:
https://www.amazon.nl/Raspberry-Pico-Simplified-Luc-Volders/dp/1329449533/ref=sr_1_1?__mk_nl_NL=%C3%85M%C3%85%C5%BD%C3%95%C3%91&keywords=raspberry+pi+pico+simplified&qid=1637182878&sr=8-1

Wacht niet te lang met bestellen, het Sinterklaasfeest komt sneller als je denkt en door de huidige Corona crisis kan het langer duren voordat bestellingen worden uitgevoerd.

Veel plezier
tot de volgende keer

Luc Volders


Friday, November 5, 2021

Cheat on your pedometer

For an index to all my stories click this text

Autumn is here. It is getting cold and rainy outside. Not really inviting to do your dayly portion of running. Nevertheless you need to keep your moyenne up. So how about a way to have your pedometer count numberous steps without getting away from the cozy warmth of your fireplace.

Last year when a friend visited me he had one of those stupid health watches with a pedometer. They cost a fortune and it is (for me) unimaginable how many people have them and don't know how they are fooled. To demonstrate this I asked for his watch, took it in my hand and shook it several times. "Hey look, you just did 20 steps while sitting on the couch"

And a bit later my girlfriend got a cheap health watch as a present from some marketing company. And then a few months ago I saw a so called smart watch with pedometer for just a few dollar at a shop. I had an idea and just could not resist.

What if I could build a device that would automate the steps.

In 2014 I wrote a story about some cardboard tubes I collected from my job. I used them as a storage and as piggy-bank. I kept some of these. http://lucstechblog.blogspot.com/2014/11/spacers-also-to-be-used-as-piggybank-at.html

I cut of a piece of about 4 cm and put the watch on that. Then I started rotating the tube and presto steps being made !!! Now the only thing to do is to put a motor on it.



So I started by designing a cilinder with a bottom in Tinkercad. The height is 3 cm and the circumfence is 6 cm. The wall is 3mm thick which is sufficient for holding a watch.



I sliced the watch and 3D printed it. Then I put a horn on the servo and glued it with my hot glue gun.

I decided to use a Raspberry Pi Pico for this project and wrote some test software in MicroPython. The software just made the servo step from 1 to 176 degrees, wait a second and then loop backwards. I held the servo in my hand an started the software. That did the trick !! Steps were made !!



Next a prototype of a frame was made in cardboard and the servo was mounted on it.



This is how it looks from the front.



And here is how the watch is mounted.


And when the prototype worked I reproduced the frame in Tinkercad so it would look nice overall


For those who want to download the frame for their own purposes above is the Tinkercad Link.

The electronics.

For this project I used a Raspberry Pi Pico. The setup is just simple.



A servo is connected to the Raspberry Pi Pico's GP13 and a button with a pull-up resistor is attached to pin GP14. For the servo I used a simple SG90. There is not a lot of weight

As the pico can not supply enough power to run the servo I attached a seperate power supply through an USB adapter.

You can find more information on the Raspberry Pi Pico in my book which is world-wide available through Amazon. The details about this hardware setup (not the actual project though) can be found in this book.


 

https://www.amazon.com/Raspberry-Pico-Simplified-Luc-Volders/dp/1329449533/ref=sr_1_1?dchild=1&keywords=raspberry+pi+pico+simplified&qid=1631477904&sr=8-1

The software

The first program is just a simple program written in MicroPython that has the servo constantly turn from 3 degrees to 176 degrees and back. The button is not needed as you can only start and stop this program by applying or cutting the power.

import machine
import time

servopin = machine.Pin(13)
servo = machine.PWM(servopin)
servo.freq(50)

min = 1400 # Tweak this
max = 7500 # Tweak this

diff = max - min
degrees = int(diff / 179)

while True:
    
    angle = 3
    step = min + (angle * degrees)
    servo.duty_u16(step)
    time.sleep(1)

    angle = 176
    step = min + (angle * degrees)
    servo.duty_u16(step)
    time.sleep(1) 

This program works and is enough to get you as many steps as you want. However you cant stop to have a look at the watch to see how many steps it registrated.
So I build a bit more advanced program.

import machine
import time

pushstart = machine.Pin(14, machine.Pin.IN)

pinstart = 0;

servopin = machine.Pin(13)
servo = machine.PWM(servopin)
servo.freq(50)

min = 1400 #tweak this
max = 7500 #tweak this

diff = max - min
degrees = int(diff / 176)

def keypress(dummy):
    global pushstart
    global pinstart
    if pushstart.value() == 0 :
        print ("button start")
        pinstart = 1 - pinstart
        time.sleep(0.2)
        
pushstart.irq(trigger=machine.Pin.IRQ_FALLING, handler=keypress)        

while True:
     
    if pinstart == 0:
       angle = 3
       step = min + (angle * degrees)
       servo.duty_u16(step)
       
    if pinstart == 1 :   
       angle = 3
       step = min + (angle * degrees)
       servo.duty_u16(step)
       time.sleep(1)

       angle = 176
       step = min + (angle * degrees)
       servo.duty_u16(step)
       time.sleep(1)   


This program uses the button to start and stop turning the watch. Pressing the button starts the sequence and pressing the button again stops it. The detection of the button is done by using an interrupt. This way you can stop the servo, have a look at the pedometer, and if needed start the servo again by pressing the button.



https://www.amazon.com/Raspberry-Pico-Simplified-Luc-Volders/dp/1329449533/ref=sr_1_1?dchild=1&keywords=raspberry+pi+pico+simplified&qid=1631477904&sr=8-1


If you want more information on programming the Raspberry Pi Pico with MicroPython have a look at my book. It starts with a course on programming with MicroPython and has information and examples on how to use many different sensors and actuators.

Using different watches.

I tested this setup with several watches with a buid-in pedometer. Some watches needed to be attached on top of the cilinder like in the photo. Others needed to have the watch start at a horizontal position. But all had the pedometer working while I was sitting after my desk. Before building this, test what works best for you.

You cheating devil.

Put the watch on the contraption. Go sit in the garden with a good book and a drink, or visit your local pub or whatever, and after an hour or brag to your friends or partner on how many steps you made !!!!

I had great fun in designing and building this project and even more when I demonstrated it to some friends.

Till next time
Have fun.

Luc Volders