Tuesday, October 25, 2022

Pico W Simplified released !!!

For an index to all my stories click this text.

I am proud to announce that my latest book is now up for sale on lulu.com or on Amazon

        Click here to buy Raspberry Pico W Simplified on Lulu

      Click here to buy Raspberry Pico W Simplified on Amazon

The book is about the, last july, released Raspberry Pi Pico W. The Pico W is, for those in the dark, a microcontroller like the Arduino but with lots of IO ports (26) a fast processor (up to 133 Mhz), 264K ram and 2Mb flash memory, I2C and SPI and best of all Wifi. The main programming languages are MicroPython and C++. And it is dead-cheap (around 8 USD) and locally available. Summarizing: this is a serious competitor for the ESP32.


The book is a book for beginners, although seasoned hobbyists might find some neat tricks in it.

Six sensors and actuators are used throughout the book. These are: button, led, dallas DS18B20 thermometer, LDR,  Pir and Vibration sensor. Each of these are explained, set up on a breadboard and demonstrated with a small program. Later on in the book they are used to demonstrate how to send their data over Wifi to several internet services and of course your own web-server running on the Pico W itself.

The rest of the book focuses on pin layout, installing MicroPython and Thonny, and the MicroPython language. The book is 275 pages so you can imagine that just a small part of MicroPython is addressed. A small part but yet enough to make some interesting projects.

The Wifi part discusses:
- How to use Ping to check if you are at home and then set a light on
- Get the values of cryptocurrencies from 2 different websites
- JSON decoding
- Sending data to Thingspeak and displaying that data on a webpage
- Getting notifications on your phone (alarms) with Pushbullet
- Sending text and data to Telegram
- Sending and obtaining data from Dweet
- Building your own webserver that displays sensor data
- Building your own webserver with buttons to set on a light

There are some specialities in the book.
For sending data from the webpage to the server I use the POST method. Advantage is that no info is seen in the URL, and data is not stored in the browsers history. So a different approach as usual.
Dweet is an anonymous service to post and receive data. Dweet has been discussed on this weblog before. It is free but stores only the 5 latest data sets and no longer as 24 housr. So great for anonymous posting. Even no log-in is required.
For decoding JSON a pathfinder is discussed that decodes JSON code and gives the analysed path so you
can easily turn it into MicroPython code.

All code is written in MicroPython and all breadboard setups made with Cirkit Designer which has also been discussed on this weblog: http://lucstechblog.blogspot.com/2022/08/create-new-component-in-cirkit.html

I invested a huge amount of time in this book. Next to that the paper and energy prices are rising. Despite this all, I tried to keep the price as low as possible

You can order the book direct from Lulu's webshop and it is available now:


Click here to buy Raspberry Pico W Simplified on Lulu

Click here to buy Raspberry Pico W Simplified on Amazon

The Holiday season is coming up. The price of the book and the price of the Pico W and the used sensors are so low that this might be the perfect gift for your kids, relatives or anyone interested in the Internet of Things and electronics.

Till next time

Have some reading fun

Luc Volders


Friday, October 14, 2022

ESP webpage with Gauges

For an index to all my stories click this text.

As some of my previous articles have shown you: an ESP8266 or ESP32 is capable of producing a webpage on which we can represent data, and put all kinds of buttons and sliders to control lights, motors etc. etc.

Until now I have presented this data in a rather dull way. Just a text on the screen that tells the temperature or the status of a sensor. While this works it is not an attractive way to show the data. Now look at the next picture.



Just look at that. Much nicer as just a text. This story tells how to put a Gauge on your ESP's webpage that shows the data of a sensor. I will give you the breadboard setup and code for both the ESP8266 and the ESP32

This story relies heavily on the article I wrote about making Gauges with Javascript. So I urge you to read that story before you jump into the pool. You can re-read that story here: http://lucstechblog.blogspot.com/2019/11/gauges-and-linecharts-in-javascript.html

What we basically are going to do is to attach a sensor to an ESP8266 or ESP32. Then in the program we build a webpage which shows the value of that sensor on a Gauge. So some basic understanding of building webpages with the ESP8266 or ESP32 will come in handy. I did an extensive series on that which you can find here:
http://lucstechblog.blogspot.com/2019/07/esp-webserver-tutorial-part-1-textfields.html
http://lucstechblog.blogspot.com/2019/07/esp-webserver-tutorial-part-2-button.html
http://lucstechblog.blogspot.com/2019/08/esp-webserver-tutorial-part-3-button.html
http://lucstechblog.blogspot.com/2019/08/esp-webserver-tutorial-part-4-slider.html

