Category Archives: ESP32

Weekend Update…

This is just a short set of updates for my weekend projects, meant to keep me in the habit. I’ll write up a more complete version of these projects going forward.

First of all, a new acquisition. My Anet A8 3D printer has proven to be, well, not the most reliable of gadgets. I still haven’t gotten around to fixing its heated bed, but should get to it shortly. But as it happens, a small windfall came my way, so I decided to get a Creality CR-10 which I caught on a good price for less than $400. Unlike the laser-cut, hours-to-assemble Anet A8, the Creality is mostly assembled. It has a 300mmx300mm bed, a much taller range of travel, and is constructed by aluminum extrusions that make for a nice, stiff, and easy to assemble printer. I mostly assembled it in a little less than an hour, but ran out of steam and decided to go to a movie with Carmen and then watch the Superbowl. I’m hoping to print a Benchy when I get home tonight: the only thing I have left to do is get the bed leveled.

I also spent some more time on the ISS clock. I added a new display mode that shows details of upcoming passes, including a diagram of the pass, showing its path across the sky and its maximum elevation. I also updated the epoch that the Plan 13 code was using so that it would be more accurate, and now it compares to within about a degree or so with what other, more sophisticated models have. There are still a couple of lingering glitches. Occasionally it looks for the next pass before the current pass is complete. I suspect that is because I used a number of global variables to communicate between processes, and something in the logic isn’t quite right. But as they say, any program worth writing is worth rewriting. I’ll try to get a version of the code up on github tonight, even though it’s kind of embarrassing.

Stay tuned for CR-10 print experiences and more on the ISS clock.

More progress on the ISS clock project…

I haven’t posted an update here recently, but I am (mostly) living up to my New Year’s resolution to spend at least 30 minutes a day working on a project. This has taken the form of some stupid but necessary chores (like fixing the broken pull cord on my lawnmower) but has mostly taken the form of additional incremental additions and improvements to my ISS clock project. This has mostly taken the form of noting a small deficiency, and then working until that deficiency is ameliorated.

The ESP32/Arduino environment still has access to the FreeRTOS operating system below to create tasks, semaphores and queues. I decided that I would implement the program as a set of tasks of different priorities. One task’s job is to compute the current latitude, longitude, altitude and azimuth for the satellite. Another lower priority task scans forward in time, and finds the next time when the satellite rises and sets. When it finds those, it pauses until the current time is beyond the found set time, and then continues searching for the next rise/set pair. The final task runs the display, showing all the current information. If the time of the next satellite rise time (or AOS — Acquisition of Signal) is set, then the display process will give a countdown in hours/minutes/seconds.

This was all working reasonably well, except that I noticed that the time display would frequently “jump” a second, skipping from 42 seconds to 40 seconds in countdown, and sometimes even in the clock display jumping from 10 to 12 seconds for example. I didn’t think any critical path in the code would account for anywhere near that amount of delay in switching between processes, but tried reorganizing the code in various ways to be sure.

In the end, I realized that it had nothing to do with multitasking or the like. I had written code in two different places to convert an internal representation of time used by my Plan 13 satellite library into H:M:S format, and had committed the same error in both locations.

The thing that I realized is that unlike normal Unix time calls, internally my code represents the current time of day as a double which represents fraction of a day. To step the time forward by one hour, I increment that value by 1/24. I have a function whose purpose is to convert this internal representation separate hours, minutes, and seconds.

Here is a (slightly edited) version of my original code.

[sourcecode lang=”cpp”]
void
DateTime::gettime(int &h, int &m, double &s)
{
double t = TN ; // TN is the time in fractions of a day
t *= 24. ;
h = (int) t ;
t -= h ;
t *= 60 ;
m = (int) t ;
t -= m ;
t *= 60 ;
s = t ;
}
[/sourcecode]

The problem appears to be rounding interacting with the timing of the display process. Staring at this code, I’m not sure what I was thinking. I rewrote this code in the following way:

