精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

電子發燒友App

硬聲App

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示
電子發燒友網>電子資料下載>電子資料>多彩世界地圖上的物聯網圣誕老人追蹤器

多彩世界地圖上的物聯網圣誕老人追蹤器

2022-12-09 | zip | 0.12 MB | 次下載 | 免費

資料介紹

描述

呼呼呼……圣誕老人來了!

每年平安夜圣誕老人都會踏上環游世界的旅程,為全世界的孩子們送出禮物。但是知道那天圣誕老人在哪里會很酷嗎?

MKR1000 圣誕老人追蹤器來救援!

您可能已經知道我們可以從兩個地方獲取圣誕老人的位置信息,一個來自NORAD ,一個來自Google 雖然 NORAD 是發起圣誕老人追蹤傳統的原始組織,但谷歌為圣誕老人追蹤提供了一個開發人員友好的(未記錄的)API 使用此 API,您將能夠跟蹤實時圣誕老人信息,包括位置、到達和離開時間、在該位置發送的禮物,與在 Google 的圣誕老人跟蹤網站上相同。所以在這個項目中我選擇使用谷歌圣誕老人數據來實現我的圣誕老人追蹤器。

這個項目的想法很簡單:使用 LED 顯示圣誕老人去過的地方以及圣誕老人在世界地圖上的當前位置。這是我在項目結束時得到的:

系統架構

總體而言,該設計使用一個樹莓派和一個 MKR1000 來處理和可視化從 Google Santa Tracker API 獲取的圣誕老人數據。

?
poYBAGOSl8OAWZgEAAFTVRhgJVk136.png
數據處理管道
?

如您所見,從 Google Santa Tracker API 獲取的數據首先通過 Raspberry PI 放置。原因是 API 響應 JSON 大約為 20M,這太大而無法放入 MKR1000 的內存(我的草圖加載后有 18M 可用)進行處理。所以我使用 Raspberry Pi 3 首先使用數據,并生成一個更小的數據格式,這是為我的應用程序量身定做的。之后的數據通過托管在 Raspberry Pi 上的 REST API 服務器公開。MKR1000 開發板將每 10 秒調用一次 REST API 以獲取當前圣誕老人的位置。

電路設計

MKR1000 連接到具有 30 個 WS2812B RGB NeoPixel LED 的定制 PCB每個 LED 代表一個地理位置。這個想法是讓離圣誕老人當前位置最近的 LED 燈閃爍,然后打開圣誕老人過去所在位置的所有 LED 燈。

PCB 針對由 Othermill 生產的雙面 PCB 進行了優化,但也應該可以通過 OSH Park 等在線 PCB 服務輕松生產。

我在PCB上鋪了30個NeoPixels,形成了一張世界地圖。您可能現在看不到它,但是在涂上負片掩模和擴散器后,它會更容易識別。

?
pYYBAGOSl86AKInsAAKAUs2pTDo970.png
為 MKR1000 和 30 NeoPixels 定制的 PCB
?

使這種家庭銑削友好的主要考慮因素是通孔的位置。由于過孔是在 PCB 板上鉆的,因此兩側未連接。因此,您需要通過電線將它們的兩側焊接在一起。正因為如此,通孔不能像在商業 PCB 中通常那樣放置在 SMT 組件下方。

