I was very excited by the Lego challenge and I had plenty of silly ideas in mind, ranging from a device that would prepare tea to a robot that would wake up my daughters on 8-bit music beat, open the store, and drag some clothes. But nothing that would really motivate me to charge the EV3 brick for another run.
On Christmas Eve, while watching YouTube videos I stumbled upon a video on the Practical Engineering channel:
I found it so cool that I decided to find some time to build it for my daughters and share the project as part of the Lego challenge.
DesignThe core idea is to be able to point to objects in the sky. It should also be able to track objects, like a satellite, the moon, or even the sun. The main users will be my daughters. They are the reason why we have Alexa in the first place, to let them listen to their favorite music (don't ask me how much time we endured the French version of "Let It Go").
The device is rather simple. I'm using two large motors. The first one drives the azimuth orientation using a large Lego turntable and a gear reduction of 1:7. The second one directly drives the elevation indicator.
There are many ways to compute the azimuth and elevation corresponding to a given body (https://en.wikipedia.org/wiki/Horizontal_coordinate_system, https://www.photopills.com/videos/planner-find-sun-or-moon-determined-position) but it is not my intent to recreate the wheel. I will thus use PyEphem that provides basic astronomical computations for Python.
InstructionsI assume that you completed and understood the third mission before reading those instructions.
The device
The device is composed of three parts, the EV3 brick, the base that controls azimuth orientation, and the tower with the elevation indicator. The design is rather crude and I mention some interesting follow-ups in the last section.
There are two important things to note:
1. I had to use the longest cable for the tower motor to ensure a smooth rotation. If you look closely I also maintain the cable in such a way that it doesn't impede the rotation.
2. There is a gear reduction for the azimuth so when computing the rotation needed, we will need to adjust it using a 1:7 reduction.
The Skill
Based on the third mission, I just updated the model (models.json) to support a move intent and a track intent, both using the same slot type TargetType which is an enumeration of all the bodies supported by the gadget. The list is not exhaustive as PyEphem catalogue is extremely rich.
I then updated the lambda code (index.js) to support those two intents: MoveIntent and TrackIntent. I won't go through them as I just forward the target in both case.
The Alexa Skill is in French as it is my daughters native language.
The gadget code
The code is again heavily based on the third mission. I duplicated the third mission and created a fifth one. I then updated the gadget code (mission-05.py).
To track objects, the gadget will need your current position. Be sure to use strings for latitude and longitude, otherwise it won't behave as expected.
# Current GPS coordinates for better accuracy
# Those can be acquired with https://www.mooncalc.org/ by filling your address.
# We could also use an API call to fetch those (google places for ex.) but relying on the
# ISP is rather imprecise in my case.
lat = '48.9146689'
lon = '2.244790'
The gadget also assume that it starts pointing at the north with an elevation of 0 degree.
self.currentAzimuth = 0 # assuming we boot with pointer to north position, at 0
self.currentElevation = 0 # assuming we boot with elevation // to the ground, at 0
The most interesting piece of code part it the following:
def _moveTowards(self, body):
home = ephem.Observer()
home.lat, home.lon = lat, lon
home.date = datetime.datetime.utcnow()
body.compute(home)
azimuth = round(deg(float(body.az)),1)
altitude = round(deg(float(body.alt)),1)
diffAzMotorAngle = azimuth - self.currentAzimuth
diffAltMotorAngle = altitude - self.currentElevation
self.azimuthMotor.on_for_degrees(30, diffAzMotorAngle * azimuthGearRatio)
self.elevationMotor.on_for_degrees(30, diffAltMotorAngle * altitudeGearRatio)
self.currentAzimuth = azimuth
self.currentElevation = altitude
I declared an observer (my device) at a specific date (now) and asked where to look at (azimuth and altitude) to see the object. I then mapped the values to motor rotations taking into account the azimuth gear ratio.
PyEphem allow us to enrich the catalogue with more bodies like the ISS or even Polaris star:
if target in Target.ISS.value:
# The TLE can be found on NASA website: http://spaceflight.nasa.gov/realdata/sightings/SSapplications/Post/JavaSSOP/orbit/ISS/SVPOST.html
return ephem.readtle('ISS',
'1 25544U 98067A 19357.53566238 .00016717 00000-0 10270-3 0 9000',
'2 25544 51.6386 142.6138 0007507 66.8859 293.3082 15.50125057 4627'
)
if target in Target.POLARIS.value:
return ephem.readdb("Polaris,f|M|F7,2:31:48.704,89:15:50.72,2.02,2000")
I used PyEphem tutorial to implement the tracking code, and mooncalc and suncalc to ensure the results were correct.
Once the code is deployed, we will need to install PyEphem. It will take some time, roughly 45 minutes:
robot@ev3dev:~/agt-missions/mission-05$ sudo pip3 install pyephem
Finally, it is time to run the code. As my native language use accents, I also need to ensure UTF-8 locale are used:
robot@ev3dev:~/agt-missions/mission-05$ export LC_CTYPE=en_US.UTF-8
robot@ev3dev:~/agt-missions/mission-05$ export LANG=en_US.UTF-8
robot@ev3dev:~/agt-missions/mission-05$ sudo python3 mission-05.py
ResultIn this sequence I ask Alexa to point to the Moon, the Sun, and ISS:
In this sequence I ask Alexa to track ISS:
Here is what should print the program when run via SSH:
robot@ev3dev:~/agt-missions/mission-05$ sudo python3 mission-05.py
[sudo] password for robot:
INFO:agt.alexa_gadget:Attempting to reconnect to Echo device with address: DC:54:D7:43:D8:CC
INFO:agt.alexa_gadget:Connected to Echo device with address: DC:54:D7:43:D8:CC
Gadget36E connected to Echo device
Control payload: {'target': 'la lune', 'type': 'move'}
Move command: (la lune, False)
Control payload: {'target': 'le soleil', 'type': 'move'}
Move command: (le soleil, False)
Control payload: {'target': 'la station spatiale internationale', 'type': 'move'}
Move command: (la station spatiale internationale, False)
Control payload: {'target': 'la station spatiale internationale', 'type': 'track'}
Track command: (la station spatiale internationale, False)
Follow-upsWhile the current device works very well and is accurate enough for my use cases, there are a bunch of improvements that I would like to make in the following days/weeks:
- Redesign the elevation mechanism to have the corresponding large motor located on the base; this in order to improve the stability and rigidity of the base, reduce the azimuth tower weight, and ensure the large motor cable doesn't impede the tower rotation. It will maybe improve the look as well.
- Use an external compass (homemade sensor) to remove the need for calibration before running the program and also to learn how to interface my own sensors to the EV3 brick.
- Generate the target list based on a catalogue and provide contextual information about the given target (can just be the Wikipedia introduction for the target if found).
- Find a way to reduce backlash. I can use gear reduction for the elevation indicator and maybe use a worm gear to turn the turntable, both will reduce backlash and increase resolution.
- Stretch: I don't really intend to move the device but I might make a GPS sensor or use a precise enough API (IP Geolocation) to get my current location and remove the last manual inputs of the program.
Comments