Raspberry Pi Minecraft ISS Tracker

This post will show you how we built a Minecraft map of the world and then used some of our previous python code to track the International Space Station on that map. It was inspired by the fact that there are now two ‘Astro Pi‘ computers in space on the ISS.

Step one is finding a suitable map and converting it into something we can use. I used the ascii art generator at picascii.com to make a text file map of the world from an image of a cylindrical projection. You can get the text file here. Download the file and save it to a folder where you will have your python code.

If you don’t have Minecraft Pi edition already then you should install by running apt-get install minecraft-pi or grab it from the website. Also have a look at this page from the Raspberry Pi website which will give you an idea of what we are doing.

Start Minecraft on your Pi and select a new world [otherwise you will lose everything!] then change desktops and open a new file in IDLE which is the python development environment and run the code below. Note: the code is for python 2.

""" Make a Map in Minecraft"""
__author__ = '@damianmooney'
from mcpi import minecraft as minecraft
from mcpi import block as block
import random


def clearZone( alocx, alocz, blocx, blocz ):
    mc.setBlocks( alocx, 1, alocz, blocx, 128, blocz, block.AIR )
    mc.setBlocks( alocx, -5, alocz, blocx, 0, blocz, block.WATER )

if __name__ == "__main__":
    mc = minecraft.Minecraft.create()
    clearZone( -128, -128, 128, 128 )
    print('Cleared')
    f = open('world3.txt', 'r')  # open your ascii art text file
    mymap = f.read()
    f.close()

    myrows = mymap.split('\n')

    print mymap

    # --start our top corner of world adjust to get 0,0 ok on map
    x = 100
    z = 85

    for i in myrows: #for each line in our map
        #print len(i)
        print i
        z -=1
        x = 100
        y = 0
        for j in i:  # go through each position on the current line
            x -=1
            if j != " ":  # if the map is not empty blank minecraft then place a grass block 
                position = (x, y, z)
                mc.setBlock(position, block.AIR)
                mc.setBlock(position, block.GRASS)
            elif j != " ":  # place water
                position = (x, y, z)
                mc.setBlock(position, block.AIR )
                mc.setBlock(position, block.WATER )


 

This code blanks the whole map, reads in our ascii art text file and then goes through each line and puts either a grass block or a water block depending on the value in that position in the text file. You can use this technique to build all sorts of things.

Hopefully you should end up with something like this.

Next we need to get the current position of the ISS so we will use the code from our previous posts. The api we are using has changed to the one by Bill Shupp and his site is here.

Now we will grab the position of the ISS and convert it to match our map dimensions. We can then update once a minute to see how things work. As we are using web based data your Pi will need an internet connection.

""" Get current ISS position from http://wheretheiss.at/ and map it on
    a raspberry pi with minecraft
"""
__author__ = '@damianmooney'
from mcpi import minecraft as minecraft
from mcpi import block as block
from datetime import datetime
import time
import urllib2
import json


def getiss():
    """ call where the iss at api thanks to Bill Shupp"""
    response = urllib2.urlopen('https://api.wheretheiss.at/v1/satellites/25544')
    mydata = response.read()
    return mydata


def do_coord(longitude):
    """ longitude: convert our longitude to a minecraft co-ordinate"""
    mine_long = longitude * -.55
    return mine_long


if __name__ == "__main__":
    mc = minecraft.Minecraft.create()
    mc.postToChat("   Minecraft ISS Tracker for @naascoderdojo")
    mc.camera.setFollow()
    mc.player.setting("autojump", False)
    mc.player.setPos(6, 20, 50)
    while True:
        iss = getiss()
        pos = json.loads(iss)
        lat = pos['latitude']
        lon = pos['longitude']

        mc.postToChat('   ISS Location Lat: %.2f Long: %.2f' % (lat,lon))
        new_long = do_coord(lon)
        mc.player.setPos(int(new_long),  20, int(lat))
        print('lon %d lat %d' % (new_long, lat))
        time.sleep(60)  # --only update once per minute - don't be greedy with api

You need to have your minecraft map running first, then switch to a second desktop on your pi and open a command window. Run the python code above and switch back to your first desktop.