PCB 文件背后有一些設計注意事項:

  • 電源通過粗干線傳輸并下沉到另一根粗地線中。這是因為 30 個 NeoPixel 會消耗相當多的電流
  • NeoPixels 盡可能靠近主干電源線連接。這是為了減少多個 NeoPixel 之間的壓降。不同的電壓會導致亮度和顏色略有不同。
  • 靠近電源連接一個 1000 uF 電容器這是使用 NeoPixels的推薦最佳實踐。
  • 過孔放置在其他 SMT 組件之外,因為它們將通過手動焊接兩側連接,焊點不會適合另一個 SMT 組件。這在商業服務生產的 PCB 上不是問題,但在家庭制作 PCM 時應考慮在內。
  • 確保在電線之間留出足夠的空間。 焊接后很容易短路,因為自制的PCB沒有絕緣層。這可以在 Otherplan 應用程序中通過將跡線間隙設置為比默認值 0.006 英寸更大的值(例如 0.06 英寸應該足夠好)來完成。我發現我的第一塊完全焊接的電路板因為短路而無法正常工作,而且修復起來比制作另一塊電路板更難。
  • 如果您要處理大量 SMT 組件,熱風返修站將為您節省大量焊接時間。雖然這是可行的,但真的不值得一個一個地手工焊接組件。熱風也會使組件自動對齊到準確的位置。
?
?
?
?
poYBAGOSl_OAV_XbAAieCWR5fGY882.png
?
1 / 8 ? V1(不工作)在左邊,V2 在右邊。
?

世界地圖面具和擴散器

因為 Othermill 可以直接從 SVG 進行銑削,所以我只使用從 wikimedia.org 找到的世界地圖

我還創建了另一個包含鉆孔的鷹文件。這些孔用于將掩模安裝到電路板上。

因為我想獲得盡可能高的銑削精度,所以最好的方法是使用對齊支架。但是輪廓肯定會和括號重疊。我找到的解決方案是首先只切割地圖而不切割輪廓。然后在不告訴軟件的情況下取下支架。然后開始銑削以鉆孔并切割輪廓。該軟件將使用相同的刀具路徑在您想要的精確位置切割輪廓。

?
?
?
?
pYYBAGOSl_iAZIpAAAFpgINwp44321.png
?
1 / 5 ?面罩的研磨設置。
?

組裝非常簡單。我使用了 4 個 M3 尼龍長螺釘、4 個支架和 4 個螺母。

?
?
?
?
poYBAGOSmAqALQVOAAR_-_Axj80737.png
?
1 / 3
?

樹莓派預處理服務器

Google Santa Tracker API 的響應是一個巨大的 JSON 文件。這對 MKR1000 來說可能是個問題,但對 Raspberry Pi 3 來說根本不是問題。所以我設置了一個 HTTP 服務器來預處理 JSON 文件并為 MKR1000 生成較小的數據。

Raspberry Pi 服務器還將位置直接映射到相應 LED 的索引,以進一步減少 MKR1000 上的計算。為此,我首先手動為每個 LED 分配一個坐標,然后計算圣誕老人路徑中的每個位置與 LED 坐標之間的距離,找到最近的 LED 來表示該位置。

服務器是用 Python 編寫的,并使用 Flask 網絡框架將 REST 端點公開給 MKR1000。