[sourcecode lang=”cpp”]
void
DateTime::gettime(int &h, int &m, double &s)
{
double t = TN ; // TN is the time in fractions of a day
int ts = (int) round(t * 24. * 60. * 60.) ;
s = ts % 60 ;
ts /= 60 ;
m = ts % 60 ;
ts /= 60 ;
h = ts % 24 ;
}
[/sourcecode]

This code works much better. I had coded a similar routine in new code which had the same error. I must admit that I’m still a little fuzzy about how the timing of the display process interacts with this rounding issue to introduce the errors that I observed, but I suspect it has to do with the fact that I inserted delays in the display process to keep that process from updating somewhere around two times a second. I think that the prediction task (which runs for about twenty seconds usually) may be starving the low priority display task just often enough to cause the rounding error to manifest.

I’ll ponder it more later.

Things that are now percolating to the top of my todo list are to understand the event handling of the NtpClientLib library. Occasionally it will toss errors from the WiFiUdp.cpp file, and error handling is not appropriate (sometimes it doesn’t set time properly). I suspect I’ll have to dig into the networking code in the library a bit deeper.

Addendum: The display on this thing is one of those tiny 0.91″ OLED displays. It’s really at the limits of what I can comfortably read, and I’d like to have more space (and potentially color). I have some small 1.8″ LCD boards, but I stumbled across the M5Stack board which appears to be available on banggood.com. It looks like a cool little box.

I ordered it from this link on banggood for about $33. Besides having an ESP32 module, it includes a case, a 320×240 2″ color LCD panel, and three buttons. The larger display size and buttons are a great fit for my ISS project. When it arrives, I’ll quickly work on a port of this code to that.

If that doesn’t work, I’ll probably work on adapting it to some of the ST7735 modules I have lying around that I ordered from icstation.com.

Stay tuned for more progress, and eventually links to the git repository for the code when I am not embarrassed by the code.

Quick tinkering of an NTP clock with the ESP32

I spent a little time today trying to make the bare minimum code necessary for the ESP32 to connect to my WiFi network and synchronizing the time using NTP. It’s not really that amazing, but required a tiny bit of snooping around to figure out how to make it work. Archived here, just for fun.

[source lang=”cpp”]
/*
* tinkering a basic wifi shell/framework together
* duplicating work that I had done for the esp8266
* but which doesn’t appear to work on the ESP32.
*/

#include <NTPClient.h>
#include <WiFi.h>
#include <WiFiUdp.h>
#include <Wire.h>
#include <SSD1306.h>

SSD1306 display(0x3c, 5, 4);

const char *ssid = "**********" ;
const char *pass = "**********" ;

const char *ntp_server = "0.us.pool.ntp.org" ;

WiFiUDP ntpUDP ;
NTPClient timeClient(ntpUDP, ntp_server, -8*60*60, 5*60*1000) ;

void
wifievent(WiFiEvent_t event)
{
switch (event) {
case SYSTEM_EVENT_STA_GOT_IP:
Serial.println() ;
Serial.print("CONNECTED ") ;
Serial.println(WiFi.localIP()) ;
Serial.println("CONTACTING NTP SERVER") ;
timeClient.begin() ;
timeClient.update() ;
break ;
case SYSTEM_EVENT_STA_DISCONNECTED:
Serial.println("DISCONNECTED") ;
break ;
}
}

void
setup()
{
Serial.begin(115200) ;
delay(500) ;
Serial.println("ESP32 harness.") ;

WiFi.disconnect(true) ;

WiFi.onEvent(wifievent) ;

WiFi.begin(ssid, pass) ;
Serial.println("CONNECTING") ;

display.init() ;
display.setFont(ArialMT_Plain_24);
}

void
loop()
{
delay(1000) ;

Serial.print(‘.’) ;

display.clear() ;
display.setTextAlignment(TEXT_ALIGN_CENTER_BOTH);
display.drawString(64, 32, String(timeClient.getFormattedTime())) ;
display.display() ;
}
[/source]