Hopefully you should no see something like the image below. Double tap the space bar so your avatar hovers.

Raspberry Pi Minecraft ISS tracker

Raspberry Pi Minecraft ISS tracker

The code itself is pretty simple, we read in the json from the api, extract the latitude and longitude and then convert that to x, y, and z values in our minecraft world. The map itself is rough and ready but it is made out of blocks.

Advertisements

Scratch (well almost) and the ISS

This is just a very short post for the Naas-Sallins Coder Dojo about a smaltalk clone of  Scratch called Phratch. As the website says “ It includes two interesting categories: Files and colors. Files allows one to manipulate local and remote files, and Colors to manipulate color features”. So in this quick post we are going to have a look at the files extension.

Phratch Files Section

Phratch Files Section

The first item here is the one we are going to use by pointing the url at the open-notify api from our previous posts. Our very short 8 line program is as follows

Phratch ISS Tracker Code

Phratch ISS Tracker Code

Inside a standard ‘When Green Flag is clicked-Forever loop’

we set the variable mydata to the contents of our api call

we set the variables lat and lon to a particular range of characters in my data. I did this by trial and error and its a bit rough and ready.

we then set x and y to the lat and lon adjusted to match the dimensions of the display window size (360×480) to standard latitude and longitude (180×360)

finally we sleep for a minute

The sprite to represent the ISS position is a simple blue dot with the stage background set to a map of the world. The map projection I used was from a python basemap example with a quick photoshop adjustment to crop it to size. The Equidistant Cylindrical Projection matches the requirements of our display window and our result turns out to be pretty decent

Real-Time ISS Tracker

Real-Time ISS Tracker

So as you can see the ability that phratch has to interact with a file or a url opens up a whole new set of interesting opportunities.

If you are interested you can download phratch here.

Python and The ISS Part 2

This is part two of a post for Naas-Sallins Coder Dojo about the International Space Station. We assume you have worked through part one and in particular have successfully installed the python libraries required. The install instructions for basemap and its dependencies are here and maybe here if you are on a Mac. Our intention is to use this library to plot the position of the ISS on a map using python. As the introduction to basemap says “the matplotlib basemap toolkit is a library for plotting 2D data on maps in Python.” It comes with a whole set of projections which are listed here. A projection is a way of representing the curved surface of the earth on a 2d map. If you click on any of the linked projections you will see the python code required to produce it and the map itself. The first thing we need to do is make sure that everything is installed ok, as is the tradition we will do this with a hello world program.

""" Hello World Check basemap is ok"""
from mpl_toolkits.basemap import Basemap
import numpy as np
import matplotlib.pyplot as plt
# lon_0, lat_0 are the center point of the projection.
# resolution = 'l' means use low resolution coastlines.
m = Basemap(projection='ortho',lon_0=-6,lat_0=53,resolution='l')
m.drawcoastlines()
m.fillcontinents(color='coral',lake_color='aqua')
# draw parallels and meridians.
m.drawparallels(np.arange(-90.,120.,30.))
m.drawmeridians(np.arange(0.,420.,60.))
m.drawmapboundary(fill_color='aqua')
plt.title("Hello")
plt.show()
Basemap

Hello World

This code is straight from the example for orthographic projections with the title changed to give us ‘Hello’ with the world underneath, and the latitude and longitude changed to center the map over Naas. Our next step is to find a way to plot a point on the map.

from mpl_toolkits.basemap import Basemap
import numpy as np
import matplotlib.pyplot as plt

# use example cassini projection from basemap website
map = Basemap(width=891185,height=1115557,resolution='i',projection='cass',lon_0=-4.36,lat_0=54.7)
map.drawcoastlines()
map.fillcontinents(color='coral',lake_color='aqua')
# draw parallels and meridians.
map.drawparallels(np.arange(-40,61.,2.))
map.drawmeridians(np.arange(-20.,21.,2.))
map.drawmapboundary(fill_color='aqua')
plt.title("We are Here")
x,y = map(-6.67, 53.22)
map.plot(x, y, 'bo', markersize=12)
plt.show()

So using the example cassini projection we added x,y = map(-6.67, 53.22) map.plot(x, y, ‘bo’, markersize=12) which sets the coordinates for the point we want to plot and then plots it on a map as a blue circle sized 12. This gives us