from flask import Flask
import requests
import json
import math
import sys
app = Flask(__name__)
# Google's Santa API. Only updates on Dec 24.
# santa_api_url = 'https://santa-api.appspot.com/info?client=web&language=en&fingerprint=&routeOffset=0&streamOffset=0'
# My Fake Santa API.
santa_api_url = 'http://localhost:1224/info'
# LEDs metadata.
leds = [
   {'name': 'North Pole', 'location': {'lat': 90.0, 'lng': 30.0}},
   {'name': 'Alaska (US)', 'location': {'lat': 64.536117, 'lng': -151.258768}},
   {'name': 'Alberta (Canada)', 'location': {'lat': 48.9202307, 'lng': -93.69738}},
   {'name': 'Ontario (Canada)', 'location': {'lat': 50.956252, 'lng': -87.369255}},
   {'name': 'Utah (US)', 'location': {'lat': 40.7765868, 'lng': -111.9905244}},
   {'name': 'Tennessee (US)', 'location': {'lat': 36.1865589, 'lng': -86.9253274}},
   {'name': 'Mexico City (Mexico)', 'location': {'lat': 19.39068, 'lng': -99.2836957}},
   {'name': 'Bogota (Columbia)', 'location': {'lat': 4.6482837, 'lng': -74.2478905}},
   {'name': 'Brasilia (Brazil)', 'location': {'lat': -15.721751, 'lng': -48.0082759}},
   {'name': 'Santiago (Chile)', 'location': {'lat': -33.4727092, 'lng': -70.7699135}},
   {'name': 'Greenland', 'location': {'lat': 70.8836652, 'lng': -59.6665893}},
   {'name': 'UK', 'location': {'lat': 64.6748061, 'lng': -7.9869018}},
   {'name': 'Spain', 'location': {'lat': 40.4379332, 'lng': -3.749576}},
   {'name': 'Mali', 'location': {'lat': 17.5237416, 'lng': -8.4791157}},
   {'name': 'Finland', 'location': {'lat': 64.6479136, 'lng': 17.1440256}},
   {'name': 'Greece', 'location': {'lat': 38.2540419, 'lng': 21.56707}},
   {'name': 'Libya', 'location': {'lat': 21.520733, 'lng': 23.237173}},
   {'name': 'Central African Republic', 'location': {'lat': 6.2540984, 'lng': -0.2809593}},
   {'name': 'Botswana', 'location': {'lat': -22.327399, 'lng': 22.4437318}},
   {'name': 'Saudi Arabia', 'location': {'lat': 24.0593214, 'lng': 40.6158589}},
   {'name': 'Turkmenistan', 'location': {'lat': 38.9423384, 'lng': 57.3349508}},
   {'name': 'Xinjiang (China)', 'location': {'lat': 42.0304225, 'lng': 77.3185349}},
   {'name': 'India', 'location': {'lat': 20.8925986, 'lng': 73.7613366}},
   {'name': 'Henan (China)', 'location': {'lat': 33.8541479, 'lng': 111.2634555}},
   {'name': 'Cambodia', 'location': {'lat': 12.2978202, 'lng': 103.8594626}},
   {'name': 'Japan', 'location': {'lat': 34.452585, 'lng': 125.382845}},
   {'name': 'Australia', 'location': {'lat': -25.0340388, 'lng': 115.2378468}},
   {'name': 'New Zealand', 'location': {'lat': -43.0225411, 'lng': 163.4767905}},
   {'name': 'South Pole', 'location': {'lat': -90.0, 'lng': 30.0}},
]
@app.route('/santa')
def santa():
   santa_info = requests.get(santa_api_url).json()
   santa_time = santa_info['now']
   response = []
   for dest_json in santa_info['destinations']:
       if santa_time < dest_json['arrival']:
           break
       dist, led, led_index = closest_led(dest_json['location'])
       response.append({
           'i': led_index,
           'd': int(dist),
           'n': dest_json['city'],
           'p': dest_json['presentsDelivered']
       })
   return app.response_class(json.dumps(response).replace(' ',''), content_type='application/json')
def distance(loc1, loc2, unit='M'):
   lat1 = loc1['lat']
   lng1 = loc1['lng']
   lat2 = loc2['lat']
   lng2 = loc2['lng']
   radlat1 = math.pi * lat1 / 180
   radlat2 = math.pi * lat2 / 180
   theta = lng1-lng2
   radtheta = math.pi * theta / 180
   dist = (math.sin(radlat1) * math.sin(radlat2) +
       math.cos(radlat1) * math.cos(radlat2) * math.cos(radtheta));
   dist = math.acos(dist)
   dist = dist * 180 / math.pi
   dist = dist * 60 * 1.1515
   if unit == 'K':
       return dist * 1.609344
   if unit == 'N':
       return dist * 0.8684
   return dist
def closest_led(loc):
   min_dist = sys.float_info.max
   min_led = None
   min_index = 0
   for index, led in enumerate(leds):
       led_loc = led['location']
       dist = distance(loc, led_loc)
       if dist < min_dist:
           min_dist = dist
           min_led = led
           min_index = index
   return min_dist, min_led, min_index
if __name__ == '__main__':
   app.run(host='0.0.0.0', port=2412)