https://lucstechblog.blogspot.com/2019/09/esp-webserver-tutorial-part-5-neopixel.html

I use a Dallas DS18B20 temperature sensor for this purpose but you can easily change the code for using it with an LDR or potmeter or any other sensor that supplies a value.

The code for the ESP32 is almost similar to the code for the ESP8266. The code is written in C++ more broadly known as Arduino language. You'll find the complete program further on and after the explanation I'll give you the necessary changes for the ESP32 which are minimal.

ESP8266 Breadboard setup

For this example I am going to use the usual breadboard setup for a Dallas DS18B20 thermometer with a Wemos D1 mini.



The Dallas DS18B20 Thermometer does not use a lot of current so can be powered directly from the ESP8266. The sensor is connected to D4 of the ESP8266 and uses a 4.7k pull-up resistor. You can use any other IO pin as long as you adjust the program.

ESP32 breadboard setup

The ESP32 breadboard setup is taken from my book about the ESP32. You can find a link to my book at the bottom of this page.



The Dallas DS18B20 is attached to IO pin 23 (D23) but you may attach it to another pin if that is more suitable for your own project. Just do not forget to adjust the program accordingly.

ESP8266 Program

As stated before this program leans heavy on two previous discussed programs: ESP webserver and Javascript Gauges. Find the links to these programs and stories at the beginning of this entry. Please re-read these stories for a complete understanding of this program.

As usual I will give you the complete code first.


// ======================================================
// Webserver program that sends temperature information
// as a Gauge to a webpage.
// by Luc Volders
// ======================================================

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

ESP8266WebServer server(80);

#include <OneWire.h>
#include <DallasTemperature.h>

#define ONE_WIRE_BUS D4

// Setup a oneWire instance 
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);

// Your routers credentials
const char* ssid = "XXXXXXXXXXXXXXXXX";
const char* password = "YYYYYYYYYYYYYYY";

// =========================================
// This is where we build the HTML page
// =========================================
String getPage()
  {
  sensors.requestTemperatures();
  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 Gauge demo</title>";
  page += "<body style='background-color:powderblue;'>";
  page += "<style>";
  page += "</style>";
  page += "</head>";
  page += "<body>";
  
  page += "<h1 style='color:red'>Hobby room";
  page += "<br>";
  page += "temperature</h1>";
  
  page += "<div id='gauge_div' style='width:280px; height: 140px;'></div>";
  page += "<br>";
  
  page += "<FORM action=\"/\" method=\"post\">";
  page += "<button type=\"submit\" name=\"button1\" id=\"button1\" value=\"but1\" onclick=\'update()\'>CLICK FOR UPDATE</button>";
  page += "</form>";
  
  page += "<script type='text/javascript' src='https://www.gstatic.com/charts/loader.js'></script>";
  page += "<script type='text/javascript'>";
  page += "google.charts.load('current', {'packages':['gauge']});";
  page += "google.charts.setOnLoadCallback(drawGauge);";

  page += "var gaugeOptions = {min: -15, max: 50,";
  // yellow color changed to blue
  page += "yellowColor: '#1a66ff',";
  page += "yellowFrom: -15, yellowTo: 15,";
  page += "greenFrom: 15, greenTo: 25,";
  page += "redFrom: 25, redTo: 50, minorTicks: 5};";
  page += "var gauge;";

  page += "function drawGauge() {";
  page += "gaugeData = new google.visualization.DataTable();";
  page += "gaugeData.addColumn('number', 'Temp.');";
  page += "gaugeData.addRows(1);";
  page += "gaugeData.setCell(0, 0,";
  page += String(int(sensors.getTempCByIndex(0)));
  page += ");";
  page += "gauge = new google.visualization.Gauge(document.getElementById('gauge_div'));";
  page += "gauge.draw(gaugeData, gaugeOptions);";
  page += "}";

  page += "function update() {";
  page += "}";
 
  page += "</script>";  
  page += "</body>";
  page += "</html>";
  return page;
  }


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


// ==================================================
// Handle submit form
// ==================================================
void handleSubmit()
{   
   if (server.hasArg("button1"))
      {
      Serial.print("The temperature is: ");
      Serial.print(int(sensors.getTempCByIndex(0)));
      Serial.println(" degrees C");
      } 
  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);

  // Start up the library
  sensors.begin();
}


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