plot Naas

Plot our position

Now that we can plot a point, we want to use our code from before to get the current position of the ISS so that we have something like

""" plot the ISS"""
import numpy as np
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
from datetime import datetime
import urllib2
import json

def getiss():
    """ call opennotify api"""
    response = urllib2.urlopen('http://api.open-notify.org/iss-now.json')
    mydata = response.read()
    return(mydata)

iss = getiss()
pos = json.loads(iss)
lat = pos['iss_position']['latitude']
lon = pos['iss_position']['longitude']

# miller projection
map = Basemap(projection='mill',lon_0=0)
# plot coastlines, draw label meridians and parallels.
map.drawcoastlines()
map.drawparallels(np.arange(-90,90,30),labels=[1,0,0,0])
map.drawmeridians(np.arange(map.lonmin,map.lonmax+30,60),labels=[0,0,0,1])
# fill continents 'coral' (with zorder=0), color wet areas 'aqua'
map.drawmapboundary(fill_color='aqua')
map.fillcontinents(color='coral',lake_color='aqua')
x,y = map(lon, lat)
map.plot(x, y, 'bo', markersize=12)
plt.show()

So this time we are using the json values returned by our getiss() function to plot the point on the map. At this stage we have an application which can draw the current position of the ISS on a map of the world which shows the power of the available python libraries. All that remains is to add some bells and whistles to our map and get it to update the position of the ISS. The code for this is below and it is mainly taken from the examples on the basemap website. We can discuss all this and play around with the various map projection options at the next few dojo sessions.

""" plot the ISS and update every 60 seconds"""
import numpy as np
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
from datetime import datetime
import time
import urllib2
import json

def getiss():
    """ call opennotify api"""
    response = urllib2.urlopen('http://api.open-notify.org/iss-now.json')
    mydata = response.read()
    return(mydata)

while True:
    iss = getiss()
    pos = json.loads(iss)
    lat = pos['iss_position']['latitude']
    lon = pos['iss_position']['longitude']

    # miller projection
    map = Basemap(projection='mill',lon_0=0)
    # plot coastlines, draw label meridians and parallels.
    map.drawcoastlines()
    map.drawparallels(np.arange(-90,90,30),labels=[1,0,0,0])
    map.drawmeridians(np.arange(map.lonmin,map.lonmax+30,60),labels=[0,0,0,1])
    # fill continents 'coral' (with zorder=0), color wet areas 'aqua'
    map.drawmapboundary(fill_color='aqua')
    map.fillcontinents(color='coral',lake_color='aqua')
    # shade the night areas, with alpha transparency so the
    # map shows through. Use current time in UTC.
    date = datetime.now()
    CS=map.nightshade(date)
    plt.title('ISS Location For for %s Lat: %.2f Long: %.2f' % (date.strftime("%d %b %Y %H:%M:%S"),lat,lon))

    x,y = map(lon, lat)
    map.plot(x, y, 'bo', markersize=12)
    plt.ion()
    plt.draw()
    plt.show(block=False)
    time.sleep(60) # --only update once per minute - dont be greedy with api
    plt.clf()

This code gives us a real time ISS tracker showing a map of the world with day/night shown that updates every minute.

ISS Tracker

ISS-Tracker in Python

To stop the app hit crtl-c in the command window where you started the application.

If the ISS is over land and it is daytime then you can have a look at a video stream of what it can see here.

Python and The ISS

In this post for Naas-Sallins Coder Dojo we are going to pick up where we left off last time but instead of getting the weather we are going to get some details about the International Space Station. Again we are going to use a free publically available web api as the source of our information, in this case we are going to use Open-Notify for our data. There are two main pieces of data available about the ISS which are its current position and the time and date of the next few overhead passes for a given location. So quickly adapting our code from our weather app last time out we get the following

""" read opennotify api"""
import urllib2
import json
import datetime

def getiss():
    """ call opennotify api"""
    response = urllib2.urlopen('http://api.open-notify.org/iss-pass.json?lat=53.22&lon=-6.67')
    mydata = response.read()
    return(mydata)