Addendum: Here’s a quick video of it working, with a small extension to display the NTP address of the clock too.

Link

If I was going to port my ISS code to the ESP32 using the ESP-IDF framework, I’d need a driver for the SSD1306 OLED display.  It does seem like some people have been down this path before.  I haven’t tried any of the following, but a little quick googling revealed some promising links:

https://github.com/yanbe/ssd1306-esp-idf-i2c
https://github.com/imxieyi/esp32-i2c-ssd1306-oled
https://github.com/nkolban/esp32-snippets/tree/master/hardware/displays/U8G2

The last is perhaps most interesting, as the UG8 library is commonly used in Arduino sketches.

The ESP32 vs. the ESP8266

Over the last year I’ve spent a small amount of money and a larger amount of time accumulating a bunch of development modules from banggood. This began mostly with me getting some spare Arduino modules cheaply. Whereas an official Arduino might cost you $25 or so from Adafruit or Sparkfun, you can get a Geekcreit clone of the same board for about $4 including shipping from China.

But you can import some other fun things besides Arduino.

A year and a half ago, I had received my first ESP8266 boards based upon the Arduino form factor. These would cool boards, based upon the ESP8266 wireless module from Espressif. The cool thing about these boards is that you can use the Arduino environment that you might already be familiar with to program, but the controllers themselves are significantly more powerful, and include wireless access. I have a few of these Arduino formfactor boards around, but they turned out to be less helpful than I would like, as the pin outs are moderately different and few shields are compatible. So instead, I’ve accumulated a fair number of ESP8266 boards which are based upon the format called “Wemos D1 Mini”:

The Wemos D1 Mini

I’ve been having a lot of fun with these.

But in the last year, Espressif has started shipping a new chip, the ESP32, which has a number of cool new features, but which most notably include Bluetooth Low Energy (BLE) and a dual core processor. At first, these chips were fairly hard to get, and modestly more expensive, but now the pipelines appear to be full, and the necessary software support is in a pretty good state.

Banggood carries a good basic module for just $7.

And, you can get a module with an OLED module premounted for about $11.

I’ve had these ESP32 modules lying around for a while and haven’t done much with them. I thought today that perhaps I should dust them off and port my satellite prediction code to these modules, and make a tiny little gadget which could sit on my desk and notify me (maybe even via bluetooth on my phone?) of upcoming passes of the ISS or other amateur satellites.

I had prototyped such a thing using a small OLED display on the ESP8266, and had the code lying around, including the graphic display which is the same sort that is on my ESP32 board.  Here’s a video I made of the old code.

I was hoping that it would be straightforward to port the code to the ESP32. Sadly, a few minutes of work revealed that the interface to WiFi capabilities on the ESP8266 and the ESP32 were not entirely compatible. In particular, most of the networking on the ESP8266 was being driven by a series of callbacks which aren’t implemented (as far as I can tell) on the ESP32. I also used an NTP client library on the ESP8266 which might be unsupported on the ESP32.

So, it appears that I’ll need to do a bit more digging to make this work.

I’ve also begun to ponder that if the Arduino code between the ESP8266 and the ESP32 is less easy to keep compatible, then maybe I should simply not use the Arduino framework at all, and use the lower-level ESP-IDF framework for programming. It’s not clear how hard it will be to port the necessary OLED drivers (or what support already exists) but I might give it a try.

Ultimately my goal is to implement some code for the $11 module that wakes up, finds open or predefined Internet access, and synchronizes its time with NTP. It then contacts celestrak.com and downloads current orbital elements for the satellites I’m interested in, and then uses my satellite code to predict the position and passes of each satellite, displaying them on the tiny OLED display.

Hey, it sounds like fun. I’ll make the code available via github when I have it sorted out.

If this project sounds interesting, drop me a note on twitter (@brainwagon) or leave a comment.