由于 Google Santa Tracker API 一年中只有一天(12 月 24 日)更新,為了測試整個系統,我還編寫了一個模擬真實圣誕老人追蹤器 API 服務器的假圣誕老人追蹤器 API 服務器。有了這個假的 API 服務器,我還可以控制行進速度并根據需要重置。該服務器也是一個 Flask Python 服務器,在 Raspberry Pi 3 的不同端口上運行。

from flask import Flask, request
import json
import time
app = Flask(__name__)
fake_start_time = 0  # initialized to first arrival time from json
real_start_time = 0  # set to start time
speed_factor = 100  # fake clock speed
all_destinations = None
current_info = {
   'status': 'OK',
   'language': 'en',
   'now': None,            # Will be set to fake time
   'timeOffset': 120000,
   'fingerprint': '3b8835bc354c6d5018344b289b833402f7079844',
   'refresh': 51449,
   'switchOff': False,
   'clientSpecific': {
       'DisableEarth': False,
       'DisableTracker': False,
       'DisableWikipedia': False,
       'DisablePhotos': False,
       'HighResolutionPhotos': False,
       'EarthAltitudeMultiplier': 1
   },
   'routeOffset': 0,
   'destinations': None    # Will only have destinations up to two towns ahead
}
@app.route('/info')
def info():
   if real_start_time != 0:
       advance_fake_time()
   return app.response_class(json.dumps(current_info), content_type='application/json')
@app.route('/start')
def start():
   global real_start_time, speed_factor
   real_start_time = real_now()
   speed_factor = int(request.args.get('speed', '100'))
   print(u'fake clock stated at speed {0}'.format(speed_factor))
   return 'ok'
@app.route('/reset')
def reset():
   global real_start_time
   real_start_time = 0
   current_info['destinations'] = all_destinations[:3]
   return 'ok'
def index_of_current_destination(ts):
   for i, dest in enumerate(all_destinations):
       if dest['departure'] > ts:
           return i
   return 0
def current_destinations():
   index = index_of_current_destination(fake_now()) + 3
   return all_destinations[:index]
def advance_fake_time():
   current_info['now'] = fake_now()
   current_info['destinations'] = current_destinations()
def real_now():
   return int(time.time() * 100)
def fake_now():
   return (real_now() - real_start_time) * speed_factor + fake_start_time
def arrival(d):
   return d['arrival']
def load_json():
   with open('santa2016.json') as data_file:
       data = json.load(data_file)
   global all_destinations, fake_start_time
   all_destinations = sorted(data['destinations'], key=arrival)
   fake_start_time = all_destinations[1]['arrival']
   reset()
   print(u'{0} destinations loaded, fake_start_time={1}'.format(len(all_destinations), fake_start_time))
if __name__ == '__main__':
   load_json()
   app.run(host='0.0.0.0', port=1224)

MKR1000 固件

現在 MKR1000 已準備好從 Raspberry Pi 服務器獲取數據,并打開和關閉 LED。