def main():
    iss = getiss()
    pos = json.loads(iss)
    passtimes = []

    for i in pos['response']:
        when =  i['risetime']
        passtimes.append(datetime.datetime.fromtimestamp(int(when)).strftime('%Y-%m-%d %H:%M:%S'))
    print passtimes

if __name__ == '__main__':
    main()

We have put the latitude and longtitude for Naas in to the api call and used the techniques from the last time to extract the relevant bits from the data returned which looks something like

{
“request”: {
“datetime”: 1399717598,
“latitude”: 53.22,
“altitude”: 100,
“passes”: 5,
“longitude”: -6.67
},
“response”: [
{
“duration”: 642,
“risetime”: 1399719911
},
{
“duration”: 605,
“risetime”: 1399725716
},
Again we parse this JSON data like the last time to extract each occurance of risetime which we add to a list called passtimes. The api documentation tells us that risetime is the time that the ISS will start passing by the location given in unix time format. A quick web search tells us how python can convert that into a more normal looking date and time by using the datetime library. If we print out our passtimes list we get the following output

[‘2014-05-10 12:05:11’, ‘2014-05-10 13:41:56’, ‘2014-05-10 15:19:22’, ‘2014-05-11 06:31:32’, ‘2014-05-11 08:04:31’]

If we want to tweet this information from our twitter account for the dojo @NaasCoderDojo then its a simple matter of putting this together with our weather twitter-bot from the last time

 

""" Python ISS for @NaasCoderDojo using tweepy and open-notify.org """
import tweepy
import urllib2
import json
import datetime

#codes below are fake: enter details from your Twitter application
CONSUMER_KEY = 'asdadjakljdakljdakljdlklm'
CONSUMER_SECRET = 'dkjahdkhakdhakjdhkajhdkjahdkjahdkahdkhakdhajhdajbi'
ACCESS_KEY = 'ajsdhakhdkajhdkjahdkjahdkjhakjdhakjdhkajhdkajhdakh'
ACCESS_SECRET = 'djaghdhakhfkahfkjahfkjahfkhakfjhakjfhakfhkfah'

def getiss():
    """ call opennotify api"""
    response = urllib2.urlopen('http://api.open-notify.org/iss-pass.json?lat=53.22&lon=-6.67')
    mydata = response.read()
    return(mydata)

auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
auth.set_access_token(ACCESS_KEY, ACCESS_SECRET)
api = tweepy.API(auth)

iss = getiss()
#print iss
pos = json.loads(iss)
passtimes = []

for i in pos['response']:
    when =  i['risetime']
    passtimes.append(datetime.datetime.fromtimestamp(int(when)).strftime('%Y-%m-%d %H:%M:%S'))

tweet = "#coderdojo #python ISS is over Naas at " + ",".join(passtimes)
print tweet
api.update_status(tweet)

The second open-notify api call gives us the current location of the ISS and we can print use this by following our same technique of calling the api, printing out all the data returned and then picking the bits out of the JSON data that we want. The code for getting the current location would be

""" Get current ISS position from open-notify.org"""
from datetime import datetime
import time
import urllib2
import json

def getiss():
    """ call opennotify api"""
    response = urllib2.urlopen('http://api.open-notify.org/iss-now.json')
    mydata = response.read()
    return(mydata)

iss = getiss()
pos = json.loads(iss)
lat = pos['iss_position']['latitude']
lon = pos['iss_position']['longitude']
when = datetime.now()
print('ISS Location For for %s Lat: %.2f Long: %.2f' % (when.strftime("%d %b %Y %H:%M:%S"),lat,lon))

This should give us something like
ISS Location For for 10 May 2014 11:58:23 Lat: 51.62 Long: -17.66

If you want to see what the ISS can see take a look at this link which is an actual case of Hello World! If you dont see anything then read the text which will explain why.

There will be second part to this ISS post which requires the installation of some python libraries so it would help if we can try to follow the instructions here and maybe here if you are on a Mac. The plan is to build an application which plots the current position of the ISS and displays it on a map. As usual we can have a look at any problems at the next dojo session.

Edit: depending on your python set-up you may also need to install pyparsing and python_dateutil packages. From a command window try

easy_install pyparsing

easy_install python_dateutil