From my Notebook >

Raku Programming Tutorial: Detect Incoming Asteroids! ...With JPL, NASA, and Raku / Perl 6

Above: A screenshot of the script alerting us to nearby space objects! With a scant few decorative embellishments, to prime a sense of foreboding, and summon your inner space hero…

Today I wanted to try an interesting and unique scripting project, since I’m learning the Raku programming language.

In the end it was a pretty fun project, so I thought I’d make what I learned into a very basic, short-format tutorial, while I’m at it.

(No guarantees as to the code quality, since I’m new to this language…but it works! Please note that I do use Linux though, so Windows or Mac OS users may need to do a bit of extra research to tie this one off.)

Let’s figure out if any dangerous asteroids are nearby!

It turns out that NASA has plenty of exciting data / nightmare fuel, ready for a unique scripting project like this!

So our script will connect to NASA, and then tell us which asteroids are passing nearest to Spaceship Earth today.

And it’ll also tell us whether they’re a hazard to our spaceship, how large they are, and how fast they’re going!

Let’s dive in.

To Work with the NASA API, Let’s Install HTTP::UserAgent

Ensure you already installed Raku and then run this command:

zef install HTTP::UserAgent

I ran the command in my Linux terminal window, and watched as the correct files were installed so we can work with web data.

Then let’s get a NASA API Key!

You can generate a key at NASA’s API website.

They will email the key to you. It looks like a long string of letters and numbers.

NASA kindly requests that you limit your requests (uses of this script, for example) to less than 1,000 per hour.

Script Content Guide

This section will offer a quick way to review the script to understand what it’s doing.

Please note that I’d love to walk you through in more detail, but a) I’m looking to publish this before I run out of time to do so, and b) I have literal seconds left here!

Script Content Guide Items (Code Sections):

  • SETUP: Add your API key to the finished code.
  • IDEAS: Here you can see some ideas I shared, to improve the script later. You can skip these for now.
  • Part 1: Specify the modules we need to use.
  • Part 2: Specify the API key, date information, and NASA URL. Then set up the user agent for connecting to NASA.
  • Part 3: Make the request to NASA, and work with the data.
    • Part 3a.: Retrieve the JSON data from NASA.
    • Part 3b.: Sort asteroids by closest miss distance and take the top 3.
    • Part 3c.: Print out the information on the closest passes.

To use the Script Content Guide: Each list item above refers to a section of the code (starting with a pound sign or hash tag, #). In the finished script code below, find the code section starting with the #-sign, and review the code.

For help in understanding the finer workings, you can refer to the Raku Docs, or join the Raku IRC, Discord, or other community zone, or even ask a nearby AI bot…

I’ll try to update this tutorial in the future if anything seems it could use improvement.

Finished Script

Here is the finished script.

To run the script:

  1. Use a text editor to paste the script into a text file. (Text editor examples would include Geany or Notepad++.)
  2. Save the script to a file named “asteroids-nearby.raku”.
  3. Make it executable. In Linux, you’d type something like chmod +x asteroids-nearby.raku to accomplish this.
  4. Run the script: On my system, I run it by typing: ./asteroids-nearby.raku

Nice!

Don’t forget to add your NASA API Key! You’ll get the error “Failed to fetch data” if you don’t.

And have fun…

#!/usr/bin/env raku

# asteroids-nearby.raku - Display the top 3 nearest asteroid pass-bys today.
# You can compare the output with the official JPL/NASA page:
# https://www.jpl.nasa.gov/asteroid-watch/next-five-approaches

# SETUP:
# Add your API Key below.

# IDEAS:
# - Filter asteroids by time, to ensure their passing hasn't already happened today.
# - Use some more info from the API, like the speed information, or the official object URL.

# Part 1: Specify the modules we need to use

use HTTP::UserAgent;
use JSON::Fast;
use URI::Escape; # Import URI encoding functionality

# Part 2: Specify the API key, date information, and NASA URL. Then set up the user agent for connecting to NASA.

# API configuration
my $api-key = 'INSERT-YOUR-API-KEY-HERE';
# Ensure API key is set and valid
die "API key is required. Set your API key before running the script." unless $api-key;

my $today = DateTime.now.Date;
my $url = "https://api.nasa.gov/neo/rest/v1/feed?start_date={$today}&end_date={$today}&api_key={$api-key}";

# Creating a user agent
my $ua = HTTP::UserAgent.new(useragent => 'My Raku Client/1.0');

# Part 3: Make the request to NASA, and work with the data.

# Making the GET request
my $response = $ua.get($url);

# Checking the response
if $response.is-success {

    # Part 3a.: Retrieve the JSON data from NASA.
    my $data = try from-json $response.content;
    unless $data {
        say "Failed to get JSON data.";
        exit;
    }
    my $neos = $data<near_earth_objects>{$today.Str};

    # Part 3b.: Sort asteroids by closest miss distance and take the top 3 using ".head(3)".
    my @sorted-neos = $neos.sort({
        # Notice the "+" sign below, which converts the string data to numeric.
        # This numeric conversion enables the sorting functionality.
        +($_<close_approach_data>[0]<miss_distance><kilometers>)
    }).head(3);

    # Part 3c.: Print out the information on the closest passes.
    # I am using Org-mode formatting. You can adjust the items below to use whatever formatting you'd like.

    say "- Top 3 Closest Asteroids Approaching Spaceship Earth Today";
    # Let's take the sorted items one at a time, referring to each as a "neo":
    for @sorted-neos -> $neo {
        # Prepare the names for use inside our URL link
        my $encoded-name = uri-escape("Asteroid {$neo<name>}");

        # Finalize the search engine query URL & link, so we can click to look up info about the neo.
        my $search-url = "https://duckduckgo.com/?q={$encoded-name}";
        say "  - {$neo<name>} [[{$search-url}][Web Search →]]";

        # Note the syntax for getting nested data: (current list element's) close approach data -> close_approach_date_full
        say "    - Close Approach At: {$neo<close_approach_data>[0]<close_approach_date_full>} UTC";

        # Example of formatting distance, with the "Miss Distance":
        # Get the current neo's: close approach data > item 0 (first item) > miss distance > ...
        #     ... kilometers (formatted with 2 digits after the decimal point)
        say "    - Miss Distance: " ~ ($neo<close_approach_data>[0]<miss_distance><kilometers>.Num / 1_000_000).fmt('%.2f') ~ " million kilometers";

        # Finally, get the size and indicate whether hazardous.
        say "    - Size - Estimated Minimum Diameter (km): {$neo<estimated_diameter><kilometers><estimated_diameter_min>.fmt('%.2f')}";
        say "    - Potentially Hazardous: {$neo<is_potentially_hazardous_asteroid> ?? '*....YES - PLEASE VERIFY....*' !! 'No'}";
    }
} else {
    # If we can't get the data, at least print the HTTP status, and give us a data URL to test in our browser.
    say "Failed to fetch data. HTTP status: {$response.status-line}";
    say "Debug URL: {$url}";
}

That’s it!

You may have noticed that I print out the Asteroid data in Org-mode formatting. This is because I use Emacs with tempel, and activate the script with a snippet. I type ‘ast’ and boom! The data appears in my journal file where I’m typing throughout the day.

I hope things worked out for you. If they didn’t, hang in there! It’s a pretty simple script overall, and troubleshooting should be straightforward.

Enjoy using Raku! And thanks to JPL and NASA for the API data.