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.