Let's have a closer look at the code so you may change it for your own purposes.

The first part of the program contains the obvious things. The libraries for the webserver and Dallas DS18B20 are loaded and the OneWire library also.


#define ONE_WIRE_BUS D4

This line is important cause here is defined at which pin the Dallas DS18B20 is connected.  I used D4 but you can change that to any other pin that might be more practical for you.


// Your routers credentials
const char* ssid = "XXXXXXXXXXXXXXXXXXXXXX";
const char* password = "YYYYYYYYYYYYYYYYYYYYYY";

Do not forget to change the XXXX and YYYY in these lines to your own routers name and password.

In the getPage() routine the webpage is build. I will not go over this as it was covered in the stories about building a webpage. I will just highlight the important parts.

sensors.requestTemperatures();

This line makes sure that the Dallas DS18B20 is activated.

page += "<div id='gauge_div' style='width:280px; height: 140px;'></div>";

In this line the space on the webpage is created that will contain the Gauge. Both the width and the height of the Gauge are defined. Alter these to your own whishes or likings.

  page += "<FORM action=\"/\" method=\"post\">";
  page += "<button type=\"submit\" name=\"button1\" id=\"button1\" value=\"but1\" onclick=\'update()\'>CLICK FOR UPDATE</button>";
  page += "</form>";

The above lines put a button on the webpage below the Gauge. Pressing the button wil send a signal to the ESP and the page will be updated with the temperature at this moment.

  page += "<script type='text/javascript' src='https://www.gstatic.com/charts/loader.js'></script>";
  page += "<script type='text/javascript'>";
  page += "google.charts.load('current', {'packages':['gauge']});";
  page += "google.charts.setOnLoadCallback(drawGauge);";

The Javascript library for the Gauge is loaded from the internet, and activated.

  page += "var gaugeOptions = {min: -15, max: 50,";
  // yellow color changed to blue
  page += "yellowColor: '#1a66ff',";
  page += "yellowFrom: -15, yellowTo: 15,";
  page += "greenFrom: 15, greenTo: 25,";
  page += "redFrom: 25, redTo: 50, minorTicks: 5};";
  page += "var gauge;";

Here is a nice trick. The variable gaugeOptions defines that the Gauge will show temperatures from -15 to 50 degrees Celsius.
My gauge starts its scale in blue. Blue is the color that represents cold. However the Google Charts library does not recognise blue as a standard color. So I redefine yellowColor to '#1a66ff' which is blue.

There is a simple way to get RGB codes for your own purpose. You can find that method in a previous story I published on this weblog and which you can find here:
http://lucstechblog.blogspot.com/2019/10/choosing-colors-for-webpage-or-for.html

The lines also define where the blue, green and red legends start and end. In this example the blue runs from -15 to 15 degrees which I define as cold. The green which I see as a bearable temperature runs from 15 to 25 degrees and above that I think it is too hot and the scale is in red.

  page += "gaugeData.setCell(0, 0,";
  page += String(int(sensors.getTempCByIndex(0)));
  page += ");";

Here the cell in the datalist (0, 0) that contains the temperature is altered in such a way that it is filled with the value from the DS18B20.

If you do not own a DS18B20 you can alter the second line to a different sensor reading.

Suppose you own an LDR or a potmeter. Attach that to the analog input pin A0 and alter the second line to:

page += String(int(analogRead(A0));

In this case you need to alter the Gauges scale too.

page += "var gaugeOptions = {min: -15, max: 50,";

The values should then be altered to min: 0 and max: 1024.

Do not forget to alter the lines in the handleSubmit() routine and the setup() routine to what is needed for your sensor.

Thats all.

ESP32 Changes

The Changes for the ESP32 are as mentioned before minimal.

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


ESP8266WebServer server(80);

Have to be changed in:

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


WebServer server(80);

You also will need to change the line that defines where the Dallas DS18B20 is connected.

#define ONE_WIRE_BUS D4

Change the D4 in 23 as the thermometer will be connected to D23 on the ESP23. You may alter this to your own liking if you have altered the connectio on the breadboard.

That's all.

Gauges on the webpage

Start the program and open the Serial Monitor in the Arduino IDE. The Serial monitor will show you the IP adress of the ESP. You can also find it in your router like I described in the web-server stories.

Copy the IP number and put it in the URL field of your browser and the webpage with the Gauge will appear in the browsers window. It looks like the page shown at the beginning of this story.


This is how it looks on a phone's webpage.

Click the button for the current temperature.

Have fun

Luc Volders

Friday, October 7, 2022

Arduino controlled maze

For an index to all my articles click this text

Usually we go to France for our Hollidays. And a few years ago we went to a region called Jura. In this region were a lot of shops that sold wooden toys. And one of these toys intrigued me. It was a maze game.



As you can see the maze is suspended in a frame and the knobs at the front and side make it possible to tilt the maze horizontally and vertically. By tilting the maze you can make the ball move and the object is ofcourse to direct the ball to the exit. It was not the maze that intrigued me but the mechanism to tilt it in both directions.

When I made my gesture controller I immediately thought that it would be a nice project to build this maze and control it with the gesture controller. And on a rainy saturday I build a prototype which I am going to show you here.

Maze generation.

The first step in building a maze is designing one. Luckily you do not have to do that yourself. I quick search with Google revealed a number of on-line maze generators. A real easy one can be found at: https://xefer.com/maze-generator



As you can see I generated a maze with a width of 10 columns and a height of 10 rows. As cell size I chose 30. A larger figure for the cell size will make the picture bigger. But that is not really important, as you can see later on.

You can find another maze creating program on this website:
http://www.mazegenerator.net/Default.aspx
This one is in fact more extensive as it can also make circular mazes etc. Just choose the one you are most comfortable with.

When I created a good looking maze I pressed Prt SCR (print screen) on my keyboard and made a screendump.
I then pasted the screendump in a drawing program and I cut out the maze and then imported the maze into Office.
In Office I scaled the picture to what I needed  and then printed the maze.



Scaling the maze is important. I bought some black beads on a market and they were 1 cm in diameter. So the corridors of my maze should be at last 1 cm wide. To make sure the beads would not get stuck I decided to make the corridors 1,5 cm wide. For the walls of the maze I used cardboard which was approximately 3 mm thick. So a cooridor would be 1,5 cm + 3 mm = 1.8 cm. I rounded that to 2 cm for convenience. As my maze had 10 corridors the total width and height would be around 20 cm x 20 cm.

When the maze was printed i lay it on a piece of cardboard and with a pen pressed the lines of the maze into the carton. Next I used a pen to trace the lines in the carton so they would be clearly visible.



Next step was to cut carton strips with a height of 2 cm. With these strips I made the walls of the maze and the walls of the corridors in the maze. I just cut the strips to length and glued them with hotglue.



I realised that you would get bored with playing with the same maze all the time. So I made a larger container to put the maze in. That way I could build several mazes and exchange them without having to rebuild the complete construction.

Next step was to have the container moving.

The electronics

The maze should be tilted horizontally and vertically. I was going to use two servo's for that purpose.

As this is a simple setup I used an Arduino pro micro for this project. You could use any Arduino which has at least 6 IO ports free. Just adjust the software to the port numbering. I used actually the same Arduino micro I used for the mouse simulation with the gesture controller I used in this project:

http://lucstechblog.blogspot.com/2019/11/sw520-mouse-gesture-controller-part-2.html

The gesture controller itself was described in detail in this story:

http://lucstechblog.blogspot.com/2019/11/an-easy-gesture-controller.html


The gesture controller is attached to the Arduino pins D6, D7, D8 and D9. It is important that the wires from the Gesture Controller are attached to the right Arduino pins otherwise the movement of the construction is unpredictable. Use the following wiring schematic:

D6  attached to UP
D7  attached to DOWN
D8  attached to LEFT
D9  attached to RIGHT

The first servo is attached to pin 4 and that controls the UP and DOWN movement. The second servo is attached to pin 5 and that controls the LEFT and RIGHT movement.

The Software

The software is actually quite simple. It looks at the position of the Gesture Controller and sends the state (UP, DOWN, LEFT, RIGHT, NEUTRAL) to some program lines that translate these to servo angles.

Here is the complete program:



/*SW520 servo control
  Luc Volders

Decides which way the servos will go by checking
which SW520 makes contact and which does not

using 4 SW520 put in a square form
top:    D6
Bottom: D7
Left:   D8
Right:   D9
*/

#include <Servo.h> 
 
Servo myservo;  // create servo object  

Servo myservo2; // for second servo

int dig1, dig2, dig3, dig4;
int pos = 0;    // store servo position

void setup()
{
  Serial.begin(115200);
  myservo.attach(4);
  delay(50);
  myservo2.attach(5);
  delay(50);
  for(int i=70; i<110; i++)
  {
    myservo.write(i);
    myservo2.write(i);
    delay(30);
  }
}

void loop() 
  { 
  dig1 = digitalRead(6);
  dig2 = digitalRead(7);
  dig3 = digitalRead(8);
  dig4 = digitalRead(9);

    if( (dig1 == 1) & (dig2 ==1) & (dig3 ==1) & (dig4 ==1))
      {
      myservo.write(90);  // neutral position
      myservo2.write(90); // neutral position
      }
    
    if (dig1 == 0)
      {
    //going up
    myservo.write(110);  // servo to 20 deg up
      }

    if (dig2 == 0)
    {
    //going down
    myservo.write(70); // servo to 20 deg down
    }

    if (dig3 == 0)
      {
      //going left
      myservo2.write(110);  // 20 deg left
      }

    if (dig4 == 0)
      {
      //going right
      myservo2.write(70);  // 20 deg right
      }
    
  delay(300);
}

As always I will show you how the program works step by step.

#include <Servo.h> 
 
Servo myservo;  // create servo object 

Servo myservo2; // for second servo

The servo library is loaded and connected to two servo instances: myservo and myservo2

  myservo.attach(4);
  delay(50);
  myservo2.attach(5);
  delay(50);

In the setup() the servo instances are coupled to the actual pins where the servo's are connected to. The first servo will be connected to pin 4 and the second to pin 5.

  for(int i=70; i<110; i++)
  {
    myservo.write(i);
    myservo2.write(i);
    delay(30);
  }

Assuming that both servo's are in the starting position (90 degrees) we move them slowly to a position where the board will be slightly tilted (110 degrees). This way we are sure they work as planned.

The loop is where the Gesture Sensor is read and the sensors put in the position the Gesture Sensor indicates.

  dig1 = digitalRead(6);
  dig2 = digitalRead(7);
  dig3 = digitalRead(8);
  dig4 = digitalRead(9);

The values of the Gesture Sensor are read and put in some some helper variables.

    if( (dig1 == 1) & (dig2 ==1) & (dig3 ==1) & (dig4 ==1))
      {
      myservo.write(90);
      myservo2.write(90);
      }

If all inputs from the Gesture Sensor are 1 (HIGH) then the sensor is in the neutral position and the servos will put the maze in the horizontal position.

    if (dig1 == 0)
      {
    //going up
    myservo.write(110);  // servo to 20 deg up
      }

If the Gesture Sensor points in a direction the servo will tilt the maze slightly. In this case the Gesture Sensor points upwards so the servo will tilt 20 dregrees UP which is enough to get the bead rolling.


    if (dig2 == 0)
    {
    //going down
    myservo.write(70);  // servo to 20 deg down
    }

This is the same as the previous piece of code but now the Gesture Sensor points DOWN and the servo will tilt slightly in the other direction.

The same is repeated for the LEFT and RIGHT positions.

That is all.

A first test



The video shows how this works. As you can see tilting the Gesture Sensor moves the servo arms.

The construction

The maze is build and put in a container as described above.
Now make an open frame slightly larger as the container. Attach the servo to the frame and glue it to the container. As you can see I attached the servo on the left side and made a suspension on the opposite side. In this prototype the suspension was just a small stick of plastic: actually some filament from my 3D printer.

Last step is to put this contraption in a frame.


Ok, OK laugh at my primitive drawing capabilities but it shows how the frame which has the container inside is suspended in a standing frame. One servo is attached to the standing frame on the right side (the blue blob) the other servo is at the back attached to the inner frame as the foto showed.

Real life.

And here is how it works.


It is all very primitive and not nicely finished. But hey it is a prototype and it works !!!

Future enhancements.

Well I have some ideas to finish this. First the suspension at the opposite side of the servo's could be made with 8mm rods and bearings. These are both available from your diy 3D printer shop or DIY hardware store.

The maze itself could be 3D printed.

The software works flawlessly.
A first extension would be to replace the Arduino Pro Micro with an ESP8266 or ESP32 and control the maze through a website. The second extension could put an IP-camera above it, made with a Raspberry or ESP32) and you could have your family and friends operate the maze from all over the world......

Have fun !!!!
Till next time

Luc Volders