#include 
#include 
#include 
#include "JsonStreamingParser.h"
#include "JsonListener.h"
#define LED_PIN 6
#define LED_NUM 30
#define BRIGHTNESS 50
Adafruit_NeoPixel strip = Adafruit_NeoPixel(LED_NUM, LED_PIN, NEO_GRB + NEO_KHZ800);
char ssid[] = "YOUR_SSID";     //  your network SSID (name)
char pass[] = "YOUR_PWRD";  // your network password
int keyIndex = 0;            // your network key Index number (needed only for WEP)
int status = WL_IDLE_STATUS;
IPAddress server(192, 168, 1, 120);  // numeric IP for RPI server
//char server[] = "rpi3.local";    // name address for RPI server
char endpoint[] = "/santa";
int port = 2412;
// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
WiFiClient client;
class Led {
 public:
   String name;
   int distance;
   int presents;
   boolean on;
};
Led leds[30];
class LedSwitcher: public JsonListener {
 public:
   void whitespace(char c) {}
   void startDocument() {}
   void key(String key) {
     Serial.println(key);
     currentKey = key;
   }
   void value(String value) {
     Serial.println(value);
     if (currentKey == "i") {
       ledIndex = value.toInt();
     } else if (currentKey == "p") {
       presents = value.toInt();
     } else if (currentKey == "d") {
       distance = value.toInt();
     } else {
       name = value;
     }
   }
   void endArray() {}
   void endObject() {
     Serial.println("End of Object");
     Serial.print(ledIndex);
     Serial.print(":");
     Serial.print(name.c_str());
     Serial.print(",");
     Serial.print(presents);
     Serial.print(",");
     Serial.print(distance);
     leds[ledIndex].on = true;
     leds[ledIndex].name = name;
     leds[ledIndex].presents = presents;
     leds[ledIndex].distance = distance;
   }
   void endDocument() {}
   void startArray() {}
   void startObject() {}
   int lastLed() {
     return ledIndex;
   }
 private:
   String currentKey;
   int ledIndex;
   int presents;
   int distance;
   String name;
};
LedSwitcher ledSwitcher;
void connectToWifi() {
 // check for the presence of the shield:
 if (WiFi.status() == WL_NO_SHIELD) {
   Serial.println("WiFi shield not present");
   // don't continue:
   while (true);
 }
 // attempt to connect to Wifi network:
 while (status != WL_CONNECTED) {
   Serial.print("Attempting to connect to SSID: ");
   Serial.println(ssid);
   // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
   status = WiFi.begin(ssid, pass);
   // wait 10 seconds for connection:
   delay(10000);
 }
 Serial.println("Connected to wifi");
 printWifiStatus();
}
boolean connectToSantaServer() {
 Serial.println("Starting connection to server...");
 return client.connect(server, port);
}
void ensureConnected() {
 if (!client.connected()) {
   while (!connectToSantaServer()) {
     Serial.println("Failed to connect to server. Retry in 5 seconds");
     delay(5000);
   }
   Serial.println("connected to server");
 }
}
void fetchSantaInfo() {
 ensureConnected();
 // Make a HTTP request:
 client.print("GET ");
 client.print(endpoint);
 client.println(" HTTP/1.1");
 client.print("Host: ");
 client.println(server);
 client.println("Connection: close");
 client.println();
 int bytes = 0;
 boolean isBody = false;
 JsonStreamingParser parser;
 parser.setListener(&ledSwitcher);
 Serial.println();
 Serial.println("Received response:");
 Serial.println();
 while (client.connected()) {
   while (client.available()) {
     char c = client.read();
     ++bytes;
     //Serial.write(c);
     if (isBody || c == '[') {
       isBody = true;
       parser.parse(c);
     }
   }
 }
 Serial.println();
 Serial.println();
 Serial.println("Disconnecting from server.");
 client.stop();
 Serial.print("Received: ");
 Serial.print(bytes);
 Serial.println(" Bytes.");
}
void flashLastLed() {
 strip.setPixelColor(ledSwitcher.lastLed(), strip.Color(0, 0, 0));
 strip.show();
 delay(500);
 strip.setPixelColor(ledSwitcher.lastLed(), strip.Color(255, 0, 0));
 strip.show();
 delay(500);
}
void setup() {
 //Initialize serial and wait for port to open:
 Serial.begin(9600);
 strip.setBrightness(BRIGHTNESS);
 strip.begin();
 strip.show(); // Initialize all pixels to 'off'.
 connectToWifi();
 fetchSantaInfo();
 for (int i = 0; i < 30; ++i) {
   if (leds[i].on) {
     strip.setPixelColor(i, strip.Color(255, 0, 0));
   } else {
     strip.setPixelColor(i, strip.Color(0, 0, 0));
   }
 }
 strip.show();
}
void loop() {
 fetchSantaInfo();
 delay(1000);
 for (int i = 0; i < 10; ++i) {
   flashLastLed();
 }
}
void printWifiStatus() {
 // print the SSID of the network you're attached to:
 Serial.print("SSID: ");
 Serial.println(WiFi.SSID());
 // print your WiFi shield's IP address:
 IPAddress ip = WiFi.localIP();
 Serial.print("IP Address: ");
 Serial.println(ip);
 // print the received signal strength:
 long rssi = WiFi.RSSI();
 Serial.print("signal strength (RSSI):");
 Serial.print(rssi);
 Serial.println(" dBm");
}

