科技爱好者博客

树莓派搭建指示灯自动显示在空间站的人数

本文翻译自:https://www.raspberrypi.org/

使用Python requests模块访问People in Space API,并创建一个指示灯,以显示当前在空间中的人数。

2015年12月15日,英国欧空局宇航员蒂姆·帕克(Tim Peake)起飞到国际空间站,他将在那里工作六个月。作为Astro Pi项目的一部分,Tim还将在太空中进行科学研究,他还将使用由两名Raspberry Pis学生学习的Python代码进行实验。通过这个资源,你可以保持蒂姆和他的宇航员在国际空间站上的数量。

浏览太空人物API

API代表应用程序编程接口。一种形式的API是一种Web API,可用于从在线提供的服务中提取数据。一些API对公众开放,免费提供数据; 其他API需要登录才能访问它们,这可以通过应用程序获取,或者可以作为服务提供给客户收费。

通过API提供数据的目的是允许人们访问它以供自己使用或使用它来构建程序。一些API提供业务关键数据集或其他重要数据,例如天气,金融活动,甚至提供访问Twitter流或Flickr的照片等。其他API只是为了好玩,如口袋妖怪API星球大战API冒险时间API。虽然这些API是有趣的,但它们仍然可以用于有趣和有用的方式。您可以在Minecraft中建立一个宠物小精灵游戏,或在冒险时间内建立关于角色的问答游戏!

