Project PROBE Voyager
I was writing this while trying to keep the nature of the project secret and realised that it was basically impossible. So, this is the project I’ve been working on; Voyager. It’s basically a two-axis sign using stepper motors that will point to Voyager I and display its distance.
Last week I introduced the first bit of this which was testing out the Arduino Rev 2 that the whole thing is going to run off. As I wrote, it needs to be able to connect to the Internet and get its own orientation. So that it can point to where Voyager I relative to where it is. The second part which occupied a lot of the week has been working out the mathematics and geometry that will allow it to work. The process will be:
- During the setup, when booting, the Arduino will grab its location from the Unwired Labs Geolocation API. It only needs to do this once when turned on.
- Then during setup it needs to calibrate the magnetometer and find magnetic north.
- Then it's into the loop. First, grab the coordinates (right ascension and declination) and distance of Voyager 1 from here. via a simplified API. Luckily I already set one up for decline.online that I can probably piggy-back on. This only needs to be done every hour or so; the celestial coordinates of Voyager are pretty stable.
- Run through the calculations that will use the right ascension and declination of Voyager with longitude, and latitude of the Arduino to work out an azimuth (heading) and altitude for Voyager from where it is.
- Using the magnetometer’s reading, turn the motors to point the right way.
Astronomy Maths
This flow reads very simple but I can already see there’s a bunch of things to think about: The Arduino needs to know its datetime in order to work out the heading and altitude of Voyager and Arduinos have no internal clock. Though the speed is obviously consistent, it changes relative to Earth as we move in our orbit (and Earth rotation) towards it, and away. You can see this on the visualisation of decline.online. Anyway, I decided to run the whole thing through Excel to check the maths and inputs before finding a way to implement on Arduino. I’ll share all of these materials this once the project’s all wrapped up but I found this a useful way of checking how the numbers would work:
The two crucial numbers I need are the azimuth (or heading) and altitude of Voyager for the point of view of the Arduino’s longitude and latitude. I found these really useful guide to converting those coordinate systems through what reads as relatively simple trigonometry.
The first thing you need to do is calculate your Local Sidereal Time (LST). This is the time at your location relative to the movement of the celestial sphere rather than the sun. You can check out your sidereal time here but I wanted a way to calculated it on the Arduino without it storing an enormous lookup table. I used a mix of guides to help but this one was the most helpful since it has worked examples and uses a formula that gives accuracy to within 0.001 seconds over 100 years.
The first stage in calculating local sidereal time is to calculate the number of days (including fractions of a day) since a date called ‘J2000’ - this is midday on 1 January 2000 at Greenwich. From this you count the time that’s elapsed and then perform a function on it to get the sidereal time at your coordinates. Once you have Local Sidereal Time, you subtract the right ascension of Voyager to get an hour angle. Hold on to this idea because this is almost entirely where everything went wrong.
sin(altitude) = sin(δ) sin(φ) + cos(δ) cos(φ) cos(H)
cos(azimuth) = { sin(δ) - sin(φ) sin(a) } / cos(φ) cos(a)
You then take these two formula above, one for altitude and one for azimuth. With the hour angle (H), latitude (φ) and declination (δ) you can now calculate the altitude and once you have the altitude you can calculate the azimuth and (in theory), huzzah! (As below):
However, throughout this process I kept checking both the live ‘tracking’ planetarium and this calculator (which also has helpful documentation) using the same formulae and found they were getting totally different results every time. If you talked to me at the tail end of last week then it would have been the only ting I was talking about. I spent hours tweaking the formulae and getting no closer.
The first thing you need to do is calculate your Local Sidereal Time (LST). This is the time at your location relative to the movement of the celestial sphere rather than the sun. You can check out your sidereal time here but I wanted a way to calculated it on the Arduino without it storing an enormous lookup table. I used a mix of guides to help but this one was the most helpful since it has worked examples and uses a formula that gives accuracy to within 0.001 seconds over 100 years.
The first stage in calculating local sidereal time is to calculate the number of days (including fractions of a day) since a date called ‘J2000’ - this is midday on 1 January 2000 at Greenwich. From this you count the time that’s elapsed and then perform a function on it to get the sidereal time at your coordinates. Once you have Local Sidereal Time, you subtract the right ascension of Voyager to get an hour angle. Hold on to this idea because this is almost entirely where everything went wrong.
sin(altitude) = sin(δ) sin(φ) + cos(δ) cos(φ) cos(H)
cos(azimuth) = { sin(δ) - sin(φ) sin(a) } / cos(φ) cos(a)
You then take these two formula above, one for altitude and one for azimuth. With the hour angle (H), latitude (φ) and declination (δ) you can now calculate the altitude and once you have the altitude you can calculate the azimuth and (in theory), huzzah! (As below):
However, throughout this process I kept checking both the live ‘tracking’ planetarium and this calculator (which also has helpful documentation) using the same formulae and found they were getting totally different results every time. If you talked to me at the tail end of last week then it would have been the only ting I was talking about. I spent hours tweaking the formulae and getting no closer.
Eventually I clocked that the problem in implementing these formulae all arose in the converting between the different coordinate conventions. Americans tend to use hours, minutes and seconds or degrees, minutes and seconds while Europeans tend to just use degrees. Because Europeans are sensible. Anyway, the whole time I had right ascension down as 17.whatever degrees when in fact it was 17.whatever hours! (eg. roughly around 250 degrees). Once that was multiplied by 15 (34 hours = 360 degrees) everything fell into place.
A new API
So assuming this all works, the next stage was to build an API that would stream the distance, right ascension and declination to the Arduino. Luckily I can hack together the one I made for decline.online together. This uses Python’s Beautiful Soup to scrape HTML contents from URLs. This was a pretty straightforward presence, made significantly easier by the fact that, unlike decline.online, it doesn’t need continuous data and it’s getting everything from one source. (I'll post it up with the project when done as well.)
Crunching the numbers on Arduino.
To recap, the idea is: when the Arduino is first turned on it grabs location data from Unwired Labs (you can only do this up to 100 times a day.) Once it has that it enters the loop where every minute or so it is calling time and date and celestial coordinates for Voyager. With these it can constantly calculate an adjusting heading and azimuth as the Earth and Voyager move.
This is the version I started building here. Here you can see where the Arduino code grabs the time and date data from the API and begins calculating the Sidereal Time. ‘d’ is the total amount of time since J2000 which is the first number you need in the run of calculations. However, immediately, the project quickly ran up against the Arduino’s limited memory and ability to calculate big numbers. The serial monitor shows the numbers are rounded and inaccurate. Arduino does strange things to big numbers that I can’t fully grasp. I spent some time reading around different ways of encoding long numbers in the Arduino's memory but it seemed like it was going to be a lot more work than I really needed. Instead I decided to move the heavier calculations over to the python API on the server which would then give the Arduino a lot of the key components of what it needs to calculate the heading and azimuth.
Once I put the exact same calculations in Python and ran them from the server and found it was delivering results exactly the same as the Excel model with no loss of accuracy. However, the problem here is that the calculations require the longitude quite early on. But these can only be gathered from Unwired Labs 100 times a day and depends on the location. Essentially, there's no simple way of getting both Arduino's location and Voyager's location from the same source. However, playing around with the maths you can actually allow for the longitude and latitude at the very end of the process by adding it on to greenwich sidereal time once it’s been reduced to the range of 0-360 degrees rather than before reducing and get the same outcomes. This means we’re not sending numbers with dozens of digits to the Arduino which is where it struggles.
So in this version, a lot of the harder calculations are done-server side with the final numbers delivered to the Arduino so it’s not crunching the big numbers at the beginning of the process when you have to calculate sidereal time. Now the API sends the current sidereal time at Greenwich to which I simply add the longitude from Unwired Labs. Since in this model the maths the Arduino will be doing occur after the bigger numbers are crunched it means that the results are much more accurate without Arduino's memory issues.
Then was then quite a lot of fiddling around to get the maths to run properly on the Arduino which actually turned out to be easier than I was expecting and finally I had the Arduino spitting out accurate and updating altitude and azimuth figures for Voyager! As you can see in the screenshot, the altitude and azimuth are not only accurate but adjusting minute-to-minute.
All The Fun of The Fair
Turns out that further down Alice Rawsthorne's Design as an Attitude that the author addresses some of the concerns I had about the way that design is popularly represented and consumed. Addressing the question of 'why make a chair about e-waste?' isn't quite achieved but there's a wonderful quote from Reyner Banham in 1967 writing for New Society:
The area worst blighted by furniturization lies right under the human arse... Check the area under yours at this moment. That chances are that it is occupied by an object too pompous for the function performed, over-elaborate for the performance actually delivered, and uncomfortable anyhow.She's quite scathing of the role of the commoditisation of design exemplified by the Salone and the cycnical appropriation of it by 'super-capitalists.' However, there's little work done to re-address the formation of an aesthetic sensibility based on what works at Salone at the cost of critical power. She mentions the role of other up and coming fairs; Eindhoven and Istanbul as counterpoints to the dry commercialism of Milan but it would be useful to see suggestions of how we might push back against Milan's creeping homogeny rather than run away from it.
Things I learned this week
- I learnt a good joke about a drowning man who asks God for help. (Ask me when you see me and I'll tell you.)
- I learnt a breathing exercise that reduces flight or fight response. I don't really suffer from this but I found it useful in controlling my body when tired. You have to imagine cat on your belly and breathe in for four and out for eight.
- I'm currently listening to the bit of the podcast about Avicenna. It's funny that I did some training this week where they were saying how in British culture, extolling what you're good at is seen as arrogance and you're expecting to constantly put yourself down. It was normal in the Islamic tradition for philosophers and thinkers to go on about how great, gifted and close to god they were so though in his writings he comes across as very arrogant; for instance, dismissing his learning of medicine as trivial and easy, it was pretty normal to do.
Channel Recommendation.
An oldie but a goldie. The boys of Prepare to Try reformed about a year ago as RKG (Rory, Krupa, Gavin) As I spent my weekend coding I had their Dark Souls II series on in the background like a sort of deep background sound.