由于大部分工作都是在 Raspberry Pi 上完成的,所以這里的代碼很簡單。它連接到 WiFi,每 10 秒從 Raspberry Pi 獲取圣誕老人數據,并相應地更新 NeoPixels。

現在讓我們啟動它:

?
?

結論

MKR1000 是一款非常強大的物聯網應用板,但它也有其自身的局限性。借助更強大的 SBC(單板計算機),如 Raspberry Pi 3,我們將能夠與具有更復雜 API 的任何服務進行交互。

希望你喜歡這個項目作為一個小小的節日驚喜。


下載該資料的人也在下載 下載該資料的人還在閱讀
更多 >

評論

查看更多

下載排行

本周

  1. 1山景DSP芯片AP8248A2數據手冊
  2. 1.06 MB  |  532次下載  |  免費
  3. 2RK3399完整板原理圖(支持平板,盒子VR)
  4. 3.28 MB  |  339次下載  |  免費
  5. 3TC358743XBG評估板參考手冊
  6. 1.36 MB  |  330次下載  |  免費
  7. 4DFM軟件使用教程
  8. 0.84 MB  |  295次下載  |  免費
  9. 5元宇宙深度解析—未來的未來-風口還是泡沫
  10. 6.40 MB  |  227次下載  |  免費
  11. 6迪文DGUS開發指南
  12. 31.67 MB  |  194次下載  |  免費
  13. 7元宇宙底層硬件系列報告
  14. 13.42 MB  |  182次下載  |  免費
  15. 8FP5207XR-G1中文應用手冊
  16. 1.09 MB  |  178次下載  |  免費

本月

  1. 1OrCAD10.5下載OrCAD10.5中文版軟件
  2. 0.00 MB  |  234315次下載  |  免費
  3. 2555集成電路應用800例(新編版)
  4. 0.00 MB  |  33566次下載  |  免費
  5. 3接口電路圖大全
  6. 未知  |  30323次下載  |  免費
  7. 4開關電源設計實例指南
  8. 未知  |  21549次下載  |  免費
  9. 5電氣工程師手冊免費下載(新編第二版pdf電子書)
  10. 0.00 MB  |  15349次下載  |  免費
  11. 6數字電路基礎pdf(下載)
  12. 未知  |  13750次下載  |  免費
  13. 7電子制作實例集錦 下載
  14. 未知  |  8113次下載  |  免費
  15. 8《LED驅動電路設計》 溫德爾著
  16. 0.00 MB  |  6656次下載  |  免費

總榜

  1. 1matlab軟件下載入口
  2. 未知  |  935054次下載  |  免費
  3. 2protel99se軟件下載(可英文版轉中文版)
  4. 78.1 MB  |  537798次下載  |  免費
  5. 3MATLAB 7.1 下載 (含軟件介紹)
  6. 未知  |  420027次下載  |  免費
  7. 4OrCAD10.5下載OrCAD10.5中文版軟件
  8. 0.00 MB  |  234315次下載  |  免費
  9. 5Altium DXP2002下載入口
  10. 未知  |  233046次下載  |  免費
  11. 6電路仿真軟件multisim 10.0免費下載
  12. 340992  |  191187次下載  |  免費
  13. 7十天學會AVR單片機與C語言視頻教程 下載
  14. 158M  |  183279次下載  |  免費
  15. 8proe5.0野火版下載(中文版免費下載)
  16. 未知  |  138040次下載  |  免費