对于这个项目,您将使用Nathan Bergey免费维护和提供的People in Space API

  1. 首先打开网页浏览器并浏览以下网址:
    http://api.open-notify.org/astros.json
  2. 您应该看到一个白色页面,其中包含一些如下所示的文本:

    您正在查看API提供的数据。这是访问数据的手动方法。

  3. 观察所提供的数据。它应该看起来像这样:
    {
      "message": "success",
      "number": 6,
      "people": [
      {
        "craft": "ISS",
        "name": "Mikhail Kornienko"
      },
      ...
    }

    该数据的格式称为JSON(发音为“Jason”),代表JavaScript Object Notation。虽然这个名字是指JavaScript的编程语言,但它是一种标准的数据交换格式,可以在语言和应用程序之间移植。如果您熟悉Python的dictionary数据结构,您将看到相似之处。在其他语言中,嵌套数组可以以相同的方式使用。

  4. 请注意,API提供了三个数据:messagenumber,和people
    • message 是包含该单词的单个字符串 success
    • number 是整数值 6
    • people 是一群宇航员
  5. people阵列中,有六个对象。每个对象包含两个数据:
    • craft 是宇航员在哪里的航天器
    • name 是宇航员的全名

使用Python的请求模块

现在您将使用requestsPython中的模块来访问API。

  1. 从主菜单中打开Python 3:
  2. 在Python shell中,键入以下行,然后按Enter键
    >>> import requests

    (注意>>>不是键入,而是表示shell输入)

    您正在使用Python shell的REPL(Read-Eval-Print Loop),这意味着每一行都会立即执行,而不是写入一个文件,保存并一次运行所有命令

  3. 现在创建一个包含API的URL作为字符串的变量:
    url = "http://api.open-notify.org/astros.json"
  4. 输入以下内容,向API发出请求:
    r = requests.get(url)
  5. 现在只需键入r并按Enter键 ; 这与输入print(r)文件相同。REPL允许您以这种方式快速检查对象。您现在应该看到以下内容:
    <Response [200]>

    这表示r包含一个Response类型对象,并显示200。这是请求的状态代码,这意味着“成功”。其他状态代码包括404,这意味着“找不到文件”和500– “服务器错误”。

  6. 现在进入help(r)。这显示对象的docstring(文档字符串)Response。你应该看到:
    Help on Response in module requests.models object:
    
    class Response(builtins.object)
     |  The :class:`Response <Response>` object, which contains a
     |  server's response to an HTTP request.
     ...
  7. 观察docstring的部分Data descriptors defined here。您将看到可用属性及其描述的列表,包括:
    • apparent_encoding
    • content
    • is_permanent_redirect
    • is_redirect
    • links
    • ok
    • text

    这些属性本质上是一个对象内可访问的变量。例如,r.ok是包含请求(TrueFalse)的成功状态的变量。

  8. 通过在REPL中输入这些属性来尝试访问这些属性:
    >>> r.ok
    True
    >>> r.is_redirect
    False
    >>> r.text
    '{\n  "message": "success", \n  "number": 6...

    你会看到r.text似乎包含你需要的数据。然而,这被提供为使其难以使用的字符串。

  9. 观察Methods defined heredocstring 的部分,其中包括:
    json(self, **kwargs)
        Returns the json-encoded content of a response, if any.

    这可以让您以JSON格式访问URL请求的内容,这将使其更有用。

    一种方法是属于一个对象的函数。它以与属性相同的方式访问,但被称为像()例如函数r.json()

  10. 输入r.json()。你应该看到:
    {'number': 6, 'message': 'success', 'people': [{'craft': 'ISS', 'name': 'Mikhail Kornienko'}, {'craft': 'ISS', 'name': 'Scott Kelly'}, {'craft': 'ISS', 'name': 'Oleg Kononenko'}, {'craft': 'ISS', 'name': 'Kimiya Yui'}, {'craft': 'ISS', 'name': 'Kjell Lindgren'}, {'craft': 'ISS', 'name': 'Sergey Volkov'}]}
  11. 将其另存为变量:
    j = r.json()
  12. 检查新变量的数据类型 type(j)
    >>> type(j)
    <class 'dict'>

    你会看到这j是一个字典,它是Python中非常有用的数据结构,基本上与JSON格式相同。

  13. 要访问字典中的数据,请按以下名称对其进行索引[]
    >>> j['number']
    6

    而已!

  14. 回顾所使用的命令并将其放在一起,需要以下代码来检索空间中的人数:
    import requests
    
    url = "http://api.open-notify.org/astros.json"
    
    r = requests.get(url)
    j = r.json()
    n = j['number']
    print(n)

添加LED

接下来,您将连接一些LED到Pi的GPIO引脚,并使用它们来代表一个人在空间。

  1. 首先使用公母对跳线将Pi的接地引脚连接到面包板,并添加一个电阻将其连接到地面导轨上:

     

  2. 现在将单个LED连接到您的面包板,将较短的腿(阴极)连接到地面导轨,并将较长的腿(阳极)放置在面包板的中间。然后使用公母对跳线将LED的行连接到Pi上的GPIO引脚2:

  3. 从GPIO Zero库导入LED类开始:
    >>> from gpiozero import LED
  4. LED在引脚2上创建一个对象的实例:
    >>> led = LED(2)
  5. 尝试点亮LED:
    >>> led.on()

    LED现在应该点亮!

  6. 将第二个LED连接到引脚3:

  7. 以相同的方式将其余LED(总共10个)连接到连续的引脚(4,14,15,17,18,22,23,27)上:

  8. 确保您以前使用的针脚2上的LED已关闭:
    >>> led.close()
  9. 创建您使用的引脚号的列表:
    >>> pins = [2, 3, 4, 14, 15, 17, 18, 27, 22, 23]
  10. 使用这些引脚号创建LED列表:
    >>> leds = [LED(pin) for pin in pins]

    这被称为列表理解:在一行中生成列表而不是使用传统的循环。

  11. 检查leds列表:
    >>> leds
    [<gpiozero.LED object on pin=2, is_active=False>,
    <gpiozero.LED object on pin=3, is_active=False>,
    <gpiozero.LED object on pin=4, is_active=False>,
    <gpiozero.LED object on pin=14, is_active=False>,
    ...]

    这将打印列表中每个对象的表示,显示一些有用的信息。

  12. leds通过将它们全部打开来测试列表:
    >>> [led.on() for led in leds]

    这是列表理解的另一个用途:在列表中的每个项目上运行命令

  13. 关闭它们:
    >>> [led.off() for led in leds]

    提示:使用Alt + P(上一个)完成命令历史记录并编辑输入的最后一个命令。

制作指示标

现在,您将使用LED显示当前在空间中的人数。

  1. 现在是把它们一起放在一个文件中的时候了。点击File > New File
  2. 将您的文件保存为 astronauts.py
  3. 首先导入您使用的库:
    from gpiozero import LED
    import requests
  4. 添加LED设置:
    pins = [2, 3, 4, 14, 15, 17, 18, 27, 22, 23]
    leds = [LED(p) for p in pins]
  5. 添加requests代码:
    url = "http://api.open-notify.org/astros.json"
    
    r = requests.get(url)
    j = r.json()
    n = j['number']
  6. 现在,而不仅仅是打印n,您可以使用它来确定应该点亮多少个LED。考虑以下循环:
    for led in leds:
        led.on()

    这允许您依次访问每个LED。但是,我们需要知道什么时候我们应该停止这样做。

  7. 您需要能够比较n每个LED号码(序列中的顺序,而不是GPIO引脚号)的数字。您将需要使用该enumerate功能按顺序为每个LED分配一个数字。enumerate通过在shell中尝试它(而不是文件)来查看它的工作原理:
    >>> list(enumerate(leds))
    [(0, <gpiozero.LED object on pin=2, is_active=False>),
     (1, <gpiozero.LED object on pin=3, is_active=False>),
     (2, <gpiozero.LED object on pin=4, is_active=False>),
    ...]

    您可以看到,它提供了与索引号相关联的LED列表,从0

  8. 由于enumerate返回两个值,索引号和LED对象,您可以循环使用它并通过使用访问这两个值for i, led in enumerate(leds)。将以下循环添加到文件中的代码中:
    for i, led in enumerate(leds):
        if n > i:
            led.on()
        else:
            led.off()
  9. 保存并运行您的代码。假设API返回6,你应该有6个LED点亮!
  10. 您将需要定期检查API的变化。确保您没有对API提出太多请求非常重要。首先通过sleep在其他文件的顶部添加导入:
    from time import sleep
  11. 现在将循环中的代码requestsLED代码进行while循环,使其持续运行并不断更新LED:
    while True:
        r = requests.get(url)
        j = r.json()
        n = j['number']
        for i, led in enumerate(leds):
            if n > i:
                led.on()
            else:
                led.off()
        sleep(60)  # update every minute

    确保最后添加睡眠,所以它在API调用之间等待60秒钟,以便每分钟检查一次结果。

  12. 运行代码,它应该总是显示当前的空间人数。让它运行,它应该在将来更新,因为宇航员交付到和从国际空间站。

尝试用木头或纸板制作自己的指示器:

显示宇航员名字

最后,学习从API调用中获取宇航员名字。

  1. 当你最初检查了JSON对象时,它显示了所有的空间的人的名字以及数字。返回到Python shell并j['people']从字典检查:
    >>> type(j['people'])
    <class 'list'>
    >>> j['people']
    [{'craft': 'ISS', 'name': 'Mikhail Kornienko'}, {'craft': 'ISS', 'name': 'Scott Kelly'}, {'craft': 'ISS', 'name': 'Oleg Kononenko'}, {'craft': 'ISS', 'name': 'Kimiya Yui'}, {'craft': 'ISS', 'name': 'Kjell Lindgren'}, {'craft': 'ISS', 'name': 'Sergey Volkov'}]
  2. 你可以看到这j['people']是一个列表。现在进一步检查清单:
    >>> len(j['people'])
    6
    >>> type(j['people'][0])
    <class 'dict'>
    >>> j['people'][0]
    {'craft': 'ISS', 'name': 'Mikhail Kornienko'}
  3. 您可以看到该列表包含6个元素,并且每个元素是另一个字典。剩下的只是访问字典中的各个元素:
    >>> type(j['people'][0]['craft'])
    <class 'str'>
    >>> j['people'][0]['craft']
    'ISS',
    >>> type(j['people'][0]['name'])
    <class 'str'>
    >>> j['people'][0]['name']
    'Mikhail Kornienko'
    >>> j['people'][1]['name']
    'Scott Kelly'
  4. 尝试打印所有的宇航员名字:
    >>> for astronaut in j['people']:
            print(astronaut['name'])
    
    Mikhail Kornienko
    Scott Kelly
    Oleg Kononenko
    Kimiya Yui
    Kjell Lindgren
    Sergey Volkov
  5. 现在返回你的代码,并在保存后添加一行来保存宇航员列表作为变量n
    n = j['number']
    astronauts = j['people']
  6. 然后在循环开始之前添加一行以关闭所有LED:
    [led.off() for led in leds]
  7. if n > i声明内,之后led.on(),添加两行打印宇航员姓名,然后睡眠1秒,以便在每个光线之间暂停:
    if n > i:
        led.on()
        print(astronauts[i]['name'])
        sleep(1)
  8. 再次运行代码,LED一次一个,同时打印出宇航员的姓名。

接下来是什么?

现在,您已经创建了一个带LED指示灯的People in Space Indicator,尝试扩展您的项目:

重要的日子

请注意国际空间站航天员计划交付和离职的以下日期:

退出移动版