<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>使い方 &#8211; sozorablog</title>
	<atom:link href="https://sozorablog.com/category/%E4%BD%BF%E3%81%84%E6%96%B9/feed/" rel="self" type="application/rss+xml" />
	<link>https://sozorablog.com</link>
	<description>Raspberry Piで電子工作をはじめよう</description>
	<lastBuildDate>Tue, 18 Aug 2026 08:29:11 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1</generator>

<image>
	<url>https://sozorablog.com/wp-content/uploads/2025/04/cropped-ChatGPT-Image-2025年4月5日-15_25_36-32x32.png</url>
	<title>使い方 &#8211; sozorablog</title>
	<link>https://sozorablog.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>ラズパイで簡単ファイル共有！初心者向けファイルサーバー設定ガイド</title>
		<link>https://sozorablog.com/raspberry-pi-file-server/</link>
					<comments>https://sozorablog.com/raspberry-pi-file-server/#respond</comments>
		
		<dc:creator><![CDATA[そぞら]]></dc:creator>
		<pubDate>Sun, 13 Jul 2025 09:01:47 +0000</pubDate>
				<category><![CDATA[Raspberry Pi]]></category>
		<category><![CDATA[使い方]]></category>
		<guid isPermaLink="false">https://sozorablog.com/?p=15364</guid>

					<description><![CDATA[Raspberry Piを買ったけれど、何に使えばいいのかよくわからない……。そんな方に試して欲しいのが「ファイルサーバー」としての活用です。 この記事ではRaspberry Piを使って、パソコンやスマホとファイルをや [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><a href="https://sozorablog.com/raspberry-pi/">Raspberry Pi</a>を買ったけれど、何に使えばいいのかよくわからない……。そんな方に試して欲しいのが「ファイルサーバー」としての活用です。</p>



<p class="wp-block-paragraph">この記事ではRaspberry Piを使って、パソコンやスマホとファイルをやり取りできる仕組みを作ります。特別な機器は必要ありません。手元のラズパイ1台で、低コストかつ省スペースなファイル共有環境が実現します。</p>



<!-- START MoshimoAffiliateEasyLink -->
<script type="text/javascript">
(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;
b[a]=b[a]||function(){arguments.currentScript=c.currentScript
||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};
c.getElementById(a)||(d=c.createElement(f),d.src=g,
d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})
(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");
msmaflink({"n":"Raspberrypi5 8G ラズベリーパイ5 技適取得済マーク入り商品","b":"Raspberry Pi","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/31ulVhoF7LL._SL500_.jpg","\/31Paz5taW5L._SL500_.jpg","\/31wPYoxjgCL._SL500_.jpg","\/31ArwA0xXgL._SL500_.jpg","\/31wPYoxjgCL._SL500_.jpg","\/314jAZZTefL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/B0CQZHN2K4","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/B0CQZHN2K4","a_id":3038653,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1}],"eid":"6dQw8","s":"s"});
</script>
<div id="msmaflink-6dQw8">リンク</div>
<!-- MoshimoAffiliateEasyLink END -->



<h2 class="wp-block-heading">ファイル共有に便利なファイルサーバー</h2>



<figure class="wp-block-image size-full"><img fetchpriority="high" decoding="async" width="800" height="357" src="https://sozorablog.com/wp-content/uploads/2025/07/raspberry-pi-file-server-diagram.jpg" alt="" class="wp-image-17061"/></figure>



<p class="wp-block-paragraph">複数のパソコンやスマホを使っていると、ファイルのやりとりが面倒なことがあります。メールで送ったり、USBメモリにコピーしたりと、操作の手間が気になるものです。</p>



<p class="wp-block-paragraph">そんなときに便利なのが、ファイルを一か所にまとめて管理できる「ファイルサーバー」です。写真や書類などをこのサーバーに保存しておけば、ほかの端末からもすぐにアクセスできます。ファイルを端末ごとに保存しなくて済むので、スマホやタブレットの容量を節約できるのも大きなメリットです。</p>



<h3 class="wp-block-heading">Raspberry Piはファイルサーバーに最適</h3>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="554" src="https://sozorablog.com/wp-content/uploads/2025/07/IMG_9253.jpeg" alt="" class="wp-image-15424"/></figure>



<p class="wp-block-paragraph">Raspberry Pi（ラズベリーパイ）は、手のひらサイズの小さなコンピューターです。消費電力が少なく、場所も取らないため、24時間ずっと動かしておくのに向いています。</p>



<p class="wp-block-paragraph">ファイルサーバーは一度設定すれば、あとは電源を入れたままにしておくだけで、いつでもファイルを保存したり取り出したりできます。ラズパイなら電気代をほとんど気にせず、静かに動作させることができます。</p>



<h2 class="wp-block-heading">準備するもの</h2>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="413" src="https://sozorablog.com/wp-content/uploads/2025/07/ChatGPT-Image-2025年7月13日-20_04_39.jpg" alt="" class="wp-image-15436"/></figure>



<p class="wp-block-paragraph">ファイル共有を始める前に、必要なものをそろえましょう。</p>



<h3 class="wp-block-heading">Raspberry Pi 本体</h3>



<p class="wp-block-paragraph">Wi-Fiに対応したモデルであれば、どれでもファイルサーバーとして利用できます。ラズパイ3や4、Zero 2 Wなど、小型で省電力なモデルが扱いやすくおすすめです。常時稼働するので、ケースを用意しましょう。</p>



<h3 class="wp-block-heading">電源アダプター</h3>



<p class="wp-block-paragraph">電源アダプターは専用品を用意しましょう。汎用品だと電流不足で正常に動作しない場合があります。</p>



<figure class="wp-block-table wp-block-sbd-table wp-block-sbd-table-vertical"><table class="has-fixed-layout"><thead><tr><th>モデル名</th><th>推奨電源</th><th>コネクタ</th><th>おすすめ</th></tr></thead><tbody><tr><td>Raspberry Pi 5</td><td>5.1V / 5A</td><td>USB-C</td><td><span class="sbd-table-btn"><a href="https://www.switch-science.com/products/9345">おすすめアダプター</a></span></td></tr><tr><td>Raspberry Pi 4</td><td>5.1V / 3A</td><td>USB-C</td><td><span class="sbd-table-btn"><a href="https://akizukidenshi.com/catalog/g/g114935/">おすすめアダプター</a></span></td></tr><tr><td>Raspberry Pi 3A+</td><td>5.1V / 2.5A</td><td>micro USB</td><td><span class="sbd-table-btn"><a href="https://akizukidenshi.com/catalog/g/g112001/">おすすめアダプター</a></span></td></tr><tr><td>Raspberry Pi Zero 2W</td><td>5.1V / 2.5A</td><td>micro USB</td><td><span class="sbd-table-btn"><a href="https://akizukidenshi.com/catalog/g/g112001/">おすすめアダプター</a></span></td></tr><tr><td>Raspberry Pi Zero W</td><td>5.1V / 2.0A</td><td>micro USB</td><td><span class="sbd-table-btn"><a href="https://akizukidenshi.com/catalog/g/g112001/">おすすめアダプター</a></span></td></tr></tbody></table></figure>



<h3 class="wp-block-heading">microSDカード</h3>



<p class="wp-block-paragraph">Raspberry PiではmicroSDカードがOSのインストール先であり、同時にファイルを保存する場所にもなります。お試しで使うなら32GBでも十分ですが、本格的にファイルを保存・共有するなら64GB以上をおすすめします。</p>



<!-- START MoshimoAffiliateEasyLink -->
<script type="text/javascript">
(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;
b[a]=b[a]||function(){arguments.currentScript=c.currentScript
||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};
c.getElementById(a)||(d=c.createElement(f),d.src=g,
d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})
(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");
msmaflink({"n":"【 サンディスク 正規品 】 SanDisk microSD カード 32GB UHS-I U1 Class10 Nintendo Switch メーカー動作確認済 Ultra SDSQUA4-032G-GH3MA 簡易デザインパッケージ 10年間限定保証","b":"SanDisk","t":"SDSQUA4-032G-GH3MA","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/41SqvUEpuxL._SL500_.jpg","\/41BWt55RLVL._SL500_.jpg","\/41CzE-jpW5L._SL500_.jpg","\/51Ooj+2u5QL._SL500_.jpg","\/51Vt9UyQ7hL._SL500_.jpg","\/41HjeLVv6sL._SL500_.jpg","\/51En9zgEKCL._SL500_.jpg","\/519N3yR7t1L._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/B0CH2WM7QY","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/B0CH2WM7QY","a_id":3038653,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":3,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/%E3%80%90%20%E3%82%B5%E3%83%B3%E3%83%87%E3%82%A3%E3%82%B9%E3%82%AF%20%E6%AD%A3%E8%A6%8F%E5%93%81%20%E3%80%91%20SanDisk%20microSD%20%E3%82%AB%E3%83%BC%E3%83%89%2032GB%20UHS-I%20U1%20Class10%20Nintendo%20Switch%20%E3%83%A1%E3%83%BC%E3%82%AB%E3%83%BC%E5%8B%95%E4%BD%9C%E7%A2%BA%E8%AA%8D%E6%B8%88%20Ultra%20SDSQUA4-032G-GH3MA%20%E7%B0%A1%E6%98%93%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%2010%E5%B9%B4%E9%96%93%E9%99%90%E5%AE%9A%E4%BF%9D%E8%A8%BC\/","a_id":3038654,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2}],"eid":"0fAL9","s":"s"});
</script>
<div id="msmaflink-0fAL9">リンク</div>
<!-- MoshimoAffiliateEasyLink END -->



<p class="wp-block-paragraph">また、外付けのHDDやSSDを使えば、OSとファイルの保存先を分けることができます。これにより、システムに不具合があっても、保存したファイルに影響が出にくくなります。外付けストレージは速度や耐久性にも優れているため、ファイルの読み書きをより安定して行えるのも利点です。</p>



<h2 class="wp-block-heading">OSのインストール</h2>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="450" src="https://sozorablog.com/wp-content/uploads/2025/07/pico-2025-07-13T175941.822.jpg" alt="" class="wp-image-15429" style="width:519px;height:auto" srcset="https://sozorablog.com/wp-content/uploads/2025/07/pico-2025-07-13T175941.822.jpg 800w, https://sozorablog.com/wp-content/uploads/2025/07/pico-2025-07-13T175941.822-320x180.jpg 320w, https://sozorablog.com/wp-content/uploads/2025/07/pico-2025-07-13T175941.822-224x126.jpg 224w" sizes="(max-width: 800px) 100vw, 800px" /><figcaption class="wp-element-caption">使用したOS</figcaption></figure>



<p class="wp-block-paragraph">ファイルサーバー専用で使うなら「Raspberry Pi OS Lite」が軽くておすすめですが、今回は初心者でも扱いやすいように、デスクトップ画面付きの「Raspberry Pi OS Desktop（GUI付き）」を使います。Zero WやZero WHを使用する場合は、32-bit版を選択します。</p>



<div class="wp-block-sbd-background-block sbd-bg-color sbd-inner-block-init is-style-yellow">
<p class="wp-block-paragraph">Raspberry Pi OSをインストールする方法は、以下の記事で詳しく解説しています。<br><strong><a href="https://sozorablog.com/raspberrypi_initial_setting/">≫【2025年最新版】OSインストールから初期設定まで｜セットアップ手順のすべて</a></strong></p>
</div>



<h2 class="wp-block-heading">Sambaでファイルサーバーを構築</h2>



<p class="wp-block-paragraph">Raspberry Piを使ってファイルサーバーを作るには、「<strong>Samba（サンバ）</strong>」というソフトを使うのが一般的です。Sambaは、WindowsやMacからもアクセスできる共有フォルダを作ることができるソフトで、無料で使えます。</p>



<p class="wp-block-paragraph">ここでは、Sambaを使って、ラズパイ上に共有フォルダを作成し、ネットワーク上のパソコンやスマホからファイルを読み書きできるように設定していきます。</p>



<h3 class="wp-block-heading">Sambaのインストール</h3>



<p class="wp-block-paragraph">まずは、Raspberry Piでコマンド操作をするために「<strong>ターミナル</strong>」を開きます。画面の左上にある黒いアイコン（ウィンドウに &gt; があるマーク）をクリックしてください。</p>



<p class="wp-block-paragraph">ターミナルが開いたら、以下のコマンドを入力して、Enterキーを押してください。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo apt update</code></pre></div>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/07/pi-terminal.jpg" alt="" class="wp-image-4"/></figure>



<div class="wp-block-sbd-balloon sbd-balloon sbd-balloon--id-4 sbd-balloon--flat sbd-balloon--l sbd-balloon--green block-box"><div class="sbd-balloon__profile"><figure class="sbd-balloon__icon"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/09/アイコン.jpg" alt="そぞら" class="sbd-balloon__img"/></figure><div class="sbd-balloon__name">そぞら</div></div><div class="sbd-balloon__text-box sbd-inner-block-init">
<p class="wp-block-paragraph"><code>sudo apt update</code> は、ソフトの最新情報を取得するコマンドです。ラズパイにインストールできるソフトの一覧を新しくして、次のインストール作業を正しく行えるようにします。</p>
</div></div>



<p class="wp-block-paragraph">以下のコマンドでSambaをインストールします。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo apt install samba -y</code></pre></div>



<h3 class="wp-block-heading">共有フォルダを作成する</h3>



<p class="wp-block-paragraph">ファイルを保存する場所となるフォルダをつくります。ここでは「share」という名前にします。以下は「<code>/home/pi</code> フォルダの中に <code>share</code> という名前の新しいフォルダを作るコマンド」です。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>mkdir /home/pi/share</code></pre></div>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="433" src="https://sozorablog.com/wp-content/uploads/2025/07/pico-2025-07-14T114702.682.png" alt="" class="wp-image-15440" style="width:436px;height:auto"/></figure>



<p class="wp-block-paragraph">作ったフォルダにファイルを保存できるように、誰でも中のファイルを読み書きできる設定にします。家庭内で使うだけなら、この設定で問題ありません。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>chmod 777 /home/pi/share</code></pre></div>



<h3 class="wp-block-heading">Sambaの設定ファイルを編集する</h3>



<p class="wp-block-paragraph">先ほど作成したフォルダを、ネットワーク上で共有するための設定を行います。Sambaの設定ファイルに、そのフォルダの場所やアクセス条件を追加します。以下を実行すると、Sambaの設定ファイル <code>smb.conf</code> をテキストエディタ（nano）で開いて編集できるようになります。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo nano /etc/samba/smb.conf</code></pre></div>



<p class="wp-block-paragraph">nanoが開いたら、キーボードの矢印キーで一番下までスクロールし、以下のような内容を追加してください。追加したら、<code>Ctrl + O</code> で保存し、<code>Enter</code> を押してから <code>Ctrl + X</code> で終了します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>[Share]
   path = /home/pi/share
   browseable = yes
   writable = yes
   guest ok = no
   valid users = pi</code></pre></div>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/07/pico-2025-07-12T045927.693.jpg" alt=""/></figure>



<p class="wp-block-paragraph">この設定では、<code>/home/pi/share</code> フォルダをネットワーク上に共有します。<code>browseable = yes</code> は、他の機器からこのフォルダを見えるようにする設定です。<code>writable = yes</code> によって、共有先からファイルの書き込みもできるようになります。<code>guest ok = no</code> は、誰でも自由にアクセスできる状態を防ぎ、ユーザー認証を求める設定です。最後の <code>valid users = pi</code> は、「pi」というユーザーだけがこのフォルダにアクセスできるよう制限しています。</p>



<div class="wp-block-sbd-checkpoint-block"><p class="sbd-checkpoint-title">チェックポイント</p><div class="sbd-checkpoint-content sbd-inner-block-init"><p>OSのインストール時に「pi」ではなく、別のユーザー名を設定した場合は、<code>valid users = pi</code> の部分を<strong>自分が設定したユーザー名に書き換える必要があります</strong>。たとえば「user1」という名前で設定していた場合は、<code>valid users = user1</code> と記載してください。設定と実際のユーザー名が一致していないと、共有フォルダにアクセスできません</p></div></div>



<h4 class="wp-block-heading">iPhoneからのアクセスに必要な追加設定</h4>



<p class="wp-block-paragraph">iPhoneの「ファイル」アプリから接続したときにファイルの保存ができないことがあるため、smb.confファイルの「[global]」という項目に、次の設定を追加してください。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code> vfs objects = fruit streams_xattr</code></pre></div>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="298" src="https://sozorablog.com/wp-content/uploads/2025/07/pico-2025-07-14T174917.187.png" alt="" class="wp-image-15446" style="width:628px;height:auto"/></figure>



<p class="wp-block-paragraph">iPhoneの「ファイル」アプリからSambaに接続すると、ログインしたユーザー名（たとえば「pi」）に対応するホームフォルダ（/home/pi）に自動でアクセスしてしまうことがあります。「share」フォルダだけを表示させたい場合は、以下のように<code>smb.conf</code> の <code>[homes]</code> セクションをすべてコメントアウトしてください。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/07/image-6.png" alt=""/></figure>



<h3 class="wp-block-heading">Sambaユーザーを登録する</h3>



<p class="wp-block-paragraph">Sambaにアクセスするためのパスワードを設定します。<br>以下のコマンドを入力してください。「pi」の部分は、自身が設定したユーザー名に適宜変更してください。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo smbpasswd -a pi</code></pre></div>



<p class="wp-block-paragraph">コマンドを実行すると、「New SMB password:」ようにパスワードを聞かれます。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/07/image.png" alt="" class="wp-image-4"/></figure>



<p class="wp-block-paragraph">ここで、自分が使いたいパスワードを入力します。<br>例：<code>raspi2025</code> など、自分で自由に決めてOKです。このパスワードは、Windowsやスマホからファイルサーバーにアクセスするときに使うことになります。</p>



<p class="wp-block-paragraph">確認のため2回パスワードを入力すると、以下のように表示され、設定が完了します。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/07/image-1.png" alt="" class="wp-image-4"/></figure>



<h3 class="wp-block-heading">Sambaを再起動する</h3>



<p class="wp-block-paragraph">設定を反映させるために、Sambaを再起動します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo systemctl restart smbd</code></pre></div>



<p class="wp-block-paragraph">これで、Raspberry Piの中にファイルを共有できるサーバーができました。</p>



<h3 class="wp-block-heading">IPアドレスの確認</h3>



<p class="wp-block-paragraph">他のデバイスからRaspberry Piに接続するために、IPアドレスを確認しておきます。画面の右上にある電波アイコンにカーソルを合わせると、IPアドレスが表示されます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/05/pico-2025-01-25T074301.726.jpg" alt="" class="wp-image-4" style="width:840px;height:auto"/></figure>



<h2 class="wp-block-heading">パソコンからアクセスする</h2>



<p class="wp-block-paragraph">Raspberry Piに共有フォルダの設定ができたら、次はパソコンからアクセスしてみましょう。ここでは、<strong>Windows</strong>と<strong>Mac</strong>の両方から接続する方法を紹介します。</p>



<h3 class="wp-block-heading">Windowsからアクセスする方法</h3>



<p class="wp-block-paragraph">キーボードの <code>Windowsキー + R</code> を押して、「ファイル名を指定して実行」ウィンドウを開きます。</p>



<p class="wp-block-paragraph">「<code>\\ラズパイのIPアドレス\share</code>」と入力してOKをクリックします。<br>　（例： <code>\\</code>192.168.1.159<code>\</code>share）</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/07/image-2.png" alt="" class="wp-image-4"/></figure>



<p class="wp-block-paragraph">ユーザー名とパスワードを求められたら、ラズパイ側で設定したものを入力します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/07/image-4.png" alt="" class="wp-image-4" style="width:473px;height:auto"/></figure>



<p class="wp-block-paragraph"><br>　ユーザー名は <code>pi</code>（または自分で設定した名前）、パスワードは <code>smbpasswd</code> で設定したものです。</p>



<p class="wp-block-paragraph">接続に成功すると、共有フォルダが表示されます。ファイルの読み書きが可能です。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/07/image-5.png" alt="" class="wp-image-4"/></figure>



<h3 class="wp-block-heading">Macからアクセスする方法</h3>



<p class="wp-block-paragraph">Finder を開き、メニューの「移動」→「サーバへ接続&#8230;」を選びます。<br>「サーバアドレス」に <code>smb://ラズパイのIPアドレス/share</code> を入力します。<br>　（例： <code>smb://192.168.1.159/share</code>）</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-13-5.10.28.png" alt="" class="wp-image-4"/></figure>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-13-5.11.54.png" alt="" class="wp-image-4"/></figure>



<p class="wp-block-paragraph">接続をクリックすると、ユーザー名とパスワードを聞かれます。<br>　ここも同様に、ユーザー名は <code>pi</code>（または自分で設定した名前）、パスワードはSamba用に設定したものです。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-13-5.12.46.png" alt="" class="wp-image-4"/></figure>



<p class="wp-block-paragraph">正しく入力すると、Finder上に共有フォルダが表示されます。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-13-5.14.08.png" alt="" class="wp-image-4"/></figure>



<h2 class="wp-block-heading">iPhoneからアクセスする</h2>



<p class="wp-block-paragraph">iPhoneからも、Raspberry Piに作った共有フォルダにアクセスできます。iPhoneに最初から入っている「<strong>ファイル</strong>」アプリを使えば簡単です。</p>



<p class="wp-block-paragraph">iPhoneで「ファイル」アプリを開きます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="640" src="https://sozorablog.com/wp-content/uploads/2025/07/pico-2025-07-13T170216.294.jpg" alt="" class="wp-image-15417" style="width:323px;height:auto"/></figure>



<p class="wp-block-paragraph">画面右上の「…（三点メニュー）」をタップし、「サーバへ接続」を選びます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="587" src="https://sozorablog.com/wp-content/uploads/2025/07/pico-2025-07-13T170502.467.png" alt="" class="wp-image-15418" style="width:324px;height:auto"/></figure>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="523" height="1080" src="https://sozorablog.com/wp-content/uploads/2025/07/pico-2025-07-13T170120.864.png" alt="" class="wp-image-15416" style="width:185px;height:auto"/></figure>



<p class="wp-block-paragraph">「smb://ラズパイのIPアドレス」を入力します（例： <code>smb://192.168.1.159<code>/</code></code>）。フォルダ名（例：<code>/share</code>）を付けても反映されないため、IPアドレスのみを入力してください。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="750" height="405" src="https://sozorablog.com/wp-content/uploads/2025/07/IMG_9252.png" alt="" class="wp-image-15419" style="width:419px;height:auto"/></figure>



<p class="wp-block-paragraph">接続方法を聞かれたら「登録ユーザー」を選び、ユーザー名（例：pi）とSambaで設定したパスワードを入力します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="750" height="750" src="https://sozorablog.com/wp-content/uploads/2025/07/IMG_9249.jpeg" alt="" class="wp-image-15422" style="width:416px;height:auto"/></figure>



<p class="wp-block-paragraph">接続が完了すると、共有フォルダが表示され、ファイルの表示・保存ができるようになります。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="750" height="501" src="https://sozorablog.com/wp-content/uploads/2025/07/IMG_9251.jpeg" alt="" class="wp-image-15421" style="width:416px;height:auto"/></figure>



<h2 class="wp-block-heading">Sambaが不要になった場合の削除方法</h2>



<p class="wp-block-paragraph">ファイル共有が不要になった場合に、Sambaを削除する方法を紹介します。使っていない共有機能を放置しておくと、思わぬセキュリティリスクになることもあるため、必要がなくなったら整理しておきましょう。</p>



<p class="wp-block-paragraph">Samba本体を削除します。ターミナルを開いて、以下のコマンドを実行してください。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo apt remove samba samba-common -y</code></pre></div>



<p class="wp-block-paragraph">これでファイル共有機能が無効になります。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://sozorablog.com/raspberry-pi-file-server/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>ラズパイで気象衛星ひまわりの画像を表示する装置を作ろう</title>
		<link>https://sozorablog.com/himawari/</link>
					<comments>https://sozorablog.com/himawari/#comments</comments>
		
		<dc:creator><![CDATA[そぞら]]></dc:creator>
		<pubDate>Tue, 17 Jun 2025 08:03:57 +0000</pubDate>
				<category><![CDATA[Raspberry Pi]]></category>
		<category><![CDATA[使い方]]></category>
		<guid isPermaLink="false">https://sozorablog.com/?p=14947</guid>

					<description><![CDATA[はるか3万6千kmの上空から、静かに地球を見つめる「気象衛星ひまわり」。 その目に映る宇宙の静けさと地球のうつろいを、自宅の小さなディスプレイに映し出せたら…そんな夢のような装置をRaspberry Piで作ってみました [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">はるか3万6千kmの上空から、静かに地球を見つめる「気象衛星ひまわり」。</p>



<p class="wp-block-paragraph">その目に映る宇宙の静けさと地球のうつろいを、自宅の小さなディスプレイに映し出せたら…そんな夢のような装置を<a href="https://sozorablog.com/raspberry-pi/">Raspberry Pi</a>で作ってみました。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="777" src="https://sozorablog.com/wp-content/uploads/2025/06/IMG_9116.jpg" alt="" class="wp-image-15147"/></figure>



<p class="wp-block-paragraph"><br>この記事では、ひまわりの最新画像を自動で取得して、ディスプレイ表示するシステムの作り方を紹介します。比較的安価な小型ディスプレイを使っているので、ぜひお試しください。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="536" src="https://sozorablog.com/wp-content/uploads/2025/06/IMG_9021.jpg" alt="" class="wp-image-15132"/></figure>



<p class="wp-block-paragraph">記事の後半では、ダイソーのミラーデジタル時計に装置一式を収納する応用方法も紹介しています。</p>



<h2 class="wp-block-heading">用意するもの</h2>



<p class="wp-block-paragraph">使用したラズパイは、<a href="https://sozorablog.com/raspberry-pi-zero-2-w/">Raspberry Pi Zero 2 W</a>にピンヘッダーを取り付けたものです。サイズ的にもスペック的にも今回のプロジェクトに適任です。まだ持っていない場合は、あらかじめピンヘッダーが実装されている「WH」モデルを選ぶと、配線作業がスムーズに進みます。</p>



<!-- START MoshimoAffiliateEasyLink -->
<script type="text/javascript">
(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;
b[a]=b[a]||function(){arguments.currentScript=c.currentScript
||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};
c.getElementById(a)||(d=c.createElement(f),d.src=g,
d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})
(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");
msmaflink({"n":"Raspberry Pi Zero 2 WH - はんだ付け済みヘッダー付き","b":"Raspberry Pi","t":"SC0721","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/3163qDOAfcL._SL500_.jpg","\/31+bar+PxKL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/B0DB2JBD9C","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/B0DB2JBD9C","a_id":3038653,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/Raspberry%20Pi%20Zero%202%20WH%20-%20%E3%81%AF%E3%82%93%E3%81%A0%E4%BB%98%E3%81%91%E6%B8%88%E3%81%BF%E3%83%98%E3%83%83%E3%83%80%E3%83%BC%E4%BB%98%E3%81%8D\/","a_id":3038654,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2}],"eid":"OtHms","s":"s"});
</script>
<div id="msmaflink-OtHms">リンク</div>
<!-- MoshimoAffiliateEasyLink END -->



<p class="wp-block-paragraph">Zero 2 Wの<a href="https://www.sengoku.co.jp/mod/sgk_cart/detail.php?code=EEHD-6JMG">電源アダプター</a>は、2.5A以上が推奨されています。コネクタはmicroUSBです。</p>



<p class="wp-block-paragraph">本記事のコードは、以下のモデルでも動作確認しています。</p>



<div class="wp-block-sbd-list"><ul class="sbd-list sbd-list-border"><li><a href="https://sozorablog.com/pi5/">Raspberry Pi 5</a></li><li><a href="https://sozorablog.com/raspberry-pi-4-revue/">Raspberry Pi 4</a></li><li><a href="https://sozorablog.com/raspberry-pi-3-model-a/">Raspberry Pi 3 A+</a></li><li><a href="https://sozorablog.com/raspberry-pi-500/">Raspberry Pi 500</a></li></ul></div>



<p class="wp-block-paragraph">表示に使用したのは、SPI接続のILI9341ドライバーを搭載した2.2インチのディスプレイです。解像度は240×320ピクセルで、気象衛星ひまわりの画像も鮮明に表示できます。</p>



<!-- START MoshimoAffiliateEasyLink -->
<script type="text/javascript">
(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;
b[a]=b[a]||function(){arguments.currentScript=c.currentScript
||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};
c.getElementById(a)||(d=c.createElement(f),d.src=g,
d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})
(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");
msmaflink({"n":"Hailege 2.2\u0022 ILI9341 SPI TFT LCDディスプレイ240x320 ILI9341 LCDスクリーン、Arduino Raspberry Pi用SDカードスロット","b":"Hailege","t":"H-A-0191","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/418wYf3koZL._SL500_.jpg","\/41t5jOFHmxL._SL500_.jpg","\/41J2n4cDVNL._SL500_.jpg","\/41J0D7SgIsL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/B08D7D14X9","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/B08D7D14X9","a_id":3038653,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/Hailege%202.2%22%20ILI9341%20SPI%20TFT%20LCD%E3%83%87%E3%82%A3%E3%82%B9%E3%83%97%E3%83%AC%E3%82%A4240x320%20ILI9341%20LCD%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%80%81Arduino%20Raspberry%20Pi%E7%94%A8SD%E3%82%AB%E3%83%BC%E3%83%89%E3%82%B9%E3%83%AD%E3%83%83%E3%83%88\/","a_id":3038654,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2}],"eid":"JcjPt","s":"s"});
</script>
<div id="msmaflink-JcjPt">リンク</div>
<!-- MoshimoAffiliateEasyLink END -->



<p class="wp-block-paragraph">Raspberry PiとLCDを接続するためのジャンパーワイヤーが必要です。ジャンパーワイヤーはGPIOピンとディスプレイの端子に差し込んで接続するための細い電線です。今回はメス－メスのジャンパーワイヤーを9本使用します。</p>



<!-- START MoshimoAffiliateEasyLink -->
<script type="text/javascript">
(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;
b[a]=b[a]||function(){arguments.currentScript=c.currentScript
||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};
c.getElementById(a)||(d=c.createElement(f),d.src=g,
d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})
(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");
msmaflink({"n":"ELEGOO 120pcs多色デュポンワイヤー、arduino用ワイヤ—ゲ—ジ28AWG オス-メス オス-オス メス –メス ブレッドボードジャンパーワイヤー","b":"ELEGOO","t":"JP-EL-CP-004","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/61TQP733AwL._SL500_.jpg","\/51HXtm4ZIlL._SL500_.jpg","\/51X0hlpDgxL._SL500_.jpg","\/51xNzsKVu0L._SL500_.jpg","\/51kRXsE11KL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/B06Y48V9DL","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/B06Y48V9DL","a_id":3038653,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/ELEGOO%20120pcs%E5%A4%9A%E8%89%B2%E3%83%87%E3%83%A5%E3%83%9D%E3%83%B3%E3%83%AF%E3%82%A4%E3%83%A4%E3%83%BC%E3%80%81arduino%E7%94%A8%E3%83%AF%E3%82%A4%E3%83%A4%E2%80%94%E3%82%B2%E2%80%94%E3%82%B828AWG%20%E3%82%AA%E3%82%B9-%E3%83%A1%E3%82%B9%20%E3%82%AA%E3%82%B9-%E3%82%AA%E3%82%B9%20%E3%83%A1%E3%82%B9%20%E2%80%93%E3%83%A1%E3%82%B9%20%E3%83%96%E3%83%AC%E3%83%83%E3%83%89%E3%83%9C%E3%83%BC%E3%83%89%E3%82%B8%E3%83%A3%E3%83%B3%E3%83%91%E3%83%BC%E3%83%AF%E3%82%A4%E3%83%A4%E3%83%BC\/","a_id":3038654,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2}],"eid":"Njd8v","s":"s"});
</script>
<div id="msmaflink-Njd8v">リンク</div>
<!-- MoshimoAffiliateEasyLink END -->



<h2 class="wp-block-heading">ラズパイとディスプレイの接続</h2>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="807" src="https://sozorablog.com/wp-content/uploads/2025/06/IMG_9089.jpg" alt="" class="wp-image-15152" style="width:477px;height:auto"/></figure>



<p class="wp-block-paragraph">ディスプレイは、SPI通信を使ってRaspberry Piと接続します。配線には、データ転送に必要なSCKやMOSIのほか、制御用のCS（チップセレクト）、DC（データ/コマンド切り替え）、RST（リセット）ピン、さらにバックライト用のBLピンを使用します。</p>



<p class="wp-block-paragraph">以下の図のように、ジャンパーワイヤーを使ってRaspberry PiのGPIOピンとディスプレイの各ピンを接続します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="450" src="https://sozorablog.com/wp-content/uploads/2025/06/pico-1.jpg" alt="" class="wp-image-15139" style="width:840px;height:auto" srcset="https://sozorablog.com/wp-content/uploads/2025/06/pico-1.jpg 800w, https://sozorablog.com/wp-content/uploads/2025/06/pico-1-320x180.jpg 320w, https://sozorablog.com/wp-content/uploads/2025/06/pico-1-224x126.jpg 224w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<h2 class="wp-block-heading">ソフトウェアの準備</h2>



<p class="wp-block-paragraph">Raspberry Pi OSはBookworm 64-bitのデスクトップ版を使用しました。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="461" height="128" src="https://sozorablog.com/wp-content/uploads/2025/06/image-1.png" alt="" class="wp-image-15146" style="width:840px;height:auto"/></figure>



<div class="wp-block-sbd-background-block sbd-bg-color sbd-inner-block-init is-style-yellow">
<p class="wp-block-paragraph">Raspberry PiのOSをインストールする方法は、以下の記事で詳しく解説しています。<br><strong><a href="https://sozorablog.com/raspberrypi_initial_setting/">≫【2025年最新版】OSインストールから初期設定まで｜セットアップ手順のすべて</a></strong></p>
</div>



<h3 class="wp-block-heading">ラズパイのSPIを有効にする</h3>



<p class="wp-block-paragraph">LCDを使うには、SPIインターフェースを有効にする必要があります。</p>



<p class="wp-block-paragraph">デスクトップ左上の「ラズベリーマーク（メニュー）」をクリックし、設定」→「Raspberry Piの設定」を選びます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/11/pico-2-3.jpg" alt="" style="width:533px;height:auto"/></figure>



<p class="wp-block-paragraph">「インターフェイス」タブを開き、「SPI」の項目を「有効」に切り替えます。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/06/pico-1.png" alt=""/><figcaption class="wp-element-caption">SPIが有効になっている状態</figcaption></figure>



<p class="wp-block-paragraph">再起動を求められた場合は「はい」を選んで再起動します。</p>



<h3 class="wp-block-heading">ライブラリのインストール</h3>



<p class="wp-block-paragraph">Pythonで使う「ライブラリ」とは、便利な機能が詰まった道具箱のようなものです。ライブラリ使うと、本来は長くなってしまうプログラムを短いコードで書けるようになります。</p>



<p class="wp-block-paragraph">以下の手順に沿って、必要なライブラリをインストールします。インストール作業はターミナルを使って行います。</p>



<div class="wp-block-sbd-balloon sbd-balloon sbd-balloon--id-4 sbd-balloon--flat sbd-balloon--l sbd-balloon--green block-box"><div class="sbd-balloon__profile"><figure class="sbd-balloon__icon"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/09/アイコン.jpg" alt="そぞら" class="sbd-balloon__img"/></figure><div class="sbd-balloon__name">そぞら</div></div><div class="sbd-balloon__text-box sbd-inner-block-init">
<p class="wp-block-paragraph">ターミナルとは、コマンドを入力してRaspberry Piを操作するための画面です。</p>
</div></div>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="485" src="https://sozorablog.com/wp-content/uploads/2025/06/pico-99.jpg" alt="" class="wp-image-15138"/></figure>



<p class="wp-block-paragraph">Pythonライブラリをインストールするため仮想環境myenvを作成します。myenvは仮想環境の名前です。好きな名前に変更できます。</p>



<div class="wp-block-sbd-checkpoint-block"><p class="sbd-checkpoint-title">チェックポイント</p><div class="sbd-checkpoint-content sbd-inner-block-init"><p>仮想環境とは、Pythonの実行環境をプロジェクトごとに独立して管理できる仕組みです。これにより、ライブラリ同士のバージョンによる競合を防ぎ、予期せぬエラーを回避できます。</p></div></div>



<div class="wp-block-sbd-balloon sbd-balloon sbd-balloon--id-4 sbd-balloon--flat sbd-balloon--l sbd-balloon--green block-box"><div class="sbd-balloon__profile"><figure class="sbd-balloon__icon"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/09/アイコン.jpg" alt="そぞら" class="sbd-balloon__img"/></figure><div class="sbd-balloon__name">そぞら</div></div><div class="sbd-balloon__text-box sbd-inner-block-init">
<p class="wp-block-paragraph">Bookwormでは仮想環境を使用せずにpipを実行するとエラーが発生し、ライブラリをインストールできない仕様になっています。</p>
</div></div>



<p class="wp-block-paragraph">下記のコマンドをターミナルに入力してEnterキーを押してください。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>python3 -m venv ~/myenv --system-site-packages</code></pre></div>



<p class="wp-block-paragraph">作成した仮想環境myenvを有効にします。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>source myenv/bin/activate</code></pre></div>



<p class="wp-block-paragraph">pipを最新バージョンにアップグレードします。pipはPython専用のインストールツールです。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>pip install --upgrade pip</code></pre></div>



<p class="wp-block-paragraph"><a href="https://www.adafruit.com/?srsltid=AfmBOoqUEpXUkQP7sp5Gpo9RHC3zaQFOsHqDF4iv92B5WlyezkfNyHgW">Adafruit</a>が公開しているRGBディスプレイを制御するための<a href="https://github.com/adafruit/Adafruit_CircuitPython_RGB_Display">adafruit-circuitpython-rgb-display</a>ライブラリをインストールします。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>pip install adafruit-circuitpython-rgb-display</code></pre></div>



<div class="wp-block-sbd-balloon sbd-balloon sbd-balloon--id-4 sbd-balloon--flat sbd-balloon--l sbd-balloon--green block-box"><div class="sbd-balloon__profile"><figure class="sbd-balloon__icon"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/09/アイコン.jpg" alt="そぞら" class="sbd-balloon__img"/></figure><div class="sbd-balloon__name">そぞら</div></div><div class="sbd-balloon__text-box sbd-inner-block-init">
<p class="wp-block-paragraph">adafruit-circuitpython-rgb-displayは、ILI9341などの汎用的なディスプレイコントローラーにも対応しており、Adafruit製以外のディスプレイでも利用できます。</p>
</div></div>



<div class="wp-block-sbd-checkpoint-block"><p class="sbd-checkpoint-title">チェックポイント</p><div class="sbd-checkpoint-content sbd-inner-block-init"><p>Raspberry Pi OSの最新版「Bookworm」を使っていると、<code>adafruit-circuitpython-rgb-display</code>をインストールした際に、<strong>Jetson.GPIOという不要なライブラリ</strong>が一緒に入ることがあります。この状態でプログラムを実行すると、「Exception: Could not determine Jetson model」のようなエラーが出ることがあります。</p><p>解決策として、次のコマンドで不要なライブラリを削除します：</p><p>pip uninstall -y Jetson.GPIO</p></div></div>



<h2 class="wp-block-heading">ディスプレイの動作確認をする</h2>



<p class="wp-block-paragraph">Raspberry PiでPythonのプログラムを動かして、ディスプレイが正常に動作するかを確認します。</p>



<h3 class="wp-block-heading">Thonnyを使ってPythonプログラムを実行する</h3>



<p class="wp-block-paragraph">Raspberry Piでは「Thonny（ソニー）」という初心者向けのPython開発環境が標準でインストールされています。以下の手順でプログラムを実行できます。</p>



<p class="wp-block-paragraph">デスクトップ画面左上の「ラズベリーメニュー」から「プログラミング」→「Thonny」を開く。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="580" src="https://sozorablog.com/wp-content/uploads/2025/06/pico-2-2.jpg" alt="" class="wp-image-15145" style="width:516px;height:auto"/></figure>



<p class="wp-block-paragraph">Thonnyでは画面上部の大きな白いスペースにプログラムを入力し、画面上の「▶（再生マーク）」をクリックします。すると、下の部分（シェル）に実行結果が表示されます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="508" src="https://sozorablog.com/wp-content/uploads/2025/06/pico-1-1-1.jpg" alt="" class="wp-image-15148" style="width:620px;height:auto"/></figure>



<p class="wp-block-paragraph">ディスプレイのプログラムを実行する前に、<span class="sbd-text-bg-yellow">仮想環境に切り替える</span>操作をします。</p>



<div class="wp-block-sbd-balloon sbd-balloon sbd-balloon--id-4 sbd-balloon--flat sbd-balloon--l sbd-balloon--green block-box"><div class="sbd-balloon__profile"><figure class="sbd-balloon__icon"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/09/アイコン.jpg" alt="そぞら" class="sbd-balloon__img"/></figure><div class="sbd-balloon__name">そぞら</div></div><div class="sbd-balloon__text-box sbd-inner-block-init">
<p class="wp-block-paragraph">仮想環境に切り替えることにより、先ほどインストールしたライブラリが使用可能になります。</p>
</div></div>



<h3 class="wp-block-heading">仮想環境への切り替え</h3>



<p class="wp-block-paragraph">Thonnyでそのままプログラムを実行すると、先ほどインストールしたライブラリが見つからずにエラーが出ます。これを避けるため、以下の手順で仮想環境に切り替えます。</p>



<p class="wp-block-paragraph">Thonnyの画面右下部分をクリックします。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/06/pico-7.png" alt="" style="width:514px;height:auto"/></figure>



<p class="wp-block-paragraph">「Configure interpreter&#8230;」をクリック。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="328" src="https://sozorablog.com/wp-content/uploads/2025/06/pico-1-1-1.png" alt="" class="wp-image-15133" style="width:512px;height:auto"/></figure>



<p class="wp-block-paragraph">「&#8230;」のボタンをクリック。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="615" src="https://sozorablog.com/wp-content/uploads/2025/06/pico-3-1.png" alt="" class="wp-image-15150" style="width:513px;height:auto"/></figure>



<p class="wp-block-paragraph">「ホーム」をクリックする。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="386" src="https://sozorablog.com/wp-content/uploads/2025/06/pico-4-2.png" alt="" class="wp-image-15135"/></figure>



<p class="wp-block-paragraph">先ほど作成した仮想環境のmyenvフォルダを開き、binフォルダ内のpythonを選択します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="450" src="https://sozorablog.com/wp-content/uploads/2025/06/pico-5-1.png" alt="" class="wp-image-15136" style="width:764px;height:auto" srcset="https://sozorablog.com/wp-content/uploads/2025/06/pico-5-1.png 800w, https://sozorablog.com/wp-content/uploads/2025/06/pico-5-1-320x180.png 320w, https://sozorablog.com/wp-content/uploads/2025/06/pico-5-1-224x126.png 224w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<p class="wp-block-paragraph">「OK」をクリックします。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/06/pico-6.png" alt="" style="width:466px;height:auto"/></figure>



<p class="wp-block-paragraph">プログラムの実行環境が仮想環境に切り替わりました。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="529" src="https://sozorablog.com/wp-content/uploads/2025/06/pico-0b6acb87-d27b-482d-8ad9-f073d7925d1f.png" alt="" class="wp-image-15137" style="width:472px;height:auto"/></figure>



<h3 class="wp-block-heading">テスト用コードの実行</h3>



<p class="wp-block-paragraph">以下は、ディスプレイに赤い背景と「Hello, ILI9341!」という文字を表示する<strong>シンプルな動作確認用コード</strong>です。Thonny画面上部のスペースにコピーペーストし、画面上の「▶（再生マーク）」をクリックします。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>from board import SCK, MOSI, MISO, D5, D18, D23, D24
from busio import SPI
from digitalio import DigitalInOut, Direction
from adafruit_rgb_display.ili9341 import ILI9341
from PIL import Image, ImageDraw, ImageFont

# Setup GPIO pins for display
CS = DigitalInOut(D5)
DC = DigitalInOut(D24)
RST = DigitalInOut(D23)
BL = DigitalInOut(D18)
BL.direction = Direction.OUTPUT
BL.value = True  # Turn on backlight

# Initialize SPI and display
spi = SPI(clock=SCK, MOSI=MOSI, MISO=MISO)
display = ILI9341(spi, cs=CS, dc=DC, rst=RST, width=240, height=320)

# Create a red image
image = Image.new(&quot;RGB&quot;, (240, 320), (255, 0, 0))
draw = ImageDraw.Draw(image)

# Load default font
font = ImageFont.load_default()

# Draw text
draw.text((20, 150), &quot;Hello, ILI9341!&quot;, font=font, fill=(255, 255, 255))

# Display the image
display.image(image)
</code></pre></div>



<p class="wp-block-paragraph">このコードでは、最初にGPIOピンを設定します。ディスプレイのCS（チップセレクト）、DC（データ/コマンド）、RST（リセット）には、それぞれD5、D24、D23のピンを割り当てています。また、D18のピンを使ってバックライト（BL）を制御し、出力として設定した上で点灯させます。</p>



<p class="wp-block-paragraph">次に、SPI通信を初期化します。Raspberry PiのSCK（クロック）、MOSI（マスターアウトスレーブイン）、MISO（マスターインスレーブアウト）のピンを使い、ILI9341ディスプレイと通信する準備を整えます。</p>



<p class="wp-block-paragraph">ディスプレイを使うために、画面の幅を240ピクセル、高さを320ピクセルとして初期設定を行います。次に、Pillowライブラリを使って赤い背景の画像を作り、その上に白い文字で「Hello, ILI9341!」というメッセージを描きます。</p>



<p class="wp-block-paragraph">最後にその画像を <code>.image()</code> メソッドを使ってディスプレイに表示します。これにより、ディスプレイの接続やSPI通信が正常に行われているかを確認できます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/06/IMG_9091.jpeg" alt="" style="width:456px;height:auto"/></figure>



<h2 class="wp-block-heading">ひまわり画像の取得先と画像タイプの違い</h2>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/06/himawari89.jpg" alt=""/></figure>



<p class="wp-block-paragraph">「ひまわり」は日本の気象庁が運用する静止気象衛星で、赤道上空約3万6千kmの宇宙空間に位置し、<span class="sbd-text-red">地球の同じ場所を常に観測</span>し続けています。現在は「ひまわり8号」と「9号」が運用されており、アジア太平洋地域全体をリアルタイムに監視しています。</p>



<p class="wp-block-paragraph">本プロジェクトでは、国立情報学研究所（NII）が提供する<a href="https://agora.ex.nii.ac.jp/digital-typhoon/">デジタル台風（Digital Typhoon）</a>という公開データベースからひまわりの画像を取得します。</p>



<p class="wp-block-paragraph">気象衛星画像には「赤外画像」と「可視画像」の2種類があります。</p>



<figure class="wp-block-table wp-block-sbd-table wp-block-sbd-table-vertical"><table class="has-fixed-layout"><thead><tr><th>種類</th><th>特徴</th><th>メリット</th><th>デメリット</th></tr></thead><tbody><tr><td>赤外画像<br><img decoding="async" width="150" height="150" class="wp-image-14991" style="width: 150px;" src="https://sozorablog.com/wp-content/uploads/2025/06/ir.jpg" alt=""></td><td>赤外線（熱）をとらえて表示</td><td>昼夜問わず常に全体を表示可能</td><td>色味がやや不自然</td></tr><tr><td>可視画像<br><img decoding="async" width="150" height="150" class="wp-image-14992" style="width: 150px;" src="https://sozorablog.com/wp-content/uploads/2025/06/20250611070000.jpg" alt=""></td><td>太陽光を反射した様子を表示</td><td>昼間は自然な見た目で美しい</td><td>夜間はほとんど見えない</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">赤外画像は、地球や雲が放つ赤外線（熱）をもとに作られており、昼夜を問わず常に地球全体が表示されます。夜でも雲の動きが見えるのが大きな利点です。ただし、<span class="sbd-text-red">色味</span><span class="sbd-text-red">が</span><span class="sbd-text-red">人工的で、可視画像のような自然な見た目ではありません</span>。</p>



<p class="wp-block-paragraph">可視画像は太陽の光を反射した様子をとらえたもので、雲や地表を<span class="sbd-text-bg-yellow">自然な美しい色合い</span>で表示します。昼間は鮮明に表示されますが、夜間は太陽光が当たらないため地球の一部が暗くなり、月の満ち欠けのように少しずつ見える範囲が変化します。そのため、<span class="sbd-text-red">夜間はほとんど何も見えず</span>、表示としては物足りない場合があります。</p>



<p class="wp-block-paragraph">本記事ではこれらの特徴を活かした<span class="sbd-text-bold">2つの表示方法</span>を紹介します。ひとつは最新の赤外画像をシンプルに表示する方法。もうひとつは直近24時間分の可視画像を集めて、連続再生するアニメーション表示です。</p>



<h2 class="wp-block-heading">ひまわりの赤外画像を表示</h2>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/06/IMG_9090.jpeg" alt=""/></figure>



<p class="wp-block-paragraph">以下のコードはRaspberry Piで気象衛星ひまわりの赤外画像を10分ごとに取得し、ILI9341ディスプレイに表示するものです。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>import time
import requests
from PIL import Image, ImageDraw
from io import BytesIO

from board import SCK, MOSI, MISO, D5, D18, D23, D24
from busio import SPI
from digitalio import DigitalInOut, Direction
from adafruit_rgb_display.ili9341 import ILI9341

# --- Display setup ---
CS = DigitalInOut(D5)
DC = DigitalInOut(D24)
RST = DigitalInOut(D23)
BL = DigitalInOut(D18)
BL.direction = Direction.OUTPUT
BL.value = True

spi = SPI(clock=SCK, MOSI=MOSI, MISO=MISO)
display = ILI9341(spi, cs=CS, dc=DC, rst=RST, width=240, height=320)

# ひまわりの最新画像を取得する関数
def fetch_image():
    url = &quot;http://agora.ex.nii.ac.jp/digital-typhoon/latest/globe/512x512/ir.jpg&quot;
    try:
        response = requests.get(url, timeout=10)
        response.raise_for_status()
        img = Image.open(BytesIO(response.content)).convert(&quot;RGB&quot;)
        return img
    except Exception as e:
        print(&quot;Fetch failed:&quot;, e)
        return None

# 表示用に画像を整形する関数
def prepare_image(img):
    img = img.rotate(90, expand=True) # 表示向きに90度回転 
    img = img.resize((240, 240))      # ディスプレイ用にサイズ変更

    # 円形マスクを作成して地球部分だけを切り抜き
    mask = Image.new(&quot;L&quot;, (240, 240), 0)
    draw = ImageDraw.Draw(mask)
    draw.ellipse((0, 0, 240, 240), fill=255)

    black_bg = Image.new(&quot;RGB&quot;, (240, 240), (0, 0, 0))       # 黒背景画像
    earth_only = Image.composite(img, black_bg, mask)        # 円形で切り抜いた画像と合成

    canvas = Image.new(&quot;RGB&quot;, (240, 320), (0, 0, 0))
    canvas.paste(earth_only, (0, 40))
    return canvas

# --- メインループ ---
last_canvas = None

while True:
    img = fetch_image()
    if img:
        last_canvas = prepare_image(img)
        print(&quot;New image fetched and prepared.&quot;)
    else:
        print(&quot;Using previous image.&quot;)

    if last_canvas:
        display.image(last_canvas)

    time.sleep(600)  # 10 minutes

</code></pre></div>



<p class="wp-block-paragraph">まず、<code>fetch_image()</code>関数では、「デジタル台風」のサイトから最新の<span class="sbd-text-red">赤外画像</span>をダウンロードし、PILライブラリを使って画像として読み込みます。使用している画像のURLは <code>http://agora.ex.nii.ac.jp/digital-typhoon/latest/globe/512x512/ir.jpg</code> で、このURLは<span class="sbd-text-bg-yellow">1時間ごと</span>に新しい画像が公開されます。</p>



<p class="wp-block-paragraph">画像を表示する前に、<code>prepare_image()</code>関数でディスプレイに合わせた加工を行います。画像は90度回転させ、ディスプレイの横向き表示に対応させています。続いて画像サイズを240×240に縮小し、円形のマスクをかけることで、日付や時刻などの文字を隠し、地球だけが目立つように調整。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="305" src="https://sozorablog.com/wp-content/uploads/2025/06/himawari_save1png-1.jpg" alt="" class="wp-image-15141" style="width:824px;height:auto"/></figure>



<p class="wp-block-paragraph">最後に、ディスプレイと同じサイズである240×320ピクセルのキャンバスの中央に、地球の画像を配置します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="313" src="https://sozorablog.com/wp-content/uploads/2025/06/himawari_save2-1.jpg" alt="" class="wp-image-15142" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph">メイン処理では、まず画像を取得して加工し、ディスプレイに表示します。取得に失敗した場合でも、最後に表示した画像をそのまま再表示することで、画面が真っ黒になってしまうのを防ぎます。この処理は10分ごとに繰り返されるため、新しい画像があれば自動的に更新されます。</p>



<p class="wp-block-paragraph">赤外画像は昼夜を問わず観測できるため、常に地球全体を表示できます。</p>



<h2 class="wp-block-heading">ひまわりの可視画像をアニメーション表示する</h2>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/06/pico-6-1.jpg" alt=""/></figure>



<p class="wp-block-paragraph">赤外画像は色合いが人工的で、可視画像のような自然な見た目にはなりません。一方、可視画像は昼間は美しく表示されますが、夜は真っ暗になります。そこで、直近24時間分の可視画像を集めて連続再生することで、常に表示があり、動きのある地球を楽しめるようにしました。</p>



<h3 class="wp-block-heading">ひまわりの可視画像を保存するプログラム</h3>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/06/pico-7-1.jpg" alt="" style="width:840px;height:auto"/><figcaption class="wp-element-caption">2つのプログラムを別々に実行する</figcaption></figure>



<p class="wp-block-paragraph">本プロジェクトではプログラムが複雑になりすぎないように、画像の取得用プログラムと、保存された画像をアニメーションのように表示するプログラムを<span class="sbd-text-bg-yellow">分けて作成</span>し、それぞれを同時に実行する構成としました。</p>



<p class="wp-block-paragraph">ここでは、まず画像を保存する側のプログラムを紹介します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>import os
import requests
from datetime import datetime, timedelta, timezone
from PIL import Image
from io import BytesIO
import time

# Constants
IMAGE_DIR = &quot;/home/pi/image&quot;
MAX_IMAGES = 144
INTERVAL = 8 * 60  # 8 minutes

# JST timezone
JST = timezone(timedelta(hours=9))

# Ensure image directory exists
os.makedirs(IMAGE_DIR, exist_ok=True)

# 最新の保存済み画像の時刻を取得する
def get_latest_saved_time():
    files = sorted(f for f in os.listdir(IMAGE_DIR) if f.endswith(&quot;.bmp&quot;))
    if not files:
        return None
    latest_file = files[-1]
    try:
        dt = datetime.strptime(latest_file[:13], &quot;%Y%m%d_%H%M&quot;)  # ?: &quot;20250612_1530&quot;
        return dt
    except Exception:
        return None

# 指定時刻から取得候補となる「分」のリストを返す（10分刻み）
def generate_valid_minute_slots(base_time_utc, full=False):
    if full:
        return [&quot;50&quot;, &quot;40&quot;, &quot;30&quot;, &quot;20&quot;, &quot;10&quot;, &quot;00&quot;]
    current_minute = int(base_time_utc.strftime(&#39;%M&#39;))
    return [f&quot;{m:02d}&quot; for m in [50, 40, 30, 20, 10, 0] if m &lt;= current_minute]

# 指定された画像を保存する（JSTのタイムスタンプをファイル名に付ける）
def save_image(canvas, jst_dt):
    filename = jst_dt.strftime(&quot;%Y%m%d_%H%M&quot;) + &quot;.bmp&quot;
    filepath = os.path.join(IMAGE_DIR, filename)
    canvas.save(filepath, format=&quot;BMP&quot;)
    print(f&quot;Saved: {filepath}\n&quot;)

# 古い画像を削除して、最大枚数を超えないようにする
def cleanup_old_images():
    files = sorted(f for f in os.listdir(IMAGE_DIR) if f.endswith(&quot;.bmp&quot;))
    print(len(files))
    while len(files) &gt; MAX_IMAGES:
        os.remove(os.path.join(IMAGE_DIR, files[0]))
        print(&quot;Deleted:&quot;, files[0])
        files.pop(0)

# 指定したUTC時刻をもとに画像を取得し、保存・整理を行う
def try_fetch_and_save(base_time_utc, full_range=False):
    date_str = base_time_utc.strftime(&#39;%Y/%m/%d&#39;)
    base_date_str = base_time_utc.strftime(&#39;%Y%m%d&#39;)
    hour_str = base_time_utc.strftime(&#39;%H&#39;)
    minute_slots = generate_valid_minute_slots(base_time_utc, full=full_range)

    for mnt in minute_slots:
        time_str = f&quot;{base_date_str}{hour_str}{mnt}&quot;
        url = f&quot;http://agora.ex.nii.ac.jp/digital-typhoon/iiif/{date_str}/{time_str}00.tif/0,0,11000,11000/688,/0/default.jpg&quot;

        try:
            response = requests.get(url, timeout=10)
            response.raise_for_status()
            img = Image.open(BytesIO(response.content)).rotate(90, expand=True)
            img = img.resize((240, 240))
            canvas = Image.new(&quot;RGB&quot;, (240, 320), (0, 0, 0))
            canvas.paste(img, (0, 40))
            jst_dt = datetime.strptime(time_str + &quot;00&quot;, &quot;%Y%m%d%H%M%S&quot;).replace(tzinfo=timezone.utc).astimezone(JST)
            save_image(canvas, jst_dt)
            cleanup_old_images()
            return True
        except Exception:
            jst_dt = datetime.strptime(time_str + &quot;00&quot;, &quot;%Y%m%d%H%M%S&quot;).replace(tzinfo=timezone.utc).astimezone(JST)
            print(&quot;No data time (JST):&quot;, jst_dt.strftime(&quot;%Y/%m/%d %H:%M:%S&quot;))
            time.sleep(2)
    return False

# Main loop
while True:
    wait_after_backfill = False

    latest_jst = get_latest_saved_time()
    if latest_jst:
        target_jst = latest_jst - timedelta(minutes=10)
        filename = target_jst.strftime(&quot;%Y%m%d_%H%M&quot;) + &quot;.bmp&quot;
        filepath = os.path.join(IMAGE_DIR, filename)
        if not os.path.exists(filepath):
            print(&quot;Trying backfill for:&quot;, filename)
            target_utc = target_jst.astimezone(timezone.utc)
            if try_fetch_and_save(target_utc):
                wait_after_backfill = True

    if wait_after_backfill:
        time.sleep(5)

    now_utc = datetime.now(timezone.utc)
    if not try_fetch_and_save(now_utc):
        print(&quot;Retrying with 1 hour earlier...&quot;)
        try_fetch_and_save(now_utc - timedelta(hours=1), full_range=True)

    time.sleep(INTERVAL)

</code></pre></div>



<p class="wp-block-paragraph">上記は「デジタル台風」から最新の気象衛星画像を定期的にダウンロードし、BMP形式で保存するプログラムです。保存された画像は指定フォルダに最大144枚まで保管され、古いものから自動で削除されます。ひまわりの可視画像は10分おきに提供されるため、144枚で24時間分のデータに相当します。</p>



<p class="wp-block-paragraph">画像の取得には以下のようなURLが使われます：</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>url = f&quot;http://agora.ex.nii.ac.jp/digital-typhoon/iiif/{date_str}/{time_str}00.tif/0,0,11000,11000/688,/0/default.jpg&quot;</code></pre></div>



<p class="wp-block-paragraph">このURLは指定した日時（<code>date_str</code>と<code>time_str</code>）に対応する可視画像を取得するためのもので、必要な時間の画像を個別にダウンロードできます。</p>



<div class="wp-block-sbd-balloon sbd-balloon sbd-balloon--id-4 sbd-balloon--flat sbd-balloon--l sbd-balloon--green block-box"><div class="sbd-balloon__profile"><figure class="sbd-balloon__icon"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/09/アイコン.jpg" alt="そぞら" class="sbd-balloon__img"/></figure><div class="sbd-balloon__name">そぞら</div></div><div class="sbd-balloon__text-box sbd-inner-block-init">
<p class="wp-block-paragraph">URLで指定する時刻は、<span class="sbd-text-red">UTC（協定世界時）</span>であり、日本時間（JST）より9時間遅れています。</p>
</div></div>



<p class="wp-block-paragraph">プログラムは8分ごとに最新のひまわり画像を取得して保存します。まず、現在の「分」情報から取得できそうな時刻の候補（たとえば35分なら、30・20・10・00）を新しい順に試していきます。最初に見つかった画像を保存し、取得できない場合は1時間前のデータまでさかのぼって取得を試みます。取得した画像は240×320に加工され、「20250612_1530.bmp」のように日本時間（JST）のタイムスタンプをファイル名として保存します。</p>



<p class="wp-block-paragraph">/home/pi/に「image」という名称のフォルダが作成され、そこに画像が自動で保存されていきます。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="369" src="https://sozorablog.com/wp-content/uploads/2025/06/pico-4-1-1.png" alt="" class="wp-image-15144"/></figure>



<div class="wp-block-sbd-balloon sbd-balloon sbd-balloon--id-4 sbd-balloon--flat sbd-balloon--l sbd-balloon--green block-box"><div class="sbd-balloon__profile"><figure class="sbd-balloon__icon"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/09/アイコン.jpg" alt="そぞら" class="sbd-balloon__img"/></figure><div class="sbd-balloon__name">そぞら</div></div><div class="sbd-balloon__text-box sbd-inner-block-init">
<p class="wp-block-paragraph">保存する画像の枚数が多くなるので、専用のフォルダを作ることにしました。</p>
</div></div>



<p class="wp-block-paragraph">画像の取りこぼしを防ぐための工夫として、保存済み画像の中で最新の時刻を確認し、その10分前の画像が存在しない場合には、そちらを優先して取得するようにしました。これは、ひまわり画像の提供時刻が必ずしも一定間隔とは限らず、8分ごとに取得しても一部の時刻が抜け落ちてしまうことがあるためです。</p>



<p class="wp-block-paragraph">プログラムを<span class="sbd-text-bold">himawari_image_save.py</span>という名称で/home/piフォルダに保存します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/06/pico-5-1.jpg" alt="" style="width:482px;height:auto"/></figure>



<p class="wp-block-paragraph">Saveボタンをクリックして、名前に「himawari_image_save.py」を入力し、OKを押します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="450" src="https://sozorablog.com/wp-content/uploads/2025/06/pico-3-1-1.jpg" alt="" class="wp-image-15143" style="width:484px;height:auto" srcset="https://sozorablog.com/wp-content/uploads/2025/06/pico-3-1-1.jpg 800w, https://sozorablog.com/wp-content/uploads/2025/06/pico-3-1-1-320x180.jpg 320w, https://sozorablog.com/wp-content/uploads/2025/06/pico-3-1-1-224x126.jpg 224w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<h4 class="wp-block-heading">ターミナルから保存用プログラムを実行</h4>



<p class="wp-block-paragraph">画像保存用のプログラム <code>himawari_image_save.py</code> は、<span class="sbd-text-bg-yellow">Thonnyではなくターミナルから実行</span>します。Thonnyで起動すると、次に紹介するアニメーション表示用のプログラムが同時に動かせなくなるためです。</p>



<p class="wp-block-paragraph">ターミナルで以下のコマンドを入力して実行します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>python3 himawari_image_save.py</code></pre></div>



<figure class="wp-block-image size-full"><img decoding="async" width="410" height="203" src="https://sozorablog.com/wp-content/uploads/2025/06/E382B9E382AFE383AAE383BCE383B3E382B7E383A7E38383E38388-2025-06-14-18.00.06.png" alt="" class="wp-image-15134"/></figure>



<p class="wp-block-paragraph">/home/pi/imageに画像が保存されていきます。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="496" height="327" src="https://sozorablog.com/wp-content/uploads/2025/06/E382B9E382AFE383AAE383BCE383B3E382B7E383A7E38383E38388-2025-06-14-19.41.00.png" alt="" class="wp-image-15140"/></figure>



<p class="wp-block-paragraph">ダブルクリックしてみると、保存された画像を確認できます。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="429" height="425" src="https://sozorablog.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-17-17.12.52.png" alt="" class="wp-image-15158"/></figure>



<h3 class="wp-block-heading">保存された画像をアニメーション表示するプログラム</h3>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="750" height="699" src="https://sozorablog.com/wp-content/uploads/2025/06/IMG_9111.jpg" alt="" class="wp-image-15151" style="width:485px;height:auto"/></figure>



<p class="wp-block-paragraph">himawari_image_save.pyが画像の保存をしている間に、アニメーション表示するプログラムを用意します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>import glob
import time
from PIL import Image

from board import SCK, MOSI, MISO, D5, D18, D23, D24
from busio import SPI
from digitalio import DigitalInOut, Direction
from adafruit_rgb_display.ili9341 import ILI9341

# Setup GPIO pins for display
CS = DigitalInOut(D5)
DC = DigitalInOut(D24)
RST = DigitalInOut(D23)
BL = DigitalInOut(D18)
BL.direction = Direction.OUTPUT
BL.value = True  # Turn on backlight

# Initialize SPI and display
spi = SPI(clock=SCK, MOSI=MOSI, MISO=MISO)
display = ILI9341(spi, cs=CS, dc=DC, rst=RST, width=240, height=320)

while True:
    # 画像フォルダからBMPファイルをすべて取得し、名前順に並べる
    image_files = sorted(glob.glob(&quot;/home/pi/image/*.bmp&quot;))

    # 画像を1枚ずつ表示
    for filepath in image_files:
        img = Image.open(filepath)
        display.image(img)
        time.sleep(0.01)

    time.sleep(5)  # 5秒待ってから画像リストを再取得（新しい画像が増えている可能性があるため）

</code></pre></div>



<p class="wp-block-paragraph">このコードは、Raspberry PiとILI9341ディスプレイを使って、「/home/pi/image」フォルダ内にあるBMP画像を順番に1枚ずつ表示するものです。画像を高速で切り替えて表示することで、アニメーションのような視覚効果を得ることができます。</p>



<p class="wp-block-paragraph">フォルダ内の画像ファイルは、「20250612_1530.bmp」のように日時が名前に含まれた形式で保存されています。そのため、ファイル名を文字列順に並べると<strong>古い順（撮影された順）</strong>になります。この順番で画像を1枚ずつ読み込み、180度回転させてディスプレイに表示します。すべての画像を表示し終わると、5秒待機してから同じ処理を繰り返します。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/06/Videotogif.gif" alt=""/></figure>



<p class="wp-block-paragraph">この処理を実行している間も、画像取得用のプログラム（<code>himawari_image_save.py</code>）が最新の画像を継続的に保存しているため、アニメーションで表示される画像も自動で更新されていきます。</p>



<h2 class="wp-block-heading">ダイソーのミラーデジタル時計に収納する</h2>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/06/IMG_9032.jpeg" alt=""/></figure>



<p class="wp-block-paragraph">表示の仕組みが完成したら、ケースに入れたくなるものです。ダイソーの<a href="https://jp.daisonet.com/products/4550480194400?srsltid=AfmBOorXrGfeIBw4te9Kv3adCBuy-j-lwUaUy7KUHFopH-qgUHVTc0QM">ミラーデジタル時計</a>を加工して、ラズパイ本体とディスプレイを収納することにしました。むき出しのディスプレイや配線のごちゃごちゃした印象をすっきり隠せるので、スマートな見た目に仕上がります。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/06/IMG_9046.jpeg" alt=""/></figure>



<p class="wp-block-paragraph">前面は鏡のような仕上がりで、周囲の風景が映り込みます。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/06/IMG_5041.jpeg" alt=""/></figure>



<p class="wp-block-paragraph">さっそく容赦なく分解していきます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/06/IMG_5042.jpeg" alt="" style="width:421px;height:auto"/></figure>



<p class="wp-block-paragraph">鏡の部分は薄いシート状になっており、時計の数字が表示される箇所だけが光を通すようになっています。それ以外の部分も、裏側のコーティングを削れば光を通すようにできます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/06/IMG_9016.jpeg" alt="" style="width:410px;height:auto"/></figure>



<p class="wp-block-paragraph">ディスプレイを取り付ける部分のコーティングを、マイナスドライバーで少しずつ削っていきます。逆に透けさせたくない部分は、油性マジックで塗りつぶして光が漏れないようにしました。</p>



<p class="wp-block-paragraph">ケース本体側も大幅に加工が必要です。ラズパイ本体やディスプレイ、配線が干渉する部分をニッパーで切り取り、必要なスペースを確保します。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/06/IMG_9118.jpeg" alt=""/></figure>



<p class="wp-block-paragraph">ディスプレイの土台部分は3Dプリンターで作成しました。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-17-12.27.22.jpg" alt=""/><figcaption class="wp-element-caption">3D CADで設計したディスプレイのベース部品</figcaption></figure>



<p class="wp-block-paragraph">電源ケーブルの取り回しを考慮し、ラズパイは以下の位置に配置することにしました。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/06/IMG_5070.jpeg" alt=""/></figure>



<p class="wp-block-paragraph">ケースに収納したラズパイを外部から操作できるようにするため、あらかじめ<a href="https://sozorablog.com/vnc/">VNC</a>の設定をしておきます。VNCとは「Virtual Network Computing（バーチャル・ネットワーク・コンピューティング）」の略で、離れた場所からラズパイの画面を操作できる仕組みです。</p>



<div class="wp-block-sbd-background-block sbd-bg-color sbd-inner-block-init is-style-yellow">
<p class="wp-block-paragraph">VNCの設定方法は、以下の記事で詳しく解説しています。<br><strong><a href="https://sozorablog.com/vnc/">≫【ラズベリーパイを遠隔操作】VNCでＰＣからリモート接続する方法</a></strong></p>
</div>



<p class="wp-block-paragraph">ディスプレイは水色の土台部分に両面テープで固定しています。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/06/IMG_9119.jpeg" alt=""/></figure>



<p class="wp-block-paragraph">ケースの背面には、ラズパイの電源コネクタに直接差し込めるように穴を追加しました。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/06/IMG_9120.jpeg" alt="" style="width:446px;height:auto"/></figure>



<p class="wp-block-paragraph">雑な加工ですが、ケーブルを差し込めばほとんど目立たなくなります。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/06/IMG_5069.jpeg" alt="" style="width:508px;height:auto"/></figure>



<p class="wp-block-paragraph">完成。ミラーの奥に、ぼんやりと地球が浮かび上がります。ミラー越しだと少しぼやけて見えるため、赤外画像のほうが輪郭がはっきりして見やすく感じます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="771" src="https://sozorablog.com/wp-content/uploads/2025/06/IMG_9122.jpeg" alt="" class="wp-image-15101" style="width:840px;height:auto"/></figure>



<h2 class="wp-block-heading">円形ディスプレイに表示する</h2>



<figure class="wp-block-image size-full"><img decoding="async" width="750" height="671" src="https://sozorablog.com/wp-content/uploads/2025/06/IMG_9145.jpeg" alt="" class="wp-image-15352"/></figure>



<p class="wp-block-paragraph">地球のアニメーションを、より魅力的に見せる方法として円形ディスプレイを使うと効果的です。円形ディスプレイの<a href="https://shop.pimoroni.com/products/hyperpixel-round?variant=39381081882707">HyperPixel 2.1 Round</a>を使って、画像をアニメーション表示してみました。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/スクリーンショット-2025-05-18-5.29.14.jpg" alt=""/><figcaption class="wp-element-caption">出典：<a href="https://shop.pimoroni.com/products/hyperpixel-round?variant=39381081882707">Pimoroni</a></figcaption></figure>



<p class="wp-block-paragraph">ひまわりの可視画像を保存するプログラムは、先ほど紹介した「<strong>himawari_image_save.py</strong>」をそのまま使用します。</p>



<p class="wp-block-paragraph">次のコードは、指定したフォルダ内のBMP画像を順番に読み込み、Raspberry PiのGUI画面上に全画面で表示するプログラムです。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>import glob
import time
from PIL import Image
import cv2
import numpy as np

# ウィンドウサイズ
WIDTH = 480
HEIGHT = 480
WINDOW_NAME = &quot;Earth Viewer&quot;

# OpenCVウィンドウを全画面で作成
cv2.namedWindow(WINDOW_NAME, cv2.WND_PROP_FULLSCREEN)
cv2.setWindowProperty(WINDOW_NAME, cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)

while True:
    # 画像ファイルを時刻順に取得
    image_files = sorted(glob.glob(&quot;/home/pi/image/*.bmp&quot;))

    for filepath in image_files:
        # BMP画像を開いてNumPy配列に変換
        pil_img = Image.open(filepath).convert(&quot;RGB&quot;)

        # 背景キャンバスを作成（黒背景）
        canvas = Image.new(&quot;RGB&quot;, (WIDTH, HEIGHT), (0, 0, 0))
        
        # PILで中心に貼り付ける位置を計算
        img_w, img_h = pil_img.size
        pos_x = (WIDTH - img_w) // 2
        pos_y = (HEIGHT - img_h) // 2
        canvas.paste(pil_img, (pos_x, pos_y))

        # NumPy配列に変換 → BGRに変換（OpenCV用）
        img_np = np.array(canvas)
        img_bgr = cv2.cvtColor(img_np, cv2.COLOR_RGB2BGR)

        # 表示
        cv2.imshow(WINDOW_NAME, img_bgr)

        # ESCキーが押されたら終了（27はESCのキーコード）
        if cv2.waitKey(10) == 27:
            cv2.destroyAllWindows()
            exit()

    time.sleep(5)

</code></pre></div>



<p class="wp-block-paragraph">先ほど紹介した「保存された画像をアニメーション表示するプログラム」との違いは、SPI接続のディスプレイではなくRaspberry PiのGUI画面（デスクトップ画面）に表示している点です。どちらも「画像フォルダの中にあるBMP画像を順番に表示する」という目的は同じです。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="481" height="491" src="https://sozorablog.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-23-12.28.42.jpg" alt="" class="wp-image-15353"/><figcaption class="wp-element-caption">円形ディスプレイに表示する画面</figcaption></figure>



<p class="wp-block-paragraph">OpenCVは以下のコマンドでインストールします。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo apt install python3-opencv</code></pre></div>



<figure class="wp-block-embed is-type-rich is-provider-twitter wp-block-embed-twitter"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="500" data-dnt="true"><p lang="ja" dir="ltr">Raspberry Piと円形ディスプレイがあったら、絶対作りたくなるやつ。 <a href="https://t.co/cov9A3QEHx">pic.twitter.com/cov9A3QEHx</a></p>&mdash; そぞら@Raspberry Pi 電子工作 (@sozoraemon) <a href="https://twitter.com/sozoraemon/status/1937090870672834744?ref_src=twsrc%5Etfw">June 23, 2025</a></blockquote><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</div></figure>
]]></content:encoded>
					
					<wfw:commentRss>https://sozorablog.com/himawari/feed/</wfw:commentRss>
			<slash:comments>6</slash:comments>
		
		
			</item>
		<item>
		<title>ラズパイとADS-B受信機でミニ飛行機レーダーを作ろう</title>
		<link>https://sozorablog.com/flightradar/</link>
					<comments>https://sozorablog.com/flightradar/#comments</comments>
		
		<dc:creator><![CDATA[そぞら]]></dc:creator>
		<pubDate>Tue, 27 May 2025 06:43:35 +0000</pubDate>
				<category><![CDATA[Raspberry Pi]]></category>
		<category><![CDATA[使い方]]></category>
		<guid isPermaLink="false">https://sozorablog.com/?p=14648</guid>

					<description><![CDATA[飛行機の音が聞こえたとき、「この機体はどこへ行くのだろう」と気になったことはありませんか？ この記事では、Raspberry Piで航空機信号用の受信機を使う方法と「レーダー風表示装置」の作り方を紹介します。リアルタイム [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">飛行機の音が聞こえたとき、「この機体はどこへ行くのだろう」と気になったことはありませんか？</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/IMG_8969.jpeg" alt="" class="wp-image-4" style="width:444px;height:auto"/></figure>



<p class="wp-block-paragraph">この記事では、<a href="https://sozorablog.com/raspberry-pi/">Raspberry Pi</a>で航空機信号用の受信機を使う方法と「レーダー風表示装置」の作り方を紹介します。リアルタイムで頭上を飛ぶ航空機の位置情報を画面に表示し、自宅で<strong>小さな管制塔気分</strong>が楽しめます。</p>



<h2 class="wp-block-heading">ラズパイで飛行機の信号を受信</h2>



<p class="wp-block-paragraph">多くの飛行機は、現在位置・高度・速度・機体番号などの情報を送信しています。そうした通信手段の中でも、旅客機をはじめとする多くの航空機で使われているのが、<strong>ADS-B（Automatic Dependent Surveillance–Broadcast）</strong> という仕組みです。</p>



<div class="wp-block-sbd-balloon sbd-balloon sbd-balloon--id-4 sbd-balloon--flat sbd-balloon--l sbd-balloon--green block-box"><div class="sbd-balloon__profile"><figure class="sbd-balloon__icon"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/09/アイコン.jpg" alt="そぞら" class="sbd-balloon__img"/></figure><div class="sbd-balloon__name">そぞら</div></div><div class="sbd-balloon__text-box sbd-inner-block-init">
<p class="wp-block-paragraph">ADS-Bの信号は、受信機を使えばRaspberry Piでも受信できます。</p>
</div></div>



<h3 class="wp-block-heading">ADS-B受信機を使用</h3>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/IMG_8943.jpeg" alt="" class="wp-image-4" style="width:459px;height:auto"/><figcaption class="wp-element-caption">NESDR Mini</figcaption></figure>



<p class="wp-block-paragraph">今回は<a href="https://www.nooelec.com/store/?srsltid=AfmBOoobYNyhKjJ7p_SQU13t7o1VFn1MbSNxhsaL8hmbh96Oa6V6am4a">Nooelec社</a>のNESDR MiniというUSBスティック型のADS-B受信機を使用します。Raspberry Piに接続し、専用のソフトウェアをインストールすることで、航空機が発信する1090MHz帯の信号を受信できます。</p>



<!-- START MoshimoAffiliateEasyLink -->
<script type="text/javascript">
(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;
b[a]=b[a]||function(){arguments.currentScript=c.currentScript
||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};
c.getElementById(a)||(d=c.createElement(f),d.src=g,
d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})
(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");
msmaflink({"n":"Nooelec NESDR Mini ミニUSB RTL-SDRおよびADS-B受信機セット、RTL2832UおよびR820Tチューナー、MCX入力。 多くのSDRソフトウェアパッケージと互換性のある低コストソフトウェア無線機。 R820Tチューナ","b":"NooElec","t":"100556","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/31Vb71v4fTL._SL500_.jpg","\/314CXt2ANJL._SL500_.jpg","\/31QS842oE2L._SL500_.jpg","\/41fYlg-Nw3L._SL500_.jpg","\/31bzg-noaGL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/B009U7WZCA","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/B009U7WZCA","a_id":3038653,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/Nooelec%20NESDR%20Mini%20%E3%83%9F%E3%83%8BUSB%20RTL-SDR%E3%81%8A%E3%82%88%E3%81%B3ADS-B%E5%8F%97%E4%BF%A1%E6%A9%9F%E3%82%BB%E3%83%83%E3%83%88%E3%80%81RTL2832U%E3%81%8A%E3%82%88%E3%81%B3R820T%E3%83%81%E3%83%A5%E3%83%BC%E3%83%8A%E3%83%BC%E3%80%81MCX%E5%85%A5%E5%8A%9B%E3%80%82%20%E5%A4%9A%E3%81%8F%E3%81%AESDR%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E3%81%A8%E4%BA%92%E6%8F%9B%E6%80%A7%E3%81%AE%E3%81%82%E3%82%8B%E4%BD%8E%E3%82%B3%E3%82%B9%E3%83%88%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E7%84%A1%E7%B7%9A%E6%A9%9F%E3%80%82%20R820T%E3%83%81%E3%83%A5%E3%83%BC%E3%83%8A\/","a_id":3038654,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2}],"eid":"8T0PA","s":"s"});
</script>
<div id="msmaflink-8T0PA">リンク</div>
<!-- MoshimoAffiliateEasyLink END -->



<div class="wp-block-sbd-balloon sbd-balloon sbd-balloon--id-4 sbd-balloon--flat sbd-balloon--l sbd-balloon--green block-box"><div class="sbd-balloon__profile"><figure class="sbd-balloon__icon"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/09/アイコン.jpg" alt="そぞら" class="sbd-balloon__img"/></figure><div class="sbd-balloon__name">そぞら</div></div><div class="sbd-balloon__text-box sbd-inner-block-init">
<p class="wp-block-paragraph">アンテナを室内に置いた状態で、<strong>約50km</strong>離れた航空機の信号を受信できました。</p>
</div></div>



<p class="wp-block-paragraph">専用アンテナも付属しているため、すぐに使い始められます。ただし、Raspberry Pi Zeroシリーズを使う場合は、別売りの<a href="https://akizukidenshi.com/catalog/g/g113430/">USB microBコネクタ用のOTGケーブル</a>が必要です。</p>



<h3 class="wp-block-heading">Flightradar24にデータ提供も可能</h3>



<p class="wp-block-paragraph">世界中の航空機をリアルタイムで表示するサービス<a href="https://www.flightradar24.com/">Flightradar24</a>も、ADS-B信号をもとにしています。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/スクリーンショット-2025-05-18-5.15.30.jpg" alt="" class="wp-image-4"/><figcaption class="wp-element-caption"><a href="https://www.flightradar24.com/">Flightradar24</a></figcaption></figure>



<p class="wp-block-paragraph">Flightradar24は基本機能を無料で使えますが、30分で自動的にセッションが終了する制限があります。一方、ADS-B受信機を設置すれば、設置場所の周辺に限定されますが、航空機の情報を制限なく受信・表示できます。</p>



<div class="wp-block-sbd-checkpoint-block"><p class="sbd-checkpoint-title">チェックポイント</p><div class="sbd-checkpoint-content sbd-inner-block-init"><p>Raspberry PiとADS-B受信機を使って<span class="sbd-text-red">Flightradar24にデータを提供</span>することで、プレミアム機能を無償で利用できます。Flightradar24へのデータ提供方法については、記事の後半で紹介しています。</p></div></div>



<h2 class="wp-block-heading">ADS-B受信機の使用準備</h2>



<p class="wp-block-paragraph">今回使用したADS-B受信機は、以下のモデルで動作を確認しました。</p>



<div class="wp-block-sbd-list"><ul class="sbd-list sbd-list-border"><li><a href="https://sozorablog.com/raspberry-pi-zero-2-w/">Raspberry Pi Zero 2 W</a></li><li><a href="https://sozorablog.com/raspberry-pi-4-revue/">Raspberry Pi 4</a></li><li><a href="https://sozorablog.com/pi5/">Raspberry Pi 5</a>　※<a href="https://shop.pimoroni.com/products/hyperpixel-round?variant=39381081882707">HyperPixel 2.1 Round</a>（円形ディスプレイ）は非対応</li></ul></div>



<p class="wp-block-paragraph">Raspberry Pi OSについては、ADS-B受信機だけを使う場合はBookwormで動作します。僕は<a href="https://shop.pimoroni.com/products/hyperpixel-round?variant=39381081882707">HyperPixel 2.1 Round</a>（円形ディスプレイ）を使いたかったので、Bullseyeを使用しました。</p>



<div class="wp-block-sbd-background-block sbd-bg-color sbd-inner-block-init is-style-yellow">
<p class="wp-block-paragraph">Raspberry PiのOSをインストールする方法は、以下の記事で詳しく解説しています。<br><strong><a href="https://sozorablog.com/raspberrypi_initial_setting/">≫【2025年最新版】OSインストールから初期設定まで｜セットアップ手順のすべて</a></strong></p>
</div>



<h3 class="wp-block-heading">ラズパイとADS-B受信機の接続</h3>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/IMG_8987.jpeg" alt="" class="wp-image-4" style="width:439px;height:auto"/></figure>



<p class="wp-block-paragraph">ADS-B受信機をRaspberry PiのUSBポートに挿すだけで接続できます。Raspberry Pi Zeroシリーズを使う場合は、別売りの<a href="https://akizukidenshi.com/catalog/g/g113430/">USB microBコネクタ用のOTGケーブル</a>が必要です。</p>



<h3 class="wp-block-heading">ソフトウェアの設定</h3>



<p class="wp-block-paragraph">ここからはRaspberry Piを起動して、ADS-B受信機を使える状態にします。</p>



<p class="wp-block-paragraph">航空機の発信するADS-B信号を受信・表示するために、<a href="https://ja.flightaware.com/">FlightAware</a>が提供する<span class="sbd-text-bg-yellow">dump1090-fa</span>というソフトを使います。</p>



<p class="wp-block-paragraph">dump1090-faを使うために、FlightAwareのパッケージリポジトリをRaspberry Piに追加します。</p>



<div class="wp-block-sbd-balloon sbd-balloon sbd-balloon--id-4 sbd-balloon--flat sbd-balloon--l sbd-balloon--green block-box"><div class="sbd-balloon__profile"><figure class="sbd-balloon__icon"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/09/アイコン.jpg" alt="そぞら" class="sbd-balloon__img"/></figure><div class="sbd-balloon__name">そぞら</div></div><div class="sbd-balloon__text-box sbd-inner-block-init">
<p class="wp-block-paragraph">リポジトリは、データを管理する「インターネット上の倉庫」のようなイメージです。その倉庫の場所をRaspberry Piに教える作業をします。</p>
</div></div>



<p class="wp-block-paragraph">ターミナルを開いて、次のコマンドを実行します。これによりFlightAwareが提供するリポジトリ登録用の.debパッケージ（設定ファイル）をインターネットからダウンロードします。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>wget https://www.flightaware.com/adsb/piaware/files/packages/pool/piaware/f/flightaware-apt-repository/flightaware-apt-repository_1.2_all.deb</code></pre></div>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/pico-2.jpg" alt="" class="wp-image-4"/></figure>



<p class="wp-block-paragraph">次のコマンドで、先ほどダウンロードした .debパッケージをインストールします。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo dpkg -i flightaware-apt-repository_1.2_all.deb</code></pre></div>



<p class="wp-block-paragraph">Raspberry Piのパッケージリストを更新します。これにより、dump1090-faがインストール候補として認識されるようになります。</p>



<div class="wp-block-sbd-balloon sbd-balloon sbd-balloon--id-4 sbd-balloon--flat sbd-balloon--l sbd-balloon--green block-box"><div class="sbd-balloon__profile"><figure class="sbd-balloon__icon"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/09/アイコン.jpg" alt="そぞら" class="sbd-balloon__img"/></figure><div class="sbd-balloon__name">そぞら</div></div><div class="sbd-balloon__text-box sbd-inner-block-init">
<p class="wp-block-paragraph">パッケージリストとは、利用可能なソフトウェアの一覧情報のことです。</p>
</div></div>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo apt update</code></pre></div>



<p class="wp-block-paragraph">dump1090-faをインストールします。<code>-y</code> オプションは「続行しますか？ [Y/n]」の確認をスキップして、自動的に「yes」と答えるためのものです。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo apt install -y dump1090-fa</code></pre></div>



<p class="wp-block-paragraph">以下はRaspberry Piの起動時に <code>dump1090-fa</code> を自動で起動するよう設定するコマンドです。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo systemctl enable dump1090-fa</code></pre></div>



<p class="wp-block-paragraph">レーダー表示を自作するために、Pythonで画像や映像を扱えるOpenCVライブラリをインストールします。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo apt install -y python3-opencv</code></pre></div>



<p class="wp-block-paragraph">Raspberry Piを再起動します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo reboot</code></pre></div>



<p class="wp-block-paragraph">再起動後にdump1090-faが自動で起動します。</p>



<h2 class="wp-block-heading">ADS-B信号の受信を確認</h2>



<p class="wp-block-paragraph">dump1090-faが正常に動作しているかを確認します。Raspberry Piの<span class="sbd-text-red">ブラウザを開いて</span>、「http://localhost:8080/」をアドレスバーに入力します。すると、dump1090の<strong>リアルタイム航空機マップ</strong>が表示されます。自宅周辺のマップを確認すると、航空機の情報がキャッチされていることがわかります。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/スクリーンショット-2025-05-17-15.10.34.jpg" alt="" class="wp-image-4" style="width:840px;height:auto"/></figure>



<h3 class="wp-block-heading">ページが表示されない場合</h3>



<p class="wp-block-paragraph">以下のようにページが表示されない場合があります。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/スクリーンショット-2026-04-04-6.37.07.jpg" alt="" class="wp-image-4" style="width:387px;height:auto"/></figure>



<p class="wp-block-paragraph">まずは、以下のコマンドで状態を確認します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo systemctl status dump1090-fa</code></pre></div>



<p class="wp-block-paragraph">「active (running)」と表示されていれば正常です。それ以外の場合は、起動に失敗しています。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/pico-6.jpg" alt="" class="wp-image-4" style="width:654px;height:auto"/></figure>



<p class="wp-block-paragraph">今回のようなケースで多い原因が、DVBドライバとの競合です。使用しているRTL-SDRドングルは、もともとテレビ受信用の機器です。そのため、Raspberry Piは自動でテレビ用のドライバ（DVBドライバ）を割り当てます。しかし、ADS-B受信ではこのドライバは不要で、逆にdump1090-faの動作を妨げてしまいます。</p>



<p class="wp-block-paragraph">この問題は、DVBドライバを無効化することで解決できます。以下のコマンドを1行ずつ順に実行して<span class="sbd-text-red">再起動</span>します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>echo &quot;blacklist dvb_usb_rtl28xxu&quot; | sudo tee /etc/modprobe.d/blacklist-rtl.conf
echo &quot;blacklist rtl2832&quot; | sudo tee -a /etc/modprobe.d/blacklist-rtl.conf
echo &quot;blacklist rtl2830&quot; | sudo tee -a /etc/modprobe.d/blacklist-rtl.conf</code></pre></div>



<p class="wp-block-paragraph">再起動後、以下を実行して状態を確認します。「active (running)」になっていれば成功です。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo systemctl status dump1090-fa</code></pre></div>



<h3 class="wp-block-heading">取得できる航空機データ</h3>



<p class="wp-block-paragraph">画面の右側には、受信した航空機のリアルタイムデータが表形式で表示されます。各列の意味は以下のとおりです。</p>



<figure class="wp-block-table wp-block-sbd-table wp-block-sbd-table-vertical"><table><tbody><tr><td>ICAO</td><td class="has-text-align-left" data-align="left">航空機ごとに割り当てられた識別コード（16進数形式）</td></tr><tr><td>Ident</td><td class="has-text-align-left" data-align="left">航空会社名と便名（例：ANA536）</td></tr><tr><td>Squawk</td><td class="has-text-align-left" data-align="left">航空機が送信している4桁の識別コード（航空交通管制で使用）</td></tr><tr><td>Altitude (ft)</td><td class="has-text-align-left" data-align="left">高度（フィート単位）</td></tr><tr><td>Speed (kt)</td><td class="has-text-align-left" data-align="left">速度（ノット単位＝海里/時）</td></tr><tr><td>Heading</td><td class="has-text-align-left" data-align="left">進行方向（度）</td></tr><tr><td>Msgs</td><td class="has-text-align-left" data-align="left">受信したメッセージの回数</td></tr><tr><td>Age</td><td class="has-text-align-left" data-align="left">最新データを受信してからの経過時間（秒）</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">この画面は同じネットワークに接続されたPCやスマホからも閲覧可能です。もしRaspberry PiのIPアドレスが <strong>192.168.1.100</strong> であれば、「http://192.168.1.100:8080/」にアクセスすることで確認できます。</p>



<p class="wp-block-paragraph">航空機の動きをリアルタイムで見るだけでもワクワクします。ですが、せっかくRaspberry Piを使っているので、受信したデータを活用して、さらに面白いことに挑戦したくなるものです。</p>



<h2 class="wp-block-heading">Pythonで受信データを処理する</h2>



<p class="wp-block-paragraph">ADS-B信号を活用して何かを作りたいとき、Pythonでデータを取得できると便利です。dump1090-faは受信した航空機の情報を <code>http://localhost:8080/data/aircraft.json</code> というURLでJSON形式として公開しています。このJSONには航空機ごとの緯度・経度・高度・速度・方位などのデータが含まれており、Pythonからアクセスできます。</p>



<h3 class="wp-block-heading">Thonnyを使ってPythonプログラムを実行する</h3>



<p class="wp-block-paragraph">Raspberry Piでは「Thonny（ソニー）」という初心者向けのPython開発環境が標準でインストールされています。以下の手順でプログラムを実行できます。</p>



<p class="wp-block-paragraph">デスクトップ画面左上の「ラズベリーメニュー」から「プログラミング」→「Thonny」を開く。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk2.jpg" alt="" class="wp-image-4" style="width:570px;height:auto"/></figure>



<p class="wp-block-paragraph">画面中央のエリアに、プログラムをコピー＆ペーストして、「実行」ボタンを押す。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/pico-3.jpg" alt="" class="wp-image-4" style="width:568px;height:auto"/></figure>



<p class="wp-block-paragraph">下部の「シェル」エリアに、実行結果（航空機の情報）が表示されます。</p>



<h3 class="wp-block-heading">航空機データの取得テスト</h3>



<p class="wp-block-paragraph">以下のプログラムを実行して、航空機のデータが表示されるかを確認します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>import time
import requests

# 航空機データを取得する関数
def get_aircraft_positions():
    try:
        res = requests.get(&quot;http://localhost:8080/data/aircraft.json&quot;, timeout=1)
        return [a for a in res.json().get(&quot;aircraft&quot;, []) if &#39;lat&#39; in a and &#39;lon&#39; in a]
    except:
        return []

# 10秒ごとに航空機データを表示
while True:
    aircraft_list = get_aircraft_positions()

    print(f&quot;現在受信中の航空機数: {len(aircraft_list)} 機&quot;)
    for a in aircraft_list:
        hex_id = a.get(&#39;hex&#39;, &#39;不明&#39;)
        flight = a.get(&#39;flight&#39;, hex_id).strip()
        lat = a.get(&#39;lat&#39;)
        lon = a.get(&#39;lon&#39;)
        alt = a.get(&#39;alt_baro&#39;, &#39;不明&#39;)
        speed = a.get(&#39;gs&#39;, &#39;不明&#39;)
        track = a.get(&#39;track&#39;, &#39;不明&#39;)

        print(f&quot;便名: {flight} | 緯度: {lat} | 経度: {lon} | 高度: {alt} ft | 速度: {speed} kt | 方位: {track}°&quot;)

    # 10秒待機
    time.sleep(10)

</code></pre></div>



<p class="wp-block-paragraph">このプログラムでは、まずURLにアクセスして航空機データを取得し、位置情報（緯度・経度）を持つものだけを抽出しています。そして、10秒ごとにその情報をシェルに表示します。表示される内容には、便名、緯度・経度、高度（フィート）、速度（ノット）、進行方向（度）が含まれており、上空を飛ぶ航空機の状況がリアルタイムに確認できます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/スクリーンショット-2025-05-18-8.03.11.png" alt="" class="wp-image-4" style="width:840px;height:auto"/><figcaption class="wp-element-caption">「シェル」エリアに表示された航空機の情報</figcaption></figure>



<p class="wp-block-paragraph">これでPythonでデータを取得できることが確認できました。ここからは、このデータを処理するプログラムを作成していきます。</p>



<h3 class="wp-block-heading">航空機と測定地点の距離を計算</h3>



<p class="wp-block-paragraph">緯度や経度の数値だけを見ても、近いのか遠いのかを判断できません。航空機と測定地点との距離を計算すると、接近しているのか遠ざかっているのかがわかります。</p>



<div class="wp-block-sbd-balloon sbd-balloon sbd-balloon--id-4 sbd-balloon--flat sbd-balloon--l sbd-balloon--green block-box"><div class="sbd-balloon__profile"><figure class="sbd-balloon__icon"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/09/アイコン.jpg" alt="そぞら" class="sbd-balloon__img"/></figure><div class="sbd-balloon__name">そぞら</div></div><div class="sbd-balloon__text-box sbd-inner-block-init">
<p class="wp-block-paragraph">緯度・経度から距離を計算する方法については、ChatGPTに相談しながらアルゴリズムを作成しました。</p>
</div></div>



<p class="wp-block-paragraph">以下のプログラムは自宅と航空機の緯度・経度をもとに直線距離を計算し、最も近い航空機の便名とその距離を表示します。この距離は測定地点と航空機の水平距離であり、高度は考慮していません。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>import time
import requests
import math

# 自宅の緯度・経度に変更してください（例：東京駅付近）
HOME_LAT = 35.681236
HOME_LON = 139.767125

# 航空機データを取得する関数
def get_aircraft_positions():
    try:
        res = requests.get(&quot;http://localhost:8080/data/aircraft.json&quot;, timeout=1)
        return [a for a in res.json().get(&quot;aircraft&quot;, []) if &#39;lat&#39; in a and &#39;lon&#39; in a]
    except:
        return []

# ハーサイン距離計算（地球上の2点間の距離をkmで返す）
def haversine(lat1, lon1, lat2, lon2):
    R = 6371.0  # 地球の半径 (km)
    lat1_rad = math.radians(lat1)
    lon1_rad = math.radians(lon1)
    lat2_rad = math.radians(lat2)
    lon2_rad = math.radians(lon2)
    dlat = lat2_rad - lat1_rad
    dlon = lon2_rad - lon1_rad
    a = math.sin(dlat/2)**2 + math.cos(lat1_rad) * math.cos(lat2_rad) * math.sin(dlon/2)**2
    c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
    return R * c

# 10秒ごとに一番近い航空機を表示
while True:
    aircraft_list = get_aircraft_positions()
    closest = None
    min_distance = float(&#39;inf&#39;)

    for a in aircraft_list:
        lat = a.get(&#39;lat&#39;)
        lon = a.get(&#39;lon&#39;)
        if lat is not None and lon is not None:
            distance = haversine(HOME_LAT, HOME_LON, lat, lon)
            if distance &lt; min_distance:
                min_distance = distance
                closest = a

    if closest:
        flight = closest.get(&#39;flight&#39;, closest.get(&#39;hex&#39;, &#39;不明&#39;)).strip()
        print(f&quot;最も近い便名: {flight} | 自宅からの距離: {min_distance:.2f} km&quot;)
    else:
        print(&quot;航空機データが取得できませんでした。&quot;)

    time.sleep(10)
</code></pre></div>



<p class="wp-block-paragraph">測定地点の座標は、プログラム内6行目の <code>HOME_LAT</code>（緯度）と <code>HOME_LON</code>（経度）という変数に設定されています。東京駅の座標が入力されていますが、この値は自由に変更できます。</p>



<div class="wp-block-sbd-checkpoint-block"><p class="sbd-checkpoint-title">チェックポイント</p><div class="sbd-checkpoint-content sbd-inner-block-init"><p>緯度と経度は<a href="https://www.google.co.jp/maps/">Googleマップ</a>で調べることができます。地図上で自宅などの位置を右クリックすると、小さなメニューが表示されます。その一番上に、「35.○○○○○○, 139.○○○○○○」のような緯度と経度の数値が出てきます。</p></div></div>



<p class="wp-block-paragraph">このプログラムは10秒ごとに航空機のデータを取得し、各機体との距離を順に計算。その中で<span class="sbd-text-red">もっとも距離が近い機体</span>を特定し、便名と距離を表示します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/スクリーンショット-2025-05-18-8.25.31.png" alt="" class="wp-image-4" style="width:572px;height:auto"/></figure>



<h4 class="wp-block-heading">LCD 1602表示する</h4>



<p class="wp-block-paragraph">コードを応用すれば、以下のようなLCD表示も可能です。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/IMG_8994.jpeg" alt="" class="wp-image-4" style="width:443px;height:auto"/></figure>



<p class="wp-block-paragraph">このLCDは「I2C接続の16文字2行キャラクタLCD（LCD1602）」と呼ばれています。もともとは並列通信で制御するタイプですが、背面にI2Cインターフェースモジュールが取り付けられており、4本の配線で使用できます。</p>



<!-- START MoshimoAffiliateEasyLink -->
<script type="text/javascript">
(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;
b[a]=b[a]||function(){arguments.currentScript=c.currentScript
||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};
c.getElementById(a)||(d=c.createElement(f),d.src=g,
d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})
(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");
msmaflink({"n":"Freenove I2C IIC LCD 1602モジュール、新タイプTWIシリアル16x2ディスプレイ、Arduino Raspberry Pi Pico ESP_Seriesと互換性あり","b":"Freenove","t":"FNK0079","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/51zdrKMSb-L._SL500_.jpg","\/51yV6Y1dg6L._SL500_.jpg","\/51wMFvA9hWL._SL500_.jpg","\/512HUqf8sPL._SL500_.jpg","\/41PAy3h0WBL._SL500_.jpg","\/41wzhotJskL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/B0B76YGDV4","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/B0B76YGDV4","a_id":3038653,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":4,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/Freenove%20I2C%20IIC%20LCD%201602%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E3%80%81%E6%96%B0%E3%82%BF%E3%82%A4%E3%83%97TWI%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%AB16x2%E3%83%87%E3%82%A3%E3%82%B9%E3%83%97%E3%83%AC%E3%82%A4%E3%80%81Arduino%20Raspberry%20Pi%20Pico%20ESP_Series%E3%81%A8%E4%BA%92%E6%8F%9B%E6%80%A7%E3%81%82%E3%82%8A\/","a_id":3038654,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2}],"eid":"QU2k0","s":"s"});
</script>
<div id="msmaflink-QU2k0">リンク</div>
<!-- MoshimoAffiliateEasyLink END -->



<p class="wp-block-paragraph">ラズパイとLCD1602は以下のように接続します。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/image-1.png" alt="" class="wp-image-4"/><figcaption class="wp-element-caption">ラズパイとLCD1602の接続</figcaption></figure>



<p class="wp-block-paragraph">LCD1602を使うためには、Raspberry PiでI2C通信を有効にする必要があります。以下のコマンドを実行後に再起動すると、I2Cを有効にできます。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo raspi-config nonint do_i2c 0</code></pre></div>



<p class="wp-block-paragraph">次のコードは自宅の位置を基準にして、近くを飛んでいる航空機の情報を取得し、LCDに表示するものです。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>import smbus
import time
import requests
import math

ADDR = 0x27 # LCDのI2Cアドレス（例: 0x27や0x3F、使用前にi2cdetectで確認）
bus = smbus.SMBus(1)

# 自宅の緯度・経度に変更してください（例：東京駅付近）
HOME_LAT = 35.681236
HOME_LON = 139.767125

def write(data, mode=0):
    for val in [(data & 0xF0), ((data &lt;&lt; 4) & 0xF0)]:
        b = val | mode | 0x08
        bus.write_byte(ADDR, b | 0x04)
        time.sleep(0.0005)
        bus.write_byte(ADDR, b)

def init():
    for cmd in [0x33, 0x32, 0x06, 0x0C, 0x28, 0x01]:
        write(cmd)
    time.sleep(0.001)

def message(text, row=0, col=0):
    addr = 0x80 + col if row == 0 else 0xC0 + col
    write(addr)
    for c in text.ljust(16 - col):
        write(ord(c), 1)

# 航空機データを取得する関数
def get_aircraft_positions():
    try:
        res = requests.get(&quot;http://localhost:8080/data/aircraft.json&quot;, timeout=1)
        return [a for a in res.json().get(&quot;aircraft&quot;, []) if &#39;lat&#39; in a and &#39;lon&#39; in a]
    except:
        return []

# ハーサイン距離計算（地球上の2点間の距離をkmで返す）
def haversine(lat1, lon1, lat2, lon2):
    R = 6371.0  # 地球の半径 (km)
    lat1_rad = math.radians(lat1)
    lon1_rad = math.radians(lon1)
    lat2_rad = math.radians(lat2)
    lon2_rad = math.radians(lon2)
    dlat = lat2_rad - lat1_rad
    dlon = lon2_rad - lon1_rad
    a = math.sin(dlat/2)**2 + math.cos(lat1_rad) * math.cos(lat2_rad) * math.sin(dlon/2)**2
    c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
    return R * c

prev_line1 = &quot;&quot;
prev_line2 = &quot;&quot;

while True:
    aircraft_list = get_aircraft_positions()
    closest = None
    min_distance = float(&#39;inf&#39;)

    for a in aircraft_list:
        lat = a.get(&#39;lat&#39;)
        lon = a.get(&#39;lon&#39;)
        if lat is not None and lon is not None:
            distance = haversine(HOME_LAT, HOME_LON, lat, lon)
            if distance &lt; min_distance:
                min_distance = distance
                closest = a

    if closest:
        flight = closest.get(&#39;flight&#39;, closest.get(&#39;hex&#39;, &#39;UNKNOWN&#39;)).strip()
        line1 = flight
        line2 = &quot;Dist: {:.2f} km&quot;.format(min_distance)
    else:
        line1 = &quot;No aircraft&quot;
        line2 = &quot;in range&quot;

    # 表示内容に変化があるときだけ更新
    if line1 != prev_line1 or line2 != prev_line2:
        print(f&quot;Updating display:\n{line1}\n{line2}&quot;)
        init()
        message(line1, row=0, col=0)
        message(line2, row=1, col=2)
        prev_line1 = line1
        prev_line2 = line2

    time.sleep(2)</code></pre></div>



<p class="wp-block-paragraph">表示内容が前回と同じであればLCDを更新せず、画面のちらつき防止を図ります。航空機がいない場合は「No aircraft」「in range」と表示します。</p>



<p class="wp-block-paragraph">距離の数値が少しずつ縮まっていくのを見ると、ワクワクして思わず窓を開け、飛行機の音に耳を澄ませてしまいます。</p>



<h3 class="wp-block-heading">簡易的なレーダー風表示の作成</h3>



<p class="wp-block-paragraph">航空機の緯度経度情報をもとに、他の機体や測定地点との位置関係をプロットする方法を模索します。以下のコードは取得した航空機の位置データをリアルタイムで画面に可視化するものです。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>import cv2
import requests
import numpy as np
import math
import time

# 自宅の緯度経度（例：東京駅周辺）
HOME_LAT = 35.6812
HOME_LON = 139.7671

# ウィンドウサイズと中心座標
WIDTH = 480
HEIGHT = 480
CENTER_X = WIDTH // 2
CENTER_Y = HEIGHT // 2

# 縮尺（緯度経度 → ピクセル）
SCALE = 400

# 航空機データ取得関数
def get_aircraft_positions():
    try:
        res = requests.get(&quot;http://localhost:8080/data/aircraft.json&quot;, timeout=1)
        return [a for a in res.json().get(&quot;aircraft&quot;, []) if &#39;lat&#39; in a and &#39;lon&#39; in a]
    except:
        return []

# 点線円を描く関数    
def draw_dotted_circle(img, center, radius, color=(0, 255, 0), spacing=2, dot_length=1):
    cx, cy = center
    circumference = 2 * math.pi * radius
    steps = int(circumference / (spacing + dot_length))

    for i in range(steps):
        angle_start = 2 * math.pi * (i * (spacing + dot_length)) / circumference
        angle_end = angle_start + (dot_length / radius)

        x1 = int(cx + radius * math.cos(angle_start))
        y1 = int(cy + radius * math.sin(angle_start))
        x2 = int(cx + radius * math.cos(angle_end))
        y2 = int(cy + radius * math.sin(angle_end))

        cv2.line(img, (x1, y1), (x2, y2), color, 1)

# 三角形で航空機を描画する関数
def draw_triangle(img, center, angle_deg, color=(0, 255, 0)):
    x, y = center
    length = 15
    width = 5
    angle_rad = math.radians(angle_deg)

    tip = (int(x + length * math.sin(angle_rad)), int(y - length * math.cos(angle_rad)))
    left = (int(x - width * math.cos(angle_rad)), int(y - width * math.sin(angle_rad)))
    right = (int(x + width * math.cos(angle_rad)), int(y + width * math.sin(angle_rad)))

    points = np.array([tip, left, right], dtype=np.int32)
    cv2.fillPoly(img, [points], color)

cv2.namedWindow(&quot;Radar Display&quot;)
cv2.resizeWindow(&quot;Radar Display&quot;, WIDTH, HEIGHT)

last_update = 0
aircraft_list = []

while True:
    frame = np.zeros((HEIGHT, WIDTH, 3), dtype=np.uint8)

    # 中心（自宅）のマーカー
    cv2.circle(frame, (CENTER_X, CENTER_Y), 2, (0, 255, 0), -1)
    
    # 緑の点線の中央縦線
    for y in range(0, HEIGHT, 10):
        if (y // 10) % 2 == 0:
            cv2.line(frame, (CENTER_X, y), (CENTER_X, y + 5), (0, 255, 0), 1)

    # 緑の点線の中央横線
    for x in range(0, WIDTH, 10):
        if (x // 10) % 2 == 0:
            cv2.line(frame, (x, CENTER_Y), (x + 5, CENTER_Y), (0, 255, 0), 1)

    # 点線円を3本描く
    for r in [60, 140, 220]:
        draw_dotted_circle(frame, (CENTER_X, CENTER_Y), r)


    # 1秒ごとにデータ更新
    if time.time() - last_update &gt; 1.0:
        aircraft_list = get_aircraft_positions()
        last_update = time.time()

    # 各航空機を描画
    for a in aircraft_list:
        dx = (a[&#39;lon&#39;] - HOME_LON) * SCALE
        dy = (a[&#39;lat&#39;] - HOME_LAT) * SCALE
        x = int(CENTER_X + dx)
        y = int(CENTER_Y - dy)

        if 0 &lt;= x &lt; WIDTH and 0 &lt;= y &lt; HEIGHT:
            if &#39;track&#39; in a and isinstance(a[&#39;track&#39;], (int, float)):
                draw_triangle(frame, (x, y), a[&#39;track&#39;])
            else:
                cv2.circle(frame, (x, y), 5, (0, 255, 0), -1)

    cv2.imshow(&quot;Radar Display&quot;, frame)

    if cv2.waitKey(30) & 0xFF == 27:  # ESCキーで終了
        break

cv2.destroyAllWindows()
</code></pre></div>



<p class="wp-block-paragraph">まず、自宅の緯度経度を基準としてウィンドウの中心に固定し、各航空機の緯度・経度の差をピクセル換算（<code>SCALE</code>）して、画面上に位置を描画します。</p>



<div class="wp-block-sbd-balloon sbd-balloon sbd-balloon--id-4 sbd-balloon--flat sbd-balloon--l sbd-balloon--green block-box"><div class="sbd-balloon__profile"><figure class="sbd-balloon__icon"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/09/アイコン.jpg" alt="そぞら" class="sbd-balloon__img"/></figure><div class="sbd-balloon__name">そぞら</div></div><div class="sbd-balloon__text-box sbd-inner-block-init">
<p class="wp-block-paragraph">この部分も、自分の環境に応じた緯度経度に変更してください。</p>
</div></div>



<p class="wp-block-paragraph">18行目の<code>SCALE = 400</code> は、緯度・経度の差を画面上のピクセルに変換するための倍率です。この値を大きくすると表示範囲が狭くなり、航空機が大きく動くように見えます。逆に小さくすると広範囲を表示できます。表示範囲や航空機の密度に応じて、<code>SCALE</code> の数値は適宜調整してください。</p>



<p class="wp-block-paragraph">進行中の機体には「track」と呼ばれる方位情報が含まれており、これは航空機がどの方角へ向かっているか（真北を0度として時計回り）を示します。</p>



<p class="wp-block-paragraph">この方位情報をもとに、航空機のアイコンを進行方向に向かって回転させて表示します。アイコンは三角形を使って機体の向きを表現しており、先端が進行方向を指すように描画します。trackの値が取得できない場合には、代わりに緑色の円で機体の位置を示します。</p>



<p class="wp-block-paragraph">1秒ごとにデータ取得・描画を繰り返すことで、リアルタイムな位置関係を描き出しています。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/IMG_9002.jpeg" alt="" class="wp-image-4" style="width:491px;height:auto"/></figure>



<p class="wp-block-paragraph">飛行機がどの方向へ向かっているか、測定地点から見てどこに位置しているかを、視覚的に把握することが可能になりました。</p>



<h2 class="wp-block-heading">ミニレーダー風表示装置の作り方</h2>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/IMG_8983.jpeg" alt="" class="wp-image-4"/></figure>



<p class="wp-block-paragraph">いよいよミニレーダーの作成に着手します。ここからの内容は、以下の構成で作成しています。</p>



<figure class="wp-block-table wp-block-sbd-table wp-block-sbd-table-vertical"><table><tbody><tr><td>モデル</td><td class="has-text-align-left" data-align="left"><a href="https://sozorablog.com/raspberry-pi-zero-2-w/">Raspberry Pi Zero 2 W</a></td></tr><tr><td>OS</td><td class="has-text-align-left" data-align="left">Raspberry Pi OS Bullseye (Legacy, 32-bit)</td></tr><tr><td>ディスプレイ</td><td class="has-text-align-left" data-align="left"><a href="https://shop.pimoroni.com/products/hyperpixel-round?variant=39381081882707">HyperPixel 2.1 Round</a></td></tr></tbody></table></figure>



<h3 class="wp-block-heading">HyperPixel 2.1 Roundの設定</h3>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/スクリーンショット-2025-05-18-5.29.14.jpg" alt="" class="wp-image-4"/><figcaption class="wp-element-caption">出典：<a href="https://shop.pimoroni.com/products/hyperpixel-round?variant=39381081882707">Pimoroni</a></figcaption></figure>



<p class="wp-block-paragraph">ディスプレイは<a href="https://shop.pimoroni.com/products/hyperpixel-round?variant=39381081882707">HyperPixel 2.1 Round</a>を使用しました。小型の円形ディスプレイで、ミニレーダーにはぴったりなアイテムです。GPIOに接続し、設定を行うことで、Raspberry Piのデスクトップ画面をそのまま表示できます。</p>



<p class="wp-block-paragraph">ラズパイはディスプレイの裏側にすっきり収まるサイズのRaspberry Pi Zero 2 Wを使用しました。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/IMG_8984.jpeg" alt="" class="wp-image-4"/><figcaption class="wp-element-caption">HyperPixel 2.1 RoundとZero 2 W</figcaption></figure>



<p class="wp-block-paragraph">Raspberry Piとディスプレイを接続します。40本のピンヘッダーをまるごと差し込みます。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/IMG_8985.jpeg" alt="" class="wp-image-4"/></figure>



<p class="wp-block-paragraph">HyperPixel 2.1 RoundでRaspberry Piの画面を表示するには、カーネルドライバを有効にする必要があります。</p>



<p class="wp-block-paragraph">ターミナルを開いて以下のコマンドを1行ずつ順に実行します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>git clone https://github.com/pimoroni/hyperpixel2r
cd hyperpixel2r
sudo ./install.sh</code></pre></div>



<p class="wp-block-paragraph">ディスプレイを正しく動作させるために、<code>/boot/config.txt</code>の中にある「dtoverlay=vc4-kms-v3d」の行を無効化します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo nano /boot/config.txt</code></pre></div>



<p class="wp-block-paragraph">開いたファイルの中で、「dtoverlay=vc4-kms-v3d」の行を探して、先頭に <code>#</code> を追加します。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/pico-1.jpg" alt="" class="wp-image-4"/></figure>



<p class="wp-block-paragraph">編集が終わったら、<strong>Ctrl + O</strong>&nbsp;で保存し、<strong>Ctrl + X</strong>&nbsp;でエディタを終了します。</p>



<p class="wp-block-paragraph">以下のコマンドでI2Cを無効化します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo raspi-config nonint do_i2c 1</code></pre></div>



<p class="wp-block-paragraph">再起動すると、画面が表示されます。ディスプレイは円形のため、画面の四隅にあるスタートメニューなどは表示されません。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/IMG_8976.jpeg" alt="" class="wp-image-4"/></figure>



<p class="wp-block-paragraph">タッチ操作にも対応していますが、このサイズではGUI操作が難しいため、基本的には<a href="https://sozorablog.com/vnc/">VNC</a>での操作をおすすめします。</p>



<h3 class="wp-block-heading">画面の自動暗転機能を無効化する</h3>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/02/pico-43.jpg" alt="" class="wp-image-4"/></figure>



<p class="wp-block-paragraph">「Raspberry Piの設定」を開いて「画面のブランク」という項目をオフにします。これは、一定時間何も操作しないと画面が暗くなる機能です。<span class="sbd-text-bg-yellow">この機能が有効になっていると、レーダーを長時間表示し続けることができません。</span></p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/02/mm7-2.png" alt="" class="wp-image-4" style="width:840px;height:auto"/></figure>



<h3 class="wp-block-heading">スタンドの作成</h3>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/IMG_8996.jpeg" alt="" class="wp-image-4" style="width:445px;height:auto"/></figure>



<p class="wp-block-paragraph">機器を設置するためのスタンドを、Tinkercadで設計して<a href="https://sozorablog.com/ankermake-m5c/">3Dプリンター</a>で作りました。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/スクリーンショット-2025-05-18-5.25.54.png" alt="" class="wp-image-4" style="width:444px;height:auto"/></figure>



<p class="wp-block-paragraph">デザインは、戦闘機のコックピットにある計器をイメージしています。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/IMG_8950.jpeg" alt="" class="wp-image-4" style="width:434px;height:auto"/></figure>



<p class="wp-block-paragraph">設計が完成したらプリント開始。およそ2時間で印刷が終わりました。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/IMG_8953.jpeg" alt="" class="wp-image-4" style="width:434px;height:auto"/></figure>



<p class="wp-block-paragraph">スタンドに機器を取り付けた様子。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/IMG_8973.jpeg" alt="" class="wp-image-4" style="width:433px;height:auto"/></figure>



<p class="wp-block-paragraph">デザインやサイズを調整しながら、5回ほど試作を重ねました。以下のボタンからSTLファイルをダウンロードできます。</p>


<div class='w3eden'><!-- WPDM Link Template: Default Template -->

<div class="link-template-default card mb-2">
    <div class="card-body">
        <div class="media">
            <div class="mr-3 img-48"><img decoding="async" class="wpdm_icon" alt="アイコン" src="https://sozorablog.com/wp-content/plugins/download-manager/assets/file-type-icons/zip.svg" /></div>
            <div class="media-body">
                <h3 class="package-title"><a href='https://sozorablog.com/download/hyperpixel-round-stand/'>HyperPixel-Round-stand</a></h3>
                <div class="text-muted text-small"><i class="fas fa-copy"></i> 1 ファイル <i class="fas fa-hdd ml-3"></i> 130.01 KB</div>
            </div>
            <div class="ml-3">
                <a class='wpdm-download-link download-on-click btn btn-primary ' rel='nofollow' href='#' data-downloadurl="https://sozorablog.com/download/hyperpixel-round-stand/?wpdmdl=16709&refresh=6a8d2e7685ec61787637366">ダウンロード</a>
            </div>
        </div>
    </div>
</div>

</div>



<h3 class="wp-block-heading">レーダー画像と飛行機アイコンの準備</h3>



<p class="wp-block-paragraph">回転するレーダーの動画は、<a href="https://pixabay.com/ja/videos/%E3%83%AC%E3%83%BC%E3%83%80%E3%83%BC-%E3%82%BD%E3%83%8A%E3%83%BC-ping-2420/">Pixabay</a>で公開されているものをダウンロードして使用します。Pixabayは著作権フリーの画像、動画、音声などを共有するサイトです。サイズは<span class="sbd-text-red">640×360</span>のものをダウンロードしました。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/03/radar2.jpg" alt="" class="wp-image-4"/><figcaption class="wp-element-caption"><a href="https://pixabay.com/ja/videos/%E3%83%AC%E3%83%BC%E3%83%80%E3%83%BC-%E3%82%BD%E3%83%8A%E3%83%BC-ping-2420/">Pixabay</a></figcaption></figure>



<p class="wp-block-paragraph">飛行機の位置を示すためのアイコン画像を作成しました。透過PNG形式の飛行機アイコン画像は、ChatGPTに作ってもらい、サイズはパソコンで48ピクセルに調整しました。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/plane_icon-1.png" alt="" class="wp-image-4"/><figcaption class="wp-element-caption">plane_icon.png</figcaption></figure>


<div class='w3eden'><!-- WPDM Link Template: Default Template -->

<div class="link-template-default card mb-2">
    <div class="card-body">
        <div class="media">
            <div class="mr-3 img-48"><img decoding="async" class="wpdm_icon" alt="アイコン" src="https://sozorablog.com/wp-content/plugins/download-manager/assets/file-type-icons/png.svg" /></div>
            <div class="media-body">
                <h3 class="package-title"><a href='https://sozorablog.com/download/%e9%a3%9b%e8%a1%8c%e6%a9%9f%e3%82%a2%e3%82%a4%e3%82%b3%e3%83%b3plane_icon-png/'>飛行機アイコン(plane_icon.png)</a></h3>
                <div class="text-muted text-small"><i class="fas fa-copy"></i> 1 ファイル <i class="fas fa-hdd ml-3"></i> 1.09 KB</div>
            </div>
            <div class="ml-3">
                <a class='wpdm-download-link download-on-click btn btn-primary ' rel='nofollow' href='#' data-downloadurl="https://sozorablog.com/download/%e9%a3%9b%e8%a1%8c%e6%a9%9f%e3%82%a2%e3%82%a4%e3%82%b3%e3%83%b3plane_icon-png/?wpdmdl=14757&refresh=6a8d2e76881781787637366">ダウンロード</a>
            </div>
        </div>
    </div>
</div>

</div>



<p class="wp-block-paragraph">動画とアイコンはファイル名をradar.mp4とplane_icon.pngに変更して、Raspberry Piの「/home/pi」ディレクトリ、または実行するプログラムを保存するディレクトリに保存します。WindowsパソコンからRaspberry Piにファイルを移動する場合は、<a href="https://sozorablog.com/winscp/">WinSCP</a>を利用すると便利です。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/pico-1-1.jpg" alt="" class="wp-image-4"/></figure>



<div class="wp-block-sbd-balloon sbd-balloon sbd-balloon--id-4 sbd-balloon--flat sbd-balloon--l sbd-balloon--green block-box"><div class="sbd-balloon__profile"><figure class="sbd-balloon__icon"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/09/アイコン.jpg" alt="そぞら" class="sbd-balloon__img"/></figure><div class="sbd-balloon__name">そぞら</div></div><div class="sbd-balloon__text-box sbd-inner-block-init">
<p class="wp-block-paragraph">ファイル名や保存場所が正しくないと、プログラムから呼び出せなくなります。</p>
</div></div>



<h3 class="wp-block-heading">ミニレーダー風ディスプレイのプログラム</h3>



<p class="wp-block-paragraph">以下のプログラムでは、先ほど保存した <code>radar.mp4</code> を背景動画として表示し、<code>plane_icon.png</code> の飛行機アイコンを航空機の位置に合わせて画面上に描画します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>import cv2
import requests
import numpy as np
import math
import time

# 自宅の緯度経度に変更してください（以下は東京駅周辺）
HOME_LAT = 35.6812
HOME_LON = 139.7671

# 画面サイズと中心座標
WIDTH = 480
HEIGHT = 480
CENTER_X = WIDTH // 2
CENTER_Y = HEIGHT // 2

# 緯度経度→ピクセル変換倍率
SCALE = 300

# 飛行機アイコンの読み込み（アルファチャンネル付き）
icon = cv2.imread(&quot;plane_icon.png&quot;, cv2.IMREAD_UNCHANGED)
icon_h, icon_w = icon.shape[:2]

# 背景レーダー動画の読み込み
cap = cv2.VideoCapture(&quot;radar.mp4&quot;)
fps = cap.get(cv2.CAP_PROP_FPS)
delay = int(1000 / fps) if fps &gt; 0 else 33  # フレーム遅延時間(ms)

# 航空機データ取得関数
def get_aircraft_positions():
    try:
        res = requests.get(&quot;http://localhost:8080/data/aircraft.json&quot;, timeout=1)
        return [a for a in res.json().get(&quot;aircraft&quot;, []) if &#39;lat&#39; in a and &#39;lon&#39; in a]
    except:
        return []

# 飛行機アイコンを回転描画する関数
def draw_icon_rotated(img, icon, center, angle_deg):
    x, y = center
    M = cv2.getRotationMatrix2D((icon_w // 2, icon_h // 2), -angle_deg, 1.0)
    rotated = cv2.warpAffine(
        icon, M, (icon_w, icon_h),
        flags=cv2.INTER_NEAREST,
        borderMode=cv2.BORDER_CONSTANT,
        borderValue=(0, 0, 0, 0)
    )

    # アイコン貼り付け位置の計算
    x1 = x - icon_w // 2
    y1 = y - icon_h // 2
    x2 = x1 + icon_w
    y2 = y1 + icon_h

    # 画面外ならスキップ
    if x1 &lt; 0 or y1 &lt; 0 or x2 &gt; img.shape[1] or y2 &gt; img.shape[0]:
        return

    # ROI合成（アルファブレンド）
    roi = img[y1:y2, x1:x2]
    if rotated.shape[2] == 4:
        alpha = rotated[:, :, 3] / 255.0
        for c in range(3):
            roi[:, :, c] = (1 - alpha) * roi[:, :, c] + alpha * rotated[:, :, c]

# ウィンドウを全画面表示
cv2.namedWindow(&quot;Radar Display&quot;, cv2.WINDOW_NORMAL)
cv2.setWindowProperty(&quot;Radar Display&quot;, cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)

# 初期化
aircraft_list = []
last_update = 0

while True:
    now = time.time()
    if now - last_update &gt;= 1.0:
        aircraft_list = get_aircraft_positions()
        last_update = now    
    
    # 動画フレームの読み込み
    ret, video_frame = cap.read()
    if not ret:
        cap.set(cv2.CAP_PROP_POS_FRAMES, 0)  # 動画を最初に戻す
        continue

    # 動画のリサイズ（1.8倍ズーム＋アスペクト比維持）
    video_h, video_w = video_frame.shape[:2]
    scale = min(WIDTH / video_w, HEIGHT / video_h) * 1.8
    new_w = int(video_w * scale)
    new_h = int(video_h * scale)
    resized = cv2.resize(video_frame, (new_w, new_h), interpolation=cv2.INTER_NEAREST)
    resized = cv2.convertScaleAbs(resized, alpha=0.6, beta=0)  # 薄く表示

    # 最終描画フレーム（黒背景）
    frame = np.zeros((HEIGHT, WIDTH, 3), dtype=np.uint8)

    # 動画の貼り付け位置計算（中央寄せ）
    x_offset = (WIDTH - new_w) // 2
    y_offset = (HEIGHT - new_h) // 2
    x1_dst = max(x_offset, 0)
    y1_dst = max(y_offset, 0)
    x1_src = max(-x_offset, 0)
    y1_src = max(-y_offset, 0)
    x2_dst = min(x_offset + new_w, WIDTH)
    y2_dst = min(y_offset + new_h, HEIGHT)
    x2_src = x1_src + (x2_dst - x1_dst)
    y2_src = y1_src + (y2_dst - y1_dst)

    # 動画フレームを合成
    frame[y1_dst:y2_dst, x1_dst:x2_dst] = resized[y1_src:y2_src, x1_src:x2_src]

    # 航空機データ取得
    aircraft_list = get_aircraft_positions()

    # 航空機ごとにアイコンを描画
    for a in aircraft_list:
        dx = (a[&#39;lon&#39;] - HOME_LON) * SCALE
        dy = (a[&#39;lat&#39;] - HOME_LAT) * SCALE
        x = int(CENTER_X + dx)
        y = int(CENTER_Y - dy)

        # 画面内に収まっているか判定
        if 0 &lt;= x &lt; WIDTH and 0 &lt;= y &lt; HEIGHT:
            if &#39;track&#39; in a and isinstance(a[&#39;track&#39;], (int, float)):
                draw_icon_rotated(frame, icon, (x, y), a[&#39;track&#39;])
            else:
                cv2.circle(frame, (x, y), 5, (0, 255, 0), -1)

    # フレーム表示
    cv2.imshow(&quot;Radar Display&quot;, frame)

    # ESCキーで終了
    key = cv2.waitKey(delay) & 0xFF
    if key == 27:
        break

# 終了処理
cap.release()
cv2.destroyAllWindows()
</code></pre></div>



<p class="wp-block-paragraph"><code>HOME_LAT</code> と <code>HOME_LON</code> は、レーダー画面の中心となる自宅の位置を表す緯度・経度です（この例では東京駅付近を指定しています）。航空機の位置は、この基準点からの相対的な距離をもとに計算され、画面上に配置されます。</p>



<div class="wp-block-sbd-balloon sbd-balloon sbd-balloon--id-4 sbd-balloon--flat sbd-balloon--l sbd-balloon--green block-box"><div class="sbd-balloon__profile"><figure class="sbd-balloon__icon"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/09/アイコン.jpg" alt="そぞら" class="sbd-balloon__img"/></figure><div class="sbd-balloon__name">そぞら</div></div><div class="sbd-balloon__text-box sbd-inner-block-init">
<p class="wp-block-paragraph">自分の環境に応じた緯度と経度に変更してください。</p>
</div></div>



<p class="wp-block-paragraph"><code>SCALE = 300</code> は、緯度・経度の差を画面上のピクセルに変換するための倍率です。この値を大きくすると表示範囲が狭くなり、航空機が大きく動くように見えます。逆に小さくすると広範囲を表示できます。表示範囲や航空機の密度に応じて、<code>SCALE</code> の数値は適宜調整してください。</p>



<p class="wp-block-paragraph">プログラムの終了は、<span class="sbd-text-bg-yellow"><code>ESC</code>キーを押す</span>ことでウィンドウが閉じられ、処理が終了します。画面はフルスクリーンで表示されるため、実際のレーダー装置のような見た目に仕上がります。</p>



<p class="wp-block-paragraph">ESCキーでプログラムを終了できます。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/スクリーンショット-2025-05-17-16.55.47.png" alt="" class="wp-image-4"/><figcaption class="wp-element-caption">レーダー画面の表示例</figcaption></figure>



<p class="wp-block-paragraph">無事にミニレーダーが完成しました。飛行機の動きを眺めているだけでも飽きません。</p>



<figure class="wp-block-embed is-type-rich is-provider-twitter wp-block-embed-twitter"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="500" data-dnt="true"><p lang="ja" dir="ltr">Raspberry Piで作ったレーダー風ガジェット。<br><br>飛行機から送信されるADS-B信号を受信し、リアルタイムな位置を表示します。 <a href="https://t.co/cRcj0Q6rCZ">pic.twitter.com/cRcj0Q6rCZ</a></p>&mdash; そぞら@Raspberry Pi 電子工作 (@sozoraemon) <a href="https://twitter.com/sozoraemon/status/1927312233266082016?ref_src=twsrc%5Etfw">May 27, 2025</a></blockquote><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</div></figure>



<h3 class="wp-block-heading">【改良版】便名を表示する</h3>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/image.png" alt="" class="wp-image-4"/></figure>



<p class="wp-block-paragraph">以下は飛行機アイコンの<strong>すぐ下に便名（flight）を表示</strong>するコードを追加したものです。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>import cv2
import requests
import numpy as np
import math
import time

# 自宅の緯度経度に変更してください（以下は東京駅周辺）
HOME_LAT = 35.6812
HOME_LON = 139.7671

# 画面サイズと中心座標
WIDTH = 480
HEIGHT = 480
CENTER_X = WIDTH // 2
CENTER_Y = HEIGHT // 2

# 緯度経度→ピクセル変換倍率
SCALE = 600

# 飛行機アイコンの読み込み（アルファチャンネル付き）
icon = cv2.imread(&quot;plane_icon.png&quot;, cv2.IMREAD_UNCHANGED)
icon_h, icon_w = icon.shape[:2]

# 背景レーダー動画の読み込み
cap = cv2.VideoCapture(&quot;radar.mp4&quot;)
fps = cap.get(cv2.CAP_PROP_FPS)
delay = int(1000 / fps) if fps &gt; 0 else 33  # フレーム遅延時間(ms)

# 航空機データ取得関数
def get_aircraft_positions():
    try:
        res = requests.get(&quot;http://localhost:8080/data/aircraft.json&quot;, timeout=1)
        return [a for a in res.json().get(&quot;aircraft&quot;, []) if &#39;lat&#39; in a and &#39;lon&#39; in a]
    except:
        return []

# 飛行機アイコンを回転描画する関数
def draw_icon_rotated(img, icon, center, angle_deg):
    x, y = center
    M = cv2.getRotationMatrix2D((icon_w // 2, icon_h // 2), -angle_deg, 1.0)
    rotated = cv2.warpAffine(
        icon, M, (icon_w, icon_h),
        flags=cv2.INTER_NEAREST,
        borderMode=cv2.BORDER_CONSTANT,
        borderValue=(0, 0, 0, 0)
    )

    # アイコン貼り付け位置の計算
    x1 = x - icon_w // 2
    y1 = y - icon_h // 2
    x2 = x1 + icon_w
    y2 = y1 + icon_h

    # 画面外ならスキップ
    if x1 &lt; 0 or y1 &lt; 0 or x2 &gt; img.shape[1] or y2 &gt; img.shape[0]:
        return

    # ROI合成（アルファブレンド）
    roi = img[y1:y2, x1:x2]
    if rotated.shape[2] == 4:
        alpha = rotated[:, :, 3] / 255.0
        for c in range(3):
            roi[:, :, c] = (1 - alpha) * roi[:, :, c] + alpha * rotated[:, :, c]

# ウィンドウを全画面表示
cv2.namedWindow(&quot;Radar Display&quot;, cv2.WINDOW_NORMAL)
cv2.setWindowProperty(&quot;Radar Display&quot;, cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)

# 初期化
aircraft_list = []
last_update = 0

while True:
    now = time.time()
    if now - last_update &gt;= 1.0:
        aircraft_list = get_aircraft_positions()
        last_update = now    
    
    # 動画フレームの読み込み
    ret, video_frame = cap.read()
    if not ret:
        cap.set(cv2.CAP_PROP_POS_FRAMES, 0)  # 動画を最初に戻す
        continue

    # 動画のリサイズ（1.8倍ズーム＋アスペクト比維持）
    video_h, video_w = video_frame.shape[:2]
    scale = min(WIDTH / video_w, HEIGHT / video_h) * 1.8
    new_w = int(video_w * scale)
    new_h = int(video_h * scale)
    resized = cv2.resize(video_frame, (new_w, new_h), interpolation=cv2.INTER_NEAREST)
    resized = cv2.convertScaleAbs(resized, alpha=0.6, beta=0)  # 薄く表示

    # 最終描画フレーム（黒背景）
    frame = np.zeros((HEIGHT, WIDTH, 3), dtype=np.uint8)

    # 動画の貼り付け位置計算（中央寄せ）
    x_offset = (WIDTH - new_w) // 2
    y_offset = (HEIGHT - new_h) // 2
    x1_dst = max(x_offset, 0)
    y1_dst = max(y_offset, 0)
    x1_src = max(-x_offset, 0)
    y1_src = max(-y_offset, 0)
    x2_dst = min(x_offset + new_w, WIDTH)
    y2_dst = min(y_offset + new_h, HEIGHT)
    x2_src = x1_src + (x2_dst - x1_dst)
    y2_src = y1_src + (y2_dst - y1_dst)

    # 動画フレームを合成
    frame[y1_dst:y2_dst, x1_dst:x2_dst] = resized[y1_src:y2_src, x1_src:x2_src]

    # 航空機ごとにアイコンを描画
    for a in aircraft_list:
        dx = (a[&#39;lon&#39;] - HOME_LON) * SCALE
        dy = (a[&#39;lat&#39;] - HOME_LAT) * SCALE
        x = int(CENTER_X + dx)
        y = int(CENTER_Y - dy)

        # 画面内に収まっているか判定
        if 0 &lt;= x &lt; WIDTH and 0 &lt;= y &lt; HEIGHT:
            if &#39;track&#39; in a and isinstance(a[&#39;track&#39;], (int, float)):
                draw_icon_rotated(frame, icon, (x, y), a[&#39;track&#39;])
            else:
                cv2.circle(frame, (x, y), 5, (0, 255, 0), -1)
                
            # --- 便名を描画 ---
            if &#39;flight&#39; in a and a[&#39;flight&#39;]:
                flight_text = a[&#39;flight&#39;]
                font = cv2.FONT_HERSHEY_SIMPLEX
                font_scale = 0.5
                thickness = 1
                text_size, _ = cv2.getTextSize(flight_text, font, font_scale, thickness)
                text_x = x - text_size[0] // 2 + 6
                text_y = y + icon_h // 2 + text_size[1] - 2 # アイコン下
                cv2.putText(frame, flight_text, (text_x, text_y), font, font_scale, (0, 255, 0), thickness, cv2.LINE_AA)                

    # フレーム表示
    cv2.imshow(&quot;Radar Display&quot;, frame)

    # ESCキーで終了
    key = cv2.waitKey(delay) & 0xFF
    if key == 27:
        break

# 終了処理
cap.release()
cv2.destroyAllWindows()
</code></pre></div>



<h2 class="wp-block-heading">Flightradar24へデータ提供する</h2>



<p class="wp-block-paragraph">自宅で受信した航空機のADS-B信号をFlightradar24に提供することで、航空ネットワークに貢献できます。その見返りとして、通常は有料のプレミアム機能が無料で使えるようになります。<br>ここでは、データ提供するメリットとデメリットを整理します。</p>



<p class="wp-block-paragraph">メリット</p>



<div class="wp-block-sbd-list"><ul class="sbd-list sbd-list-border"><li>Flightradar24のContributorプランが利用可能</li><li>いつでもやめられる（データ送信を停止しても金銭的・法的な不利益なし）</li></ul></div>



<p class="wp-block-paragraph">デメリット</p>



<div class="wp-block-sbd-list"><ul class="sbd-list sbd-list-border"><li>Raspberry Piのリソースを使用（低スペック機では他の作業に影響）</li><li>ラズパイの位置情報をFlightradar24に提供する必要あり</li></ul></div>



<h3 class="wp-block-heading">Flightradar24のアカウントを作成する</h3>



<p class="wp-block-paragraph">データを提供するには、Flightradar24のアカウントが必要です。</p>



<p class="wp-block-paragraph"><a href="https://www.flightradar24.com/">Flightradar24のウェブサイト</a>にアクセスし、画面右上の「Login」をクリックします。</p>



<p class="wp-block-paragraph">表示されたウィンドウの下部にある　<strong>“Learn more | Create account”</strong> をクリックします。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/pico-1.png" alt="" class="wp-image-4" style="width:451px;height:auto"/></figure>



<p class="wp-block-paragraph">表示されたこのプラン比較画面で、左端の「Free」プランの下にある「Create account」ボタンをクリックします。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/pico-4.jpg" alt="" class="wp-image-4"/></figure>



<p class="wp-block-paragraph">メールアドレス・パスワードを入力し、アカウントを作成します。</p>



<p class="wp-block-paragraph">登録したメールアドレスに確認メールが届くので、リンクをクリックして認証します。</p>



<h3 class="wp-block-heading">fr24feed（フィーダーソフト）をインストールする</h3>



<p class="wp-block-paragraph">次に、Flightradar24にデータを送るためのソフト「fr24feed」をRaspberry Piにインストールします。</p>



<div class="wp-block-sbd-balloon sbd-balloon sbd-balloon--id-4 sbd-balloon--flat sbd-balloon--l sbd-balloon--green block-box"><div class="sbd-balloon__profile"><figure class="sbd-balloon__icon"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/09/アイコン.jpg" alt="そぞら" class="sbd-balloon__img"/></figure><div class="sbd-balloon__name">そぞら</div></div><div class="sbd-balloon__text-box sbd-inner-block-init">
<p class="wp-block-paragraph">このソフトを使うには、<strong>dump1090-fa</strong>がインストールされていて、起動している必要があります。</p>
</div></div>



<p class="wp-block-paragraph">dump1090-faのインストールや起動がまだの場合は、この記事の前半にある<span class="sbd-text-bg-yellow">「ソフトウェアの設定」パートの手順を先に行ってください。</span></p>



<p class="wp-block-paragraph">ターミナルで以下のコマンドを実行</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo bash -c &quot;$(wget -O - https://repo-feed.flightradar24.com/install_fr24_rpi.sh)&quot;</code></pre></div>



<p class="wp-block-paragraph">このコマンドは、Flightradar24のデータ送信ソフト「fr24feed」をRaspberry Piにダウンロードしてインストールするためのものです。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/スクリーンショット-2025-05-23-4.07.37.png" alt="" class="wp-image-4" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph">インストール後、自動的に設定ウィザードが始まります。ターミナルにいくつかの質問が表示されるので、それぞれに答えてエンターキーを押してください。以下のように回答します。</p>



<figure class="wp-block-table wp-block-sbd-table wp-block-sbd-table-vertical"><table><thead><tr><th>Step</th><th class="has-text-align-left" data-align="left">質問内容</th><th>回答の例</th></tr></thead><tbody><tr><td>1.1</td><td class="has-text-align-left" data-align="left">Flightradar24アカウントのメールアドレス</td><td>登録したメールアドレスを入力</td></tr><tr><td>1.2</td><td class="has-text-align-left" data-align="left">Sharing keyの入力</td><td>以前使用したキーがあれば入力<br>なければそのままEnter</td></tr><tr><td>1.3</td><td class="has-text-align-left" data-align="left">MLAT(Multilateration)に参加するか？<br>※複数の受信機が同時に受け取った信号の到達時間差からADS-B信号のない航空機の位置を推定する技術</td><td><br>yes または no を入力してEnter<br>（基本は yes でOK）</td></tr><tr><td>3.A</td><td class="has-text-align-left" data-align="left">アンテナ設置位置の緯度</td><td>例：35.6812<br><a href="https://www.google.com/maps/?hl=ja">Googleマップ</a>等で調査可</td></tr><tr><td>3.B</td><td class="has-text-align-left" data-align="left">アンテナ設置位置の経度</td><td>例：139.7671</td></tr><tr><td>3.C</td><td class="has-text-align-left" data-align="left">アンテナ設置位置の高度（フィート）</td><td>例: <code>108</code><br>地面の標高＋アンテナ設置位置までの高さ（m）× 3.28084（フィート換算）<br>標高は<a href="https://maps.gsi.go.jp/">国土地理院地図</a>で調査可</td></tr><tr><td></td><td class="has-text-align-left" data-align="left">入力内容の確認</td><td>yes または no を入力してEnter</td></tr><tr><td></td><td class="has-text-align-left" data-align="left">「autoconfig 機能」を使うかどうかの確認</td><td>基本は yes でOK</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">すべて正常に完了すると、「Installation and configuration completed!」と表示されます。</p>



<h3 class="wp-block-heading">データ提供の確認</h3>



<p class="wp-block-paragraph">以下のコマンドでfr24feedの動作状況を確認します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>fr24feed-status</code></pre></div>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/pico-2-1.jpg" alt="" class="wp-image-4"/></figure>



<p class="wp-block-paragraph">最下行の「FR24 MLAT: not running &#8230; failed!」は、MLAT（複数の受信機で航空機の位置を推定する機能）が正常に動作していないことを示しています。</p>



<div class="wp-block-sbd-checkpoint-block"><p class="sbd-checkpoint-title">申し訳ありません</p><div class="sbd-checkpoint-content sbd-inner-block-init"><p>「FR24 MLAT: not running &#8230; failed!」について、以下の記事を参考に設定を見直しましたが、解決には至っていません。<a href="https://intaa.net/archives/21762">https://intaa.net/archives/21762</a>　</p></div></div>



<p class="wp-block-paragraph"><a href="https://forum.flightradar24.com/forum/radar-forums/flightradar24-feeding-data-to-flightradar24/9479-fr24feed-uploader-additional-info">Flightradar24（FR24）の公式フォーラム</a>によると、MLATが動作するには、同じ航空機の信号を<strong>複数の受信局</strong>が同時に受信している必要があります。今回はMLATだけが停止しているため、この受信条件が満たされていない可能性があると推測されますが、現時点で断定はできません。</p>



<p class="wp-block-paragraph">なお、ADS-B信号の受信とFlightradar24へのデータ提供は正常に行われており、<span class="sbd-text-red">Businessプランの適用に影響はありません。</span></p>



<div class="wp-block-sbd-balloon sbd-balloon sbd-balloon--id-4 sbd-balloon--flat sbd-balloon--l sbd-balloon--green block-box"><div class="sbd-balloon__profile"><figure class="sbd-balloon__icon"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/09/アイコン.jpg" alt="そぞら" class="sbd-balloon__img"/></figure><div class="sbd-balloon__name">そぞら</div></div><div class="sbd-balloon__text-box sbd-inner-block-init">
<p class="wp-block-paragraph">今後、MLATが正常に動作する方法が分かり次第、この記事に追記します。</p>
</div></div>



<p class="wp-block-paragraph">Raspberry Piのブラウザで <code>http://localhost:8754</code> にアクセスすると、fr24feedの動作状況（受信状態、送信状態、MLATの状態など）をリアルタイムで確認できます。</p>



<p class="wp-block-paragraph">Flightradar24のウェブサイトにアクセスし、画面右上のユーザーアイコンに「CONTRIBUTOR」と表示されていれば、CONTRIBUTORプランが適用済みです。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/pico-1-1-1.jpg" alt="" class="wp-image-4"/></figure>



<h3 class="wp-block-heading">Flightradar24へのデータ提供を中止する</h3>



<p class="wp-block-paragraph">データ提供はいつでも停止することができます。中止しても料金が発生することはありません。</p>



<p class="wp-block-paragraph">データ提供を中止するには、以下を1行ずつ実行します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo systemctl stop fr24feed
sudo systemctl disable fr24feed</code></pre></div>



<p class="wp-block-paragraph">これにより、fr24feedが停止し、次回以降の起動時にも自動実行されなくなります。</p>



<h2 class="wp-block-heading">まとめ</h2>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/Videotogif.gif" alt="" class="wp-image-4"/></figure>



<p class="wp-block-paragraph">ADS-B受信機は買って大正解のアイテムでした。Raspberry Piとの相性も抜群で、ラズパイユーザーには特におすすめです。</p>



<!-- START MoshimoAffiliateEasyLink -->
<script type="text/javascript">
(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;
b[a]=b[a]||function(){arguments.currentScript=c.currentScript
||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};
c.getElementById(a)||(d=c.createElement(f),d.src=g,
d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})
(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");
msmaflink({"n":"Nooelec NESDR Mini ミニUSB RTL-SDRおよびADS-B受信機セット、RTL2832UおよびR820Tチューナー、MCX入力。 多くのSDRソフトウェアパッケージと互換性のある低コストソフトウェア無線機。 R820Tチューナ","b":"NooElec","t":"100556","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/31Vb71v4fTL._SL500_.jpg","\/314CXt2ANJL._SL500_.jpg","\/31QS842oE2L._SL500_.jpg","\/41fYlg-Nw3L._SL500_.jpg","\/31bzg-noaGL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/B009U7WZCA","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/B009U7WZCA","a_id":3038653,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/Nooelec%20NESDR%20Mini%20%E3%83%9F%E3%83%8BUSB%20RTL-SDR%E3%81%8A%E3%82%88%E3%81%B3ADS-B%E5%8F%97%E4%BF%A1%E6%A9%9F%E3%82%BB%E3%83%83%E3%83%88%E3%80%81RTL2832U%E3%81%8A%E3%82%88%E3%81%B3R820T%E3%83%81%E3%83%A5%E3%83%BC%E3%83%8A%E3%83%BC%E3%80%81MCX%E5%85%A5%E5%8A%9B%E3%80%82%20%E5%A4%9A%E3%81%8F%E3%81%AESDR%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E3%81%A8%E4%BA%92%E6%8F%9B%E6%80%A7%E3%81%AE%E3%81%82%E3%82%8B%E4%BD%8E%E3%82%B3%E3%82%B9%E3%83%88%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E7%84%A1%E7%B7%9A%E6%A9%9F%E3%80%82%20R820T%E3%83%81%E3%83%A5%E3%83%BC%E3%83%8A\/","a_id":3038654,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2}],"eid":"8T0PA","s":"s"});
</script>
<div id="msmaflink-8T0PA">リンク</div>
<!-- MoshimoAffiliateEasyLink END -->



<p class="wp-block-paragraph">受信したデータを自動で処理したり、リアルタイムに表示したりといった処理を、小型で省電力なRaspberry Piだけで完結できるからです。</p>



<div class="wp-block-sbd-balloon sbd-balloon sbd-balloon--id-4 sbd-balloon--flat sbd-balloon--l sbd-balloon--green block-box"><div class="sbd-balloon__profile"><figure class="sbd-balloon__icon"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/09/アイコン.jpg" alt="そぞら" class="sbd-balloon__img"/></figure><div class="sbd-balloon__name">そぞら</div></div><div class="sbd-balloon__text-box sbd-inner-block-init">
<p class="wp-block-paragraph">本記事で紹介したプログラムは、ChatGPTの力を借りながら作成しました。</p>
</div></div>



<p class="wp-block-paragraph">初心者の方でも、AIを活用すれば比較的ハードルを感じずに取り組めると思います。</p>



<p class="wp-block-paragraph">ADS-B受信機はほかにもいろいろな活用ができそうなので、試行錯誤を楽しんでいるところです。新しいものを作ったらまた紹介します。</p>



<h2 class="wp-block-heading">ドラゴンレーダー風ミニレーダーの作成</h2>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/IMG_9077.jpeg" alt="" class="wp-image-4" style="width:496px;height:auto"/></figure>



<p class="wp-block-paragraph">飛行機レーダーのノウハウと手頃な円形ディスプレイがあれば、「あのドラゴンレーダー」を作ってみたくなるものです。</p>



<p class="wp-block-paragraph">円形ディスプレイは<a href="https://www.switch-science.com/products/9027?srsltid=AfmBOoo1W1ysVXjDQQNc0XH-GR_97YopXnXRjNjTt5BqhrL31AldC4ko">1.28inch Touch LCD</a>を使用しました。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/pico-2-2.jpg" alt="" class="wp-image-4"/></figure>



<p class="wp-block-paragraph">円形ディスプレイを収納するケースは3Dプリンターで作成。Thingiverseで公開されている<a href="https://www.thingiverse.com/thing:6637362">Radar Dragon Ball</a>をベースに、サイズやデザインを調整しています。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/スクリーンショット-2025-06-13-9.49.30.jpg" alt="" class="wp-image-4"/></figure>



<p class="wp-block-paragraph">レーダーの背景となる画像はCanvaで作成しました。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/スクリーンショット-2025-06-13-9.41.07.png" alt="" class="wp-image-4"/></figure>



<p class="wp-block-paragraph">レーダーを表示するだけではおもしろくないので、方位がわかる地磁気センサーを使ってみました。レーダー本体が向いている方向にあわせて画面が回るようにして、飛行機の位置が感覚的にわかるようにしました。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/IMG_9078.jpeg" alt="" class="wp-image-4"/><figcaption class="wp-element-caption">ケース内に搭載した地磁気センサー</figcaption></figure>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>#!/usr/bin/python3
# -*- coding: utf-8 -*-
import os
import sys
import time
import math
import smbus2
import requests
import numpy as np
import cv2
from PIL import Image
sys.path.append(&quot;..&quot;)
from lib import LCD_1inch28

# ── QMC5883L 設定 ──
QMC5883L_ADDRESS = 0x0D
X_OFFSET    = -110.0
Y_OFFSET    = -587.5
X_SCALE     = 1.0234375
Y_SCALE     = 0.95
DECLINATION = -8.0
HEADING_OFFSET = 76.4

# ── 自宅座標とスケール ──
HOME_LAT = 35.6812
HOME_LON = 139.7671
SCALE = 250 #350
WIDTH = 240
HEIGHT = 240
CENTER_X = WIDTH // 2
CENTER_Y = HEIGHT // 2

# ── LCD 初期化 ──
disp = LCD_1inch28.LCD_1inch28()
disp.Init()
disp.clear()

# ── I2C 初期化 ──
bus = smbus2.SMBus(1)
bus.write_byte_data(QMC5883L_ADDRESS, 0x0B, 0x01)
time.sleep(0.1)
bus.write_byte_data(QMC5883L_ADDRESS, 0x09, 0x1D)
time.sleep(0.1)

# ── 方位取得 ──
def read_axis(reg_lsb):
    lsb = bus.read_byte_data(QMC5883L_ADDRESS, reg_lsb)
    msb = bus.read_byte_data(QMC5883L_ADDRESS, reg_lsb + 1)
    value = (msb &lt;&lt; 8) | lsb
    if value &gt;= 0x8000:
        value -= 0x10000
    return value

def get_heading():
    raw_x = read_axis(0x00)
    raw_y = read_axis(0x02)
    adj_x = (raw_x - X_OFFSET) * X_SCALE
    adj_y = (raw_y - Y_OFFSET) * Y_SCALE
    raw_heading = math.degrees(math.atan2(adj_y, adj_x))
    if raw_heading &lt; 0:
        raw_heading += 360.0
    heading = (raw_heading - HEADING_OFFSET + DECLINATION) % 360.0
    return heading

# ── 航空機データ取得 ──
def get_aircraft_positions():
    try:
        res = requests.get(&quot;http://192.168.1.46:8080/data/aircraft.json&quot;, timeout=1)
        return [a for a in res.json().get(&quot;aircraft&quot;, []) if &#39;lat&#39; in a and &#39;lon&#39; in a]
    except:
        return []

# ── 背景画像の読み込み ──
original = Image.open(&quot;dragon2.png&quot;).convert(&quot;RGB&quot;)
original = original.resize((240, 240))
original_cv = cv2.cvtColor(np.array(original), cv2.COLOR_RGB2BGR)

# ── メインループ ──
last_update = 0
aircraft_list = []

while True:
    # 背景画像をコピー（毎回初期化）
    frame = original_cv.copy()

    # 1秒ごとに航空機情報を更新
    if time.time() - last_update &gt; 2.0:
        aircraft_list = get_aircraft_positions()
        last_update = time.time()
    print(&quot;航空機数: {}&quot;.format(len(aircraft_list)))
    for a in aircraft_list:
        print(&quot;  LAT: {:.4f}, LON: {:.4f}&quot;.format(a[&#39;lat&#39;], a[&#39;lon&#39;]))        

    # 航空機を黄色い円で描画
    for a in aircraft_list:
        dx = (a[&#39;lon&#39;] - HOME_LON) * SCALE
        dy = (a[&#39;lat&#39;] - HOME_LAT) * SCALE
        x = int(CENTER_X + dx)
        y = int(CENTER_Y - dy)
        if 0 &lt;= x &lt; WIDTH and 0 &lt;= y &lt; HEIGHT:
            cv2.circle(frame, (x, y), 6, (0, 255, 255), -1)  # BGRで黄色

    # OpenCV → PIL に変換して回転
    image_pil = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
    # ── センサー読み取り ──
    raw_x = read_axis(0x00)
    raw_y = read_axis(0x02)
    raw_z = read_axis(0x04)

    adj_x = (raw_x - X_OFFSET) * X_SCALE
    adj_y = (raw_y - Y_OFFSET) * Y_SCALE

    raw_heading = math.degrees(math.atan2(adj_y, adj_x))
    if raw_heading &lt; 0:
        raw_heading += 360.0

    heading = raw_heading - HEADING_OFFSET + DECLINATION
    heading %= 360.0

    # ── デバッグ表示 ──
    #print(&quot;raw_x = {:6d}, raw_y = {:6d}, heading = {:.2f}°&quot;.format(raw_x, raw_y, heading))
    rotated = image_pil.rotate(heading, expand=True)

    # 黒背景に中央配置
    background = Image.new(&quot;RGB&quot;, (240, 240), (0, 0, 0))
    x_offset = (240 - rotated.width) // 2
    y_offset = (240 - rotated.height) // 2
    background.paste(rotated, (x_offset, y_offset))

    # LCDに表示
    disp.ShowImage(background)

    time.sleep(0.3)
</code></pre></div>



<p class="wp-block-paragraph">今回は本記事の前半で紹介したRaspberry Pi Zero 2 Wから、ネットワーク経由で航空機データを取得しています。「http://192.168.1.46:8080/data/aircraft.json」のようにZero 2 WのIPアドレスを指定することで、周囲を飛行中の航空機の情報（緯度・経度など）を含むデータを取得できます。</p>



<p class="wp-block-paragraph">取得した情報をもとに、ディスプレイ上に航空機の位置をプロットします。さらに、内蔵の地磁気センサー（QMC5883L）で取得した方位に応じて画面を回転させることで、レーダーの向いている方向に合わせた直感的な表示を実現します。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/IMG_9093.jpeg" alt="" class="wp-image-4"/></figure>



<h2 class="wp-block-heading">くるくる進行方向表示装置</h2>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/IMG_9332.jpeg" alt="" class="wp-image-4"/></figure>



<p class="wp-block-paragraph">これまではディスプレイを使い航空機の情報を可視化してきましたが、今回はその手法を変え、動きで示す装置を作りました。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/IMG_9326.jpeg" alt="" class="wp-image-4" style="width:840px;height:auto"/><figcaption class="wp-element-caption">受信待ちしている状態</figcaption></figure>



<p class="wp-block-paragraph">この装置は最も近くを飛んでいる航空機の進行方向をリアルタイムで取得し、模型の飛行機をその方向に回転させます。便名や距離はLCDに表示され、動く模型とテキスト情報が重なることで、空で起きていることをよりリアルに感じ取ることが可能です。画面を見るだけでは味わえなかった臨場感が、そこに生まれます。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/IMG_9337.jpeg" alt="" class="wp-image-4"/></figure>



<p class="wp-block-paragraph">今回の装置はRaspberry Pi Pico 2 Wを使用しました。ADS-B受信機を接続したRaspberry PiからWi-Fi経由で航空機のデータを取得する仕組みです。LCDは、本記事の前半でも紹介したI2C接続の16文字2行キャラクタLCD（LCD1602）を使用しています。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/image-2.png" alt="" class="wp-image-4"/><figcaption class="wp-element-caption">各パーツの接続</figcaption></figure>



<p class="wp-block-paragraph">回転の制御には<a href="https://akizukidenshi.com/catalog/g/g108761/">SG90</a>というサーボモーターを使用しています。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/IMG_9338.jpeg" alt="" class="wp-image-4"/></figure>



<p class="wp-block-paragraph">本来であれば180°しか回転できないこのモーターにギヤを組み合わせることで、模型が360度回転できるように工夫しました。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/IMG_9322.jpeg" alt="" class="wp-image-4"/></figure>



<p class="wp-block-paragraph">各パーツを収納する筐体やギヤの部分は、3Dプリンターで作成しています。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/IMG_9303.jpeg" alt="" class="wp-image-4"/><figcaption class="wp-element-caption">装置の内部</figcaption></figure>



<p class="wp-block-paragraph">起動後、Raspberry Pi Pico 2 WはWi-Fiに接続し、ローカルネットワーク内のRaspberry PiからADS-Bデータを定期的に取得します。その中から最も近い航空機を特定し、自宅からの相対位置と進行方向を計算します。取得した便名と距離はLCDに表示され、進行方向に応じてサーボモーターが駆動します。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/Videotogif-2.gif" alt="" class="wp-image-4"/></figure>



<p class="wp-block-paragraph"><br>進行方向のデータ（0〜360度）は、南を基準に±90度の範囲へ変換します。これはサーボモーターの可動範囲に収めるためです。そのうえで、サーボの出力をギヤで拡大し、模型が1回転できるようにしました。</p>



<h2 class="wp-block-heading">空港の案内表示風画面を作成</h2>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/IMG_9858-1.jpeg" alt="" class="wp-image-4" style="width:447px;height:auto"/></figure>



<p class="wp-block-paragraph">自宅の上空を飛ぶ航空機の情報を、空港の案内板のように表示してみました。使用したディスプレイは、Raspberry Pi公式 <a href="https://sozorablog.com/touch-display-2/">Touch Display 2</a>（5インチ）です。このプロジェクトでは、航空会社のロゴとともに3便分の「便名」「到着地」「到着時刻」を表示します。</p>



<p class="wp-block-paragraph">記事の前半部分で紹介しているADS-B受信機のデータには、到着地や到着予定時刻は含まれていません。そこで、それらを補うために <strong>「AeroDataBox API」</strong> を使います。</p>



<p class="wp-block-paragraph">実現したいことは次の通りです。</p>



<div class="wp-block-sbd-list"><ul class="sbd-list sbd-list-border"><li>ADS-B受信機からリアルタイムの航空機位置情報を取得</li><li><strong>AeroDataBox API</strong> で便名から到着地と到着予定時刻を取得</li><li>航空会社のロゴとともに3便分表示</li></ul></div>



<div class="wp-block-sbd-checkpoint-block"><p class="sbd-checkpoint-title">チェックポイント</p><div class="sbd-checkpoint-content sbd-inner-block-init"><p>AeroDataBoxの無料プランでは、月あたり最大 1,000回までリクエスト可能という制限があります。そのため、短い間隔で何度もデータを取得するような「常時更新」には向いていません。</p></div></div>



<h3 class="wp-block-heading">AeroDataBox APIを使用</h3>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/IMG_9859.jpeg" alt="" class="wp-image-4"/></figure>



<p class="wp-block-paragraph">AeroDataBox API は、便名を指定するだけでフライト情報を取得できる便利なAPIです。このAPIは、RapidAPIというAPIマーケットプレイスで提供されています。利用するには次の手順でAPIキーを取得します。</p>



<p class="wp-block-paragraph"><a href="https://rapidapi.com/">RapidAPI公式サイト</a> にアクセスして無料アカウントを作成します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/pico-31.jpg" alt="" class="wp-image-4" style="width:691px;height:auto"/></figure>



<p class="wp-block-paragraph">「AeroDataBox」で検索し、APIページを開きます。</p>



<p class="wp-block-paragraph">「Subscribe to Test」を選択します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/pico-30.png" alt="" class="wp-image-4" style="width:679px;height:auto"/></figure>



<p class="wp-block-paragraph">Basic（無料）プランを選択します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/pico-30-1.png" alt="" class="wp-image-4" style="width:358px;height:auto"/></figure>



<p class="wp-block-paragraph">表示された <strong>X-RapidAPI-Key</strong> が、コードで使用するAPIキーです。</p>



<h3 class="wp-block-heading">完成したコード</h3>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/IMG_9856.jpeg" alt="" class="wp-image-4"/></figure>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>import requests
import math
from datetime import datetime
from PIL import Image, ImageDraw, ImageFont
from io import BytesIO
import cv2
import numpy as np
import re

# ===============================
# 設定
# ===============================

# 自宅の緯度経度に変更してください（以下は東京駅周辺）
HOME_LAT = 35.6812
HOME_LON = 139.7671

# RapidAPI（AeroDataBox）キー
RAPIDAPI_KEY = &quot;RapidAPIキーを入力してください&quot;

# dump1090-fa のローカルURL
DUMP1090_URL = &quot;http://localhost:8080/data/aircraft.json&quot;

# ===============================
# 航空機データ取得関数
# ===============================
def get_aircraft_positions_dump1090():
    &quot;&quot;&quot;dump1090-fa から航空機位置データを取得&quot;&quot;&quot;
    try:
        res = requests.get(DUMP1090_URL, timeout=1)
        data = res.json()
        return [a for a in data.get(&quot;aircraft&quot;, []) if &#39;lat&#39; in a and &#39;lon&#39; in a]
    except:
        return []

# ===============================
# 距離計算
# ===============================

def haversine(lat1, lon1, lat2, lon2):
    &quot;&quot;&quot;2点間の距離（km）をハーサイン式で計算&quot;&quot;&quot;
    R = 6371.0
    dlat = math.radians(lat2 - lat1)
    dlon = math.radians(lon2 - lon1)
    a = math.sin(dlat / 2)**2 + math.cos(math.radians(lat1)) * math.cos(math.radians(lat2)) * math.sin(dlon / 2)**2
    return R * 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))

# ===============================
# AeroDataBox から便情報取得
# ===============================

def get_flight_info(flight_number):
    &quot;&quot;&quot;便名から到着地と到着時刻を取得&quot;&quot;&quot;
    date = datetime.today().strftime(&#39;%Y-%m-%d&#39;)
    url = f&quot;https://aerodatabox.p.rapidapi.com/flights/number/{flight_number}/{date}&quot;
    headers = {
        &quot;X-RapidAPI-Key&quot;: RAPIDAPI_KEY,
        &quot;X-RapidAPI-Host&quot;: &quot;aerodatabox.p.rapidapi.com&quot;
    }
    try:
        res = requests.get(url, headers=headers, timeout=3)
        data = res.json()
        if isinstance(data, list) and data:
            f = data[0]
            flight = f[&#39;number&#39;]
            airport = f[&#39;arrival&#39;][&#39;airport&#39;][&#39;name&#39;]
            time_str = f[&#39;arrival&#39;][&#39;scheduledTime&#39;][&#39;local&#39;]
            arrival_time = datetime.fromisoformat(time_str).strftime(&#39;%H:%M&#39;)
            return flight, airport, arrival_time
    except:
        pass
    return None, None, None

# ===============================
# メイン処理
# ===============================

# 航空機データを取得
aircraft_list = get_aircraft_positions_dump1090()

if not aircraft_list:
    print(&quot;航空機が見つかりませんでした。&quot;)
    exit()

# ===============================
# 距離順にソートして3機選択
# ===============================

for a in aircraft_list:
     # 各航空機について、自宅（HOME_LAT, HOME_LON）からの距離を計算して追加
    a[&quot;distance&quot;] = haversine(HOME_LAT, HOME_LON, a[&quot;lat&quot;], a[&quot;lon&quot;])
    
# 距離（&quot;distance&quot;）の値を基準に昇順ソート（最も近い機体が先頭に来る）
aircraft_list.sort(key=lambda x: x[&quot;distance&quot;])
# 最も近い3機だけを抽出
closest_aircrafts = aircraft_list[:3]

# ===============================
# 表示処理（3機を縦に並べて描画）
# ===============================

icao_to_iata = {
    &quot;ANA&quot;: &quot;NH&quot;, &quot;JAL&quot;: &quot;JL&quot;, &quot;ADO&quot;: &quot;HD&quot;, &quot;SNA&quot;: &quot;7G&quot;, &quot;SKY&quot;: &quot;BC&quot;,
    &quot;APJ&quot;: &quot;MM&quot;, &quot;FDA&quot;: &quot;JH&quot;, &quot;CPA&quot;: &quot;CX&quot;, &quot;UAE&quot;: &quot;EK&quot;, &quot;THA&quot;: &quot;TG&quot;,
    &quot;MAS&quot;: &quot;MH&quot;, &quot;CES&quot;: &quot;MU&quot;, &quot;CSN&quot;: &quot;CZ&quot;, &quot;CCA&quot;: &quot;CA&quot;, &quot;PAL&quot;: &quot;PR&quot;,
    &quot;TGW&quot;: &quot;TR&quot;, &quot;SIA&quot;: &quot;SQ&quot;, &quot;JST&quot;: &quot;JQ&quot;, &quot;JJP&quot;: &quot;GK&quot;, &quot;TNA&quot;: &quot;9C&quot;,
    &quot;BAW&quot;: &quot;BA&quot;, &quot;AAL&quot;: &quot;AA&quot;, &quot;UAL&quot;: &quot;UA&quot;, &quot;DAL&quot;: &quot;DL&quot;, &quot;KLM&quot;: &quot;KL&quot;,
    &quot;AFR&quot;: &quot;AF&quot;, &quot;DLH&quot;: &quot;LH&quot;, &quot;QFA&quot;: &quot;QF&quot;,
}

base = Image.new(&quot;RGB&quot;, (1280, 720), (0, 0, 80))
draw = ImageDraw.Draw(base)
font_path = &quot;/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf&quot;
font = ImageFont.truetype(font_path, 60)

y_base = 60          # 1段目（最初の航空機情報）の描画開始位置（上から60pxの位置）
block_height = 220   # 各段の高さ（1つの航空機情報を描く縦スペース）

# ==== 近い3機を順に処理して、便情報を取得 ====
for idx, ac in enumerate(closest_aircrafts):
    # 航空機の便名（flight）を取得。空白やNoneの場合は空文字に置き換え
    ident = ac.get(&quot;flight&quot;, &quot;&quot;).strip()
    
    # 便名が空、または先頭が英字でない（例: 数字のみや不正データ）の場合はスキップ
    if not ident or not ident[0].isalpha():
        continue
    
    # AeroDataBox APIを使って、便名から到着地と到着時刻を取得
    flight, airport, arrival_time = get_flight_info(ident)
    if not all([flight, airport, arrival_time]):
        continue
    
    print(f&quot;[{idx}] 便名: {flight}&quot;)
    print(f&quot;    距離: {ac[&#39;distance&#39;]:.1f} km&quot;)
    print(f&quot;    到着地: {airport}&quot;)
    print(f&quot;    到着時刻: {arrival_time}&quot;)
    print()
    
    # 便名の先頭3文字を抽出（例: &quot;JAL124&quot; → &quot;JAL&quot;）
    airline_code = flight.strip()[:3].upper()
    
    # ICAOコード（3文字）をIATAコード（2文字）に変換
    # 変換できない場合は、先頭2文字をそのまま使う    
    iata = icao_to_iata.get(airline_code, airline_code[:2])
    
     # 便名から数字部分だけを抽出（例: &quot;JAL124&quot; → &quot;124&quot;）
    flight_number = &#39;&#39;.join(re.findall(r&#39;\d+&#39;, flight))
    
    # 到着地の文字列を最大9文字までに制限（長すぎる地名対策）
    destination = airport[:9]

    # ==== 航空会社ロゴの取得 ====
    # Daisycon APIを利用して、航空会社のロゴ画像を取得
    # IATAコードを使ってURLを生成（白色ロゴ・横幅300px）
    if iata == &quot;BC&quot;:
        # スカイマーク（IATA: BC）は正しいロゴが取得できないため、例外的に Airhex（https://content.airhex.com/）のロゴを使用
        url = &quot;https://content.airhex.com/content/logos/airlines_BC_300_100_s.png&quot;
    else:
        # それ以外の航空会社は Daisycon から白色ロゴを取得
        url = f&quot;https://images.daisycon.io/airline/?width=300&height=95&color=ffffff&iata={iata}&quot;
        
    img_data = requests.get(url, timeout=5).content# 画像データをダウンロード（バイナリとして取得）
    logo = Image.open(BytesIO(img_data)).convert(&quot;RGBA&quot;)# 取得したロゴをRGBA形式（透過対応）で読み込み
    white_bg = Image.new(&quot;RGBA&quot;, logo.size, (255,255,255,255))# 白背景を作成（透過部分を白に塗りつぶすため）
    logo_with_white = Image.alpha_composite(white_bg, logo)# 白背景とロゴを合成（透過部分が白になる）
    logo_w, logo_h = logo_with_white.size# ロゴ画像の幅と高さを取得（後で配置位置を計算するため）

    # 配置位置
    y_offset = y_base + idx * block_height
    base.paste(logo_with_white.convert(&quot;RGB&quot;), (40, y_offset), mask=logo_with_white.split()[3])

    # テキスト描画
    text_start_x = 360  # テキストの描画開始位置（左からのオフセット）
    # 便名（数字部分）を描画
    draw.text((text_start_x, y_offset+10), flight_number, fill=(255,255,255), font=font)
    # 到着地（空港名）を描画
    draw.text((text_start_x+190, y_offset+10), destination, fill=(255,255,255), font=font)
    # 到着予定時刻を描画
    draw.text((text_start_x+630, y_offset+10), arrival_time, fill=(255,255,255), font=font)

# ===============================
# OpenCVで全画面表示
# ===============================

cv2.namedWindow(&quot;Flight Info&quot;, cv2.WINDOW_NORMAL)
cv2.setWindowProperty(&quot;Flight Info&quot;, cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
img_cv = cv2.cvtColor(np.array(base), cv2.COLOR_RGB2BGR)
cv2.imshow(&quot;Flight Info&quot;, img_cv)

while True:
    if cv2.waitKey(10) == 27:
        break
cv2.destroyAllWindows()


</code></pre></div>



<p class="wp-block-paragraph"><code>dump1090-fa</code> のJSONデータを取得し、自宅位置（<code>HOME_LAT</code>, <code>HOME_LON</code>）からの距離を計算し、<span class="sbd-text-bg-yellow">距離が近い3機</span>を選んで表示対象にします。取得した便名を使って <strong>AeroDataBox API</strong> に問い合わせ、「到着地」と「到着予定時刻」を取得します。</p>



<p class="wp-block-paragraph">航空会社名はシステムによって呼び方が異なります。dump1090-fa では「ANA」「JAL」などの <strong>ICAOコード（3文字）</strong>を返しますが、航空会社ロゴを提供するAPIは「NH」「JL」などの <strong>IATAコード（2文字）</strong>で指定する必要があります。そのため、<code>icao_to_iata</code> という対応表を用意して、コードを変換しています。</p>



<p class="wp-block-paragraph">ロゴ画像は主に<a href="https://www.daisycon.com/en/developers/productfeeds/product-images/airline-logos/">Daisycon</a><strong>（</strong>航空会社ロゴを無料で提供するAPI<strong>）</strong>から取得しますが、スカイマーク（BC）など<span class="sbd-text-red">一部の航空会社は正しいロゴが取得できない</span>ため、代わりに航空会社ロゴデータベース の<a href="https://www.airhex.com/">Airhex</a>から取得したロゴを使用しています。</p>



<p class="wp-block-paragraph">最後に<code>cv2.namedWindow</code> と <code>setWindowProperty</code> でウィンドウを全画面モードにし、<code>imshow</code> で描いた画像を表示します。空港の案内板のように見せるために全画面にしていますが、操作できなくなると困るので、<span class="sbd-text-bg-yellow">Escキーを押すと終了できる</span>ようにしています。</p>



<h2 class="wp-block-heading">戦闘機のHUD風に表示</h2>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/IMG_9943.jpeg" alt="" class="wp-image-4" style="width:507px;height:auto"/></figure>



<p class="wp-block-paragraph">戦闘機のHUD（ヘッドアップディスプレイ）のように、空の映像上に航空機情報を重ねてリアルな飛行感覚を再現しました。今回使用したのは、<a href="https://www.switch-science.com/products/9032">4インチ円形タッチスクリーンディスプレイ</a>です。ディスプレイ裏側に<a href="https://sozorablog.com/raspberry-pi-4-revue/">Raspberry Pi ４</a>を取り付けています。</p>



<p class="wp-block-paragraph">実際に戦闘機を操縦しているような臨場感を演出するために、コックピットから撮影された空の動画を背景に使用します。動画は<a href="https://pixabay.com/ja/videos/%e7%a9%8d%e9%9b%b2-%e3%82%b3%e3%83%83%e3%82%af%e3%83%94%e3%83%83%e3%83%88-%e8%88%aa%e7%a9%ba-47338/">Pixabay</a>からダウンロードしました。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/スクリーンショット-2025-11-01-16.03.41.jpg" alt="" class="wp-image-4"/><figcaption class="wp-element-caption">出典：<a href="https://pixabay.com/ja/videos/%e7%a9%8d%e9%9b%b2-%e3%82%b3%e3%83%83%e3%82%af%e3%83%94%e3%83%83%e3%83%88-%e8%88%aa%e7%a9%ba-47338/">Pixabay</a></figcaption></figure>



<p class="wp-block-paragraph">動画のサイズは1280×720を選択しています。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/スクリーンショット-2025-11-01-5.00.43.png" alt="" class="wp-image-4"/></figure>



<p class="wp-block-paragraph">動画ファイルは、/home/piに「cockpit_view.mp4」という名称で保存します。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/スクリーンショット-2025-11-01-5.03.29.png" alt="" class="wp-image-4"/></figure>



<p class="wp-block-paragraph">以下のプログラムは空の映像に、実際の航空機データを重ね合わせて戦闘機風に表示するものです。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>import cv2
import numpy as np
from datetime import datetime
import requests
import math
import time

# 自宅の緯度・経度（東京駅周辺など）
HOME_LAT = 35.681236
HOME_LON = 139.767125

# データ取得関数
def get_aircraft_positions():
    try:
        res = requests.get(&quot;http://192.168.1.46:8080/data/aircraft.json&quot;, timeout=1)
        return res.json().get(&quot;aircraft&quot;, [])
    except Exception as e:
        print(&quot;データ取得エラー:&quot;, e)
        return []
    
# 緯度経度から距離(km)を求める関数（簡易版・近距離用）
def calc_distance(lat1, lon1, lat2, lon2):
    R = 6371  # 地球の半径(km)
    dlat = math.radians(lat2 - lat1)
    dlon = math.radians(lon2 - lon1)
    a = math.sin(dlat / 2)**2 + math.cos(math.radians(lat1)) * math.cos(math.radians(lat2)) * math.sin(dlon / 2)**2
    c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
    return R * c

# HUD風オーバーレイ描画
def draw_target_overlay(img, offset_x=0, offset_y=0):
    &quot;&quot;&quot;中央ターゲットや計器枠などのHUD風描画（元の形状そのまま＋オフセット対応）&quot;&quot;&quot;
    scale = img.shape[0] / 128
    def s(x): return int(x * scale)

    ox = int(offset_x)
    oy = int(offset_y)

    # 中央座標
    center_x = img.shape[1] // 2 + ox
    center_y = img.shape[0] // 2 + oy

    # 中央円
    cv2.circle(img, (center_x, center_y), s(18), (0, 255, 0), 2)
    cv2.circle(img, (center_x, center_y), s(1), (0, 255, 0), -1)

    # 十字補助線
    cv2.line(img, (s(42) + ox, center_y), (s(50) + ox, center_y), (0, 255, 0), 2)
    cv2.line(img, (s(78) + ox, center_y), (s(86) + ox, center_y), (0, 255, 0), 2)
    cv2.line(img, (center_x, s(42) + oy), (center_x, s(50) + oy), (0, 255, 0), 2)
    cv2.line(img, (center_x, s(78) + oy), (center_x, s(86) + oy), (0, 255, 0), 2)

    cv2.line(img, (s(56) + ox, center_y), (s(60) + ox, center_y), (0, 255, 0), 2)
    cv2.line(img, (s(68) + ox, center_y), (s(72) + ox, center_y), (0, 255, 0), 2)
    cv2.line(img, (center_x, s(56) + oy), (center_x, s(60) + oy), (0, 255, 0), 2)
    cv2.line(img, (center_x, s(68) + oy), (center_x, s(72) + oy), (0, 255, 0), 2)

    # 左側グラフ
    cv2.line(img, (83 + ox, s(60) + oy), (83 + ox, s(92) + oy), (0, 255, 0), 2)
    cv2.line(img, (83 + ox, s(60) + oy), (99 + ox, s(60) + oy), (0, 255, 0), 2)
    cv2.line(img, (83 + ox, s(68) + oy), (93 + ox, s(68) + oy), (0, 255, 0), 2)
    cv2.line(img, (83 + ox, s(76) + oy), (99 + ox, s(76) + oy), (0, 255, 0), 2)
    cv2.line(img, (83 + ox, s(84) + oy), (93 + ox, s(84) + oy), (0, 255, 0), 2)
    cv2.line(img, (83 + ox, s(92) + oy), (99 + ox, s(92) + oy), (0, 255, 0), 2)

    # 右側グラフ
    cv2.line(img, (613 + ox, s(30) + oy), (613 + ox, s(92) + oy), (0, 255, 0), 2)
    cv2.line(img, (595 + ox, s(30) + oy), (628 + ox, s(30) + oy), (0, 255, 0), 2)
    cv2.line(img, (613 + ox, s(36) + oy), (623 + ox, s(36) + oy), (0, 255, 0), 2)
    cv2.line(img, (613 + ox, s(43) + oy), (623 + ox, s(43) + oy), (0, 255, 0), 2)
    cv2.line(img, (613 + ox, s(50) + oy), (628 + ox, s(50) + oy), (0, 255, 0), 2)
    cv2.line(img, (613 + ox, s(56) + oy), (623 + ox, s(56) + oy), (0, 255, 0), 2)
    cv2.line(img, (613 + ox, s(63) + oy), (623 + ox, s(63) + oy), (0, 255, 0), 2)
    cv2.line(img, (613 + ox, s(71) + oy), (628 + ox, s(71) + oy), (0, 255, 0), 2)
    cv2.line(img, (613 + ox, s(77) + oy), (623 + ox, s(77) + oy), (0, 255, 0), 2)
    cv2.line(img, (613 + ox, s(84) + oy), (623 + ox, s(84) + oy), (0, 255, 0), 2)
    cv2.line(img, (595 + ox, s(92) + oy), (628 + ox, s(92) + oy), (0, 255, 0), 2)

    # 半円ゲージ
    cv2.ellipse(
        img,
        (center_x, s(122) + oy),
        (s(20), s(20)),
        0, 180, 360,
        (0, 255, 0),
        2
    )
    cv2.line(img, (center_x, s(102) + oy), (center_x, s(105) + oy), (0, 255, 0), 2)
    cv2.line(img, (s(44) + ox, s(122) + oy), (s(46) + ox, s(122) + oy), (0, 255, 0), 2)
    cv2.line(img, (s(82) + ox, s(122) + oy), (s(84) + ox, s(122) + oy), (0, 255, 0), 2)

    # 半円ゲージの目盛り
    cv2.line(img, (300 + ox, 592 + oy), (305 + ox, 600 + oy), (0, 255, 0), 2)
    cv2.line(img, (259 + ox, 640 + oy), (268 + ox, 645 + oy), (0, 255, 0), 2)
    cv2.line(img, (417 + ox, 600 + oy), (422 + ox, 592 + oy), (0, 255, 0), 2)
    cv2.line(img, (453 + ox, 645 + oy), (462 + ox, 640 + oy), (0, 255, 0), 2)

    return img

# =============================
# メイン処理ループ
# =============================
cap = cv2.VideoCapture(&quot;cockpit_view.mp4&quot;)
if not cap.isOpened():
    print(&quot;動画ファイルを開けませんでした。&quot;)
    exit()

cv2.namedWindow(&quot;Square View&quot;, cv2.WINDOW_NORMAL)
cv2.resizeWindow(&quot;Square View&quot;, 720, 720)
cv2.setWindowProperty(&quot;Square View&quot;, cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)

# 総フレーム数を取得
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
skip_point = int(total_frames * 0.85)  # 後半1/4の開始フレーム

# 前回のデータ取得時刻を記録
last_fetch = 0

while True:
    ret, frame = cap.read()
    if not ret:
        cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
        continue
    
    # 8枚スキップして再生を速くする
    for _ in range(8):
        cap.grab()    
    
    # --- 2秒に1回だけAPIを呼ぶ ---
    now = time.time()
    if now - last_fetch &gt;= 2.0:
        aircraft_data = get_aircraft_positions()
        last_fetch = now  # 時刻を更新
        
        # 有効な座標を持つ航空機だけを抽出
        valid = [a for a in aircraft_data if &#39;lat&#39; in a and &#39;lon&#39; in a]

        if not valid:
            print(&quot;有効なデータがありません。&quot;)
            ident = &quot;No aircraft&quot;
            alt_m = 0
            hdg = 0
            dist = 0
            spd_kmh = 0
        else:
            # それぞれの機体との距離を計算
            for a in valid:
                a[&quot;distance_km&quot;] = calc_distance(HOME_LAT, HOME_LON, a[&quot;lat&quot;], a[&quot;lon&quot;])

            # 最も近い機体を選択
            nearest = min(valid, key=lambda a: a[&quot;distance_km&quot;])

            ident = nearest.get(&quot;flight&quot;, &quot;Unknown&quot;)
            alt_ft = nearest.get(&quot;alt_baro&quot;, &quot;N/A&quot;)
            spd_kt = nearest.get(&quot;gs&quot;, &quot;N/A&quot;)
            hdg = nearest.get(&quot;track&quot;, &quot;0&quot;)
            dist = nearest.get(&quot;distance_km&quot;, 0)
            
            # フィート→メートル換算
            if isinstance(alt_ft, (int, float)):
                alt_m = alt_ft * 0.3048
            else:
                alt_m = 0
                
            # ノット→km/h換算
            spd_kmh = spd_kt * 1.852 if isinstance(spd_kt, (int, float)) else 0            

            print(f&quot;最も近い航空機:&quot;)
            print(f&quot;Ident: {ident}&quot;)
            print(f&quot;Altitude: {alt_ft} ft ({alt_m:.0f} m)&quot;)
            print(f&quot;Speed: {spd_kt} kt ({spd_kmh:.0f} km/h)&quot;)
            print(f&quot;Heading: {hdg}&quot;)
            print(f&quot;Distance: {dist:.1f} km&quot;)        
    
    # 現在のフレーム番号を取得
    current_frame = int(cap.get(cv2.CAP_PROP_POS_FRAMES))  

    # --- 後半1/4に到達したら最初に戻す ---
    if current_frame &gt;= skip_point:
        cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
        continue    

    height, width, _ = frame.shape
    frame = frame[:int(height * 0.6), int(width * 0.35):]
    square_size = frame.shape[0]
    frame = frame[:, :square_size]
    frame_resized = cv2.resize(frame, (720, 720), interpolation=cv2.INTER_AREA)
    
    # --- 少し黒っぽく（明るさを下げる）処理 ---
    dark_factor = 0.5  # 0.7で少し暗め（0.5ならもっと黒っぽい）
    frame_resized = (frame_resized * dark_factor).astype(np.uint8)        

    # --- 図形を描画（オフセット指定可能）---
    frame_resized = draw_target_overlay(frame_resized)
    
    # --- HUDテキスト描画 ---
    font = cv2.FONT_HERSHEY_SIMPLEX
    color = (0, 255, 0)
    aa = cv2.LINE_AA

    cv2.putText(frame_resized, ident, (80, 170), font, 1.5, color, 2, aa)
    cv2.putText(frame_resized, &#39;ALTITUDE&#39;, (80, 250), font, 0.7, color, 2, aa)
    cv2.putText(frame_resized, f&quot;{alt_m:.0f}&quot;, (80, 290), font, 1.2, color, 2, aa)

    cv2.putText(frame_resized, &#39;RANGE&#39;, (499, 195), font, 0.7, color, 2, aa)
    cv2.putText(frame_resized, f&quot;{dist:.1f}&quot;, (499, 230), font, 1.2, color, 2, aa)

    cv2.putText(frame_resized, &#39;HEADING&#39;, (469, 495), font, 0.7, color, 2, aa)
    cv2.putText(frame_resized, str(int(hdg)), (470, 540), font, 1.5, color, 2, aa)

    cv2.putText(frame_resized, &#39;SPEED&#39;, (325, 645), font, 0.7, color, 2, aa)
    cv2.putText(frame_resized, str(int(spd_kmh)), (315, 690), font, 1.5, color, 2, aa)

    cv2.putText(frame_resized, &#39;-0&#39;, (40, 433), font, 0.8, color, 2, aa)
    cv2.putText(frame_resized, &#39;3800&#39;, (635, 290), font, 0.6, color, 1, aa)
    cv2.putText(frame_resized, &#39;4000&#39;, (635, 407), font, 0.6, color, 1, aa)
    cv2.putText(frame_resized, &#39;46&#39;, (348, 605), font, 0.6, color, 1, aa)
    cv2.putText(frame_resized, &#39;10&#39;, (258, 690), font, 0.6, color, 1, aa)

    cv2.imshow(&quot;Square View&quot;, frame_resized)
    if cv2.waitKey(1) == 27:
        break

cap.release()
cv2.destroyAllWindows()

</code></pre></div>



<p class="wp-block-paragraph">今回は本記事の前半で紹介したRaspberry Pi Zero 2 Wから、ネットワーク経由で航空機データを取得しています。「http://192.168.1.46:8080/data/aircraft.json」のようにZero 2 WのIPアドレスを指定することで、周囲を飛行中の航空機の情報（緯度・経度など）を含むデータを取得できます。</p>



<p class="wp-block-paragraph">プログラムは、ADS-B受信機などから航空機データを定期的に取得し、最も近い機体の便名、高度、速度、方位、距離を算出して画面に表示します。映像上には中央ターゲットや半円ゲージなどが緑色で描かれ、戦闘機のHUDのような雰囲気を再現しています。</p>



<p class="wp-block-paragraph">動画再生時に8枚のフレームをスキップし、より戦闘機らしいスピード感を演出しています。映像は少し暗く調整し、重ねた緑色のデータが際立って見えるよう工夫しました。</p>



<h2 class="wp-block-heading">GPSモジュールで緯度・経度を取得</h2>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/05/IMG_0721.jpeg" alt="" style="width:450px;height:auto"/><figcaption class="wp-element-caption">車載も可能</figcaption></figure>



<p class="wp-block-paragraph">GPSモジュールを使えば、緯度・経度を自動で取得できます。あらかじめ設定した座標を使う方法と違い、設置場所が変わっても現在位置をそのまま反映できるため、より実用的な表示が可能です。</p>



<p class="wp-block-paragraph">今回使用する<strong><a href="https://electronicwork.shop/items/69bb8f24ea2af023b7c4dcaf?srsltid=AfmBOopbuqSxRQoW4GcFqsHuqpRh8SVM-W_oIYcuM1_EbPAt2TTO_r08">ATGM336H</a></strong>は、電子工作で定番の安価なGPSモジュールです。上空にある複数のGPS衛星からの電波を受信し、現在地の「緯度・経度・高度」および「正確な時刻」を計算します。データは「UART（シリアル通信）」という形式で出力されるため、Raspberry Piで簡単に受け取ることができます。</p>



<h3 class="wp-block-heading">配線</h3>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="790" src="https://sozorablog.com/wp-content/uploads/2025/05/pico-7.jpg" alt="" class="wp-image-16661" style="aspect-ratio:1.0126754572522332;width:311px;height:auto"/></figure>



<p class="wp-block-paragraph">Raspberry PiとATGM336Hは、以下のように接続します。</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>ATGM336H</th><th>Raspberry Pi</th></tr></thead><tbody><tr><td>VCC</td><td>5V</td></tr><tr><td>GND</td><td>GND</td></tr><tr><td>TX</td><td>RX（GPIO15 / ピン10）</td></tr><tr><td>RX</td><td>TX（GPIO14 / ピン8）</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">電源はVCCを5V、GNDをGNDに接続します。通信はシリアル通信を使うため、GPSのTXをRaspberry PiのRX（GPIO15 / ピン10）、GPSのRXをRaspberry PiのTX（GPIO14 / ピン8）に交差して接続します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="627" src="https://sozorablog.com/wp-content/uploads/2025/05/IMG_0677.jpeg" alt="" class="wp-image-16673" style="width:537px;height:auto"/></figure>



<h3 class="wp-block-heading">UARTを有効にする</h3>



<p class="wp-block-paragraph">ターミナルで以下のコマンドを入力します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo raspi-config</code></pre></div>



<p class="wp-block-paragraph">矢印キーで <strong><code>3 Interface Options</code></strong>を選択して <code>Enter</code> を押します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="353" src="https://sozorablog.com/wp-content/uploads/2025/05/スクリーンショット-2026-04-03-11.15.39.jpg" alt="" class="wp-image-16613" style="aspect-ratio:2.266340177057826;width:510px;height:auto"/></figure>



<p class="wp-block-paragraph">矢印キーで <strong><code>3 Interface Options</code></strong>を選択して <code>Enter</code> を押します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="361" src="https://sozorablog.com/wp-content/uploads/2025/05/スクリーンショット-2026-04-03-11.16.33.jpg" alt="" class="wp-image-16614" style="width:474px;height:auto"/></figure>



<p class="wp-block-paragraph">&#8220;Would you like a login shell to be accessible over serial?&#8221;で<strong>いいえ (No)</strong> を選択します。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="475" height="315" src="https://sozorablog.com/wp-content/uploads/2025/05/スクリーンショット-2026-04-10-19.54.12.png" alt="" class="wp-image-16666"/></figure>



<p class="wp-block-paragraph">&#8220;Would you like the serial port hardware to be enabled?&#8221;で<strong>はい (Yes)</strong> を選択します。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="464" height="306" src="https://sozorablog.com/wp-content/uploads/2025/05/スクリーンショット-2026-04-10-19.55.01.png" alt="" class="wp-image-16667"/></figure>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="357" src="https://sozorablog.com/wp-content/uploads/2025/05/スクリーンショット-2026-04-03-11.20.31.jpg" alt="" class="wp-image-16617" style="width:509px;height:auto"/></figure>



<p class="wp-block-paragraph"><strong><code>&lt;Finish&gt;</code></strong> を選択します。<code>Would you like to reboot now?</code> と聞かれたら <strong><code>&lt;Yes&gt;</code></strong> を選択して再起動してください。</p>



<h3 class="wp-block-heading">テストコード</h3>



<p class="wp-block-paragraph">以下のコードは、<strong>GPSモジュールから送られてくる位置情報を読み取って、読みやすい形式に変換するプログラム</strong>です。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>import serial
import time

ser = serial.Serial(&quot;/dev/serial0&quot;, 9600, timeout=1)

def convert_to_decimal(raw, direction):
    if raw == &quot;&quot;:
        return None

    if direction in [&quot;N&quot;, &quot;S&quot;]:
        deg = int(raw[:2])
        minutes = float(raw[2:])
    else:
        deg = int(raw[:3])
        minutes = float(raw[3:])

    value = deg + minutes / 60

    if direction in [&quot;S&quot;, &quot;W&quot;]:
        value *= -1

    return value

def convert_time(utc_str):
    if utc_str == &quot;&quot;:
        return None

    hh = int(utc_str[0:2])
    mm = int(utc_str[2:4])
    ss = int(utc_str[4:6])

    hh = (hh + 9) % 24
    return f&quot;{hh:02}:{mm:02}:{ss:02}&quot;

while True:
    try:
        line = ser.readline()
    except:
        print(&quot;serial error&quot;)
        time.sleep(1)
        continue

    if not line:
        continue

    try:
        line = line.decode(&quot;utf-8&quot;).strip()
    except:
        continue

    # ★ 生データ確認（必要なら）
    # print(line)

    if line.startswith(&quot;$GNGGA&quot;) or line.startswith(&quot;$GPGGA&quot;):
        parts = line.split(&quot;,&quot;)

        if len(parts) &gt; 6:
            fix = parts[6]
            lat = convert_to_decimal(parts[2], parts[3])
            lon = convert_to_decimal(parts[4], parts[5])
            jst = convert_time(parts[1])

            if lat is not None and lon is not None:
                print(f&quot;{lat},{lon}&quot;)
            else:
                print(&quot;位置未取得&quot;)

            print(&quot;fix:&quot;, fix, &quot;日本時間:&quot;, jst)
</code></pre></div>



<p class="wp-block-paragraph">GPSの電波は微弱なため、厚いコンクリートの壁や金属の板、屋根などに遮断されやすいという特性があります。そのため、テストを行う際は窓際や屋外といった、上空が開けていて空が見える場所を選んでください。</p>



<p class="wp-block-paragraph">GPSモジュールの動作状況は、基板裏側のLEDで確認できます。電源を入れた直後は赤色のLEDが点灯したままの状態が続きますが、これが1秒おきに点滅し始めたら、複数の衛星を捕捉して測位に成功したことを示しています。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="617" src="https://sozorablog.com/wp-content/uploads/2025/05/IMG_0722.jpeg" alt="" class="wp-image-16679" style="width:364px;height:auto"/><figcaption class="wp-element-caption">受信状況を示すLED</figcaption></figure>



<p class="wp-block-paragraph">初めて電源を入れた場合は、衛星を見つけて位置を特定するまでに5〜10分ほどの時間が必要です。衛星の軌道情報を取得するために必要な待ち時間ですので、LEDの点滅が始まるまで待ちましょう。</p>



<h3 class="wp-block-heading">完成したコード</h3>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="842" src="https://sozorablog.com/wp-content/uploads/2025/05/IMG_0723.jpeg" alt="" class="wp-image-16687" style="width:474px;height:auto"/></figure>



<p class="wp-block-paragraph">以下はGPSで取得した現在位置を中心として航空機との位置関係を計算し、周辺の航空機をレーダー風にリアルタイム表示するコードです。今回は720×720の<a href="https://www.switch-science.com/products/9032">4インチ円形タッチスクリーンディスプレイ</a>を使用しました。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>import cv2
import numpy as np
import math
import time
import serial
import requests

# ===== GPS設定 =====
ser = serial.Serial(&quot;/dev/serial0&quot;, 9600, timeout=1)

last_lat = None
last_lon = None
has_fix_once = False
gps_status = &quot;WAITING GPS&quot;

def convert_to_decimal(raw, direction):
    if raw == &quot;&quot;:
        return None

    if direction in [&quot;N&quot;, &quot;S&quot;]:
        deg = int(raw[:2])
        minutes = float(raw[2:])
    else:
        deg = int(raw[:3])
        minutes = float(raw[3:])

    value = deg + minutes / 60

    if direction in [&quot;S&quot;, &quot;W&quot;]:
        value *= -1

    return value

def get_gps():
    global last_lat, last_lon, has_fix_once, gps_status

    try:
        line = ser.readline()
    except:
        gps_status = &quot;GPS ERROR&quot;
        return last_lat, last_lon

    if not line:
        return last_lat, last_lon

    try:
        line = line.decode(&quot;utf-8&quot;).strip()
    except:
        return last_lat, last_lon

    if line.startswith(&quot;$GNGGA&quot;) or line.startswith(&quot;$GPGGA&quot;):
        parts = line.split(&quot;,&quot;)

        if len(parts) &gt; 6:
            fix = parts[6]
            lat = convert_to_decimal(parts[2], parts[3])
            lon = convert_to_decimal(parts[4], parts[5])

            current_valid = (lat is not None and lon is not None and fix != &quot;0&quot;)

            if current_valid:
                last_lat = lat
                last_lon = lon
                has_fix_once = True
                gps_status = &quot;GPS OK&quot;
            else:
                if has_fix_once:
                    gps_status = &quot;GPS LOST (using last)&quot;
                else:
                    gps_status = &quot;WAITING GPS&quot;

    return last_lat, last_lon


# ===== 表示設定 =====
WIDTH = 720
HEIGHT = 720
CENTER_X = WIDTH // 2
CENTER_Y = HEIGHT // 2
SCALE = 450

icon = cv2.imread(&quot;plane_icon.png&quot;, cv2.IMREAD_UNCHANGED)
icon_h, icon_w = icon.shape[:2]

cap = cv2.VideoCapture(&quot;radar.mp4&quot;)
fps = cap.get(cv2.CAP_PROP_FPS)
delay = int(1000 / fps) if fps &gt; 0 else 33


# ===== 航空機データ取得関数 =====
def get_aircraft_positions():
    try:
        res = requests.get(&quot;http://localhost:8080/data/aircraft.json&quot;, timeout=1)
        return [a for a in res.json().get(&quot;aircraft&quot;, []) if &#39;lat&#39; in a and &#39;lon&#39; in a]
    except:
        return []

# ===== アイコン描画 =====
def draw_icon_rotated(img, icon, center, angle_deg):
    x, y = center

    M = cv2.getRotationMatrix2D((icon_w // 2, icon_h // 2), -angle_deg, 1.0)
    rotated = cv2.warpAffine(
        icon, M, (icon_w, icon_h),
        flags=cv2.INTER_NEAREST,
        borderMode=cv2.BORDER_CONSTANT,
        borderValue=(0, 0, 0, 0)
    )

    x1 = x - icon_w // 2
    y1 = y - icon_h // 2
    x2 = x1 + icon_w
    y2 = y1 + icon_h

    if x1 &lt; 0 or y1 &lt; 0 or x2 &gt; img.shape[1] or y2 &gt; img.shape[0]:
        return

    roi = img[y1:y2, x1:x2]

    if rotated.shape[2] == 4:
        alpha = rotated[:, :, 3] / 255.0
        for c in range(3):
            roi[:, :, c] = (1 - alpha) * roi[:, :, c] + alpha * rotated[:, :, c]


# ===== 画面 =====
cv2.namedWindow(&quot;Radar Display&quot;, cv2.WINDOW_NORMAL)
cv2.setWindowProperty(&quot;Radar Display&quot;, cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)

aircraft_list = []
last_update = 0


# ===== メインループ =====
while True:

    # GPS取得
    HOME_LAT, HOME_LON = get_gps()

    # 初回待ち
    if not has_fix_once:
        frame = np.zeros((HEIGHT, WIDTH, 3), dtype=np.uint8)

        cv2.putText(frame, &quot;WAITING GPS&quot;, (330, 20),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 255), 2)

        cv2.imshow(&quot;Radar Display&quot;, frame)

        if cv2.waitKey(delay) & 0xFF == 27:
            break
        continue

    # 航空機更新
    now = time.time()
    if now - last_update &gt;= 1.0:
        aircraft_list = get_aircraft_positions()
        last_update = now

    # 背景動画
    ret, video_frame = cap.read()
    if not ret:
        cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
        continue

    video_h, video_w = video_frame.shape[:2]
    scale = min(WIDTH / video_w, HEIGHT / video_h) * 1.8
    new_w = int(video_w * scale)
    new_h = int(video_h * scale)

    resized = cv2.resize(video_frame, (new_w, new_h), interpolation=cv2.INTER_NEAREST)
    resized = cv2.convertScaleAbs(resized, alpha=0.6, beta=0)

    frame = np.zeros((HEIGHT, WIDTH, 3), dtype=np.uint8)

    x_offset = (WIDTH - new_w) // 2
    y_offset = (HEIGHT - new_h) // 2

    x1_dst = max(x_offset, 0)
    y1_dst = max(y_offset, 0)
    x1_src = max(-x_offset, 0)
    y1_src = max(-y_offset, 0)
    x2_dst = min(x_offset + new_w, WIDTH)
    y2_dst = min(y_offset + new_h, HEIGHT)
    x2_src = x1_src + (x2_dst - x1_dst)
    y2_src = y1_src + (y2_dst - y1_dst)

    frame[y1_dst:y2_dst, x1_dst:x2_dst] = resized[y1_src:y2_src, x1_src:x2_src]

    # 飛行機描画
    for a in aircraft_list:
        dx = (a[&#39;lon&#39;] - HOME_LON) * SCALE
        dy = (a[&#39;lat&#39;] - HOME_LAT) * SCALE

        x = int(CENTER_X + dx)
        y = int(CENTER_Y - dy)

        if 0 &lt;= x &lt; WIDTH and 0 &lt;= y &lt; HEIGHT:
            if &#39;track&#39; in a and isinstance(a[&#39;track&#39;], (int, float)):
                draw_icon_rotated(frame, icon, (x, y), a[&#39;track&#39;])
            else:
                cv2.circle(frame, (x, y), 5, (0, 255, 0), -1)

            # ===== 便名表示 =====
            flight = a.get(&#39;flight&#39;, &#39;&#39;).strip()

            if flight != &quot;&quot;:
                font = cv2.FONT_HERSHEY_SIMPLEX
                font_scale = 0.4
                thickness = 1

                text_size, _ = cv2.getTextSize(flight, font, font_scale, thickness)

                text_x = x - text_size[0] // 2
                text_y = y + 25  # アイコンの下

                cv2.putText(frame, flight,
                            (text_x, text_y),
                            font, font_scale,
                            (0, 255, 0),
                            thickness,
                            cv2.LINE_AA)

    # GPS状態表示
    color = (0, 255, 0) if gps_status == &quot;GPS OK&quot; else (0, 0, 255)

    cv2.putText(frame, gps_status, (330, 20),
                cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)

    # 表示
    cv2.imshow(&quot;Radar Display&quot;, frame)

    if cv2.waitKey(delay) & 0xFF == 27:
        break


cap.release()
cv2.destroyAllWindows()
</code></pre></div>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="591" height="427" src="https://sozorablog.com/wp-content/uploads/2025/05/スクリーンショット-2026-04-11-4.35.51-1.png" alt="" class="wp-image-16683" style="width:431px;height:auto"/><figcaption class="wp-element-caption">GPS取得待機画面</figcaption></figure>



<p class="wp-block-paragraph">まず、画面の中央点となる「基準座標」を決定します。GPSモジュールから送られてくる文字列を解析し、緯度と経度を数値として抽出します。この位置が確定するまでは、計算の基準が作れないため、画面上には「WAITING GPS」というステータスのみが表示されます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="726" height="717" src="https://sozorablog.com/wp-content/uploads/2025/05/スクリーンショット-2026-04-11-5.11.33.jpg" alt="" class="wp-image-16684" style="width:409px;height:auto"/><figcaption class="wp-element-caption">GPSの測位が開始するとアニメーションが表示される</figcaption></figure>



<p class="wp-block-paragraph">現在位置が確定すると、画面中央（360, 360）が自分の現在地として固定されます。次に、背景として読み込んだアニメーション動画が描画されます。この背景の上に、ネットワークから取得した航空機の位置を重ねていきます。</p>



<p class="wp-block-paragraph">動作中にGPS信号が途絶えた場合、最後に正常に受信できた座標を保持し続けます。これにより、航空機との相対位置を維持したまま表示を継続します。このとき、画面上部のステータス表示は「GPS OK」から「GPS LOST (using last)」へと変化し、ユーザーにGPSデータの更新が止まっていることを通知します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="711" height="559" src="https://sozorablog.com/wp-content/uploads/2025/05/スクリーンショット-2026-04-11-16.39.06.jpg" alt="" class="wp-image-16698" style="width:387px;height:auto"/><figcaption class="wp-element-caption">円形ディスプレイのスタンド</figcaption></figure>



<p class="wp-block-paragraph">円形ディスプレイのスタンドは3Dプリンターで作成しました。以下のボタンからSTLファイルをダウンロードできます。</p>


<div class='w3eden'><!-- WPDM Link Template: Default Template -->

<div class="link-template-default card mb-2">
    <div class="card-body">
        <div class="media">
            <div class="mr-3 img-48"><img decoding="async" class="wpdm_icon" alt="アイコン" src="https://sozorablog.com/wp-content/plugins/download-manager/assets/file-type-icons/zip.svg" /></div>
            <div class="media-body">
                <h3 class="package-title"><a href='https://sozorablog.com/download/round-touch-display-stand/'>Round Touch Display Stand</a></h3>
                <div class="text-muted text-small"><i class="fas fa-copy"></i> 1 ファイル <i class="fas fa-hdd ml-3"></i> 21 KB</div>
            </div>
            <div class="ml-3">
                <a class='wpdm-download-link download-on-click btn btn-primary ' rel='nofollow' href='#' data-downloadurl="https://sozorablog.com/download/round-touch-display-stand/?wpdmdl=16705&refresh=6a8d2e768982f1787637366">ダウンロード</a>
            </div>
        </div>
    </div>
</div>

</div>
]]></content:encoded>
					
					<wfw:commentRss>https://sozorablog.com/flightradar/feed/</wfw:commentRss>
			<slash:comments>35</slash:comments>
		
		
			</item>
		<item>
		<title>外からラズパイを操作！Raspberry Pi Connectの設定方法</title>
		<link>https://sozorablog.com/raspberry-pi-connect/</link>
					<comments>https://sozorablog.com/raspberry-pi-connect/#comments</comments>
		
		<dc:creator><![CDATA[そぞら]]></dc:creator>
		<pubDate>Sat, 01 Feb 2025 19:09:58 +0000</pubDate>
				<category><![CDATA[Raspberry Pi]]></category>
		<category><![CDATA[使い方]]></category>
		<guid isPermaLink="false">https://sozorablog.com/?p=13849</guid>

					<description><![CDATA[自宅のラズパイに接続したカメラ映像の確認や、センサーのデータをリアルタイムでチェックしたいと思ったことはありませんか？　Raspberry Pi Connectを使えば、世界中どこからでも安全にラズパイへアクセスできます [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">自宅の<a href="https://sozorablog.com/raspberry-pi/">ラズパイ</a>に接続したカメラ映像の確認や、センサーのデータをリアルタイムでチェックしたいと思ったことはありませんか？　<a href="https://www.raspberrypi.com/software/connect/">Raspberry Pi Connect</a>を使えば、世界中どこからでも安全にラズパイへアクセスできます。しかも<strong>無料</strong>で利用可能です。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/01/IMG_6818-1.jpeg" alt="" class="wp-image-4"/><figcaption class="wp-element-caption">スマホやPCから接続できる</figcaption></figure>



<p class="wp-block-paragraph">従来の<a href="https://sozorablog.com/vnc/">VNC</a>は基本的にLAN内での接続が前提でしたが、Raspberry Pi Connectは外部からアクセス可能。IoTシステムの遠隔監視や離れた場所からラズパイを操作することができます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="750" height="1334" src="https://sozorablog.com/wp-content/uploads/2021/09/IMG_1076.jpg" alt="" class="wp-image-17423" style="aspect-ratio:0.5622212973422914;width:235px;height:auto"/><figcaption class="wp-element-caption">スマートフォンに表示したカメラ映像</figcaption></figure>



<p class="wp-block-paragraph">カメラを接続すれば、外出先からリアルタイムの映像を確認できる<a href="https://sozorablog.com/camera_shooting/">監視カメラ</a>としても活用可能です。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/02/pico-2025-02-04T062648.623.jpg" alt="" class="wp-image-4"/><figcaption class="wp-element-caption">VNCとRaspberry Pi Connectの違い</figcaption></figure>



<p class="wp-block-paragraph">本記事ではRaspberry Pi Connectの導入手順や設定方法を詳しく解説します。</p>



<h2 class="wp-block-heading"><strong>待望のRaspberry Pi Connect</strong></h2>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="388" src="https://sozorablog.com/wp-content/uploads/2025/02/スクリーンショット-2026-05-18-15.12.51.jpg" alt="" class="wp-image-17131" style="width:804px;height:auto"/><figcaption class="wp-element-caption">出典：<a href="https://www.raspberrypi.com/software/connect/">Raspberry Pi公式サイト</a></figcaption></figure>



<p class="wp-block-paragraph">Raspberry Pi Connectは<span class="sbd-text-red">公式から発表された</span>リモートアクセスツールです。これにより、インターネット経由でRaspberry Piを遠隔操作・管理することが可能になりました。特別なネットワーク設定やファイアウォールのポート開放なしで使用できるよう設計されています。</p>



<div class="wp-block-sbd-balloon sbd-balloon sbd-balloon--id-4 sbd-balloon--flat sbd-balloon--l sbd-balloon--green block-box"><div class="sbd-balloon__profile"><figure class="sbd-balloon__icon"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/09/アイコン.jpg" alt="そぞら" class="sbd-balloon__img"/></figure><div class="sbd-balloon__name">そぞら</div></div><div class="sbd-balloon__text-box sbd-inner-block-init">
<p class="wp-block-paragraph">外出先から自宅のRaspberry Piに簡単に接続し、デスクトップやシェルを使ってリモート操作できます。</p>
</div></div>



<h3 class="wp-block-heading">Raspberry Pi Connectの対応デバイスと必要な環境</h3>



<p class="wp-block-paragraph">Raspberry Pi Connectには、<strong>リモートデスクトップ機能</strong> と <strong>リモートシェル機能</strong> の2種類があります。リモートデスクトップ機能は、Raspberry Pi OS <span class="sbd-text-bg-yellow">Bookworm</span>が動作するモデルに限定されています。一方、リモートシェル機能は、<a href="https://sozorablog.com/raspberry-pi-pico/">Raspberry Pi Pico</a>を除くすべてのRaspberry Piで動作します。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/02/pico-3.jpg" alt=""/></figure>



<p class="wp-block-paragraph">Raspberry Pi Connectを利用するためには、Raspberry Pi本体と操作する端末の両方がインターネットに接続されている必要があります。</p>



<h3 class="wp-block-heading">Raspberry Pi Connectの仕組み</h3>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/02/pico-2.jpg" alt="" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph">Raspberry Pi ConnectはWebRTCを利用してピアツーピア（P2P）接続を確立し、<span class="sbd-text-bg-yellow">ブラウザとRaspberry Piの間で直接データをやり取り</span>します。これはZoomやSlackなどのリアルタイム通信ツールと同様で、安全かつ低遅延な接続を実現します。（参考：<a href="https://www.raspberrypi.com/news/raspberry-pi-connect/">Raspberry Pi公式ブログ</a>）</p>



<p class="wp-block-paragraph">基本的にP2P接続が優先される設計ですが、ネットワーク環境によっては確立できない場合があります。その際は、<span class="sbd-text-red">Raspberry Pi ConnectのTURNサーバーを経由したリレー接続</span>が行われます。この通信はDTLSで暗号化されますが、現在TURNサーバーはイギリスに1つしかないため、遅延が発生する可能性があります。</p>



<h2 class="wp-block-heading">Raspberry Pi Connectの設定</h2>



<p class="wp-block-paragraph">Raspberry Pi Connectを利用するには、まずRaspberry Piのデスクトップ画面で設定を行います。ここでは、有効化の手順やデバイスの登録方法を説明します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/02/image-1.png" alt="" style="width:840px;height:auto"/><figcaption class="wp-element-caption">使用したOS</figcaption></figure>



<p class="wp-block-paragraph">今回は<span class="sbd-text-bg-yellow">Raspberry Pi OS Bookworm(64-bit)</span>を使用しました。</p>



<h3 class="wp-block-heading">Raspberry Pi Connectを有効にする</h3>



<p class="wp-block-paragraph">デフォルトでは、Raspberry Pi Connectはインストール済みですが無効化されています。有効にするには、以下の手順を実行します。</p>



<p class="wp-block-paragraph">メニューバーからRaspberry Pi Connectのアイコンをクリックします。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="450" src="https://sozorablog.com/wp-content/uploads/2025/02/pico-1.jpg" alt="" class="wp-image-17125" style="width:583px;height:auto" srcset="https://sozorablog.com/wp-content/uploads/2025/02/pico-1.jpg 800w, https://sozorablog.com/wp-content/uploads/2025/02/pico-1-320x180.jpg 320w, https://sozorablog.com/wp-content/uploads/2025/02/pico-1-224x126.jpg 224w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<p class="wp-block-paragraph">「Turn On Raspberry Pi Connect」をクリックすると、Raspberry Pi Connectの機能が有効になります。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="450" src="https://sozorablog.com/wp-content/uploads/2025/02/pico-5.jpg" alt="" class="wp-image-17126" style="width:567px;height:auto" srcset="https://sozorablog.com/wp-content/uploads/2025/02/pico-5.jpg 800w, https://sozorablog.com/wp-content/uploads/2025/02/pico-5-320x180.jpg 320w, https://sozorablog.com/wp-content/uploads/2025/02/pico-5-224x126.jpg 224w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<p class="wp-block-paragraph">初めて利用する場合は、ブラウザが開いて<a href="https://connect.raspberrypi.com/sign-in">Raspberry Pi Connectのウェブページ</a>が表示されます。</p>



<h3 class="wp-block-heading">Raspberry Pi IDを作成する</h3>



<p class="wp-block-paragraph">Raspberry Pi Connectを利用するには、Raspberry Pi IDが必要です。「create one for free」（無料でアカウントを作成）をクリックし、新規アカウントを作成します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/01/pico-2025-01-31T093251.595.png" alt="" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph">必要な情報を入力します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/01/pico-2025-01-31T100004.918.png" alt="" style="width:431px;height:auto"/></figure>



<p class="wp-block-paragraph">Continueボタンをクリックすると、登録したメールアドレスに確認メールが届きます。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/01/pico-2025-01-31T050423.588.png" alt=""/></figure>



<h4 class="wp-block-heading">メールアドレスを認証する</h4>



<p class="wp-block-paragraph">PCまたはスマートフォンで、「id@raspberrypi.com」から届いた確認メールを開き、「Verify email」をクリックします。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/01/picone3.png" alt="" style="width:800px;height:auto"/></figure>



<p class="wp-block-paragraph">「Sign in」をクリックします。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/01/picone4.png" alt=""/></figure>



<p class="wp-block-paragraph">先ほど設定したメールアドレスとパスワードを入力します。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/01/piconect1.png" alt=""/></figure>



<p class="wp-block-paragraph">以下の画面が出れば、サインイン完了です。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/01/pico-2025-01-31T050728.948.png" alt=""/></figure>



<h3 class="wp-block-heading">デバイスを登録する</h3>



<p class="wp-block-paragraph">Raspberry Pi Connectに自分のRaspberry Piを紐づけて、リモートアクセスできるようにします。</p>



<p class="wp-block-paragraph">Raspberry Piの「Raspberry Pi Connect」アイコンをクリック後、「Sign In」をクリックします。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/01/pico-2025-01-31T113735.666.jpg" alt="" style="width:444px;height:auto"/></figure>



<p class="wp-block-paragraph">「Sign in as 〇〇」をクリックします。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/01/pico-2025-01-31T114922.727.png" alt="" style="width:798px;height:auto"/></figure>



<p class="wp-block-paragraph">デバイス登録画面が表示されたら、デバイス名を入力し（例：「MyPi」など）、「Create device and sign in」ボタンをクリックします。複数のラズパイを使用している場合は、「Pi5-8GB」などの名前を付けると識別しやすくなります。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/01/pico-2025-01-31T115218.881.png" alt="" class="wp-image-4" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph">「Device sign in successful」の画面が出たら設定は完了です。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/01/picone11.png" alt="" class="wp-image-4"/></figure>



<p class="wp-block-paragraph">「view your dashboard」 をクリックして、登録されたデバイスが正しく表示されているか確認してみます。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/01/picone12.png" alt="" class="wp-image-4"/></figure>



<div class="wp-block-sbd-checkpoint-block"><p class="sbd-checkpoint-title">チェックポイント</p><div class="sbd-checkpoint-content sbd-inner-block-init"><p>デバイス名は、各デバイスごとに割り当てる必要があります。試しに同じmicroSDを別のラズパイに挿してRaspberry Pi Connectを使おうとしましたが、新たにデバイス名を設定しなければなりませんでした。</p></div></div>



<h2 class="wp-block-heading">PCからリモート操作する</h2>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/02/IMG_8392.jpeg" alt=""/></figure>



<p class="wp-block-paragraph">PCのブラウザで <a href="https://connect.raspberrypi.com/">Raspberry Pi Connect</a> にアクセスします。サインインすると、以下の画面が出ます。「Connect via」 ボタンをクリックします。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/01/pico-2025-01-31T123408.740.png" alt=""/></figure>



<p class="wp-block-paragraph">「Screen sharing」または「Remote shell」 を選択します。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/01/pico-2025-01-31T131250.188.png" alt="" class="wp-image-4"/><figcaption class="wp-element-caption">どちらかを選択</figcaption></figure>



<p class="wp-block-paragraph">「Screen sharing」はRaspberry Pi の<span class="sbd-text-red">デスクトップ画面</span>をブラウザ上で操作できます。マウスやキーボードを使ってGUIアプリを操作したり、デスクトップ環境の設定を変更したりするときに便利です。</p>



<p class="wp-block-paragraph">「Remote shell」Raspberry Pi の<span class="sbd-text-bg-yellow">ターミナル</span>（CLI）に接続されます。コマンドを直接入力してシステムの設定変更や再起動を行ったり、PythonやBashのスクリプトを実行したりする際に役立ちます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/01/pico-2025-01-31T130848.863.jpg" alt="" class="wp-image-4" style="width:840px;height:auto"/></figure>



<h3 class="wp-block-heading">Screen sharingを使った操作感</h3>



<p class="wp-block-paragraph">「Screen sharing」を選択すると、以下のようにデスクトップ画面が表示されます。接続までにかかった時間は15秒でした。VNC接続と比べると、やや時間がかかる印象です。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/01/picone13.jpg" alt="" class="wp-image-4"/></figure>



<p class="wp-block-paragraph">VNC接続をしている場合は画面が表示されませんでした。<span class="sbd-text-bg-yellow">「Raspberry Pi Connect」とVNCは同時に使用できない</span>ようです。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/02/IMG_8394.jpeg" alt="" class="wp-image-4"/></figure>



<p class="wp-block-paragraph">キーボードやマウスを使って快適に操作できます。遠隔地からでも自在に扱えるのは、とても便利です。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/02/pico-4.jpg" alt="" class="wp-image-4"/><figcaption class="wp-element-caption">上部のボタンで操作可能</figcaption></figure>



<h2 class="wp-block-heading">スマートフォンからリモート操作する</h2>



<p class="wp-block-paragraph">PCの場合と同様に、ブラウザで <a href="https://connect.raspberrypi.com/">Raspberry Pi Connect</a> にアクセスします。以下はiPhoneからアクセスした際の画面です。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/01/IMG_8377.jpeg" alt="" class="wp-image-4" style="width:349px;height:auto"/></figure>



<p class="wp-block-paragraph">サインインすると、デバイス管理画面が表示されます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/01/IMG_8379.jpeg" alt="" class="wp-image-4" style="width:340px;height:auto"/></figure>



<p class="wp-block-paragraph">「Screen sharing」（画面共有）を押すと、以下のようにデスクトップ画面が表示されます。画面の拡大縮小はできないようです。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/02/IMG_8390.jpeg" alt="" class="wp-image-4" style="width:335px;height:auto"/></figure>



<p class="wp-block-paragraph">PCから接続しているかどうかで、<span class="sbd-text-red">スマホに表示される画面サイズが変わります</span>。PCで先に接続すると、その解像度が適用され、後からスマホで接続すると表示が変わるようです。これは、Raspberry Pi Connectが最初に接続したデバイスの解像度を基準にセッションを設定し、後から接続するデバイスはその解像度を引き継ぐためと思われます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/01/pico-2025-01-31T175653.200.jpg" alt="" class="wp-image-4" style="width:840px;height:auto"/><figcaption class="wp-element-caption">スマホ縦向き表示の比較</figcaption></figure>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/01/pico-2025-01-31T181735.433.jpg" alt="" class="wp-image-4" style="width:840px;height:auto"/><figcaption class="wp-element-caption">スマホ横向き表示の比較</figcaption></figure>



<p class="wp-block-paragraph">スマートフォン仕様の画面だと一部の領域しか表示できませんが、ボタンの操作は可能です。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/01/Videotogif.gif" alt="" class="wp-image-4"/></figure>



<p class="wp-block-paragraph">逆にPCを先に接続した場合の画面では、全画面表示されますが、ボタンが小さくて操作は困難です。</p>



<h3 class="wp-block-heading">スマホからコマンドを実行</h3>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/01/IMG_8385.png" alt="" class="wp-image-4" style="width:319px;height:auto"/><figcaption class="wp-element-caption">「Remote shell」モードでは文字入力可能</figcaption></figure>



<p class="wp-block-paragraph">Raspberry PiのCPU温度を取得するコマンドを実行してみました。以下のコマンドを使用します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>vcgencmd measure_temp</code></pre></div>



<p class="wp-block-paragraph">スマートフォンからの操作で、CPU温度を取得できました。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/01/image.png" alt="画像に alt 属性が指定されていません。ファイル名: IMG_8386.png" class="wp-image-4" style="width:320px;height:auto"/></figure>



<h2 class="wp-block-heading">カメラの映像をリモートで確認する</h2>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2025/02/IMG_8396.jpeg" alt="" class="wp-image-4"/><figcaption class="wp-element-caption">Raspberry Pi 5とカメラモジュールV3</figcaption></figure>



<p class="wp-block-paragraph"><a href="https://sozorablog.com/camera-module-v3/">カメラモジュールV3</a>で撮影した映像をスマートフォンに表示してみます。</p>



<p class="wp-block-paragraph">以下のコマンドはカメラのプレビュー画面を表示するためのものです。あらかじめRaspberry Pi側でこのコマンドを実行し、その映像をスマートフォンから確認できるか試してみます。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>libcamera-hello --timeout 0</code></pre></div>



<h3 class="wp-block-heading">スマホからの操作性は今後の改善に期待</h3>



<p class="wp-block-paragraph">スマートフォンからRaspberry Pi Connectに接続すると、以下のように表示されます。遅延はほぼ気にならないレベルです。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="1040" src="https://sozorablog.com/wp-content/uploads/2025/02/IMG_8397.jpeg" alt="" class="wp-image-14010" style="width:449px;height:auto"/></figure>



<p class="wp-block-paragraph">スマートフォンでは<span class="sbd-text-red">全画面表示ができない</span>ようです。スマートフォンを横向きにしても、画像のサイズはあまり大きくなりませんでした。そのため、デスクトップ画面のGUI操作はほとんどできない状態です。スマホで本格的なプログラミングをするわけではないにせよ、エディターを開いてプログラムを起動するなど、最低限の操作ができるようになってほしいところです。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://sozorablog.com/raspberry-pi-connect/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>【近未来的】ラズパイで透明OLEDディスプレイを使いこなそう</title>
		<link>https://sozorablog.com/pi-transparent-oled/</link>
					<comments>https://sozorablog.com/pi-transparent-oled/#comments</comments>
		
		<dc:creator><![CDATA[そぞら]]></dc:creator>
		<pubDate>Sun, 14 Apr 2024 08:27:03 +0000</pubDate>
				<category><![CDATA[Raspberry Pi]]></category>
		<category><![CDATA[使い方]]></category>
		<guid isPermaLink="false">https://sozorablog.com/?p=12147</guid>

					<description><![CDATA[数あるラズパイ用ディスプレイの中でも、トップクラスの近未来感を放つ透明ディスプレイ。コンパクトながらも「つい見とれてしまう」魅力的なアイテムです。 リンク 本記事ではRaspberry Piを使い、透明ディスプレイにさま [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">数あるラズパイ用ディスプレイの中でも、トップクラスの近未来感を放つ<a href="https://www.waveshare.com/1.51inch-transparent-oled.htm">透明ディスプレイ</a>。コンパクトながらも「つい見とれてしまう」魅力的なアイテムです。</p>



<!-- START MoshimoAffiliateEasyLink -->
<script type="text/javascript">
(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;
b[a]=b[a]||function(){arguments.currentScript=c.currentScript
||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};
c.getElementById(a)||(d=c.createElement(f),d.src=g,
d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})
(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");
msmaflink({"n":"Waveshare 1.5インチ 透明 OLED 128×64 解像度 Raspberry Pi 4B\/3B+\/3A+ 埋め込み独立ドライバーチップ SPI\/I2C インターフェース ライトブルー カラーディスプレイ","b":"WaveShare","t":"1.51inch Transparent OLED","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/412MDN0TnEL._SL500_.jpg","\/41MyrAS9gJL._SL500_.jpg","\/41DDQ4fLYXL._SL500_.jpg","\/41BUTklySEL._SL500_.jpg","\/419BGMtZFkL._SL500_.jpg","\/51iReNJjpHL._SL500_.jpg","\/41SK77hmTpL._SL500_.jpg","\/41FcON3klgL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/B0B8N46G24","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/B0B8N46G24","a_id":3038653,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":4,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/Waveshare%201.5%E3%82%A4%E3%83%B3%E3%83%81%20%E9%80%8F%E6%98%8E%20OLED%20128%C3%9764%20%E8%A7%A3%E5%83%8F%E5%BA%A6%20Raspberry%20Pi%204B%2F3B%2B%2F3A%2B%20%E5%9F%8B%E3%82%81%E8%BE%BC%E3%81%BF%E7%8B%AC%E7%AB%8B%E3%83%89%E3%83%A9%E3%82%A4%E3%83%90%E3%83%BC%E3%83%81%E3%83%83%E3%83%97%20SPI%2FI2C%20%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%95%E3%82%A7%E3%83%BC%E3%82%B9%20%E3%83%A9%E3%82%A4%E3%83%88%E3%83%96%E3%83%AB%E3%83%BC%20%E3%82%AB%E3%83%A9%E3%83%BC%E3%83%87%E3%82%A3%E3%82%B9%E3%83%97%E3%83%AC%E3%82%A4\/","a_id":3038654,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2}],"eid":"xwjSp","s":"s"});
</script>
<div id="msmaflink-xwjSp">リンク</div>
<!-- MoshimoAffiliateEasyLink END -->



<p class="wp-block-paragraph">本記事では<a href="https://sozorablog.com/raspberry-pi/">Raspberry Pi</a>を使い、透明ディスプレイにさまざまな情報を表示するためのテクニックを紹介します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/04/IMG_8930.jpeg" alt="" style="width:840px;height:auto"/><figcaption class="wp-element-caption">透明OLEDディスプレイを6枚同時に使用した作例</figcaption></figure>



<p class="wp-block-paragraph">今回使用する<strong>1.51インチ透明 青色OLEDディスプレイ（128×64 SPI/I2C）</strong>は、<a href="https://www.switch-science.com/products/8315?_pos=3&amp;_sid=9405dc02d&amp;_ss=r">スイッチサイエンス</a>や<a href="https://www.sengoku.co.jp/mod/sgk_cart/detail.php?code=EEHD-6FDJ">せんごくネット通販</a>で購入できます。メーカーは<a href="https://sozorablog.com/magicmirror/">円形ディスプレイ</a>や<a href="https://www.waveshare.com/product/displays/e-paper.htm">電子ペーパー</a>などを製造している<a href="https://www.waveshare.com/1.51inch-transparent-oled.htm">Waveshare</a>です。</p>



<h2 class="wp-block-heading">透明ディスプレイを使う準備</h2>



<p class="wp-block-paragraph">透明ディスプレイとコントローラーをケーブルで接続します。表裏の向きに注意しましょう。QCのシールが目印になります。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/04/toumei9.jpg" alt="" class="wp-image-4" style="width:840px;height:auto"/></figure>



<h3 class="wp-block-heading">ラズパイ側の準備</h3>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/11/スクリーンショット-2026-05-16-5.27.00.png" alt="" style="width:552px;height:auto"/></figure>



<p class="wp-block-paragraph">使用するRaspberry Piの準備をします。Raspberry Pi OS Trixieのデスクトップ版を使用しました。</p>



<div class="wp-block-sbd-background-block sbd-bg-color sbd-inner-block-init is-style-yellow">
<p class="wp-block-paragraph">OSをインストールする方法は以下の記事で詳しく解説しています。<br><strong><a href="https://sozorablog.com/raspberrypi_initial_setting/">≫【2026年最新版】OSインストールから初期設定まで｜セットアップ手順のすべて</a></strong></p>
</div>



<h3 class="wp-block-heading">ラズパイと透明ディスプレイの接続</h3>



<p class="wp-block-paragraph">ラズパイと透明ディスプレイは以下のように配線します。配線作業時はラズパイ本体の電源を切りましょう。付属のワイヤは色分けされているため、色に従って簡単に配線ができます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/04/toumei2.jpg" alt="" class="wp-image-4" style="width:840px;height:auto"/><figcaption class="wp-element-caption">出典：<a href="https://www.waveshare.com/1.51inch-transparent-oled.htm">WaveShareの公式サイト</a></figcaption></figure>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/04/IMG_6706.jpeg" alt="" class="wp-image-4" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph">接続が完了したら、Raspberry Piを起動します。</p>



<h3 class="wp-block-heading">SPIを有効にする</h3>



<p class="wp-block-paragraph">Raspberry Piと透明ディスプレイは、SPIを通じて通信します。SPI（Serial Peripheral Interface）はデバイス間で、データを通信するためのインターフェースです。初期設定ではSPIが使える状態になっていないため、以下の手順で設定します。</p>



<p class="wp-block-paragraph">スタートメニューから「設定」→「Control Centre」の順に展開します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/11/pico-6.jpg" alt="" style="width:565px;height:auto"/></figure>



<p class="wp-block-paragraph">左側の「インターフェイス」タブをクリック後、SPIを有効にします。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="509" src="https://sozorablog.com/wp-content/uploads/2024/04/スクリーンショット-2026-05-30-16.19.41.png" alt="" class="wp-image-17204" style="width:645px;height:auto"/></figure>



<p class="wp-block-paragraph">設定を有効にしたら、Raspberry Piを再起動します。</p>



<h3 class="wp-block-heading">フォントのインストール</h3>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/04/toumei5.jpg" alt=""/></figure>



<p class="wp-block-paragraph">透明ディスプレイに日本語を表示させるため、Takaoフォントをインストールします。</p>



<p class="wp-block-paragraph">以下のコマンドを入力して、Enterキーを押します。このとき、安全確認として<span class="sbd-text-red">パスワード入力</span>が求められます。ラズベリーパイにログインするときのパスワードを入力後、Enterキーを押してください。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo apt install -y fonts-takao</code></pre></div>



<h2 class="wp-block-heading">表示テストをしてみよう</h2>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/04/IMG_6684.jpeg" alt="" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph">透明ディスプレイに3Dアニメーションを表示するためのプログラムを実行してみましょう。</p>



<p class="wp-block-paragraph">スタートメニューの「プログラミング」から「Thonny」を開きます。ThonnyはPythonの統合開発環境（IDE）で、コードの記述、実行、保存などを行うことができます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2026/04/pico-2.jpg" alt="" style="width:555px;height:auto"/></figure>



<p class="wp-block-paragraph">以下がThonnyの画面です。後述のコードをコピーペーストして「Run」ボタンを押すと、プログラムが実行されます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/04/toumei14.jpg" alt="" style="width:840px;height:auto"/></figure>



<h3 class="wp-block-heading">3Dアニメーションを表示するコード</h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>import spidev
import lgpio
import time
from PIL import Image, ImageDraw
from math import sin, cos, radians

# SPI初期化
spi=spidev.SpiDev()
spi.open(0,0)
spi.max_speed_hz=8000000

h=lgpio.gpiochip_open(0)
lgpio.gpio_claim_output(h,25)
lgpio.gpio_claim_output(h,27)

# コマンド/データ送信関数
send=lambda dc,d:(lgpio.gpio_write(h,25,dc),spi.writebytes(d))

# ディスプレイをリセット
lgpio.gpio_write(h,27,0);time.sleep(0.05)
lgpio.gpio_write(h,27,1);time.sleep(0.05)

# SSD1306初期化
send(0,[0xAE,0xD5,0x80,0xA8,0x3F,0xD3,0x00,0x40,0x8D,0x14,
0x20,0x00,0xA1,0xC8,0xDA,0x12,0x81,0xCF,0xD9,0xF1,
0xDB,0x40,0xA4,0xA6,0xAF,0x21,0,127,0x22,0,7])

# 拡大率
scale_factor=0.8

# X方向の位置調整
x_offset=65

# Y方向中心座標
Y_CENTER=32

# 三角錐の頂点座標
pyramid=((0,-20,0),(-20,20,-20),(20,20,-20),(0,20,20))

while True:

    # 0〜360度回転
    for angle in range(0,361,10):

        # 座標保存用
        f=[[0.0 for _ in range(3)] for _ in range(4)]

        # ラジアン変換
        r=radians(angle)

        # 各頂点を回転計算
        for i in range(4):

            x1=pyramid[i][2]*sin(r)+pyramid[i][0]*cos(r)

            ya=pyramid[i][1]

            z1=pyramid[i][2]*cos(r)-pyramid[i][0]*sin(r)

            y2=ya*cos(r)-z1*sin(r)

            x3=(x1*cos(r)-y2*sin(r))*scale_factor+x_offset

            y3=(x1*sin(r)+y2*cos(r))*scale_factor+Y_CENTER

            f[i][0]=x3
            f[i][1]=y3

        # 白黒画像作成
        image=Image.new(&quot;1&quot;,(128,64),0)

        # 描画オブジェクト作成
        draw=ImageDraw.Draw(image)

        # 線を描画
        for i in range(3):

            draw.line(
                (f[0][0],f[0][1],f[i+1][0],f[i+1][1]),
                fill=1
            )

            draw.line(
                (f[i+1][0],f[i+1][1],
                f[(i+1)%3+1][0],f[(i+1)%3+1][1]),
                fill=1
            )

        # SSD1306転送用バッファ
        buffer=[]

        # 8ページ分変換
        for page in range(8):

            for x in range(128):

                byte=0

                for bit in range(8):

                    # ピクセル確認
                    if image.getpixel((x,page*8+bit)):
                        byte|=(1&lt;&lt;bit)

                buffer.append(byte)

        # ディスプレイへ転送
        send(1,buffer)

        time.sleep(0.1)
</code></pre></div>



<p class="wp-block-paragraph">このプログラムは透明ディスプレイに三角錐の回転アニメーションを表示するものです。まず、SPI接続を設定してディスプレイと通信します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/04/IMG_6686.gif" alt="" style="width:243px;height:auto"/></figure>



<p class="wp-block-paragraph">三角錐の頂点を計算し、それをスケーリングしてディスプレイの特定の位置に合わせます。三角錐は連続して異なる角度から描画され、それによって立体的に回転しているように見えるアニメーションが生成されます。</p>



<p class="wp-block-paragraph">各頂点の座標は三角関数を用いて計算され、その結果に基づいてディスプレイ上で線が描かれます。この処理は無限ループ内で実行され、ユーザーがキーボード割り込み（Ctrl+C）を行うまで続けられます。割り込みが発生すると、GPIOピンの設定がクリーンアップされ、プログラムが終了します。</p>



<div class="wp-block-sbd-background-block sbd-bg-color sbd-inner-block-init is-style-yellow">
<p class="wp-block-paragraph">プログラムを実行しても透明ディスプレイに何も表示されない場合、配線の接続ミスが考えられます。もう一度、ワイヤーが正しいピンに接続されているかを確認してみましょう。</p>
</div>



<h2 class="wp-block-heading">図形を表示してみよう</h2>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/04/IMG_6714.jpeg" alt="" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph">PIL（Pillowライブラリ）には、さまざまな図形を描画するための関数が多数用意されています。これらの関数を使えば、シンプルなコードで図形を表示できます。</p>



<p class="wp-block-paragraph">以下のコードはディスプレイに6種類の図形を描画するためのものです。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>import spidev
import lgpio
import time
from PIL import Image, ImageDraw

# SPI初期化
spi=spidev.SpiDev()
spi.open(0,0)
spi.max_speed_hz=8000000

h=lgpio.gpiochip_open(0)
lgpio.gpio_claim_output(h,25)
lgpio.gpio_claim_output(h,27)

# コマンド/データ送信関数
send=lambda dc,d:(lgpio.gpio_write(h,25,dc),spi.writebytes(d))

# ディスプレイをリセット
lgpio.gpio_write(h,27,0);time.sleep(0.05)
lgpio.gpio_write(h,27,1);time.sleep(0.05)

# SSD1306初期化
send(0,[0xAE,0xD5,0x80,0xA8,0x3F,0xD3,0x00,0x40,0x8D,0x14,
0x20,0x00,0xA1,0xC8,0xDA,0x12,0x81,0xCF,0xD9,0xF1,
0xDB,0x40,0xA4,0xA6,0xAF,0x21,0,127,0x22,0,7])

# SSD1306用バッファ変換
def image_to_buffer(image):

    buffer=[]

    for page in range(8):
        for x in range(128):
            byte=0
            for bit in range(8):
                if image.getpixel((x,page*8+bit)):
                    byte|=(1&lt;&lt;bit)
            buffer.append(byte)

    return buffer

# 表示用画像作成
img = Image.new(&quot;1&quot;, (128, 64), 0)

# 描画オブジェクト作成
draw = ImageDraw.Draw(img)

# 1. 左下に四角形（塗りつぶし）
draw.rectangle([(10, 48), (30, 64)], fill=1)

# 2. 右上に円（塗りつぶし）
draw.ellipse([(98, 2), (118, 22)], fill=1)

# 3. 左上から右下へ線
draw.line([(0, 0), (127, 63)], fill=1)

# 4. 中央に三角形（枠線のみ）
draw.polygon([(60, 25), (70, 5), (80, 25)], outline=1)

# 5. 中央右に四角形（枠線のみ）
draw.rectangle([(50, 40), (70, 60)], outline=1)

# 6. 左上に円（枠線のみ）
draw.ellipse([(5, 15), (25, 35)], outline=1)

# SSD1306へ転送
send(1, image_to_buffer(img))</code></pre></div>



<p class="wp-block-paragraph">図形を描画する際の座標指定について説明します。座標は図形の位置を指定するために使用されます。具体的には、ディスプレイの左上を（0, 0）として、右方向へのX座標と下方向へのY座標で位置を定めます。</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/04/toumei16.jpg" alt=""/></figure>



<p class="wp-block-paragraph">各図形の座標の指定方法は次の通りです。</p>



<div class="wp-block-sbd-list"><ul class="sbd-list sbd-list-border"><li>線・・・始点と終点の座標を指定</li><li>円・・・外接する四角形の左上と右下の座標を指定</li><li>三角形・・・三点の座標をリストとして指定</li><li>四角形・・・左上の角と右下の角の座標を指定</li></ul></div>



<h2 class="wp-block-heading">文字を表示してみよう</h2>



<p class="wp-block-paragraph">次は文字の表示方法を紹介します。</p>



<h3 class="wp-block-heading">文字を1行ずつ表示</h3>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/04/IMG_6701.jpeg" alt="" class="wp-image-4" style="width:842px;height:auto"/></figure>



<p class="wp-block-paragraph">以下のコードは透明ディスプレイに、日本語のテキストを表示するためのものです。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>import spidev
import lgpio
import time
from PIL import Image, ImageDraw, ImageFont
from math import sin, cos, radians

# SPI初期化
spi=spidev.SpiDev()
spi.open(0,0)
spi.max_speed_hz=8000000

h=lgpio.gpiochip_open(0)
lgpio.gpio_claim_output(h,25)
lgpio.gpio_claim_output(h,27)

# コマンド/データ送信関数
send=lambda dc,d:(lgpio.gpio_write(h,25,dc),spi.writebytes(d))

# ディスプレイをリセット
lgpio.gpio_write(h,27,0);time.sleep(0.05)
lgpio.gpio_write(h,27,1);time.sleep(0.05)

# SSD1306初期化
send(0,[0xAE,0xD5,0x80,0xA8,0x3F,0xD3,0x00,0x40,0x8D,0x14,
0x20,0x00,0xA1,0xC8,0xDA,0x12,0x81,0xCF,0xD9,0xF1,
0xDB,0x40,0xA4,0xA6,0xAF,0x21,0,127,0x22,0,7])

# SSD1306用バッファ変換
def image_to_buffer(image):

    buffer=[]

    for page in range(8):
        for x in range(128):
            byte=0
            for bit in range(8):
                if image.getpixel((x,page*8+bit)):
                    byte|=(1&lt;&lt;bit)
            buffer.append(byte)

    return buffer

# フォントのパスとサイズ設定
font_size=11
font=ImageFont.truetype(&quot;/usr/share/fonts/truetype/takao-gothic/TakaoGothic.ttf&quot;,font_size)

# 白黒画像作成
image=Image.new(&quot;1&quot;,(128,64),0)

# 描画オブジェクト
draw=ImageDraw.Draw(image)

# テキスト描画
draw.text((0,0),&quot;1.51インチ透明&quot;,font=font,fill=1)

draw.text((5,30),&quot;青色OLEDディスプレイ&quot;,font=font,fill=1)

# 表示
send(1,image_to_buffer(image))
</code></pre></div>



<p class="wp-block-paragraph">Takaoフォントを使用するために、フォントファイルのパスを指定し、文字のサイズとして11ピクセルを選択します。<span class="sbd-text-bg-yellow">文字サイズの数値（font_size = 11）は自由に変更できます。</span></p>



<p class="wp-block-paragraph">新しい画像オブジェクトを作成した後、この画像上でDrawオブジェクトを使ってテキストを描画します。テキストの位置はxとyの座標を使って指定します。座標の指定方法は、<strong>ディスプレイの左上を0として考えます。</strong></p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/04/toumei11.jpg" alt="" class="wp-image-4"/></figure>



<p class="wp-block-paragraph">テキスト「1.51インチ透明」は<em>x</em>=0、<em>y</em>=0の位置に配置され、これは画像の左上からスタートすることを意味します。次のテキスト「青色OLEDディスプレイ」は<em>x</em>=5、<em>y</em>=30の位置に表示されます。</p>



<h3 class="wp-block-heading">長文をスクロールして表示</h3>



<p class="wp-block-paragraph">先ほどのコードでは、1行の表示範囲を超える長さの文を表示することができません。そこで、文字を自動的に<span class="sbd-text-red">改行やスクロールしながら表示</span>する方法を紹介します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>import spidev
import lgpio
import time
from PIL import Image, ImageDraw, ImageFont
from math import sin, cos, radians

# SPI初期化
spi=spidev.SpiDev()
spi.open(0,0)
spi.max_speed_hz=8000000

h=lgpio.gpiochip_open(0)
lgpio.gpio_claim_output(h,25)
lgpio.gpio_claim_output(h,27)

# コマンド/データ送信関数
send=lambda dc,d:(lgpio.gpio_write(h,25,dc),spi.writebytes(d))

# ディスプレイをリセット
lgpio.gpio_write(h,27,0);time.sleep(0.05)
lgpio.gpio_write(h,27,1);time.sleep(0.05)

# SSD1306初期化
send(0,[0xAE,0xD5,0x80,0xA8,0x3F,0xD3,0x00,0x40,0x8D,0x14,
0x20,0x00,0xA1,0xC8,0xDA,0x12,0x81,0xCF,0xD9,0xF1,
0xDB,0x40,0xA4,0xA6,0xAF,0x21,0,127,0x22,0,7])

# SSD1306用バッファ変換
def image_to_buffer(image):

    buffer=[]

    for page in range(8):
        for x in range(128):
            byte=0
            for bit in range(8):
                if image.getpixel((x,page*8+bit)):
                    byte|=(1&lt;&lt;bit)
            buffer.append(byte)

    return buffer

# フォントのパスとサイズ設定
font_size=11
font=ImageFont.truetype(&quot;/usr/share/fonts/truetype/takao-gothic/TakaoGothic.ttf&quot;,font_size)

# 行高さ
line_height=font_size+2

# テキストスクロール表示
def draw_text_with_scroll(text):

    lines=[]

    for char in text:

        current_text=(lines[-1] if lines else &quot;&quot;)+char

        bbox=font.getbbox(current_text)

        text_width=bbox[2]-bbox[0]

        # 横幅超過で改行
        if text_width&gt;128:
            lines.append(char)

        else:

            if not lines:
                lines.append(current_text)

            else:
                lines[-1]=current_text

        # 縦幅超過でスクロール
        if len(lines)*line_height&gt;64:
            lines.pop(0)

        # 白黒画像作成
        image=Image.new(&quot;1&quot;,(128,64),0)

        draw=ImageDraw.Draw(image)

        # 行描画
        y=0

        for line in lines:

            draw.text((0,y),line,font=font,fill=1)

            y+=line_height

        # 表示
        send(1,image_to_buffer(image))

        time.sleep(0.04)
        
# 表示テキスト
text=&quot;こんにちは、Raspberry Piと透明OLEDディスプレイを使っています。文字がディスプレイの幅を超えた場合は自動的に改行やスクロールを行い、長いテキストも適切に扱えるようにしました。&quot;

draw_text_with_scroll(text)
</code></pre></div>



<p class="wp-block-paragraph"><code>draw_text_with_scroll</code>関数では、与えられたテキストを一文字ずつ処理し、現在の行のテキストと新しい文字を組み合わせて幅を計算します。テキストの幅がディスプレイの幅を超えると、新しい行を開始します。また、テキストの行がディスプレイの高さを超えた場合には、最上行を削除してスクロールさせる処理を行います。このスクロール処理により、ディスプレイ上では常に最新のテキストが表示され続けます。</p>



<p class="wp-block-paragraph">関数内の最終行である「<code>time.sleep(0.04)」</code>の数値を変更することにより、文字の表示スピードを調整可能です。</p>



<figure class="wp-block-embed is-type-rich is-provider-x wp-block-embed-x"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="500" data-dnt="true"><p lang="ja" dir="ltr">透明OLEDディスプレイへのテキスト表示をChatGPT風にしたら、近未来感が倍増した。 <a href="https://t.co/V1gYt9XGtE">pic.twitter.com/V1gYt9XGtE</a></p>&mdash; そぞら@Raspberry Pi 電子工作 (@sozoraemon) <a href="https://x.com/sozoraemon/status/1775110781480403412?ref_src=twsrc%5Etfw">April 2, 2024</a></blockquote><script async src="https://platform.x.com/widgets.js" charset="utf-8"></script>
</div></figure>



<h2 class="wp-block-heading">時計を作ろう</h2>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/04/toumei10-1.jpg" alt="" class="wp-image-4" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph">これまでに紹介したテクニックを応用して、時計を作ってみましょう。</p>



<h3 class="wp-block-heading">フォントファイルのダウンロード</h3>



<p class="wp-block-paragraph">時計の雰囲気を盛り上げるために、<a href="https://www.dafont.com/seven-segment.font">Seven Segmentフォント</a>という7セグメント風のフォントを利用します。7セグメント（通称：7セグ）は、デジタル時計などでよく使われる表示装置のことで、数字などの文字を表示するために7つの発光部分（セグメント）から構成されています。</p>



<p class="wp-block-paragraph">通常のフォントから7セグ風のフォントに変更することで、より時計らしい表示の作成が可能です。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/04/toumei15-1.jpg" alt="" class="wp-image-4" style="width:841px;height:auto"/><figcaption class="wp-element-caption">フォントの比較</figcaption></figure>



<p class="wp-block-paragraph">Seven Segmentフォントは<span class="sbd-text-red">個人利用に関しては無料</span>で使用できますが、商用利用の場合は5ドルのライセンス料が必要です。詳細は<a href="https://www.dafont.com/seven-segment.font">こちら</a>を確認してください。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/04/toumei8.jpg" alt="" class="wp-image-4" style="width:840px;height:auto"/><figcaption class="wp-element-caption">出典：<a href="https://www.dafont.com/seven-segment.font">dafont.com</a></figcaption></figure>



<p class="wp-block-paragraph">フォントファイルは上記のサイトからダウンロードできます。Raspberry Piのブラウザで「ダウンロードボタン」を押すと、ダウンロードフォルダに保存されます。</p>



<p class="wp-block-paragraph">ターミナルを開き、以下のコマンドを実行して、ZIPファイルを展開し「/home/pi」に移動します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>unzip /home/pi/Downloads/seven_segment.zip -d /home/pi/</code></pre></div>



<p class="wp-block-paragraph">手動で移動する場合も、「/home/pi」に以下のように保存します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/04/pico-60-1.jpg" alt="" style="width:841px;height:auto"/><figcaption class="wp-element-caption">/home/piに保存されたフォントファイル</figcaption></figure>



<p class="wp-block-paragraph">「/home/pi」に正しく保存しないと、後述するコードを実行した際にフォントファイルが読み込めず、エラーが出ます。</p>



<h3 class="wp-block-heading">デジタル時計のコード</h3>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/04/IMG_6699.jpeg" alt="" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph">以下のプログラムは、透明ディスプレイにアニメーションと時刻を表示するためのものです。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>import spidev
import lgpio
import time
import datetime
from PIL import Image, ImageDraw, ImageFont
from math import sin, cos, radians

# SPI初期化
spi=spidev.SpiDev()
spi.open(0,0)
spi.max_speed_hz=8000000

h=lgpio.gpiochip_open(0)
lgpio.gpio_claim_output(h,25)
lgpio.gpio_claim_output(h,27)

# コマンド/データ送信関数
send=lambda dc,d:(lgpio.gpio_write(h,25,dc),spi.writebytes(d))

# ディスプレイをリセット
lgpio.gpio_write(h,27,0);time.sleep(0.05)
lgpio.gpio_write(h,27,1);time.sleep(0.05)

# SSD1306初期化
send(0,[0xAE,0xD5,0x80,0xA8,0x3F,0xD3,0x00,0x40,0x8D,0x14,
0x20,0x00,0xA1,0xC8,0xDA,0x12,0x81,0xCF,0xD9,0xF1,
0xDB,0x40,0xA4,0xA6,0xAF,0x21,0,127,0x22,0,7])

# SSD1306用バッファ変換
def image_to_buffer(image):

    buffer=[]

    for page in range(8):
        for x in range(128):
            byte=0
            for bit in range(8):
                if image.getpixel((x,page*8+bit)):
                    byte|=(1&lt;&lt;bit)
            buffer.append(byte)

    return buffer

# フォント
font_path = &quot;/home/pi/Seven Segment.ttf&quot;

font1 = ImageFont.truetype(font_path, 14)
font2 = ImageFont.truetype(font_path, 15)
font3 = ImageFont.truetype(font_path, 25)
font4 = ImageFont.truetype(font_path, 38)

# スケーリング係数
scale_factor = 0.7
x_offset = 25

# 画面中心
Y_CENTER = 32

# 三角錐
pyramid = (
    (0, -20, 0),
    (-20, 20, -20),
    (20, 20, -20),
    (0, 20, 20)
)

scroll_x = 0

try:

    while True:

        for angle in range(0, 361, 10):

            # 描画用画像を作成
            img = Image.new(&quot;1&quot;, (128, 64), 0)
            draw = ImageDraw.Draw(img)

            # 現在日時を取得
            dt_now = datetime.datetime.now()

            date1 = dt_now.strftime(&quot;%m/%d&quot;)
            weekday = dt_now.strftime(&quot;%a&quot;).upper()
            hour = dt_now.strftime(&quot;%H&quot;)
            minute = dt_now.strftime(&quot;%M&quot;)
            second = dt_now.strftime(&quot;%S&quot;)
            second = dt_now.strftime(&quot;%S&quot;)
            
            scroll_text = dt_now.strftime(&quot;%Y/%m/%d %a&quot;).upper()

            # 頂点座標格納用
            f = [[0, 0] for _ in range(4)]

            r = radians(angle)

            # 三角錐を回転
            for i in range(4):

                x1 = pyramid[i][2] * sin(r) + pyramid[i][0] * cos(r)
                ya = pyramid[i][1]
                z1 = pyramid[i][2] * cos(r) - pyramid[i][0] * sin(r)

                y2 = ya * cos(r) - z1 * sin(r)

                x3 = (x1 * cos(r) - y2 * sin(r)) * scale_factor + x_offset
                y3 = (x1 * sin(r) + y2 * cos(r)) * scale_factor + Y_CENTER

                f[i][0] = x3
                f[i][1] = y3

            # 三角錐を描画
            for i in range(3):

                draw.line((f[0][0], f[0][1], f[i + 1][0], f[i + 1][1]), fill=1)

                draw.line(
                    (
                        f[i + 1][0],
                        f[i + 1][1],
                        f[(i + 1) % 3 + 1][0],
                        f[(i + 1) % 3 + 1][1]
                    ),
                    fill=1
                )

            # 日時を描画
            scroll_img = Image.new(&quot;1&quot;, (300, 18), 0)
            scroll_draw = ImageDraw.Draw(scroll_img)

            scroll_draw.text((0, 0), scroll_text, font=font2, fill=1)

            text_width = scroll_draw.textlength(scroll_text, font=font2)

            scroll_draw.text((text_width + 20, 0), scroll_text, font=font2, fill=1)

            crop = scroll_img.crop((scroll_x, 0, scroll_x + 85, 18))

            img.paste(crop, (43, 5))            
            
            draw.text((50, 28), hour, font=font3, fill=1)
            draw.text((71, 12), &quot;:&quot;, font=font4, fill=1)
            draw.text((78, 28), minute, font=font3, fill=1)
            draw.text((108, 37), second, font=font2, fill=1)
            
            scroll_x += 2

            if scroll_x &gt;= text_width + 20:
                scroll_x = 0            
            

            # SSD1306へ転送
            send(1, image_to_buffer(img))

            time.sleep(0.1)

except KeyboardInterrupt:
    pass

finally:
    lgpio.gpiochip_close(h)
    spi.close()
</code></pre></div>



<p class="wp-block-paragraph">無限ループ内で現在の時刻を取得し、三角錐のアニメーションとともに時刻を表示しています。アニメーションは<code>canvas</code>コンテキストを使用してディスプレイに描画され、時刻や曜日、秒数も同時に表示されます。</p>



<p class="wp-block-paragraph"><br></p>



<h2 class="wp-block-heading">画像を表示</h2>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/04/IMG_6702.jpeg" alt=""/></figure>



<p class="wp-block-paragraph">透明ディスプレイに画像を表示する方法を紹介します。ここでは、僕が作成した「tenki.png」という画像を表示してみます。</p>



<p class="wp-block-paragraph">以下のボタンを押すと、画像をダウンロードできます。</p>


<div class='w3eden'><!-- WPDM Link Template: Default Template -->

<div class="link-template-default card mb-2">
    <div class="card-body">
        <div class="media">
            <div class="mr-3 img-48"><img decoding="async" class="wpdm_icon" alt="アイコン" src="https://sozorablog.com/wp-content/plugins/download-manager/assets/file-type-icons/png.svg" /></div>
            <div class="media-body">
                <h3 class="package-title"><a href='https://sozorablog.com/download/%e9%80%8f%e6%98%8e%e3%83%87%e3%82%a3%e3%82%b9%e3%83%97%e3%83%ac%e3%82%a4%e7%94%a8%e7%94%bb%e5%83%8f/'>透明ディスプレイ用画像（tenki.png）</a></h3>
                <div class="text-muted text-small"><i class="fas fa-copy"></i> 1 ファイル <i class="fas fa-hdd ml-3"></i> 2.93 KB</div>
            </div>
            <div class="ml-3">
                <a class='wpdm-download-link download-on-click btn btn-primary ' rel='nofollow' href='#' data-downloadurl="https://sozorablog.com/download/%e9%80%8f%e6%98%8e%e3%83%87%e3%82%a3%e3%82%b9%e3%83%97%e3%83%ac%e3%82%a4%e7%94%a8%e7%94%bb%e5%83%8f/?wpdmdl=12222&refresh=6a8d2e769892e1787637366">ダウンロード</a>
            </div>
        </div>
    </div>
</div>

</div>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/04/tenki.png" alt=""/><figcaption class="wp-element-caption">tenki.png</figcaption></figure>



<p class="wp-block-paragraph">tenki.pngは<a href="https://www.canva.com/ja_jp/">Canva</a>を使って作成しました。自身で作成する場合は、64×64ピクセル程度のサイズで作成すると良いでしょう。複雑な画像は、つぶれて表示されてしまいます。シンプルで塗りつぶしの少ない、アイコンのような画像が表示に向いています。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/04/toumei12.png" alt="" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph">ダウンロードした「tenki.png」をラズパイの「/home/pi」に保存します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/04/toumei13.jpg" alt="" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph">以下のコードは透明ディスプレイに画像とテキストを表示するためのものです。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>import spidev
import lgpio
import time
from PIL import Image, ImageDraw, ImageFont, ImageOps

# SPI初期化
spi=spidev.SpiDev()
spi.open(0,0)
spi.max_speed_hz=8000000

h=lgpio.gpiochip_open(0)
lgpio.gpio_claim_output(h,25)
lgpio.gpio_claim_output(h,27)

# コマンド/データ送信関数
send=lambda dc,d:(lgpio.gpio_write(h,25,dc),spi.writebytes(d))

# ディスプレイをリセット
lgpio.gpio_write(h,27,0);time.sleep(0.05)
lgpio.gpio_write(h,27,1);time.sleep(0.05)

# SSD1306初期化
send(0,[0xAE,0xD5,0x80,0xA8,0x3F,0xD3,0x00,0x40,0x8D,0x14,
0x20,0x00,0xA1,0xC8,0xDA,0x12,0x81,0xCF,0xD9,0xF1,
0xDB,0x40,0xA4,0xA6,0xAF,0x21,0,127,0x22,0,7])

# SSD1306用バッファ変換
def image_to_buffer(image):

    buffer=[]

    for page in range(8):
        for x in range(128):
            byte=0
            for bit in range(8):
                if image.getpixel((x,page*8+bit)):
                    byte|=(1&lt;&lt;bit)
            buffer.append(byte)

    return buffer

# 画像読み込み
image = Image.open(&quot;tenki.png&quot;)

# 色反転
image = ImageOps.invert(image.convert(&quot;RGB&quot;))

# 表示用画像作成
img = Image.new(&quot;1&quot;, (128, 64), 0)

# 画像貼り付け
img.paste(image.convert(&quot;1&quot;), (0, 0))

# フォント読み込み
font = ImageFont.truetype(
    &quot;/usr/share/fonts/truetype/takao-gothic/TakaoGothic.ttf&quot;,
    11
)

# テキスト描画
draw = ImageDraw.Draw(img)
draw.text((60, 10), &quot;Hello,OLED!&quot;, font=font, fill=1)

# SSD1306へ転送
send(1, image_to_buffer(img))</code></pre></div>



<p class="wp-block-paragraph">最初に指定されたパスから画像ファイル「tenki.png」を読み込み、その色をRGB形式に変換した後、反転させます。次にディスプレイの解像度に合わせた新しい黒背景の画像を作成し、その背景に読み込んだ画像を左上の座標に配置します。</p>



<p class="wp-block-paragraph">また、背景画像上に「Hello, OLED!」というテキストを描画します。最終的に、この背景画像をディスプレイに表示することで、画像とテキストが組み合わされた内容を表示します。</p>



<h2 class="wp-block-heading">ビットコインのチャートを表示</h2>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/04/IMG_6696.jpeg" alt="" class="wp-image-4"/></figure>



<h3 class="wp-block-heading">ビットコイン価格をグラフ表示</h3>



<p class="wp-block-paragraph">以下のコードは、ビットコインの価格変動を透明ディスプレイにグラフとして表示するものです。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>import spidev
import lgpio
import time
import json
import requests
from datetime import datetime
from PIL import Image, ImageDraw, ImageFont

# SPI初期化
spi=spidev.SpiDev()
spi.open(0,0)
spi.max_speed_hz=8000000

h=lgpio.gpiochip_open(0)
lgpio.gpio_claim_output(h,25)
lgpio.gpio_claim_output(h,27)

# コマンド/データ送信関数
send=lambda dc,d:(lgpio.gpio_write(h,25,dc),spi.writebytes(d))

# ディスプレイをリセット
lgpio.gpio_write(h,27,0);time.sleep(0.05)
lgpio.gpio_write(h,27,1);time.sleep(0.05)

# SSD1306初期化
send(0,[0xAE,0xD5,0x80,0xA8,0x3F,0xD3,0x00,0x40,0x8D,0x14,
0x20,0x00,0xA1,0xC8,0xDA,0x12,0x81,0xCF,0xD9,0xF1,
0xDB,0x40,0xA4,0xA6,0xAF,0x21,0,127,0x22,0,7])

# SSD1306用バッファ変換
def image_to_buffer(image):

    buffer=[]

    for page in range(8):
        for x in range(128):
            byte=0
            for bit in range(8):
                if image.getpixel((x,page*8+bit)):
                    byte|=(1&lt;&lt;bit)
            buffer.append(byte)

    return buffer

def draw_dotted_line(draw, start, end, dash=2):

    x1, y1 = start
    x2, y2 = end

    if y1 == y2:

        for x in range(int(x1), int(x2), dash * 2):
            draw.line((x, y1, min(x + dash, x2), y1), fill=1)

    elif x1 == x2:

        for y in range(int(y1), int(y2), dash * 2):
            draw.line((x1, y, x1, min(y + dash, y2)), fill=1)

# CoinGecko API
url=&quot;https://api.coingecko.com/api/v3/coins/bitcoin/market_chart&quot;

params={
    &quot;vs_currency&quot;:&quot;jpy&quot;,
    &quot;days&quot;:80
}

# フォント
font_path=&quot;/usr/share/fonts/truetype/takao-gothic/TakaoGothic.ttf&quot;

font=ImageFont.truetype(font_path,11)
font_s=ImageFont.truetype(font_path,8)

try:

    while True:

        # 価格取得
        response=requests.get(url,params=params)
        response.raise_for_status()

        data=json.loads(response.text)

        prices=[x[1] for x in data[&quot;prices&quot;]]

        min_price=min(prices)
        max_price=max(prices)

        sorted_prices=sorted(prices)
        prices_len=len(sorted_prices)

        if prices_len%2==1:
            median_price=sorted_prices[prices_len//2]
        else:
            middle1=sorted_prices[(prices_len//2)-1]
            middle2=sorted_prices[prices_len//2]
            median_price=(middle1+middle2)/2

        formatted_min_price=f&quot;{min_price/1000000:.1f}M&quot;
        formatted_median_price=f&quot;{median_price/1000000:.1f}M&quot;
        formatted_max_price=f&quot;{max_price/1000000:.1f}M&quot;

        last_price=prices[-1]
        formatted_price=&quot;{:,}&quot;.format(int(last_price))

        # 描画用画像
        img=Image.new(&quot;1&quot;,(128,64),0)
        draw=ImageDraw.Draw(img)

        # グラフ設定
        width=128
        height=64

        top_margin=13
        bottom_margin=0
        left_margin=22
        right_margin=0

        inner_margin=3

        graph_width=width-left_margin-right_margin
        graph_height=height-top_margin-bottom_margin

        # 現在価格
        draw.text((28,0),f&quot;BTC:{formatted_price}円&quot;,font=font,fill=1)

        # 目盛
        draw.text((0,10),formatted_max_price,font=font_s,fill=1)
        draw.text((0,33),formatted_median_price,font=font_s,fill=1)
        draw.text((0,55),formatted_min_price,font=font_s,fill=1)

        # グラフ
        for i in range(1,len(prices)):

            x1=left_margin+inner_margin+(i-1)*(
                (graph_width-inner_margin*2)/(len(prices)-1)
            )

            y1=top_margin+inner_margin+(
                graph_height-inner_margin*2
            )-(
                (prices[i-1]-min_price)
                /(max_price-min_price)
                *(graph_height-inner_margin*2)
            )

            x2=left_margin+inner_margin+i*(
                (graph_width-inner_margin*2)/(len(prices)-1)
            )

            y2=top_margin+inner_margin+(
                graph_height-inner_margin*2
            )-(
                (prices[i]-min_price)
                /(max_price-min_price)
                *(graph_height-inner_margin*2)
            )

            draw.line((x1,y1,x2,y2),fill=1)

        # 枠線
        draw.rectangle(
            [
                left_margin,
                top_margin,
                left_margin+graph_width-1,
                top_margin+graph_height-1
            ],
            outline=1
        )

        # 横中央点線
        middle_y=top_margin+graph_height/2

        draw_dotted_line(
            draw,
            (left_margin,middle_y),
            (width-right_margin-1,middle_y)
        )

        # 縦点線
        third_x1=left_margin+graph_width/3
        third_x2=left_margin+graph_width*2/3

        draw_dotted_line(
            draw,
            (third_x1,top_margin),
            (third_x1,height-bottom_margin-1)
        )

        draw_dotted_line(
            draw,
            (third_x2,top_margin),
            (third_x2,height-bottom_margin-1)
        )

        # OLEDへ転送
        send(1,image_to_buffer(img))

        # 取得時刻表示
        now=datetime.now()
        print(f&quot;取得時刻: {now.strftime(&#39;%Y-%m-%d %H:%M:%S&#39;)}&quot;)

        # 10分待機
        time.sleep(600)

except Exception as e:
    print(e)

except KeyboardInterrupt:
    pass

finally:
    lgpio.gpiochip_close(h)
    spi.close()</code></pre></div>



<p class="wp-block-paragraph">まず、CoinGeckoのAPIから過去80日間のビットコイン価格データを日本円単位で取得します。データを受け取った後、最小価格、最大価格、中央値を計算し、軸の目盛の数値として表示する準備をします。さらに、最新の価格を整形してグラフ上部に表示します。</p>



<p class="wp-block-paragraph">グラフの表示エリアは、ディスプレイのサイズに基づいて計算され、適切なマージンを設定して内部にグラフを描画します。価格データは線グラフとして描かれ、各点は連続して接続されます。グラフの外側には枠が描かれ、縦横の中間点に点線が引かれます。</p>



<p class="wp-block-paragraph"><code>time.sleep(600)</code>は、プログラムがデータを取得してから次のデータ取得まで10分間待つように設定しています。<span class="sbd-text-bg-yellow">この待機時間を極端に短くすると、CoinGeckoのAPIサーバーへのアクセスが頻繁になりすぎてしまいます。</span>自動で情報収集する場合は、相手側のサーバーに過度な負荷をかけないよう注意が必要です。</p>



<h2 class="wp-block-heading">６枚の透明ディスプレイを同時に制御</h2>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/04/IMG_8940.jpeg" alt="" class="wp-image-4"/><figcaption class="wp-element-caption">6枚のディスプレイに気象情報を表示</figcaption></figure>



<p class="wp-block-paragraph">魅力的な透明ディスプレイですが、サイズが小さいのが難点です。一度に表示できる情報が限られ、見た目の迫力も今ひとつ。現時点では、大型の透明ディスプレイは手に入りません。</p>



<div class="wp-block-sbd-balloon sbd-balloon sbd-balloon--id-4 sbd-balloon--flat sbd-balloon--l sbd-balloon--green block-box"><div class="sbd-balloon__profile"><figure class="sbd-balloon__icon"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/09/アイコン.jpg" alt="そぞら" class="sbd-balloon__img"/></figure><div class="sbd-balloon__name">そぞら</div></div><div class="sbd-balloon__text-box sbd-inner-block-init">
<p class="wp-block-paragraph">そこで考えたのが、複数の透明ディスプレイを組み合わせて使うというアイデアです。</p>
</div></div>



<p class="wp-block-paragraph">今回はこの仕組みを使って、気温や湿度、気圧、降水量などの気象情報をリアルタイムに表示する装置を作成しました。</p>



<h3 class="wp-block-heading">スタンドの作成</h3>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/04/スクリーンショット-2025-05-13-19.47.55.png" alt="" class="wp-image-4" style="width:477px;height:auto"/><figcaption class="wp-element-caption">3D CADで設計したスタンド</figcaption></figure>



<p class="wp-block-paragraph">まずは、パソコンのマルチディスプレイのように6枚の透明ディスプレイを並べて設置するためのスタンドを、3Dプリンターで作成しました。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/04/IMG_8900.jpeg" alt="" class="wp-image-4" style="width:476px;height:auto"/></figure>



<p class="wp-block-paragraph"><br>このデザインは、NEKOPLAさんが公開されている作品「<a href="https://note.com/nekopla/n/n00a80ff21389">株トレーダーみたいなミニチュア机</a>」から影響を受けています。圧倒的な完成度と遊び心に惹かれ、その世界観を取り入れたいと思いました。</p>



<p class="wp-block-paragraph">作品紹介ページ（NEKOPLAさん）：<a href="https://note.com/nekopla/n/n00a80ff21389">https://note.com/nekopla/n/n00a80ff21389</a></p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/04/IMG_8894.jpeg" alt="" class="wp-image-4" style="width:479px;height:auto"/><figcaption class="wp-element-caption">試作品（４枚バージョンのスタンド）</figcaption></figure>



<h3 class="wp-block-heading">配線</h3>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="597" src="https://sozorablog.com/wp-content/uploads/2024/04/IMG_8942.jpeg" alt="" class="wp-image-14640" style="width:474px;height:auto"/></figure>



<p class="wp-block-paragraph">6枚の透明ディスプレイはすべてSPI接続です。SPI通信は共通のクロックやデータライン（SCLK, MOSI）を共有できますが、CSピンを分けることで1枚ずつ選択して制御できます。</p>



<p class="wp-block-paragraph">SCLKとMOSIは共通にして、CS（チップセレクト）、DC（データ/コマンド）、RST（リセット）はディスプレイごとに個別のGPIOピンに割り当てました。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/04/IMG_8931.jpeg" alt="" class="wp-image-4" style="width:454px;height:auto"/></figure>



<p class="wp-block-paragraph">CSピンはGPIO 21, 7, 22, 18, 12, 16、DCピンはGPIO 25, 24, 5, 13, 20, 2、RSTピンはGPIO 27, 23, 6, 19, 26, 3を使用しています。電源（3V3）とGNDは全ディスプレイで共通です。</p>



<div class="wp-block-sbd-checkpoint-block"><p class="sbd-checkpoint-title">チェックポイント</p><div class="sbd-checkpoint-content sbd-inner-block-init"><p>当初、ディスプレイ1のCSピンにはGPIO 8を割り当てていました。1枚だけを接続している状態では問題なく動作しましたが、ディスプレイを追加したところ、他のディスプレイを更新するたびに、GPIO 8を使っているディスプレイの表示が上書きされる現象が発生しました。</p><p>GPIO 8はのSPI0のCS0ピンとしてハードウェア的に制御されており、その影響で意図しないタイミングで選択状態になることが原因と思われます。そこで、ディスプレイ1のCSピンをGPIO 21に変更したところ、不具合が解消されました。</p></div></div>



<h3 class="wp-block-heading">表示テスト</h3>



<p class="wp-block-paragraph">次のコードは6枚のOLEDディスプレイをRaspberry PiにSPI接続し、それぞれに1〜6の番号を表示するものです。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>import RPi.GPIO as GPIO
from luma.oled.device import ssd1306
from luma.core.interface.serial import spi
from PIL import Image, ImageDraw, ImageFont

# ====== GPIO設定（6枚分）======
CS_PINS  = [21, 7, 22, 18, 12, 16]
DC_PINS  = [25, 24, 5, 13, 20, 2]
RST_PINS = [27, 23, 6, 19, 26, 3]

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)

for cs in CS_PINS:
    GPIO.setup(cs, GPIO.OUT)
    GPIO.output(cs, GPIO.HIGH)

# ====== OLEDインスタンスの初期化 ======
devices = []
for i in range(6):
    GPIO.output(CS_PINS[i], GPIO.LOW)
    serial = spi(port=0, device=0, gpio_DC=DC_PINS[i], gpio_RST=RST_PINS[i])
    device = ssd1306(serial)
    devices.append(device)
    GPIO.output(CS_PINS[i], GPIO.HIGH)

# ====== フォント設定 ======
font_path = &quot;/usr/share/fonts/truetype/takao-gothic/TakaoGothic.ttf&quot;
font = ImageFont.truetype(font_path, 68)

# ====== 表示（白背景に黒文字）======
for i in range(6):
    for cs in CS_PINS:
        GPIO.output(cs, GPIO.HIGH)
    GPIO.output(CS_PINS[i], GPIO.LOW)
    image = Image.new(&#39;1&#39;, (128, 64), color=0)
    draw = ImageDraw.Draw(image)
    draw.text((50, 0), str(i+1), font=font, fill=255)
    devices[i].display(image)
    GPIO.output(CS_PINS[i], GPIO.HIGH)

# 全て非選択に戻す
for cs in CS_PINS:
    GPIO.output(cs, GPIO.HIGH)</code></pre></div>



<p class="wp-block-paragraph">まず、CS（チップセレクト）、DC（データ／コマンド切り替え）、RST（リセット）用のGPIOピンをそれぞれ6枚分用意して設定します。</p>



<p class="wp-block-paragraph">次に、各ディスプレイについて、個別にCSピンをアクティブにして初期化を行い、<code>devices</code> リストにインスタンスとして保存します。続いて、各ディスプレイを順番に選択し、1〜6の番号を表示します。すべての表示が終わったら、CSピンをすべて非アクティブに戻して終了します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/04/IMG_8901.jpeg" alt="" class="wp-image-4" style="width:501px;height:auto"/></figure>



<p class="wp-block-paragraph">6枚のOLEDそれぞれに異なる番号が表示できることを確認できました。</p>



<h3 class="wp-block-heading">複数ディスプレイを使った動きのある表示の制御</h3>



<p class="wp-block-paragraph">文字のスクロールやアニメーションなど、動きのある表示をディスプレイごとに個別に制御する必要があります。先ほどの表示確認用のコードでは、1〜6の数字を表示するだけでしたが、ここでは動きのある表示が可能かどうかをテストします。</p>



<p class="wp-block-paragraph">次のコードではそれぞれのディスプレイに異なる種類の文字を割り当て、スレッドを使って<strong>非同期で表示内容を切り替えていきます</strong>。</p>



<div class="wp-block-sbd-balloon sbd-balloon sbd-balloon--id-4 sbd-balloon--flat sbd-balloon--l sbd-balloon--green block-box"><div class="sbd-balloon__profile"><figure class="sbd-balloon__icon"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/09/アイコン.jpg" alt="そぞら" class="sbd-balloon__img"/></figure><div class="sbd-balloon__name">そぞら</div></div><div class="sbd-balloon__text-box sbd-inner-block-init">
<p class="wp-block-paragraph">スレッドとは、1つのプログラムの中で複数の処理を並行して実行できる仕組みのことです。</p>
</div></div>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>import RPi.GPIO as GPIO
from luma.oled.device import ssd1306
from luma.core.interface.serial import spi
from luma.core.render import canvas
from PIL import ImageFont
import time
import threading

# GPIO定義
CS_PINS  = [21, 7, 22, 18, 12, 16]
DC_PINS  = [25, 24, 5, 13, 20, 2]
RST_PINS = [27, 23, 6, 19, 26, 3]

# 初期化
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
for pin in CS_PINS:
    GPIO.setup(pin, GPIO.OUT)
    GPIO.output(pin, GPIO.HIGH)

devices = []
for i in range(6):
    GPIO.output(CS_PINS[i], GPIO.LOW)
    serial = spi(port=0, device=0, gpio_DC=DC_PINS[i], gpio_RST=RST_PINS[i])
    devices.append(ssd1306(serial))
    GPIO.output(CS_PINS[i], GPIO.HIGH)

# フォント
font_path = &quot;/usr/share/fonts/truetype/takao-gothic/TakaoGothic.ttf&quot;
font = ImageFont.truetype(font_path, 60)

# SPIロック
lock = threading.Lock()

# 共通処理
def draw_centered_text(draw, device_index, char):
    bbox = draw.textbbox((0, 0), char, font=font)
    w = bbox[2] - bbox[0]
    h = bbox[3] - bbox[1]
    draw.text(((128 - w)//2, (64 - h)//2), char, font=font, fill=255)

# 各ディスプレイごとのスレッド処理
def display0_thread():
    chars = list(&quot;0123456789&quot;)
    pos = 0
    while True:
        char = chars[pos % len(chars)]
        with lock:
            GPIO.output(CS_PINS[0], GPIO.LOW)
            with canvas(devices[0]) as draw:
                draw_centered_text(draw, 0, char)
            GPIO.output(CS_PINS[0], GPIO.HIGH)
        pos += 1
        time.sleep(1)

def display1_thread():
    chars = list(&quot;ABCDEFGHIJKLMNOPQRSTUVWXYZ&quot;)
    pos = 0
    while True:
        char = chars[pos % len(chars)]
        with lock:
            GPIO.output(CS_PINS[1], GPIO.LOW)
            with canvas(devices[1]) as draw:
                draw_centered_text(draw, 1, char)
            GPIO.output(CS_PINS[1], GPIO.HIGH)
        pos += 1
        time.sleep(0.5)

def display2_thread():
    chars = list(&quot;あいうえおかきくけこ&quot;)
    pos = 0
    while True:
        char = chars[pos % len(chars)]
        with lock:
            GPIO.output(CS_PINS[2], GPIO.LOW)
            with canvas(devices[2]) as draw:
                draw_centered_text(draw, 2, char)
            GPIO.output(CS_PINS[2], GPIO.HIGH)
        pos += 1
        time.sleep(0.3)

def display3_thread():
    chars = list(&quot;漢字東京大阪明日元気&quot;)
    pos = 0
    while True:
        char = chars[pos % len(chars)]
        with lock:
            GPIO.output(CS_PINS[3], GPIO.LOW)
            with canvas(devices[3]) as draw:
                draw_centered_text(draw, 3, char)
            GPIO.output(CS_PINS[3], GPIO.HIGH)
        pos += 1
        time.sleep(0.1)

def display4_thread():
    chars = list(&quot;♠♥♦♣★☆♪☀☁☂&quot;)
    pos = 0
    while True:
        char = chars[pos % len(chars)]
        with lock:
            GPIO.output(CS_PINS[4], GPIO.LOW)
            with canvas(devices[4]) as draw:
                draw_centered_text(draw, 4, char)
            GPIO.output(CS_PINS[4], GPIO.HIGH)
        pos += 1
        time.sleep(0.7)

def display5_thread():
    chars = list(&quot;←→↑↓◎◉◇◆■□&quot;)
    pos = 0
    while True:
        char = chars[pos % len(chars)]
        with lock:
            GPIO.output(CS_PINS[5], GPIO.LOW)
            with canvas(devices[5]) as draw:
                draw_centered_text(draw, 5, char)
            GPIO.output(CS_PINS[5], GPIO.HIGH)
        pos += 1
        time.sleep(0.5)

# スレッド起動
threads = [
    threading.Thread(target=display0_thread),
    threading.Thread(target=display1_thread),
    threading.Thread(target=display2_thread),
    threading.Thread(target=display3_thread),
    threading.Thread(target=display4_thread),
    threading.Thread(target=display5_thread),
]
for t in threads:
    t.start()

try:
    for t in threads:
        t.join()
except KeyboardInterrupt:
    GPIO.cleanup()
</code></pre></div>



<p class="wp-block-paragraph">今回は6枚のディスプレイのSCLKとMOSIを共通にして接続しているため、同時に複数のディスプレイに命令を送ると信号が混ざり、表示が乱れる可能性があります。そこで「ロック処理」と呼ばれる仕組みを使い、他の処理が終わるまで一時的に待機させることで、1つのディスプレイに対して順番に安全に通信を行えるようにしています。ロックを使うことで、複数の処理が同時にSPI信号を使おうとしても衝突しないように制御しています。</p>



<p class="wp-block-paragraph">コードを実行すると、6枚のOLEDディスプレイにそれぞれ異なる種類の文字（数字、英字、ひらがな、漢字、記号、矢印など）が表示され、<strong>各ディスプレイごとに設定された異なる間隔で</strong>次々に切り替わっていきます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="589" src="https://sozorablog.com/wp-content/uploads/2024/04/IMG_8941.jpeg" alt="" class="wp-image-14639" style="width:458px;height:auto"/></figure>



<p class="wp-block-paragraph">ロック処理による待機は体感的には気にならないレベルであり、6枚のディスプレイそれぞれに異なる動きのある表示を行えることを確認できました。</p>



<h3 class="wp-block-heading">OpenWeatherMapのAPIキーを取得</h3>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2024/04/openweathrer1.jpg" alt="" class="wp-image-4" style="width:840px;height:auto"/><figcaption class="wp-element-caption"><a href="https://openweathermap.org/">OpenWeatherMap</a></figcaption></figure>



<p class="wp-block-paragraph">気象情報は<a href="https://openweathermap.org/">OpenWeatherMap</a>からAPIを使って取得します。OpenWeatherMapは、世界中の天気・気象データを提供しているサービスで、「<a href="https://openweathermap.org/price">Free Access（無料アクセス）</a>」という形で<strong>無料でも利用できます</strong>。無料利用枠では<strong>1日あたり1,000件、1分あたり60件までのリクエスト</strong>が可能です。</p>



<p class="wp-block-paragraph">APIを使うには、<a href="https://openweathermap.org/">公式サイト</a>で無料アカウントを作成します。画面右上の「Sign in」から「Create an Account」を選び、必要事項を入力して登録を進めます。登録後、入力したメールアドレスに確認メールが届くので、そこから認証を完了させてください。</p>



<p class="wp-block-paragraph">認証完了後、右上のアカウント名をクリックして「My API keys」セクションに進むと、デフォルトのAPIキーが表示されます。取得したAPIキーは、APIリクエストのパラメータとして使用します。</p>



<h3 class="wp-block-heading">6枚のOLEDディスプレイに気象データを表示</h3>



<p class="wp-block-paragraph">次のコードは6枚のOLEDディスプレイを使って、天気に関するさまざまな情報を表示するプログラムです。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>import RPi.GPIO as GPIO
from luma.oled.device import ssd1306
from luma.core.interface.serial import spi
from luma.core.render import canvas
from PIL import Image, ImageDraw, ImageFont
import time
import threading
from math import sin, cos, radians
import requests
from datetime import datetime, timedelta
from bs4 import BeautifulSoup

# 気象データ共有クラス
class WeatherDataStore:
    def __init__(self):
        self.lock = threading.Lock()
        self.temps = []
        self.pressures = []
        self.humidities = []
        self.rains = []
        self.icon_code = &quot;&quot;
        self.summary = &quot;&quot;

    def update(self, temps, pressures, humidities, rains, summary=&quot;&quot;):
        with self.lock:
            self.temps = temps
            self.pressures = pressures
            self.humidities = humidities
            self.rains = rains
            self.summary = summary            

    def get_data(self):
        with self.lock:
            return (
                self.temps[:],
                self.pressures[:],
                self.humidities[:],
                self.rains[:],
                self.summary
            )            


# インスタンス作成（全スレッドで共有）
weather_store = WeatherDataStore()

# データ取得スレッド
def weather_fetch_thread():
    api_key = &#39;OPENWEATHERMAP_API_KEY&#39;# OpenWeatherMap の APIキー ※ 自分のAPIキーに置き換えてください。
    city = &#39;Shizuoka,JP&#39; # 天気予報を取得したい都市（&quot;都市名,国コード&quot; の形式）
    url = &#39;https://api.openweathermap.org/data/2.5/forecast&#39;
    params = {&#39;q&#39;: city, &#39;appid&#39;: api_key, &#39;units&#39;: &#39;metric&#39;, &#39;lang&#39;: &#39;en&#39;}
    
    pref_name = &quot;静岡&quot;  # 気象庁の天気概況（日本語の天気概要）取得に使用する都道府県名

    while True:
        try:
            res = requests.get(url, params=params)
            data = res.json()
            temps = [e[&#39;main&#39;][&#39;temp&#39;] for e in data[&#39;list&#39;][:16]]
            pressures = [e[&#39;main&#39;][&#39;pressure&#39;] for e in data[&#39;list&#39;][:16]]
            humidities = [e[&#39;main&#39;][&#39;humidity&#39;] for e in data[&#39;list&#39;][:16]]
            rains = [e.get(&#39;rain&#39;, {}).get(&#39;3h&#39;, 0.0) for e in data[&#39;list&#39;][:16]]
            
            summary_text = &quot;&quot;
            try:
                feed_url = &quot;https://www.data.jma.go.jp/developer/xml/feed/regular.xml&quot;
                feed_res = requests.get(feed_url)
                soup = BeautifulSoup(feed_res.content, &quot;xml&quot;)

                for entry in soup.find_all(&quot;entry&quot;):
                    if entry.find(&quot;title&quot;).text.strip() != &quot;府県天気概況&quot;:
                        continue

                    xml_url = entry.find(&quot;link&quot;)[&quot;href&quot;]
                    xml_res = requests.get(xml_url)
                    xml_soup = BeautifulSoup(xml_res.content, &quot;xml&quot;)

                    target_area = xml_soup.find(&quot;TargetArea&quot;)
                    if target_area and pref_name in target_area.text:
                        text_tag = xml_soup.find(&quot;Text&quot;, {&quot;type&quot;: &quot;本文&quot;})
                        if text_tag:
                            full_text = text_tag.text.strip()
                            if &quot;【&quot; in full_text:
                                summary_text = full_text.split(&quot;【&quot;)[0].strip()
                            else:
                                summary_text = full_text
                        break            

            except Exception as e:
                print(&quot;天気概況取得エラー:&quot;, e)

            weather_store.update(
                temps=temps,
                pressures=pressures,
                humidities=humidities,
                rains=rains,
                summary=summary_text
            )
            
            print(&quot;データ取得完了&quot;)
        except Exception as e:
            print(&quot;取得エラー:&quot;, e)
            
        time.sleep(3600)  # 1時間ごと
        
def draw_dotted_line(draw, start, end, interval=3, dot_length=1):
    x1, y1 = start
    x2, y2 = end
    total_length = ((x2 - x1) ** 2 + (y2 - y1) ** 2) ** 0.5
    num_dots = int(total_length / interval)

    for i in range(num_dots):
        dot_start = i * interval + (interval - dot_length) / 2
        dot_end = dot_start + dot_length
        dot_start_x = x1 + (x2 - x1) * (dot_start / total_length)
        dot_start_y = y1 + (y2 - y1) * (dot_start / total_length)
        dot_end_x = x1 + (x2 - x1) * (dot_end / total_length)
        dot_end_y = y1 + (y2 - y1) * (dot_end / total_length)
        draw.line([(dot_start_x, dot_start_y), (dot_end_x, dot_end_y)], fill=&quot;white&quot;)        

# ====== GPIO設定（6枚分）======
CS_PINS  = [21, 7, 22, 18, 12, 16]
DC_PINS  = [25, 24, 5, 13, 20, 2]
RST_PINS = [27, 23, 6, 19, 26, 3]

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
for pin in CS_PINS:
    GPIO.setup(pin, GPIO.OUT)
    GPIO.output(pin, GPIO.HIGH)

# デバイス初期化
devices = []
for i in range(6):
    GPIO.output(CS_PINS[i], GPIO.LOW)
    serial = spi(port=0, device=0, gpio_DC=DC_PINS[i], gpio_RST=RST_PINS[i])
    devices.append(ssd1306(serial))
    GPIO.output(CS_PINS[i], GPIO.HIGH)

font_path = &quot;/usr/share/fonts/truetype/takao-gothic/TakaoGothic.ttf&quot;
font = ImageFont.truetype(font_path, 10)
font_s = ImageFont.truetype(font_path, 8)
        
lock = threading.Lock()

# Display 1: アニメーション
def display1_thread():
    font1 = ImageFont.truetype(font_path, 13)
    font2 = ImageFont.truetype(font_path, 15)
    font3 = ImageFont.truetype(font_path, 25)

    scale_factor = 0.7
    x_offset = 25
    Y_CENTER = 32

    pyramid = ((0, -20, 0), (-20, 20, -20), (20, 20, -20), (0, 20, 20))

    while True:
        for angle in range(0, 361, 10):
            now = datetime.now()
            date1 = now.strftime(&#39;%b %-d&#39;)
            weekday = now.strftime(&#39;%a&#39;).upper()
            time1 = now.strftime(&#39;%H:%M&#39;)
            second = now.strftime(&#39;%S&#39;)
            f = [[0.0, 0.0] for _ in range(4)]
            r = radians(angle)

            for i in range(4):
                x1 = pyramid[i][2] * sin(r) + pyramid[i][0] * cos(r)
                ya = pyramid[i][1]
                z1 = pyramid[i][2] * cos(r) - pyramid[i][0] * sin(r)
                y2 = ya * cos(r) - z1 * sin(r)
                x3 = (x1 * cos(r) - y2 * sin(r)) * scale_factor + x_offset
                y3 = (x1 * sin(r) + y2 * cos(r)) * scale_factor + Y_CENTER
                f[i] = [x3, y3]

            with lock:
                GPIO.output(CS_PINS[0], GPIO.LOW)
                with canvas(devices[0]) as draw:
                    for i in range(3):
                        draw.line((f[0][0], f[0][1], f[i+1][0], f[i+1][1]), fill=&quot;white&quot;)
                        draw.line((f[i+1][0], f[i+1][1], f[(i+1)%3+1][0], f[(i+1)%3+1][1]), fill=&quot;white&quot;)

                    draw.text((46, 5), date1, font=font2, fill=&quot;white&quot;)
                    draw.text((100, 5), weekday, font=font2, fill=&quot;white&quot;)
                    draw.text((46, 29), time1, font=font3, fill=&quot;white&quot;)
                    draw.text((114, 38), second, font=font1, fill=&quot;white&quot;)
                GPIO.output(CS_PINS[0], GPIO.HIGH)

            time.sleep(0.1)

# Display 2: 
def display2_thread():
    while True:
        try:
            _, _, humidities, _, _ = weather_store.get_data()
            if not humidities:
                time.sleep(1)
                continue

            values = humidities
            title = &quot;Humidity (%)&quot;

            # 湿度は0〜100に固定
            min_v = 0
            max_v = 100

            width = devices[1].width
            height = devices[1].height
            margin = 5
            left_label_width = 16
            bottom_label_height = 10
            top_padding = 10

            graph_width = width - margin - left_label_width
            graph_height = height - margin - bottom_label_height - top_padding
            step_x = graph_width / (len(values) - 1)
            fixed_lines = 5

            with lock:
                GPIO.output(CS_PINS[1], GPIO.LOW)
                with canvas(devices[1]) as draw:
                    draw.text((margin + 20, 0), title, font=font, fill=255)

                    # 補助線とラベル（0〜100を等間隔に）
                    for i in range(fixed_lines):
                        ratio = i / (fixed_lines - 1)
                        label_value = max_v - ratio * (max_v - min_v)
                        y = int(top_padding + ratio * graph_height)
                        draw_dotted_line(draw, (left_label_width, y), (width - margin, y))
                        draw.text((0, y - 4), f&quot;{int(label_value)}&quot;, font=font_s, fill=255)

                    # 縦の点線（1/4、1/2、3/4）
                    for x in [
                        left_label_width + graph_width // 4,
                        left_label_width + graph_width // 2,
                        left_label_width + (graph_width * 3) // 4
                    ]:
                        draw_dotted_line(draw, (x, top_padding), (x, top_padding + graph_height))

                    # 折れ線グラフ（四捨五入しない）
                    for i in range(len(values) - 1):
                        x1 = int(left_label_width + i * step_x)
                        x2 = int(left_label_width + (i + 1) * step_x)
                        y1 = int(top_padding + (max_v - values[i]) / (max_v - min_v) * graph_height)
                        y2 = int(top_padding + (max_v - values[i + 1]) / (max_v - min_v) * graph_height)
                        draw.line((x1, y1, x2, y2), fill=255)

                    # グラフ枠線
                    draw.rectangle(
                        (left_label_width, top_padding, left_label_width + graph_width, top_padding + graph_height),
                        outline=255
                    )

                    # 横軸ラベル（仮で0d, 1d）
                    for i in range(2):
                        x = int(left_label_width + (i * 8 * step_x)) - 5
                        draw.text((x, height - bottom_label_height), f&quot;{i}d&quot;, font=font_s, fill=255)

                GPIO.output(CS_PINS[1], GPIO.HIGH)
            time.sleep(60)

        except Exception as e:
            print(f&quot;エラー in display1: {e}&quot;)
            time.sleep(60)    

# Display 3: 
def display3_thread():
    while True:
        try:
            _, pressures, _, _, _= weather_store.get_data()
            if not pressures:
                time.sleep(1)
                continue

            values = pressures
            title = &quot;Pressure (hPa)&quot;
            min_v = min(values)
            max_v = max(values)

            # 値の差に応じて余白（padding）を計算。ただし差が小さい場合は、最低5を確保する
            padding = max((max_v - min_v) * 0.1, 5)  
            min_v -= padding
            max_v += padding

            width = devices[2].width
            height = devices[2].height
            margin = 5
            left_label_width = 16
            bottom_label_height = 10
            top_padding = 10

            graph_width = width - margin - left_label_width
            graph_height = height - margin - bottom_label_height - top_padding
            step_x = graph_width / (len(values) - 1)
            fixed_lines = 5

            with lock:
                GPIO.output(CS_PINS[2], GPIO.LOW)
                with canvas(devices[2]) as draw:
                    draw.text((margin + 20, 0), title, font=font, fill=255)

                    for i in range(fixed_lines):
                        ratio = i / (fixed_lines - 1)
                        label_value = max_v - ratio * (max_v - min_v)
                        y = int(top_padding + ratio * graph_height)
                        draw_dotted_line(draw, (left_label_width, y), (width - margin, y))
                        draw.text((0, y - 4), f&quot;{int(label_value)}&quot;, font=font_s, fill=255)

                    quarter_x1 = left_label_width + graph_width // 4
                    center_x = left_label_width + graph_width // 2
                    quarter_x3 = left_label_width + (graph_width * 3) // 4

                    draw_dotted_line(draw, (quarter_x1, top_padding), (quarter_x1, top_padding + graph_height))
                    draw_dotted_line(draw, (center_x, top_padding), (center_x, top_padding + graph_height))
                    draw_dotted_line(draw, (quarter_x3, top_padding), (quarter_x3, top_padding + graph_height))

                    for i in range(len(values) - 1):
                        x1 = int(left_label_width + i * step_x)
                        x2 = int(left_label_width + (i + 1) * step_x)
                        y1 = int(top_padding + (max_v - values[i]) / (max_v - min_v) * graph_height)
                        y2 = int(top_padding + (max_v - values[i + 1]) / (max_v - min_v) * graph_height)
                        draw.line((x1, y1, x2, y2), fill=255)

                    draw.rectangle(
                        (left_label_width, top_padding, left_label_width + graph_width, top_padding + graph_height),
                        outline=255
                    )

                    for i in range(2):
                        x = int(left_label_width + (i * 8 * step_x)) - 5
                        draw.text((x, height - bottom_label_height), f&quot;{i}d&quot;, font=font_s, fill=255)

                GPIO.output(CS_PINS[2], GPIO.HIGH)

            time.sleep(60)

        except Exception as e:
            print(f&quot;エラー: {e}&quot;)
            time.sleep(60)

# Display 4:
def display4_thread():
    while True:
        try:
            temps, _, _, _, _= weather_store.get_data()
            if not temps:
                time.sleep(1)
                continue

            values = temps
            title = &quot;Temperature (°C)&quot;
            min_v = min(values)
            max_v = max(values)
            padding = (max_v - min_v) * 0.1
            min_v -= padding
            max_v += padding

            width = devices[3].width
            height = devices[3].height
            margin = 5
            left_label_width = 16
            bottom_label_height = 10
            top_padding = 10

            graph_width = width - margin - left_label_width
            graph_height = height - margin - bottom_label_height - top_padding
            step_x = graph_width / (len(values) - 1)
            fixed_lines = 5

            with lock:
                GPIO.output(CS_PINS[3], GPIO.LOW)
                with canvas(devices[3]) as draw:
                    draw.text((margin + 20, 0), title, font=font, fill=255)

                    for i in range(fixed_lines):
                        ratio = i / (fixed_lines - 1)
                        label_value = max_v - ratio * (max_v - min_v)
                        y = int(top_padding + ratio * graph_height)
                        draw_dotted_line(draw, (left_label_width, y), (width - margin, y))
                        draw.text((0, y - 4), f&quot;{round(label_value)}&quot;, font=font_s, fill=255)

                    quarter_x1 = left_label_width + graph_width // 4
                    center_x = left_label_width + graph_width // 2
                    quarter_x3 = left_label_width + (graph_width * 3) // 4

                    draw_dotted_line(draw, (quarter_x1, top_padding), (quarter_x1, top_padding + graph_height))
                    draw_dotted_line(draw, (center_x, top_padding), (center_x, top_padding + graph_height))
                    draw_dotted_line(draw, (quarter_x3, top_padding), (quarter_x3, top_padding + graph_height))

                    for i in range(len(values) - 1):
                        y1 = round(top_padding + (max_v - values[i]) / (max_v - min_v) * graph_height)
                        y2 = round(top_padding + (max_v - values[i + 1]) / (max_v - min_v) * graph_height)
                        x1 = int(left_label_width + i * step_x)
                        x2 = int(left_label_width + (i + 1) * step_x)
                        draw.line((x1, y1, x2, y2), fill=255)

                    draw.rectangle(
                        (left_label_width, top_padding, left_label_width + graph_width, top_padding + graph_height),
                        outline=255
                    )

                    for i in range(2):
                        x = int(left_label_width + (i * 8 * step_x)) - 5
                        draw.text((x, height - bottom_label_height), f&quot;{i}d&quot;, font=font_s, fill=255)

                GPIO.output(CS_PINS[3], GPIO.HIGH)

            time.sleep(60)  # 毎分更新で十分

        except Exception as e:
            print(f&quot;エラー in display4: {e}&quot;)
            time.sleep(60)
            
# Display 5:
def display5_thread():
    while True:
        try:
            _, _, _, rains, _ = weather_store.get_data()
            if not rains:
                time.sleep(1)
                continue

            values = rains
            title = &quot;Rainfall (mm)&quot;
            min_v = 0  # 降水量は 0 からスタート
            max_v = round(max(values + [0.0]) + 1.0)  # 最大値 + 1.0 mm

            width = devices[4].width
            height = devices[4].height
            margin = 5
            left_label_width = 16
            bottom_label_height = 10
            top_padding = 10

            graph_width = width - margin - left_label_width
            graph_height = height - margin - bottom_label_height - top_padding
            bar_width = graph_width / len(values)
            fixed_lines = 5

            with lock:
                GPIO.output(CS_PINS[4], GPIO.LOW)
                with canvas(devices[4]) as draw:
                    draw.text((margin + 20, 0), title, font=font, fill=255)

                    # 補助線とラベル
                    for i in range(fixed_lines):
                        ratio = i / (fixed_lines - 1)
                        label_value = max_v - ratio * (max_v - min_v)
                        y = int(top_padding + ratio * graph_height)
                        draw_dotted_line(draw, (left_label_width, y), (width - margin, y))
                        draw.text((0, y - 4), f&quot;{label_value:.1f}&quot;, font=font_s, fill=255)

                    # 縦の点線（1/4, 1/2, 3/4）
                    for x in [
                        left_label_width + graph_width // 4,
                        left_label_width + graph_width // 2,
                        left_label_width + (graph_width * 3) // 4
                    ]:
                        draw_dotted_line(draw, (x, top_padding), (x, top_padding + graph_height))

                    # 棒グラフ
                    for i, value in enumerate(values):
                        x = int(left_label_width + i * bar_width)
                        h = int((value - min_v) / (max_v - min_v) * graph_height)
                        y_top = top_padding + graph_height - h
                        y_bottom = top_padding + graph_height
                        draw.rectangle((x, y_top, x + int(bar_width) - 1, y_bottom), fill=255)

                    # 枠線
                    draw.rectangle(
                        (left_label_width, top_padding, left_label_width + graph_width, top_padding + graph_height),
                        outline=255
                    )

                    # 横軸ラベル（例：0d, 1d）
                    for i in range(2):
                        x = int(left_label_width + (i * 8 * bar_width)) - 5
                        draw.text((x, height - bottom_label_height), f&quot;{i}d&quot;, font=font_s, fill=255)

                GPIO.output(CS_PINS[4], GPIO.HIGH)

            time.sleep(60)

        except Exception as e:
            print(f&quot;エラー in display5: {e}&quot;)
            time.sleep(60)


# Display 6:
def display6_thread():
    font_news = ImageFont.truetype(font_path, 12)
    font_size_s = 12

    device = devices[5]

    top_margin = 5
    offset_x = 5
    line_height = font_size_s + 7
    text_area_width = device.width - offset_x + 14

    last_summary = &quot;&quot;

    while True:
        _, _, _, _, summary = weather_store.get_data()
        if not summary:
            time.sleep(1)
            continue
        last_summary = summary

        sentences = [s.strip() + &quot;。&quot; for s in summary.split(&quot;。&quot;) if s.strip()]

        for sentence in sentences:
            lines = []
            current_line = &quot;&quot;

            for char in sentence:
                test_line = current_line + char
                bbox = font_news.getbbox(test_line)
                line_width = bbox[2] - bbox[0]

                if line_width &gt; (text_area_width-12):
                    lines.append(current_line)
                    current_line = char
                else:
                    current_line = test_line

                # 最大2行＋current_lineまで
                display_lines = lines[-2:]

                image = Image.new(&quot;1&quot;, (device.width, device.height))
                draw = ImageDraw.Draw(image)

                text_y = top_margin
                for line in display_lines:
                    draw.text((offset_x, text_y), line, font=font_news, fill=&quot;white&quot;)
                    text_y += line_height
                draw.text((offset_x, text_y), current_line, font=font_news, fill=&quot;white&quot;)

                with lock:
                    GPIO.output(CS_PINS[5], GPIO.LOW)
                    device.display(image)
                    GPIO.output(CS_PINS[5], GPIO.HIGH)

                time.sleep(0.1)
            time.sleep(1)    

        time.sleep(0.1)

# スレッド起動
threads = [
    threading.Thread(target=weather_fetch_thread),
    threading.Thread(target=display1_thread),
    threading.Thread(target=display2_thread),
    threading.Thread(target=display3_thread),
    threading.Thread(target=display4_thread),
    threading.Thread(target=display5_thread),
    threading.Thread(target=display6_thread),
]    

for t in threads:
    t.start()

try:
    for t in threads:
        t.join()
except KeyboardInterrupt:
    GPIO.cleanup()</code></pre></div>



<p class="wp-block-paragraph">OpenWeatherMapのAPIから静岡市の3時間ごとの天気予報を取得し、その中から16件（48時間分）の温度・湿度・気圧・降水量を抽出して、それぞれグラフで表示します。折れ線グラフでは、各データ点の数値を縦方向の位置に変換し、隣り合う点を線でつなぐことで変化の流れを表現しています。</p>



<p class="wp-block-paragraph">また、気象庁が提供するXML形式のデータから静岡県の天気概況のテキストを取得し、スクロール表示します。これらのデータは1時間ごとに自動で更新されます。</p>



<p class="wp-block-paragraph">各ディスプレイは個別のスレッドで制御されており、時刻表示には3Dピラミッド風のアニメーションも含まれています。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="502" src="https://sozorablog.com/wp-content/uploads/2024/04/IMG_8938.jpeg" alt="" class="wp-image-14602" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph">プログラムを応用すれば、表示する内容を自由に変更できます。たとえば、ニュースの見出しやビットコインの価格、CPUの状態などを表示することも可能です。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="545" src="https://sozorablog.com/wp-content/uploads/2024/04/IMG_8908.jpeg" alt="" class="wp-image-14638" style="width:840px;height:auto"/></figure>



<h2 class="wp-block-heading">6枚のディスプレイでスクロール表示</h2>



<figure class="wp-block-image size-full"><img decoding="async" width="250" height="200" src="https://sozorablog.com/wp-content/uploads/2024/04/Videotogif-2.gif" alt="" class="wp-image-15382"/></figure>



<p class="wp-block-paragraph">透明ディスプレイを6枚リング状に並べて、株価がぐるぐる回る「<a href="https://www.jpx.co.jp/corporate/learning/tour/arrows/05.html">東証チッカー</a>風ディスプレイ」を作ってみました。透明ディスプレイは裏側からも表示が透けて見えるため、表と裏に画面があるような視覚効果も楽しめます。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="533" src="https://sozorablog.com/wp-content/uploads/2024/04/tosyo.jpg" alt="" class="wp-image-15384"/><figcaption class="wp-element-caption">東証チッカーのイメージ</figcaption></figure>



<p class="wp-block-paragraph">Raspberry Piとディスプレイの接続方法は先ほどと同じです。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="459" src="https://sozorablog.com/wp-content/uploads/2024/04/3d-cad.png" alt="" class="wp-image-15383"/></figure>



<p class="wp-block-paragraph">ベース部分は3Dプリンターで作成しました。</p>



<p class="wp-block-paragraph">次のコードは、透明ディスプレイを6枚使って株価情報をスクロール表示する仕組みを実装したものです。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>import yfinance as yf
import time
import RPi.GPIO as GPIO
from luma.oled.device import ssd1306
from luma.core.interface.serial import spi
from PIL import Image, ImageDraw, ImageFont
import unicodedata

# ====== GPIOピンの設定 ======
CS_PINS  = [21, 7, 22, 18, 12, 16]
DC_PINS  = [25, 24, 5, 13, 20, 2]
RST_PINS = [27, 23, 6, 19, 26, 3]

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
for cs in CS_PINS:
    GPIO.setup(cs, GPIO.OUT)
    GPIO.output(cs, GPIO.HIGH)

# ====== フォント（24px） ======
font_path = &quot;/usr/share/fonts/truetype/takao-gothic/TakaoGothic.ttf&quot;
font = ImageFont.truetype(font_path, 24)

devices = []

for i in range(6):
    GPIO.output(CS_PINS[i], GPIO.LOW)
    serial = spi(port=0, device=0, gpio_DC=DC_PINS[i], gpio_RST=RST_PINS[i])
    device = ssd1306(serial)
    devices.append(device)
    GPIO.output(CS_PINS[i], GPIO.HIGH)

companies = {
    &quot;9432.T&quot;: &quot;NTT&quot;,
    &quot;8035.T&quot;: &quot;東京エレクトロン&quot;,    
    &quot;6902.T&quot;: &quot;デンソー&quot;,
    &quot;4063.T&quot;: &quot;信越化学&quot;,
    &quot;6367.T&quot;: &quot;ダイキン&quot;,
    &quot;7203.T&quot;: &quot;トヨタ&quot;,
    &quot;6758.T&quot;: &quot;ソニー&quot;,
    &quot;9984.T&quot;: &quot;ソフトバンク&quot;,
    &quot;8306.T&quot;: &quot;三菱UFJ&quot;,
    &quot;6861.T&quot;: &quot;キーエンス&quot;,
    &quot;6098.T&quot;: &quot;リクルート&quot;,
    &quot;^N225&quot;: &quot;日経平均&quot;
}

# ====== 表示サイズと余白 ======
name_width = 70
price_width = 70
diff_width = 70
gap = 0
block_width = name_width + price_width + diff_width + gap

display_width = 128 * len(devices)
display_height = 64

# ====== 描画準備 ======
dummy_img = Image.new(&quot;1&quot;, (1, 1))
dummy_draw = ImageDraw.Draw(dummy_img)

# データ取得と描画領域の計算
stock_data = []
for ticker, name in companies.items():
    stock = yf.Ticker(ticker)
    price = int(stock.fast_info[&quot;lastPrice&quot;])
    prev_close = int(stock.fast_info[&quot;previousClose&quot;])
    diff = price - prev_close
    sign = &quot;+&quot; if diff &gt;= 0 else &quot;-&quot;
    diff_text = f&quot;{sign}{abs(diff)}&quot;
    stock_data.append((name, str(price), diff_text))

canvas_width = len(stock_data) * block_width
image = Image.new(&quot;1&quot;, (canvas_width, display_height))
draw = ImageDraw.Draw(image)

# 各行を右揃えで描画
x = 0
for name, price, diff in stock_data:
    name_x = x + name_width - dummy_draw.textbbox((0, 0), name, font=font)[2]
    price_x = x + price_width - dummy_draw.textbbox((0, 0), price, font=font)[2]
    diff_x = x + diff_width - dummy_draw.textbbox((0, 0), diff, font=font)[2]

    draw.text((name_x, 0), name, font=font, fill=255)
    draw.text((price_x, 21), price, font=font, fill=255)
    draw.text((diff_x, 42), diff, font=font, fill=255)

    x += block_width

# ====== スクロール範囲 ======
scroll_width = canvas_width
start_offset = -display_width
end_offset = scroll_width

# ====== 無限スクロールループ ======
while True:
    for offset in range(start_offset, end_offset, 2):
        for i in range(len(devices)):
            for cs in CS_PINS:
                GPIO.output(cs, GPIO.HIGH)
            GPIO.output(CS_PINS[i], GPIO.LOW)

            right_index = len(devices) - 1 - i
            x_start = offset + right_index * 128
            x_end = x_start + 128
            frame = image.crop((x_start, 0, x_end, display_height))

            devices[i].display(frame)
            GPIO.output(CS_PINS[i], GPIO.HIGH)

        time.sleep(0.01)</code></pre></div>



<p class="wp-block-paragraph">表示する銘柄はNTTやトヨタ、ソフトバンクなど、日本の代表的な企業10社と日経平均をリスト化しています。<code>yfinance</code>ライブラリを使って、それぞれの株価と前日比を取得し、銘柄名・株価・差額を並べた画像を1枚の大きなキャンバスとして描画します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="774" src="https://sozorablog.com/wp-content/uploads/2024/04/IMG_9205.jpeg" alt="" class="wp-image-15388" style="width:513px;height:auto"/></figure>



<p class="wp-block-paragraph">描画後は、6枚のディスプレイに表示させる部分を左右に少しずつずらしながら切り出して表示することで、全体がリング状にスクロールしているような演出を実現しています。スクロールは高速でループしており、株価が絶えず回転して見えるようになっています。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://sozorablog.com/pi-transparent-oled/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
			</item>
		<item>
		<title>【ラズパイIoT活用】Blynkで外出先からエアコンを操作しよう</title>
		<link>https://sozorablog.com/blynk/</link>
					<comments>https://sozorablog.com/blynk/#respond</comments>
		
		<dc:creator><![CDATA[そぞら]]></dc:creator>
		<pubDate>Mon, 11 Mar 2024 06:08:55 +0000</pubDate>
				<category><![CDATA[Raspberry Pi]]></category>
		<category><![CDATA[使い方]]></category>
		<guid isPermaLink="false">https://sozorablog.com/?p=11954</guid>

					<description><![CDATA[Raspberry PiとBlynkアプリを使って、どこからでもエアコンの運転操作が行えるシステムの構築方法について解説します。このシステムを使えば、外出先から家のエアコンを運転できるようになり、帰宅前に室温を快適に設定 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><a href="https://sozorablog.com/raspberry-pi/">Raspberry Pi</a>と<a href="https://blynk.io/">Blynkアプリ</a>を使って、<span class="sbd-text-bg-yellow">どこからでもエアコンの運転操作が行える</span>システムの構築方法について解説します。このシステムを使えば、外出先から家のエアコンを運転できるようになり、帰宅前に室温を快適に設定することが可能です。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="450" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk52-1.png" alt="" class="wp-image-12080" srcset="https://sozorablog.com/wp-content/uploads/2024/03/blynk52-1.png 800w, https://sozorablog.com/wp-content/uploads/2024/03/blynk52-1-320x180.png 320w, https://sozorablog.com/wp-content/uploads/2024/03/blynk52-1-224x126.png 224w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<div class="wp-block-sbd-balloon sbd-balloon sbd-balloon--id-4 sbd-balloon--flat sbd-balloon--l sbd-balloon--green block-box"><div class="sbd-balloon__profile"><figure class="sbd-balloon__icon"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/09/アイコン.jpg" alt="そぞら" class="sbd-balloon__img"/></figure><div class="sbd-balloon__name">そぞら</div></div><div class="sbd-balloon__text-box sbd-inner-block-init">
<p class="wp-block-paragraph">本記事の内容を応用すれば、さまざまな家電製品を外出先から操作できるようになります。</p>
</div></div>



<h2 class="wp-block-heading"><strong>Blynkを使ったエアコン操作システム</strong></h2>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="550" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk50.jpeg" alt="" class="wp-image-12076"/><figcaption class="wp-element-caption">Blynkで作成したアプリ画面</figcaption></figure>



<p class="wp-block-paragraph">スマートフォン上のアプリからエアコンを遠隔操作できる装置の概要を見ていきましょう。</p>



<h3 class="wp-block-heading">システムのイメージ</h3>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="298" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk40.png" alt="" class="wp-image-12039"/></figure>



<p class="wp-block-paragraph">Blynkを利用して作ったアプリのボタンを押すことで、自宅に設置されたラズベリーパイにつながった赤外線LEDを通じてエアコンを操作するという仕組みです。</p>



<p class="wp-block-paragraph">BlynkはIoTプロジェクトを容易にするためのプラットフォームで、アプリケーションとデバイスを簡単に接続できるように設計されています。このため、スマートフォンアプリを通じてさまざまなデバイスをコントロールできます。</p>



<div class="wp-block-sbd-balloon sbd-balloon sbd-balloon--id-4 sbd-balloon--flat sbd-balloon--l sbd-balloon--green block-box"><div class="sbd-balloon__profile"><figure class="sbd-balloon__icon"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/09/アイコン.jpg" alt="そぞら" class="sbd-balloon__img"/></figure><div class="sbd-balloon__name">そぞら</div></div><div class="sbd-balloon__text-box sbd-inner-block-init">
<p class="wp-block-paragraph">Blynkを使えば、外出先からラズパイを操作するシステムを比較的簡単に組むことが可能です。</p>
</div></div>



<h3 class="wp-block-heading"><strong>準備するもの</strong></h3>



<p class="wp-block-paragraph">ラズパイの本体は<strong><a href="https://sozorablog.com/raspberry-pi-4-revue/">Raspberry Pi 4</a></strong>を使用しました。他のモデルでもできますが、ソフトウェアが対応していないため、最新モデルのRaspberry Pi 5は使用できません。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="531" src="https://sozorablog.com/wp-content/uploads/2024/01/pidog25.jpg" alt="" class="wp-image-11592"/><figcaption class="wp-element-caption"><a href="https://sozorablog.com/raspberry-pi-4-revue/">Raspberry Pi 4</a></figcaption></figure>



<p class="wp-block-paragraph">さらに、OSについても<span class="sbd-text-bg-yellow">最新版のBookwormではソフトウェアが動作しない</span>ため、以前のバージョンである<span class="sbd-text-red">Bullseye</span>を使用する必要があります。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="564" src="https://sozorablog.com/wp-content/uploads/2024/01/pidog1.jpg" alt="" class="wp-image-11511"/></figure>



<div class="wp-block-sbd-background-block sbd-bg-color sbd-inner-block-init is-style-yellow">
<p class="wp-block-paragraph">OSをインストールする方法は以下の記事で詳しく解説しています。<br><strong><a href="https://sozorablog.com/raspberrypi_initial_setting/">≫【2024年最新版】OSインストールから初期設定まで｜セットアップ手順のすべて</a></strong></p>
</div>



<p class="wp-block-paragraph">使用する電子パーツは以下の通りです。名称をクリックすると、秋月電子の販売ページに飛べます。</p>



<div class="wp-block-sbd-list"><ul class="sbd-list sbd-list-border"><li><a href="https://akizukidenshi.com/catalog/g/g104659/">赤外線リモコン受信モジュール</a></li><li><a href="https://akizukidenshi.com/catalog/g/g112612/">5mm赤外線LED</a></li><li><a href="https://akizukidenshi.com/catalog/g/g125101/">1/4Wカーボン抵抗 100Ω</a></li></ul></div>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="862" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk41.jpg" alt="" class="wp-image-12043" style="width:497px;height:auto"/><figcaption class="wp-element-caption"><a href="https://akizukidenshi.com/catalog/g/g104659/">赤外線リモコン受信モジュール</a></figcaption></figure>



<p class="wp-block-paragraph">装置の初期設定段階で、この赤外線リモコン受信モジュールを使用してエアコンリモコンの各ボタンから発せられる赤外線信号を読み取り、それらの信号をラズパイが理解できる形式で保存します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="852" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk42.jpg" alt="" class="wp-image-12044" style="width:497px;height:auto"/><figcaption class="wp-element-caption"><a href="https://akizukidenshi.com/catalog/g/g112612/">5mm赤外線LED</a></figcaption></figure>



<p class="wp-block-paragraph">5mm赤外線LEDは、保存された赤外線信号をエアコンに送信する目的で使用されます。</p>



<p class="wp-block-paragraph">この他には、ジャンパーワイヤーとブレッドボードが必要です。</p>



<!-- START MoshimoAffiliateEasyLink -->
<script type="text/javascript">
(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;
b[a]=b[a]||function(){arguments.currentScript=c.currentScript
||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};
c.getElementById(a)||(d=c.createElement(f),d.src=g,
d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})
(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");
msmaflink({"n":"ELEGOO 120pcs多色デュポンワイヤー、arduino用ワイヤ—ゲ—ジ28AWG オス-メス オス-オス メス –メス ブレッドボードジャンパーワイヤー","b":"ELEGOO","t":"JP-EL-CP-004","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/61TQP733AwL._SL500_.jpg","\/51HXtm4ZIlL._SL500_.jpg","\/51X0hlpDgxL._SL500_.jpg","\/51xNzsKVu0L._SL500_.jpg","\/51kRXsE11KL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/B06Y48V9DL","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/B06Y48V9DL","a_id":3038653,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"u_bc":"#f76956","u_tx":"楽天市場で見る","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/ELEGOO%20120pcs%E5%A4%9A%E8%89%B2%E3%83%87%E3%83%A5%E3%83%9D%E3%83%B3%E3%83%AF%E3%82%A4%E3%83%A4%E3%83%BC%E3%80%81arduino%E7%94%A8%E3%83%AF%E3%82%A4%E3%83%A4%E2%80%94%E3%82%B2%E2%80%94%E3%82%B828AWG%20%E3%82%AA%E3%82%B9-%E3%83%A1%E3%82%B9%20%E3%82%AA%E3%82%B9-%E3%82%AA%E3%82%B9%20%E3%83%A1%E3%82%B9%20%E2%80%93%E3%83%A1%E3%82%B9%20%E3%83%96%E3%83%AC%E3%83%83%E3%83%89%E3%83%9C%E3%83%BC%E3%83%89%E3%82%B8%E3%83%A3%E3%83%B3%E3%83%91%E3%83%BC%E3%83%AF%E3%82%A4%E3%83%A4%E3%83%BC\/","s_n":"rakuten","u_so":4,"a_id":3038654,"p_id":54,"pc_id":54,"pl_id":27059,"id":3}],"eid":"ElW7D","s":"s"});
</script>
<div id="msmaflink-ElW7D">リンク</div>
<!-- MoshimoAffiliateEasyLink END -->



<!-- START MoshimoAffiliateEasyLink -->
<script type="text/javascript">
(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;
b[a]=b[a]||function(){arguments.currentScript=c.currentScript
||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};
c.getElementById(a)||(d=c.createElement(f),d.src=g,
d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})
(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");
msmaflink({"n":"YMS PARTS【1個入り】ブレッドボード小","b":"ＹＭＳ　ＰＡＲＴＳ","t":"KCHIKA-001","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/51mBIAIIK8L._SL500_.jpg","\/51OZa99gvpL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/B0CV86X6B2","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/B0CV86X6B2","a_id":3038653,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"u_bc":"#f76956","u_tx":"楽天市場で見る","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/YMS%20PARTS%E3%80%901%E5%80%8B%E5%85%A5%E3%82%8A%E3%80%91%E3%83%96%E3%83%AC%E3%83%83%E3%83%89%E3%83%9C%E3%83%BC%E3%83%89%E5%B0%8F\/","s_n":"rakuten","u_so":4,"a_id":3038654,"p_id":54,"pc_id":54,"pl_id":27059,"id":3}],"eid":"rJJva","s":"s"});
</script>
<div id="msmaflink-rJJva">リンク</div>
<!-- MoshimoAffiliateEasyLink END -->



<h2 class="wp-block-heading">ラズパイからエアコンを操作</h2>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="450" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk46.png" alt="" class="wp-image-12057" srcset="https://sozorablog.com/wp-content/uploads/2024/03/blynk46.png 800w, https://sozorablog.com/wp-content/uploads/2024/03/blynk46-320x180.png 320w, https://sozorablog.com/wp-content/uploads/2024/03/blynk46-224x126.png 224w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<p class="wp-block-paragraph">まずは、ラズパイのプログラムでエアコンを操作する方法を確認していきます。以下の記事を参考にさせていただいております。</p>



<p class="wp-block-paragraph"><strong><a href="https://ediy-fan.com/ir-remote/">ラズパイを赤外線リモコン化してエアコンや扇風機を自動制御する</a></strong></p>



<h3 class="wp-block-heading">パーツの配線</h3>



<p class="wp-block-paragraph">Raspberry Piと電子パーツを以下のように配線します。配線するときはRaspberry Piの電源を切った状態で作業しましょう。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="742" height="552" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk4.png" alt="" class="wp-image-11975" style="width:840px;height:auto"/></figure>



<h4 class="wp-block-heading">赤外線リモコン受信モジュールの接続</h4>



<ol class="wp-block-list">
<li><strong>Vcc（電源）ピン</strong>をRaspberry Piの3.3Vピンに接続します。</li>



<li><strong>GND（グラウンド）ピン</strong>をRaspberry PiのGNDピンに接続します。</li>



<li><strong>OUT（信号出力）ピン</strong>をRaspberry PiのGPIO21ピンに接続します。このピンは赤外線信号を読み取るために使います。</li>
</ol>



<h4 class="wp-block-heading">赤外線LEDの接続</h4>



<p class="wp-block-paragraph">赤外線LEDは信号の送信に使いますが、直接Raspberry Piに接続すると電流が多すぎてLEDを損傷する可能性があるため、100Ωの抵抗を使用して電流を制限します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="450" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk53.jpg" alt="" class="wp-image-12090" style="width:496px;height:auto" srcset="https://sozorablog.com/wp-content/uploads/2024/03/blynk53.jpg 800w, https://sozorablog.com/wp-content/uploads/2024/03/blynk53-320x180.jpg 320w, https://sozorablog.com/wp-content/uploads/2024/03/blynk53-224x126.jpg 224w" sizes="(max-width: 800px) 100vw, 800px" /><figcaption class="wp-element-caption">100Ωの抵抗</figcaption></figure>



<p class="wp-block-paragraph">LEDのアノード（長い足）を3.3Vに接続し、カソード（短い足）を100Ωの抵抗を介してGPIO20ピンに接続します。</p>



<h5 class="wp-block-heading">5ｍｍ赤外線LEDの仕様（<a href="https://akizukidenshi.com/catalog/g/g112612/">秋月電子の販売ページ</a>より）</h5>



<ul class="wp-block-list">
<li><strong>順電圧（Vf）</strong>: 1.35V。LEDに電流を流すために必要な電圧です。</li>



<li><strong>順電流（If）</strong>: 最大100mA。LEDに安全に流せる最大電流です。</li>
</ul>



<h5 class="wp-block-heading">抵抗100Ωの根拠</h5>



<p class="wp-block-paragraph">Raspberry PiのGPIOピンは3.3Vで動作します。LEDを点灯させるには、この電圧からLEDの順電圧を差し引いた電圧が抵抗を通る必要があります。</p>



<p class="wp-block-paragraph">抵抗を使用する主な目的は、LEDに適切な電流が流れるように制限することです。順電圧が1.35Vで、Raspberry Piから供給される電圧が3.3Vの場合、LEDを通過後の残りの電圧は</p>



<p class="wp-block-paragraph">3.3<em>V</em>−1.35<em>V</em>=1.95<em>V</em></p>



<p class="wp-block-paragraph">この残りの電圧1.95Vが抵抗を通過するときに、LEDに適切な電流を流すための抵抗値を計算します。LEDの安全な動作電流を考慮して、20mA（0.02A）を使用電流とすると、オームの法則により抵抗値は</p>



<p class="wp-block-paragraph"><em>R</em>=V／<em>I</em>​=1.95<em>V</em>​／0.02<em>A</em>=97.5Ω</p>



<p class="wp-block-paragraph">と計算されます。市販されている抵抗の標準値には97.5Ωがないため、近似値として100Ωが選ばれます。これにより、LEDに適切な電流が流れ、過剰な電流による損傷を防ぐことができます。</p>



<h3 class="wp-block-heading"><strong>リモコンの信号を学習</strong></h3>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="589" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk6.jpeg" alt="" class="wp-image-11977" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph">ここからはRaspberry Piのターミナルを使って作業します。ターミナルとはコンピューターにテキスト形式で命令を入力し、実行するための画面のことです。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="379" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk1.jpg" alt="" class="wp-image-11967" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph">まず、「pigpio」をRaspberry Piが起動するたびに自動的に開始するように設定します。pigpioはGPIO（Raspberry Piの汎用入出力端子）を制御するパッケージです。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo systemctl enable pigpiod.service</code></pre></div>



<p class="wp-block-paragraph">次に、以下のコマンドで「pigpio」を開始します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo systemctl start pigpiod.service</code></pre></div>



<p class="wp-block-paragraph">赤外線信号の読み取りや送信をするためのPythonスクリプトをダウンロードします。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>wget http://abyz.me.uk/rpi/pigpio/code/irrp_py.zip</code></pre></div>



<p class="wp-block-paragraph">以下のコマンドで、「irrp_py.zip」という名前の圧縮ファイルを解凍し、中に含まれるファイルを取り出します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>unzip irrp_py.zip</code></pre></div>



<p class="wp-block-paragraph">私が使っているリモコンには、「暖房」と「冷房」のボタンが別々にあります。今回はこれら2つのボタンを学習します。</p>



<div class="wp-block-sbd-balloon sbd-balloon sbd-balloon--id-4 sbd-balloon--flat sbd-balloon--l sbd-balloon--green block-box"><div class="sbd-balloon__profile"><figure class="sbd-balloon__icon"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/09/アイコン.jpg" alt="そぞら" class="sbd-balloon__img"/></figure><div class="sbd-balloon__name">そぞら</div></div><div class="sbd-balloon__text-box sbd-inner-block-init">
<p class="wp-block-paragraph">使用しているリモコンに合わせて、学習させるボタンの種類を調整してみてください。</p>
</div></div>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="496" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk7.jpg" alt="" class="wp-image-11978" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph">「暖房」と「冷房」の赤外線信号を学習するコマンドは次のようになります。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>python3 irrp.py -r -g21 -f air_conditioner heating cooling</code></pre></div>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="272" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk8-1.png" alt="" class="wp-image-11980" style="width:840px;height:auto"/></figure>



<div class="wp-block-sbd-list"><ul class="sbd-list sbd-list-border"><li><strong>-r</strong>: このオプションは「読み取りモード」を意味します。赤外線リモコンの信号を読み取って、それをファイルに保存します。</li><li><strong>-g21</strong>: ここで指定されている21は、赤外線リモコン受信モジュールが接続されているGPIOピンの番号です。</li><li><strong>-f air_conditioner</strong>: -fオプションの後に続くair_conditionerは、読み取った赤外線信号を保存するファイルの名前です。</li><li><strong>heating cooling</strong>: これらは、保存する赤外線信号の「キー」です。つまり、エアコンの暖房モードと冷房モードの信号を読み取り、それぞれheatingとcoolingという名前で保存します。</li></ul></div>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="448" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk5.jpeg" alt="" class="wp-image-11976" style="width:840px;height:auto" srcset="https://sozorablog.com/wp-content/uploads/2024/03/blynk5.jpeg 800w, https://sozorablog.com/wp-content/uploads/2024/03/blynk5-320x180.jpeg 320w, https://sozorablog.com/wp-content/uploads/2024/03/blynk5-224x126.jpeg 224w" sizes="(max-width: 800px) 100vw, 800px" /><figcaption class="wp-element-caption">リモコンの信号を学習している様子</figcaption></figure>



<p class="wp-block-paragraph">コマンドを実行すると「Press key for &#8216;heating&#8217;」と画面に表示されるので、赤外線受信モジュールに向けてリモコンの暖房ボタンを押します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="620" height="80" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk44.png" alt="" class="wp-image-12050" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph">次に、「Press key for &#8216;heating&#8217; to confirm」と表示され、確認のために暖房ボタンを再度押すように求められます。</p>



<p class="wp-block-paragraph">「No match」が出力された場合は、再度ボタンを押します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="230" height="29" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk45.png" alt="" class="wp-image-12052" style="width:523px;height:auto" srcset="https://sozorablog.com/wp-content/uploads/2024/03/blynk45.png 230w, https://sozorablog.com/wp-content/uploads/2024/03/blynk45-224x29.png 224w" sizes="(max-width: 230px) 100vw, 230px" /></figure>



<p class="wp-block-paragraph">その後、「Press key for &#8216;cooling&#8217;」と表示されたら、冷房ボタンを押してその信号も同じように学習させます。</p>



<p class="wp-block-paragraph">この手順を全て終えると、irrp.pyのファイルがある同じフォルダ内に「air_conditioner」という名前のファイルが作成されます。後でこれらの信号を使ってプログラムからエアコンを制御することができます。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="824" height="94" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk43.png" alt="" class="wp-image-12049"/></figure>



<h3 class="wp-block-heading">リモコンの信号を送信</h3>



<p class="wp-block-paragraph">以下のコマンドを実行すると、暖房運転開始の信号が赤外線LEDから送信され、エアコンを暖房モードで運転することができます。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>python3 irrp.py -p -g20 -f air_conditioner heating</code></pre></div>



<p class="wp-block-paragraph">赤外線LEDの先端をリモコン受信部の方向に向けるのがポイントです。うまくいかない場合は送信する角度や位置を調整しましょう。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="530" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk9.jpg" alt="" class="wp-image-11982" style="width:840px;height:auto"/></figure>



<div class="wp-block-sbd-list"><ul class="sbd-list sbd-list-border"><li><strong>-p</strong>: このオプションは「送信モード」を意味します。保存された赤外線信号をエアコンに送信する際に使用します。</li><li><strong>-g20</strong>: ここで指定されている<code>20</code>は、赤外線送信機が接続されているGPIOピンの番号です。</li><li><strong>-f air_conditioner</strong>: -fオプションに続くair_conditionerは、信号を保存したファイルの名前です。このファイルからエアコンの操作に必要な信号を読み込みます。</li><li><strong>heating</strong>: 送信する赤外線信号の「キー」です。この場合は、暖房モードを示します。</li></ul></div>



<p class="wp-block-paragraph">このコマンドを実行することで、air_conditionerファイルに保存された暖房モードの信号をエアコンに送信します。</p>



<p class="wp-block-paragraph">冷房モードで運転するコマンドは以下のようになります。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>python3 irrp.py -p -g20 -f air_conditioner cooling</code></pre></div>



<h4 class="wp-block-heading">Pythonスクリプトからリモコンの信号を送信</h4>



<p class="wp-block-paragraph">Blynkアプリとラズベリーパイを連携させ、エアコンなどの家電を遠隔操作するには、<span class="sbd-text-red">Pythonスクリプトでの記述が必要</span>になります。</p>



<p class="wp-block-paragraph">先ほどのコマンドをPythonスクリプトから実行してみましょう。スタートメニューのプログラミングから「Thonny」を開きます。</p>



<div class="wp-block-sbd-background-block sbd-bg-color sbd-inner-block-init is-style-yellow">
<p class="wp-block-paragraph">ThonnyはPythonの統合開発環境（IDE）で、コードの記述、実行、デバッグを行うことができます。</p>
</div>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="498" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk2.jpg" alt="" class="wp-image-11970" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph">以下のプログラムをThonnyにペーストしてください。これにより、「python3 irrp.py -p -g20 -f air_conditioner heating」という<span class="sbd-text-red">コマンドをPythonスクリプトから実行できる</span>ようになります。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>import subprocess

# 暖房運転スタートのスクリプトを実行
subprocess.call([&#39;python3&#39;, &#39;irrp.py&#39;, &#39;-p&#39;, &#39;-g20&#39;, &#39;-f&#39;, &#39;air_conditioner&#39;, &#39;heating&#39;])
</code></pre></div>



<p class="wp-block-paragraph">ペーストしたら「Run」ボタンでプログラムを実行します。すると、暖房運転開始の信号が送信されます。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="335" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk3.png" alt="" class="wp-image-11972"/></figure>



<p class="wp-block-paragraph">このプログラムではPythonの標準ライブラリの一部である<code>subprocess</code>モジュールを使用します。</p>



<p class="wp-block-paragraph"><code>subprocess.call</code>関数は、指定されたコマンドを実行し、そのコマンドが終了するのを待ちます。この関数の引数には、実行するコマンドの名前と、そのコマンドに渡す引数をリスト形式で指定します。</p>



<p class="wp-block-paragraph">このコードを実行すると、Pythonスクリプト<code>irrp.py</code>が起動され、指定された引数（<code>-p -g20 -f air_conditioner heating</code>）を使ってエアコンを暖房モードで運転する信号が送信されます。</p>



<h2 class="wp-block-heading"><strong>Blynk</strong>アプリからエアコンを操作</h2>



<p class="wp-block-paragraph">Blynkアプリを使ってエアコンを遠隔操作する方法について紹介します。この手順を通じて、どこからでもスマートフォンを使って自宅のエアコンを操作できるようになります。</p>



<h3 class="wp-block-heading"><strong>Blynk</strong>のアカウントを作成</h3>



<p class="wp-block-paragraph"><span class="sbd-text-red">Blynkは基本無料で使えます</span>が、追加の機能を使いたい場合は有料のプランを選択することもできます。</p>



<p class="wp-block-paragraph"><span class="sbd-text-bg-yellow">パソコンから</span><a href="https://blynk.io/">Blynkのサイト</a>を開き、「START&nbsp;FREE」をクリックしてアカウントを作成します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="352" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk20.jpg" alt="" class="wp-image-12009" style="width:841px;height:auto"/></figure>



<p class="wp-block-paragraph">メールアドレスの認証をして、パスワードと名前を設定すると以下の画面が開きます。「Skip」をクリックします。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="388" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk21.jpg" alt="" class="wp-image-12010" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph">「Cancel」をクリックします。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="418" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk22.jpg" alt="" class="wp-image-12011" style="width:840px;height:auto"/></figure>



<h3 class="wp-block-heading">テンプレートの作成</h3>



<p class="wp-block-paragraph">「Deveropper Zone」をクリックします。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="513" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk25.jpg" alt="" class="wp-image-12014" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph">「New Template」をクリックします。Template（テンプレート）は、デバイス（Raspberry Pi）を操作するための設定をまとめたものです。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="643" height="449" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk26.png" alt="" class="wp-image-12015" style="width:342px;height:auto"/></figure>



<p class="wp-block-paragraph">以下のように入力して「Done」をクリックします。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="906" height="604" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk24.png" alt="" class="wp-image-12013"/></figure>



<h3 class="wp-block-heading">Blynkの認証トークンを取得</h3>



<p class="wp-block-paragraph">「Add first Device」をクリックします。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="534" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk27.png" alt="" class="wp-image-12016" style="width:442px;height:auto"/></figure>



<p class="wp-block-paragraph">「DEVICE NAME」に「Raspberry Pi」を入力して、「Create」をクリックします。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="451" height="273" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk11.png" alt="" class="wp-image-11994"/></figure>



<p class="wp-block-paragraph">画面右側にBlynkの認証トークンが表示されます。Raspberry Piでプログラムを作成するときに、このトークンが必要になります。<span class="sbd-text-bg-yellow">トークンをコピーして保管しておきましょう。</span></p>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="450" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk28.jpg" alt="" class="wp-image-12017" srcset="https://sozorablog.com/wp-content/uploads/2024/03/blynk28.jpg 800w, https://sozorablog.com/wp-content/uploads/2024/03/blynk28-320x180.jpg 320w, https://sozorablog.com/wp-content/uploads/2024/03/blynk28-224x126.jpg 224w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<h3 class="wp-block-heading">仮想ピン（Virtual Pin）の作成</h3>



<p class="wp-block-paragraph">「Datastreams」のタブを開きます。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="370" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk29.png" alt="" class="wp-image-12019"/></figure>



<div class="wp-block-sbd-background-block-title sbd-bg-color sbd-inner-block-init is-style-gray">
<p class="wp-block-paragraph">Datastream（データストリーム）は、ラズパイとBlynkのサーバー間でデータを送受信するための通信チャンネルを設定する仕組みです。仮想ピン（Virtual Pin）のデータタイプ、およびデータの最小値と最大値を設定することで、ラズパイからのデータをどのように扱うかを定義できます。今回はデータタイプを<strong>Integer（整数）</strong>に設定します。</p>
</div>



<p class="wp-block-paragraph">「+ New Datastream」をクリックして、「Virtual Pin」を選択します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="812" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk13.jpg" alt="" class="wp-image-11996" style="width:419px;height:auto"/></figure>



<p class="wp-block-paragraph">設定を確認して「Create」をクリックします。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="731" height="544" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk14-1.png" alt="" class="wp-image-11998" style="width:481px;height:auto"/></figure>



<p class="wp-block-paragraph">今回は暖房用と冷房用の<span class="sbd-text-red">2種類のピン</span>を作成します。「+ New Datastream」をクリックして、<span class="sbd-text-bg-yellow">V1のピン</span>をV0と同様の方法で作成します。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="295" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk31.png" alt="" class="wp-image-12023"/></figure>



<p class="wp-block-paragraph">V0とV1のピンが作成できたら「Save And Apply」をクリックします。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="328" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk30.png" alt="" class="wp-image-12022" style="width:810px;height:auto"/></figure>



<p class="wp-block-paragraph">これでパソコン側の設定は完了です。</p>



<h3 class="wp-block-heading">スマートフォンのアプリ画面を作成</h3>



<p class="wp-block-paragraph">Blynkのアプリを<span class="sbd-text-bg-yellow">スマートフォン</span>にインストールします。このアプリはiOSとAndroidの両方で利用可能です。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="375" height="400" src="https://sozorablog.com/wp-content/uploads/2024/03/pico6-2-2.png" alt="" class="wp-image-11984" style="width:345px;height:auto"/></figure>



<p class="wp-block-paragraph">「Log In」をタップします。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="750" height="923" src="https://sozorablog.com/wp-content/uploads/2024/03/pico6-2-3.png" alt="" class="wp-image-11985" style="width:365px;height:auto"/></figure>



<p class="wp-block-paragraph">ログインするとパソコンで作成したテンプレートが表示されます。タップしてボタンを設定していきます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="750" height="697" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk32.jpeg" alt="" class="wp-image-12029" style="width:353px;height:auto"/></figure>



<p class="wp-block-paragraph">画面右上のスパナのアイコンをクリックします。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="487" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk34.png" alt="" class="wp-image-12030" style="width:352px;height:auto"/></figure>



<p class="wp-block-paragraph">中央のエリアをタップして、「Widget Box」を開きます。ここではラズパイを制御するためのスイッチや計器を選ぶことができます。「Button」をタップするとテンプレート画面にボタンが配置されます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="450" src="https://sozorablog.com/wp-content/uploads/2024/03/pico6-2-9h.png" alt="" class="wp-image-11989" style="width:551px;height:auto" srcset="https://sozorablog.com/wp-content/uploads/2024/03/pico6-2-9h.png 800w, https://sozorablog.com/wp-content/uploads/2024/03/pico6-2-9h-320x180.png 320w, https://sozorablog.com/wp-content/uploads/2024/03/pico6-2-9h-224x126.png 224w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<p class="wp-block-paragraph">ボタンの位置や大きさは変更可能です。オブジェクトを長押しすると、移動や大きさの変更ができます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="750" height="1287" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk35.png" alt="" class="wp-image-12031" style="width:238px;height:auto"/></figure>



<p class="wp-block-paragraph">作成したボタンをタップして設定画面を開きます。さらに、「DATASTREAM」の設定画面を開きます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="450" src="https://sozorablog.com/wp-content/uploads/2024/03/pico6-2-10h.png" alt="" class="wp-image-11990" style="width:601px;height:auto" srcset="https://sozorablog.com/wp-content/uploads/2024/03/pico6-2-10h.png 800w, https://sozorablog.com/wp-content/uploads/2024/03/pico6-2-10h-320x180.png 320w, https://sozorablog.com/wp-content/uploads/2024/03/pico6-2-10h-224x126.png 224w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<p class="wp-block-paragraph">「Integer V0(v0)」を選択します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="392" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk18.png" alt="" class="wp-image-12004" style="width:404px;height:auto"/></figure>



<p class="wp-block-paragraph">同様の方法で<span class="sbd-text-bg-yellow">ボタンを1つ追加で作成</span>します。このボタンのDatastreamは、V1のピンに設定します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="750" height="861" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk36.png" alt="" class="wp-image-12033" style="width:314px;height:auto"/></figure>



<p class="wp-block-paragraph">暖房ボタンと冷房ボタンを判別できるように、デザインを変更します。「Integer V0 (v0)」を選択します。ボタンの設定画面の「Design」をタップします。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="681" height="1080" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk16.png" alt="" class="wp-image-12002" style="width:310px;height:auto"/></figure>



<p class="wp-block-paragraph">LabelsのOFF (0)を「暖房」に変更します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="688" height="1080" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk19.png" alt="" class="wp-image-12006" style="width:338px;height:auto"/></figure>



<p class="wp-block-paragraph">同様の方法でV1のボタンのOFF表示を「冷房」に変更します。</p>



<p class="wp-block-paragraph">左上の✕ボタンを押して、表示が反映されたことを確認してみましょう。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="726" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk37.png" alt="" class="wp-image-12034" style="width:327px;height:auto"/></figure>



<p class="wp-block-paragraph">「暖房ボタン」と「冷房ボタン」ができました。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="750" height="809" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk38.png" alt="" class="wp-image-12035" style="width:343px;height:auto"/></figure>



<p class="wp-block-paragraph">余裕がある方はボタンのデザインをアレンジしてみましょう。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="750" height="1289" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk39.png" alt="" class="wp-image-12037" style="width:316px;height:auto"/><figcaption class="wp-element-caption">完成したアプリ画面</figcaption></figure>



<p class="wp-block-paragraph">これで、Blynkアプリの設定は完了です。</p>



<h3 class="wp-block-heading"><strong>Blynkライブラリをインストール</strong></h3>



<p class="wp-block-paragraph">次はRaspberry Pi側のソフトウェアを設定します。</p>



<p class="wp-block-paragraph">BlynkライブラリはBlynkのAPIとのやり取りを行うための関数やクラスを提供します。</p>



<p class="wp-block-paragraph">まず、GitHub上にあるBlynkのPythonライブラリのリポジトリを、現在のディレクトリに複製（クローン）します。これにより、BlynkのPythonライブラリのコードがラズパイにダウンロードされます。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>git clone https://github.com/vshymanskyy/blynk-library-python.git</code></pre></div>



<p class="wp-block-paragraph">ダウンロードしたライブラリのディレクトリに移動します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>cd blynk-library-python</code></pre></div>



<p class="wp-block-paragraph"><code>setup.py</code>スクリプトを実行して、BlynkのPythonライブラリをシステムにインストールします。この手順により、PythonスクリプトからBlynkライブラリを利用できるようになります。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo python3 setup.py install</code></pre></div>



<h3 class="wp-block-heading"><strong>エアコンを遠隔操作するスクリプト</strong></h3>



<p class="wp-block-paragraph">以下のコードBlynkアプリと連携して、スマートフォンからエアコンを制御するためのものです。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>import BlynkLib
import subprocess

BLYNK_AUTH = &#39;Your_Blynk_Auth_Token&#39;  # Blynkの認証トークンに置き換えてください

# Blynkインスタンスを初期化
blynk = BlynkLib.Blynk(BLYNK_AUTH)

# 仮想ピンV0に対するコールバック関数を定義（暖房モードで運転）
@blynk.on(&quot;V0&quot;)
def v0_write_handler(value):
    # ボタンが押されたら暖房モード運転のスクリプトを実行
    if int(value[0]) == 1:
        print(&quot;暖房ボタンが押されました。&quot;)
        subprocess.call([&#39;python3&#39;, &#39;irrp.py&#39;, &#39;-p&#39;, &#39;-g20&#39;, &#39;-f&#39;, &#39;air_conditioner&#39;, &#39;heating&#39;])

# 仮想ピンV1に対するコールバック関数を定義（冷房モードで運転）
@blynk.on(&quot;V1&quot;)
def v1_write_handler(value):
    # ボタンが押されたら冷房モードのスクリプトを実行
    if int(value[0]) == 1:
        print(&quot;冷房ボタンが押されました。&quot;)
        subprocess.call([&#39;python3&#39;, &#39;irrp.py&#39;, &#39;-p&#39;, &#39;-g20&#39;, &#39;-f&#39;, &#39;air_conditioner&#39;, &#39;cooling&#39;])

# メインループ
while True:
    blynk.run()</code></pre></div>



<p class="wp-block-paragraph">まず、<code>BlynkLib</code>モジュールをインポートすることから始めます。このモジュールはBlynkライブラリをPythonで使用できるようにするもので、BlynkのAPIとのやり取りを行うための関数やクラスを提供します。</p>



<p class="wp-block-paragraph"><code>BLYNK_AUTH</code>変数には、<span class="sbd-text-red">Blynkアプリから取得した認証トークンを入力します。</span>このトークンは、BlynkサーバーがRaspberry Piを識別するために使用されます。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="257" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk49.png" alt="" class="wp-image-12069"/></figure>



<p class="wp-block-paragraph"><code>@blynk.on("V0")</code>と<code>@blynk.on("V1")</code>デコレータは、Blynkアプリ上の仮想ピンV1とV2に対するコールバック関数を定義しています。これらの関数は対応するピンの状態が変化した（スマートフォン上のボタンが押された）時に呼び出されるように設定されます。</p>



<p class="wp-block-paragraph">各コールバック関数内では、<code>subprocess.call</code>を使用して外部スクリプト<code>irrp.py</code>を実行しています。このスクリプトは赤外線リモコン信号を送信するためのもので、第二引数以降で指定されたオプションにより、エアコンを暖房モードまたは冷房モードで運転するように指示しています。</p>



<p class="wp-block-paragraph">最後に、無限ループ内で<code>blynk.run()</code>を呼び出すことにより、Blynkライブラリがイベントを監視し続けるようにしています。これにより、アプリからの入力をリアルタイムで受け取り、設定したコールバック関数を実行することができます。</p>



<p class="wp-block-paragraph">コードを実行すると、コンソールに以下の表示が出ます。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="426" height="266" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk47.png" alt="" class="wp-image-12066"/></figure>



<p class="wp-block-paragraph">スマートフォンのアプリ画面の「暖房」ボタンを押すと、以下の表示が出てリモコン信号が送信されます。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="427" height="159" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk48.png" alt="" class="wp-image-12067"/></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="674" src="https://sozorablog.com/wp-content/uploads/2024/03/blynk51.jpeg" alt="" class="wp-image-12075"/></figure>
]]></content:encoded>
					
					<wfw:commentRss>https://sozorablog.com/blynk/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>ラズパイでYouTube動画再生機能付き時計を作る方法【MagicMirror2使用】</title>
		<link>https://sozorablog.com/magicmirror/</link>
					<comments>https://sozorablog.com/magicmirror/#respond</comments>
		
		<dc:creator><![CDATA[そぞら]]></dc:creator>
		<pubDate>Fri, 16 Feb 2024 19:24:35 +0000</pubDate>
				<category><![CDATA[Raspberry Pi]]></category>
		<category><![CDATA[使い方]]></category>
		<guid isPermaLink="false">https://sozorablog.com/?p=11711</guid>

					<description><![CDATA[Raspberry Piを使った「YouTube動画を再生できる時計」の作り方をご紹介します。MagicMirror2というソフトを使用すれば、高度なコーディングの知識がなくても、比較的簡単に自作可能です。 YouTub [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><a href="https://sozorablog.com/raspberry-pi/">Raspberry Pi</a>を使った「YouTube動画を再生できる時計」の作り方をご紹介します。MagicMirror<sup>2</sup>というソフトを使用すれば、高度なコーディングの知識がなくても、比較的簡単に自作可能です。</p>



<figure class="wp-block-embed is-type-rich is-provider-x wp-block-embed-x"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="500" data-dnt="true"><p lang="ja" dir="ltr">水族館のライブ映像を楽しめる時計を作りました。<br><br>アメリカのモントレーベイ水族館のライブカメラ映像を表示。日々の暮らしに、ちょっとした非日常をプラスする提案です。小型PCの「ラズベリーパイ」を使って表示しています。 <a href="https://t.co/rVsg9wUSK1">pic.twitter.com/rVsg9wUSK1</a></p>&mdash; そぞら@Raspberry Pi 電子工作 (@sozoraemon) <a href="https://x.com/sozoraemon/status/1756632118669754508?ref_src=twsrc%5Etfw">February 11, 2024</a></blockquote><script async src="https://platform.x.com/widgets.js" charset="utf-8"></script>
</div></figure>



<p class="wp-block-paragraph">YouTube動画はお好みの動画を再生できますが、おすすめは次のライブカメラです。</p>



<div class="wp-block-sbd-list"><ul class="sbd-list sbd-list-border"><li><a href="https://www.youtube.com/watch?v=fO9e9jnhYK8">国際宇宙ステーション</a></li><li><a href="https://www.youtube.com/watch?v=n_GpVsz4nHU">モントレー・ベイ水族館</a></li><li><a href="https://www.youtube.com/watch?v=O52zDyxg5QI">オーロラ鑑賞スポット（アラスカ）</a></li><li><a href="https://www.youtube.com/watch?v=GsD9QQEKSzQ">富士山（静岡市さった峠）</a></li><li><a href="https://www.youtube.com/watch?v=m3XYGdoOv18">ラスベガスの球体型アリーナ「Sphere（スフィア）」</a></li></ul></div>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="600" src="https://sozorablog.com/wp-content/uploads/2024/05/IMG_6847.jpeg" alt="" class="wp-image-12489" style="width:468px;height:auto"/></figure>



<p class="wp-block-paragraph"><br>YouTube動画を全画面で表示し、その上に時刻を表示する仕組みは、通常のPCでも作成できます。しかし、専用の装置を作る場合には、コンパクトな「Raspberry Pi」がとても便利です。Raspberry Piの魅力は消費電力が少なく長時間の使用でも電気代を抑えられる点と、場所を取らないためディスプレイの裏側などにも簡単に収納できる点にあります。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="574" src="https://sozorablog.com/wp-content/uploads/2024/02/mm21.jpg" alt="" class="wp-image-11769"/><figcaption class="wp-element-caption">HDMI対応ディスプレイにも表示可能</figcaption></figure>



<p class="wp-block-paragraph"><a href="https://www.switch-science.com/products/9032">円形ディスプレイ</a>でなくても、一般的なHDMI対応ディスプレイで同様に表示を作成できます。</p>



<h2 class="wp-block-heading">準備</h2>



<p class="wp-block-paragraph">円形ディスプレイに対応しているRaspberry Piのモデルを以下に示します。</p>



<div class="wp-block-sbd-list"><ul class="sbd-list sbd-list-border"><li>Raspberry Pi 4 Model B</li><li>Raspberry Pi 3 Model B+</li><li>Raspberry Pi 3 Model A+</li></ul></div>



<p class="wp-block-paragraph">僕は<a href="https://sozorablog.com/raspberry-pi-4-revue/">Raspberry Pi 4</a>を使用しました。メモリは1GBです。YouTube動画をスムーズに再生するためには、Raspberry Pi 4をおすすめします。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="531" src="https://sozorablog.com/wp-content/uploads/2024/01/pidog25.jpg" alt="" class="wp-image-11592"/></figure>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="564" src="https://sozorablog.com/wp-content/uploads/2024/01/pidog1.jpg" alt="" class="wp-image-11511" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph">microSDにOSをインストールします。Raspberry Pi OS（Legacy,32-bit）を選択しました。最新版のBookwormだと円形ディスプレイのセットアップがうまくいきませんでした。</p>



<div class="wp-block-sbd-background-block sbd-bg-color sbd-inner-block-init is-style-yellow">
<p class="wp-block-paragraph">OSをインストールする方法は以下の記事で詳しく解説しています。<br><strong><a href="https://sozorablog.com/raspberrypi_initial_setting/">≫【2024年最新版】OSインストールから初期設定まで｜セットアップ手順のすべて</a></strong></p>
</div>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="560" src="https://sozorablog.com/wp-content/uploads/2024/02/IMG_6294.jpeg" alt="" class="wp-image-11772"/></figure>



<p class="wp-block-paragraph">Waveshare製の4インチ円形タッチスクリーンディスプレイは<a href="https://www.switch-science.com/products/9032">スイッチサイエンス</a>で購入可能です。<a href="https://www.switch-science.com/products/9028">3.4インチ</a>と<a href="https://www.switch-science.com/products/9029">5インチ</a>のタイプもあります。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="450" src="https://sozorablog.com/wp-content/uploads/2024/03/pico-51.jpg" alt="" class="wp-image-12084" style="width:840px;height:auto" srcset="https://sozorablog.com/wp-content/uploads/2024/03/pico-51.jpg 800w, https://sozorablog.com/wp-content/uploads/2024/03/pico-51-320x180.jpg 320w, https://sozorablog.com/wp-content/uploads/2024/03/pico-51-224x126.jpg 224w" sizes="(max-width: 800px) 100vw, 800px" /><figcaption class="wp-element-caption">ディスプレイの裏側にRaspberry Piを取り付け</figcaption></figure>



<p class="wp-block-paragraph">ラズパイをディスプレイのボードに取り付けると、4つのピンがラズパイのGPIOピンの裏側に接触します。これにより、ラズパイからディスプレイへ直接電力が供給されます。その結果、<span class="sbd-text-bg-yellow">ラズパイに電源をつなぐだけで、ディスプレイも同時に給電される</span>仕組みになっています。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="643" src="https://sozorablog.com/wp-content/uploads/2024/02/mm9.jpg" alt="" class="wp-image-11733" style="width:840px;height:auto"/><figcaption class="wp-element-caption">ディスプレイのケーブルをDSIコネクターに接続</figcaption></figure>



<p class="wp-block-paragraph">円形ディスプレイの裏側にRaspberry Piを取り付けます。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="547" src="https://sozorablog.com/wp-content/uploads/2024/02/mm8.jpg" alt="" class="wp-image-11734"/></figure>



<p class="wp-block-paragraph">ディスプレイのコネクターを接続したら、電源ケーブルはRaspberry Pi側のコネクターに差し込みます。これにより、Raspberry Piが起動し、ディスプレイ側にも電源が供給されます。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="574" src="https://sozorablog.com/wp-content/uploads/2024/02/mm20.jpg" alt="" class="wp-image-11763"/></figure>



<p class="wp-block-paragraph">マウスやキーボード、ディスプレイを接続してRaspberry Piの初期設定をします。</p>



<div class="wp-block-sbd-background-block sbd-bg-color sbd-inner-block-init is-style-yellow">
<p class="wp-block-paragraph">初回起動時は円形ディスプレイ以外のHDMI対応ディスプレイが必要です。</p>
</div>



<p class="wp-block-paragraph">初期設定が完了したら、メーカーの<a href="https://www.waveshare.com/wiki/4inch_DSI_LCD_(C)">マニュアル</a>に沿って円形ディスプレイのセットアップをします。</p>



<p class="wp-block-paragraph">以下のコマンドを１行ずつ実行していきます。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>git clone https://github.com/waveshare/Waveshare-DSI-LCD
cd Waveshare-DSI-LCD
cd 6.1.21
cd 64
sudo bash ./WS_xinchDSI_MAIN.sh 40C I2C0
sudo reboot</code></pre></div>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="320" src="https://sozorablog.com/wp-content/uploads/2024/02/pico-42.jpg" alt="" class="wp-image-11795" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph">再起動後、円形ディスプレイにRaspberry Piのデスクトップ画面が表示されます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="690" src="https://sozorablog.com/wp-content/uploads/2024/02/mm11.jpg" alt="" class="wp-image-11730" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph">ディスプレイの表示方向は変更可能です。４種類の角度から選択できます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="540" height="352" src="https://sozorablog.com/wp-content/uploads/2024/02/mm12.png" alt="" class="wp-image-11731" style="width:840px;height:auto"/></figure>



<h4 class="wp-block-heading">画面の自動暗転機能を無効化する</h4>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="607" src="https://sozorablog.com/wp-content/uploads/2024/02/pico-43.jpg" alt="" class="wp-image-11797"/></figure>



<p class="wp-block-paragraph">「Raspberry Piの設定」を開いて「画面のブランク」という項目をオフにします。これは、一定時間何も操作しないと画面が暗くなる機能です。<span class="sbd-text-bg-yellow">この機能が有効になっていると、時計を長時間表示し続けることができません。</span></p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="450" src="https://sozorablog.com/wp-content/uploads/2024/02/mm7-2.png" alt="" class="wp-image-11736" style="width:840px;height:auto" srcset="https://sozorablog.com/wp-content/uploads/2024/02/mm7-2.png 800w, https://sozorablog.com/wp-content/uploads/2024/02/mm7-2-320x180.png 320w, https://sozorablog.com/wp-content/uploads/2024/02/mm7-2-224x126.png 224w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<h2 class="wp-block-heading">MagicMirror<sup>2</sup>をインストールする</h2>



<p class="wp-block-paragraph">MagicMirror<sup>2</sup>は情報表示が可能なスマートミラーを作成するためのオープンソースソフトウェアです。MagicMirror<sup>2</sup>を使えば、ミラーがなくてもクールな見た目のディスプレイ表示を作れます。</p>



<div class="wp-block-sbd-background-block sbd-bg-color sbd-inner-block-init is-style-yellow">
<p class="wp-block-paragraph">MagicMirror²の使い方で参考にさせていただいたサイト<br><strong><a href="https://raspida.com/magicmirror-for-info-board#index_id13">マジックミラーが無くても情報表示にMagicMirror²を使う</a></strong></p>
</div>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="415" src="https://sozorablog.com/wp-content/uploads/2024/02/mm3.jpg" alt="" class="wp-image-11712" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph">まず、ターミナルを開いて以下のコマンドを実行します。Node.jsの特定バージョンをインストールするための準備作業です。Node.jsはMagicMirror<sup>2</sup>で情報を表示するためのプログラムを作成する際に必要となります。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -</code></pre></div>



<p class="wp-block-paragraph">次に、以下のコマンドでNode.jsのインストールを行います。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo apt install -y nodejs</code></pre></div>



<p class="wp-block-paragraph">以下のコマンドでGitHub上にあるMagicMirrorのリポジトリを複製します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>git clone https://github.com/MichMich/MagicMirror</code></pre></div>



<p class="wp-block-paragraph">MagicMirrorのディレクトリに移動します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>cd MagicMirror/</code></pre></div>



<p class="wp-block-paragraph">MagicMirrorに必要な追加セットアップや構成を行います。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>npm run install-mm</code></pre></div>



<p class="wp-block-paragraph">MagicMirrorのインストールが正常に完了すると、以下のような表示が出ます。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="460" src="https://sozorablog.com/wp-content/uploads/2024/02/スクリーンショット-2025-05-01-8.40.41.jpg" alt="" class="wp-image-14579"/></figure>



<p class="wp-block-paragraph"><code>config.js.sample</code> というサンプル設定ファイルを <code>config.js</code> という名前でコピーします。<code>config.js</code>はMagicMirrorの画面設定を行うためのファイルです。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>cp config/config.js.sample config/config.js</code></pre></div>



<p class="wp-block-paragraph">以下を実行すると、MagicMirrorが起動して、<code>config.js</code>により設定された画面が表示されます。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>npm run start</code></pre></div>



<p class="wp-block-paragraph">MagicMirrorの画面が表示されました。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="675" src="https://sozorablog.com/wp-content/uploads/2024/02/mm10.jpg" alt="" class="wp-image-11738"/></figure>



<p class="wp-block-paragraph"><span class="sbd-text-red">表示を中断するには、CtrlキーとQキーを同時に押してください。</span></p>



<p class="wp-block-paragraph">ホームディレクトリからMagicMirrorを起動するときは、以下のコマンドを実行します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>cd MagicMirror/ && npm run start</code></pre></div>



<p class="wp-block-paragraph">ここで表示される内容は/home/pi/MagicMirror/config/config.jsのファイルにより設定されています。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="368" src="https://sozorablog.com/wp-content/uploads/2024/02/mm13-1.jpg" alt="" class="wp-image-11742" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph">config.jsの中身を見ていきましょう。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>let config = {
	address: &quot;localhost&quot;,	// Address to listen on, can be:
							// - &quot;localhost&quot;, &quot;127.0.0.1&quot;, &quot;::1&quot; to listen on loopback interface
							// - another specific IPv4/6 to listen on a specific interface
							// - &quot;0.0.0.0&quot;, &quot;::&quot; to listen on any interface
							// Default, when address config is left out or empty, is &quot;localhost&quot;
	port: 8080,
	basePath: &quot;/&quot;,	// The URL path where MagicMirror² is hosted. If you are using a Reverse proxy
									// you must set the sub path here. basePath must end with a /
	ipWhitelist: [&quot;127.0.0.1&quot;, &quot;::ffff:127.0.0.1&quot;, &quot;::1&quot;],	// Set [] to allow all IP addresses
									// or add a specific IPv4 of 192.168.1.5 :
									// [&quot;127.0.0.1&quot;, &quot;::ffff:127.0.0.1&quot;, &quot;::1&quot;, &quot;::ffff:192.168.1.5&quot;],
									// or IPv4 range of 192.168.3.0 --&gt; 192.168.3.15 use CIDR format :
									// [&quot;127.0.0.1&quot;, &quot;::ffff:127.0.0.1&quot;, &quot;::1&quot;, &quot;::ffff:192.168.3.0/28&quot;],

	useHttps: false,			// Support HTTPS or not, default &quot;false&quot; will use HTTP
	httpsPrivateKey: &quot;&quot;,	// HTTPS private key path, only require when useHttps is true
	httpsCertificate: &quot;&quot;,	// HTTPS Certificate path, only require when useHttps is true

	language: &quot;en&quot;,
	locale: &quot;en-US&quot;,
	logLevel: [&quot;INFO&quot;, &quot;LOG&quot;, &quot;WARN&quot;, &quot;ERROR&quot;], // Add &quot;DEBUG&quot; for even more logging
	timeFormat: 24,
	units: &quot;metric&quot;,

	modules: [
		{
			module: &quot;alert&quot;,
		},
		{
			module: &quot;updatenotification&quot;,
			position: &quot;top_bar&quot;
		},
		{
			module: &quot;clock&quot;,
			position: &quot;top_left&quot;
		},
		{
			module: &quot;calendar&quot;,
			header: &quot;US Holidays&quot;,
			position: &quot;top_left&quot;,
			config: {
				calendars: [
					{
						fetchInterval: 7 * 24 * 60 * 60 * 1000,
						symbol: &quot;calendar-check&quot;,
						url: &quot;https://ics.calendarlabs.com/76/mm3137/US_Holidays.ics&quot;
					}
				]
			}
		},
		{
			module: &quot;compliments&quot;,
			position: &quot;lower_third&quot;
		},
		{
			module: &quot;weather&quot;,
			position: &quot;top_right&quot;,
			config: {
				weatherProvider: &quot;openweathermap&quot;,
				type: &quot;current&quot;,
				location: &quot;New York&quot;,
				locationID: &quot;5128581&quot;, //ID from http://bulk.openweathermap.org/sample/city.list.json.gz; unzip the gz file and find your city
				apiKey: &quot;YOUR_OPENWEATHER_API_KEY&quot;
			}
		},
		{
			module: &quot;weather&quot;,
			position: &quot;top_right&quot;,
			header: &quot;Weather Forecast&quot;,
			config: {
				weatherProvider: &quot;openweathermap&quot;,
				type: &quot;forecast&quot;,
				location: &quot;New York&quot;,
				locationID: &quot;5128581&quot;, //ID from http://bulk.openweathermap.org/sample/city.list.json.gz; unzip the gz file and find your city
				apiKey: &quot;YOUR_OPENWEATHER_API_KEY&quot;
			}
		},
		{
			module: &quot;newsfeed&quot;,
			position: &quot;bottom_bar&quot;,
			config: {
				feeds: [
					{
						title: &quot;New York Times&quot;,
						url: &quot;https://rss.nytimes.com/services/xml/rss/nyt/HomePage.xml&quot;
					}
				],
				showSourceTitle: true,
				showPublishDate: true,
				broadcastNewsFeeds: true,
				broadcastNewsUpdates: true
			}
		},
	]
};

/*************** DO NOT EDIT THE LINE BELOW ***************/
if (typeof module !== &quot;undefined&quot;) { module.exports = config; }
</code></pre></div>



<p class="wp-block-paragraph">MagicMirror²では、「モジュール」を使用して画面に特定の情報や機能を表示します。ここでのモジュールは、例えば時計や天気予報のような要素の一つ一つのことを指します。</p>



<p class="wp-block-paragraph">上記の設定で使用しているモジュールは以下の通りです。</p>



<div class="wp-block-sbd-list"><ul class="sbd-list sbd-list-border"><li>alert：重要なお知らせや警告を画面に表示</li><li>updatenotification：MagicMirrorの新しい更新情報を表示</li><li>clock：現在時刻を表示</li><li>calendar：アメリカの休日を含むカレンダーを表示</li><li>compliments：その時々に合わせた優しい言葉を表示</li><li>weather：ニューヨークの今の天気とこれからの天気予報を表示（APIキーが必要）</li><li>newsfeed：ニューヨークタイムズの最新ニュースの見出しを表示</li></ul></div>



<p class="wp-block-paragraph">MagicMirror²にはこれらのモジュールが豊富に用意されており、それらを組み合わせることで自分好みの表示にカスタマイズできます。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="615" src="https://sozorablog.com/wp-content/uploads/2024/02/mm22.jpg" alt="" class="wp-image-11770"/></figure>



<p class="wp-block-paragraph">円形ディスプレイではなく、HDMI対応ディスプレイに表示した場合は、このような画面になります。</p>



<h2 class="wp-block-heading">YouTube動画を表示するための設定</h2>



<p class="wp-block-paragraph">ここからはMagicMirror²をカスタマイズしていきます。</p>



<h3 class="wp-block-heading">MMM-EmbedYoutubeをインストールする</h3>



<p class="wp-block-paragraph">MagicMirrorの画面にYouTube動画を表示するには「MMM-EmbedYoutube」というモジュールをインストールする必要があります。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="413" height="246" src="https://sozorablog.com/wp-content/uploads/2024/02/mm14.png" alt="" class="wp-image-11744" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph">以下のコマンドを1行ずつ順に実行します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>cd
cd ~/MagicMirror/modules
git clone https://github.com/nitpum/MMM-EmbedYoutube.git
cd MMM-EmbedYoutube
npm install</code></pre></div>



<p class="wp-block-paragraph">MMM-EmbedYoutube モジュールが MagicMirror に追加され、使用する準備が整いました。</p>



<h3 class="wp-block-heading">config.jsを編集する</h3>



<p class="wp-block-paragraph">インストールが完了したら、MMM-EmbedYoutubeを表示するための設定に進みます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="368" src="https://sozorablog.com/wp-content/uploads/2024/02/mm13-1.jpg" alt="" class="wp-image-11742" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph">/home/pi/MagicMirror/config/config.jsをダブルクリックして開きます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="568" height="380" src="https://sozorablog.com/wp-content/uploads/2024/02/mm15.png" alt="" class="wp-image-11752" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph">今回はアメリカの<a href="https://www.youtube.com/watch?v=R34ot1LETK0">モントレーベイ水族館のライブカメラ</a>を表示します。</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-4-3 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="Live Open Sea Cam | Monterey Bay Aquarium" width="500" height="375" src="https://www.youtube.com/embed/n_GpVsz4nHU?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<p class="wp-block-paragraph">config.jsを以下の内容に書き換えて保存します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>var config = {
    address: &quot;0.0.0.0&quot;,
    port: 8080,
    ipWhitelist: [&quot;127.0.0.1&quot;, &quot;::ffff:127.0.0.1&quot;, &quot;::1&quot;],

    language: &quot;ja&quot;,
    timeFormat: 24,
    units: &quot;metric&quot;,

    modules: [
    		{
			module: &quot;clock&quot;,
			position: &quot;top_center&quot;,
            config: {
                showDate: false,
                displaySeconds: true, 
                },
		},
{
    module: &#39;MMM-EmbedYoutube&#39;, // Path to youtube module from modules folder Exmaple: MagicMirror/modules/custom/MMM-EmbedYoutube/ so it&#39;s custom/MMM-EmbedYoutube
    position: &#39;top_left&#39;, // This can be any of the regions.
    config: {
      // See &#39;Configuration options&#39; in README.md for more information.
      video_id: &#39;n_GpVsz4nHU&#39;,
      loop: true,
      autoplay: true,
    },
  },
    ]
};

/*************** DO NOT EDIT THE LINE BELOW ***************/
if (typeof module !== &quot;undefined&quot;) { module.exports = config; }

</code></pre></div>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="163" src="https://sozorablog.com/wp-content/uploads/2024/02/mm23.png" alt="" class="wp-image-11779"/></figure>



<p class="wp-block-paragraph">選択する動画のURLの末尾の部分（この場合は&#8221;R34ot1LETK0&#8243;）をvideo_id:に入力します。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="409" src="https://sozorablog.com/wp-content/uploads/2024/02/mm24.jpg" alt="" class="wp-image-11781"/></figure>



<h3 class="wp-block-heading"><code>MMM-EmbedYoutube.js</code>の修正</h3>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="377" height="199" src="https://sozorablog.com/wp-content/uploads/2024/02/mm25.png" alt="" class="wp-image-11783" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph"><code>MMM-EmbedYoutube</code>は長期間更新されておらず、そのままではYouTubeの仕様変更により「エラー153」が発生する場合があります。そこで、YouTubeの現在の仕様に対応できるようプログラムを修正します。</p>



<p class="wp-block-paragraph">MagicMirrorにYouTube動画を表示する処理を行うプログラムである/home/pi/MagicMirror/modules/MMM-EmbedYoutube/MMM-EmbedYoutube.jsを以下のように変更してください。ここでは画面の横幅を1300ピクセル、縦の長さを900ピクセルにしています。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-js" data-lang="JavaScript"><code>
/* Magic Mirror
 * Module: Embed Youtube
 *
 * v 1.4.0
 *
 * By Nitipoom Unrrom (aka nitpum) https://nitpum.com
 * MIT Licensed.
 */
Module.register(&quot;MMM-EmbedYoutube&quot;, {
    defaults: {
        autoplay: false,
        cc_load_policy: false,
        color: &quot;red&quot;,
        controls: false,
        disablekb: false,
        fs: true,
        height: 900,
        width: 1300,
        loop: false,
        modestbranding: false,
        rel: false,
        showinfo: false,
        video_id: &quot;&quot;,
        playlist: &quot;&quot;,
        video_list: []
    },

    getDom: function () {
        var wrapper = document.createElement(&quot;div&quot;);

        // Parameter
        var params = &quot;&quot;;

        var videoList = &quot;&quot;;
        if (this.config.video_list && this.config.video_list.length &gt; 0) {
            videoList = &quot;&playlist=&quot;;
            for (var i = 0; i &lt; this.config.video_list.length; i++) {
                videoList += this.config.video_list[i];
                if (i + 1 &lt; this.config.video_list.length) {
                    videoList += &quot;,&quot;;
                }
            }
        }

        params += this.config.autoplay ? &quot;autoplay=1&quot; : &quot;autoplay=0&quot;;
        params += this.config.cc_load_policy ? &quot;&cc_load_policy=1&quot; : &quot;&cc_load_policy=0&quot;;
        params += (typeof this.config.color !== &quot;undefined&quot; && this.config.color != &quot;red&quot;) ? &quot;&color=&quot; + this.config.color : &quot;&quot;;
        params += this.config.controls ? &quot;&controls=1&quot; : &quot;&controls=0&quot;;
        params += this.config.disablekb ? &quot;&disablekb=1&quot; : &quot;&quot;;
        params += this.config.fs ? &quot;&quot; : &quot;&fs=0&quot;;
        params += (videoList != &quot;&quot; && (typeof this.config.playlist === &quot;undefined&quot; || this.config.playlist == &quot;&quot;)) ? videoList : &quot;&playlist=&quot; + this.config.video_id;
        params += this.config.loop ? &quot;&loop=1&quot; : &quot;&quot;;
        params += this.config.modestbranding ? &quot;&modestbranding=1&quot; : &quot;&quot;;
        params += this.config.rel ? &quot;&rel=1&quot; : &quot;&rel=0&quot;;
        params += this.config.showinfo ? &quot;&showinfo=1&quot; : &quot;&showinfo=0&quot;;

        var videoId = this.config.video_id + &quot;?version=3&quot;;
        if (typeof this.config.playlist !== &quot;undefined&quot; && this.config.playlist != &quot;&quot;) {
            videoId = &quot;playlist?list=&quot; + this.config.playlist + &quot;&&quot;;
        }

        wrapper.innerHTML =
            &quot;&lt;iframe width=\&quot;&quot; + this.config.width +
            &quot;\&quot; height=\&quot;&quot; + this.config.height +
            &quot;\&quot; src=\&quot;https://www.youtube.com/embed/&quot; + videoId + &quot;&&quot; + params +
            &quot;\&quot; frameborder=\&quot;0\&quot;&quot; +
            &quot; referrerpolicy=\&quot;strict-origin-when-cross-origin\&quot;&quot; +
            &quot; allow=\&quot;autoplay; encrypted-media\&quot;&quot; +
            &quot; allowfullscreen&gt;&lt;/iframe&gt;&quot;;

        return wrapper;
    }
});
</code></pre></div>



<p class="wp-block-paragraph">上記のコードは、Nitipoom Unrrom氏がMITライセンスで公開している<code>MMM-EmbedYoutube</code>を一部改変したものです。</p>



<p class="wp-block-paragraph">cd MagicMirror/ &amp;&amp; npm run start　を実行して表示してみます。表示してみると、以下のようになりました。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="610" src="https://sozorablog.com/wp-content/uploads/2024/02/mm17.jpg" alt="" class="wp-image-11755"/></figure>



<p class="wp-block-paragraph">表示サイズは大きくなりましたが、もっと左上に表示を移動させたいところです。</p>



<h3 class="wp-block-heading">YouTube動画の表示位置の調整</h3>



<p class="wp-block-paragraph">モジュールの表示位置は、config.jsの中で<code>position:</code>を使って調整可能です。ただし、すでに<code>'top_left'</code>に設定されているため、画面の左上に表示されています。さらに左上に動かしたい場合はcustom.cssで設定します。</p>



<p class="wp-block-paragraph">まず、以下のコマンドで<code>custom.css</code> という名前の新しいファイルを作成します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>touch /home/pi/MagicMirror/config/custom.css</code></pre></div>



<p class="wp-block-paragraph">以下のコマンドを使い、作成したファイルを<code>nano</code>エディタで開きます。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>nano /home/pi/MagicMirror/config/custom.css</code></pre></div>



<p class="wp-block-paragraph">以下の内容を書き込みます。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>.MMM-EmbedYoutube {
  margin-left: -370px;    
  margin-top: -150px;
}</code></pre></div>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="377" height="237" src="https://sozorablog.com/wp-content/uploads/2024/02/mm18.png" alt="" class="wp-image-11758" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph">nanoエディタでファイルを保存して終了するには、<code>Ctrl + O</code>を押して保存し、<code>Enter</code>を押してから、<code>Ctrl + X</code>で終了します。</p>



<ul class="wp-block-list">
<li><code>margin-left: -370px;</code>：動画の表示エリアを左に370ピクセルずらすように指定しています。マイナスの値を使うことで、通常の位置から左に移動します。</li>



<li><code>margin-top: -150px;</code>：動画の表示エリアを上に150ピクセルずらすように指定しています。マイナスの値を使っているため、通常の位置から上に移動します。</li>
</ul>



<h3 class="wp-block-heading">完成</h3>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="536" src="https://sozorablog.com/wp-content/uploads/2024/02/mm27.jpg" alt="" class="wp-image-11787"/></figure>



<p class="wp-block-paragraph">無事に全画面表示ができました。</p>



<h3 class="wp-block-heading">【応用】一定間隔で動画を切り替える</h3>



<p class="wp-block-paragraph">ここからは応用になります。オーロラのライブカメラを見ていたのですが、オーロラが現れる様子が全くありませんでした。そこで、異なる場所にあるライブカメラを順番に切り替えて表示することで、オーロラを見つけるチャンスを高めようと考えました。ここでは、複数の動画を定期的に切り替える表示方法を紹介します。</p>



<p class="wp-block-paragraph">まず、MMM-EmbedYoutube.jsを以下のように変更します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-js" data-lang="JavaScript"><code>Module.register(&quot;MMM-EmbedYoutube&quot;, {
    defaults: {
        autoplay: false,
        cc_load_policy: false,
        color: &quot;red&quot;,
        controls: false,
        disablekb: false,
        fs: true,
        height: 900,
        width: 1300,
        loop: false,
        modestbranding: false,
        rel: false,
        showinfo: false,
        video_id: &quot;&quot;,
        playlist: &quot;&quot;,
        video_list: [],
        videoRotationList: &quot;&quot;, // 動画IDのリスト
        rotationInterval: 60000, // 1分おきに動画を切り替える
    },

    start: function() {
        this.currentVideoIndex = 0; // 現在の動画インデックス
        this.updateVideo(); // 最初の動画を設定
        this.scheduleUpdate(); // 動画更新スケジュールを設定
    },

    scheduleUpdate: function() {
        var self = this;
        setInterval(function() {
            self.updateVideo();
        }, this.config.rotationInterval);
    },

    updateVideo: function() {
        if (this.config.videoRotationList.length &gt; 0) {
            this.config.video_id = this.config.videoRotationList[this.currentVideoIndex];
            this.currentVideoIndex += 1;
            if (this.currentVideoIndex &gt;= this.config.videoRotationList.length) {
                this.currentVideoIndex = 0; // リストの最初に戻る
            }
            this.updateDom();
        }
    },

    getDom: function() {
        var wrapper = document.createElement(&quot;div&quot;);

        // Parameter
        var params = &quot;&quot;;

        var videoList = &quot;&quot;;
        if (this.config.video_list && this.config.video_list.length &gt; 0) {
            videoList = &quot;&playlist=&quot;;
            for (var i = 0; i &lt; this.config.video_list.length; i++) {
                videoList += this.config.video_list[i];
                if (i + 1 &lt; this.config.video_list.length) videoList += &quot;,&quot;;
            }
        }
        params += (this.config.autoplay) ? &quot;autoplay=1&quot; : &quot;autoplay=0&quot;;
        params += (this.config.cc_load_policy) ? &quot;&cc_load_policy=1&quot; : &quot;&cc_load_policy=0&quot;;
        params += (typeof this.config.color !== &quot;undefined&quot; && this.config.color != &quot;red&quot;) ? &quot;&color=&quot; + this.config.color : &quot;&quot;;
        params += (this.config.controls) ? &quot;&controls=1&quot; : &quot;&controls=0&quot;;
        params += (this.config.disablekb) ? &quot;&disablekb=1&quot; : &quot;&quot;;
        params += (this.config.fs) ? &quot;&quot; : &quot;&fs=0&quot;;
        params += (videoList != &quot;&quot; && (typeof this.config.playlist === &quot;undefined&quot; || this.config.playlist == &quot;&quot;)) ? videoList : &quot;&playlist=&quot; + this.config.video_id;
        params += (this.config.loop) ? &quot;&loop=1&quot; : &quot;&quot;;
        params += (this.config.modestbranding) ? &quot;&modestbranding=1&quot; : &quot;&quot;;
        params += (this.config.rel) ? &quot;&rel=1&quot; : &quot;&rel=0&quot;;
        params += (this.config.showinfo) ? &quot;&showinfo=1&quot; : &quot;&showinfo=0&quot;;

        var videoId = this.config.video_id + &quot;?version=3&quot;;
        if (typeof this.config.playlist !== &quot;undefined&quot; && this.config.playlist != &quot;&quot;)
            videoId = &quot;playlist?list=&quot; + this.config.playlist + &quot;&&quot;;

        wrapper.innerHTML = &quot;&lt;iframe width=\&quot;&quot; + this.config.width + &quot;\&quot; height=\&quot;&quot; + this.config.height + &quot;\&quot; src=\&quot;https://www.youtube.com/embed/&quot; + videoId + &quot;&&quot; + params + &quot;\&quot; frameborder=\&quot;0\&quot; allowfullscreen&gt;&lt;/iframe&gt;&quot;;
        return wrapper;
    }
});
</code></pre></div>



<p class="wp-block-paragraph">次に、config.jsを以下の内容に書き換えます。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-js" data-lang="JavaScript"><code>var config = {
    address: &quot;0.0.0.0&quot;,
    port: 8080,
    ipWhitelist: [&quot;127.0.0.1&quot;, &quot;::ffff:127.0.0.1&quot;, &quot;::1&quot;],

    language: &quot;ja&quot;,
    timeFormat: 24,
    units: &quot;metric&quot;,

    modules: [
    		{
			module: &quot;clock&quot;,
			position: &quot;top_center&quot;,
            config: {
                showDate: false,
                displaySeconds: true 
                },
		},
        
{
    module: &#39;MMM-EmbedYoutube&#39;, // Path to youtube module from modules folder Exmaple: MagicMirror/modules/custom/MMM-EmbedYoutube/ so it&#39;s custom/MMM-EmbedYoutube
    position: &#39;top_left&#39;, // This can be any of the regions.
    config: {
      // See &#39;Configuration options&#39; in README.md for more information.
      videoRotationList: [&#39;dkLjO4TE634&#39;, &#39;O52zDyxg5QI&#39;],
      rotationInterval: 60000, // 1分おきに動画を切り替える
      loop: true,
      autoplay: true,
    },
  },
    ]
};

/*************** DO NOT EDIT THE LINE BELOW ***************/
if (typeof module !== &quot;undefined&quot;) { module.exports = config; }
</code></pre></div>



<p class="wp-block-paragraph">更新間隔はrotationInterval: 60000の数値で変更できます。単位はミリ秒なので、60000は60秒です。</p>



<figure class="wp-block-embed is-type-rich is-provider-x wp-block-embed-x"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="500" data-dnt="true"><p lang="ja" dir="ltr">オーロラを観測できる時計を作りました。<br><br>アラスカのリアルタイム映像を表示しています。いつ出るのか分からないのが良いところ。時間を見るのが楽しみになる時計です。ディスプレイの表示には、小型PCの「ラズベリーパイ」を使っています。 <a href="https://t.co/IpAwCk6S4f">pic.twitter.com/IpAwCk6S4f</a></p>&mdash; そぞら@Raspberry Pi 電子工作 (@sozoraemon) <a href="https://x.com/sozoraemon/status/1758809664064795064?ref_src=twsrc%5Etfw">February 17, 2024</a></blockquote><script async src="https://platform.x.com/widgets.js" charset="utf-8"></script>
</div></figure>



<h2 class="wp-block-heading">MagicMirror²は面白い</h2>



<figure class="wp-block-image size-full"><img decoding="async" width="322" height="110" src="https://sozorablog.com/wp-content/uploads/2024/02/ezgif-4-892cf468b9.gif" alt="" class="wp-image-11809" srcset="https://sozorablog.com/wp-content/uploads/2024/02/ezgif-4-892cf468b9.gif 322w, https://sozorablog.com/wp-content/uploads/2024/02/ezgif-4-892cf468b9-320x110.gif 320w" sizes="(max-width: 322px) 100vw, 322px" /><figcaption class="wp-element-caption"><a href="https://github.com/Isaac-the-Man/MMM-nixie-clock">MMM-nixie-clock</a>を使用</figcaption></figure>



<p class="wp-block-paragraph">MagicMirror²には、多くの<a href="https://github.com/MagicMirrorOrg/MagicMirror/wiki/3rd-Party-Modules">サードパーティ製モジュール</a>が公開されています。興味があるものを試して、自分だけのオリジナル表示を作成してみるのはいかがでしょうか。</p>



<p class="wp-block-paragraph">以下は、MagicMirror²を使用して作成した表示の例です。</p>



<figure class="wp-block-embed is-type-rich is-provider-x wp-block-embed-x"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="500" data-dnt="true"><p lang="ja" dir="ltr">ラズパイを使って、国際宇宙ステーションのライブ映像が見られる時計を作りました。<br><br>背後にはゆっくり動く巨大な地球。ラズパイはロマンの塊だ。 <a href="https://t.co/7fEfMGzinU">pic.twitter.com/7fEfMGzinU</a></p>&mdash; そぞら@Raspberry Pi 電子工作 (@sozoraemon) <a href="https://x.com/sozoraemon/status/1728009738489901321?ref_src=twsrc%5Etfw">November 24, 2023</a></blockquote><script async src="https://platform.x.com/widgets.js" charset="utf-8"></script>
</div></figure>



<figure class="wp-block-embed is-type-rich is-provider-x wp-block-embed-x"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="500" data-dnt="true"><p lang="ja" dir="ltr">ひまわり8号のリアルタイム画像に時計と天気予報を表示してみた。<br><br>使用したのは、ラズパイとMagicMirror2というソフト。Magic Mirror2は、豊富なオプションがあり、魅力的な表示がサクッと作れます。 <a href="https://t.co/MEFxoHotLp">pic.twitter.com/MEFxoHotLp</a></p>&mdash; そぞら@Raspberry Pi 電子工作 (@sozoraemon) <a href="https://x.com/sozoraemon/status/1722216807644422188?ref_src=twsrc%5Etfw">November 8, 2023</a></blockquote><script async src="https://platform.x.com/widgets.js" charset="utf-8"></script>
</div></figure>



<figure class="wp-block-embed is-type-rich is-provider-x wp-block-embed-x"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="500" data-dnt="true"><p lang="ja" dir="ltr">ラズパイで自分好みの表示装置を作りました。「MagicMirror²」というソフトを使用。中央部分には好きなYouTube動画を埋め込んでいます。<br><br>ワイドモニターは表示の向きを縦横に変更することで、さまざまなシチュエーションに対応可能です。 <a href="https://t.co/riiXhXXgMA">https://t.co/riiXhXXgMA</a> <a href="https://t.co/MARDYeGraw">pic.twitter.com/MARDYeGraw</a></p>&mdash; そぞら@Raspberry Pi 電子工作 (@sozoraemon) <a href="https://x.com/sozoraemon/status/1706984622452875367?ref_src=twsrc%5Etfw">September 27, 2023</a></blockquote><script async src="https://platform.x.com/widgets.js" charset="utf-8"></script>
</div></figure>



<figure class="wp-block-embed is-type-rich is-provider-x wp-block-embed-x"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="500" data-dnt="true"><p lang="ja" dir="ltr">ラズパイとオープンソースのアプリケーション「MagicMirror2」で作ったデジタル時計。いろんなバリエーションの表示ができて普通に楽しい。 <a href="https://t.co/1muqUMw8OO">pic.twitter.com/1muqUMw8OO</a></p>&mdash; そぞら@Raspberry Pi 電子工作 (@sozoraemon) <a href="https://x.com/sozoraemon/status/1727275210506965087?ref_src=twsrc%5Etfw">November 22, 2023</a></blockquote><script async src="https://platform.x.com/widgets.js" charset="utf-8"></script>
</div></figure>



<figure class="wp-block-embed is-type-rich is-provider-x wp-block-embed-x"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="500" data-dnt="true"><p lang="ja" dir="ltr">ラズパイを使って、今日の「月の形」がわかる時計を作りました。モノトーンの画面がお気に入り。画像は自動更新です。 <a href="https://t.co/16mRdkTxT3">pic.twitter.com/16mRdkTxT3</a></p>&mdash; そぞら@Raspberry Pi 電子工作 (@sozoraemon) <a href="https://x.com/sozoraemon/status/1725837143829045607?ref_src=twsrc%5Etfw">November 18, 2023</a></blockquote><script async src="https://platform.x.com/widgets.js" charset="utf-8"></script>
</div></figure>



<figure class="wp-block-embed is-type-rich is-provider-x wp-block-embed-x"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="500" data-dnt="true"><p lang="ja" dir="ltr">ラズパイを使って、富士山ライブカメラ専用モニターを作りました。絶景パノラマビューを自宅で楽しめます。<br><br>全画面表示と表示範囲の調整にこだわりました。ライブ映像なので、画面を鳥が横切ることも。 <a href="https://t.co/mjsF6VlzZ4">pic.twitter.com/mjsF6VlzZ4</a></p>&mdash; そぞら@Raspberry Pi 電子工作 (@sozoraemon) <a href="https://x.com/sozoraemon/status/1714228213436830082?ref_src=twsrc%5Etfw">October 17, 2023</a></blockquote><script async src="https://platform.x.com/widgets.js" charset="utf-8"></script>
</div></figure>
]]></content:encoded>
					
					<wfw:commentRss>https://sozorablog.com/magicmirror/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>次世代の電子工作！Raspberry PiでChatGPTを使う方法</title>
		<link>https://sozorablog.com/raspberry-pi-chatgpt/</link>
					<comments>https://sozorablog.com/raspberry-pi-chatgpt/#respond</comments>
		
		<dc:creator><![CDATA[そぞら]]></dc:creator>
		<pubDate>Wed, 19 Apr 2023 14:32:12 +0000</pubDate>
				<category><![CDATA[Raspberry Pi]]></category>
		<category><![CDATA[使い方]]></category>
		<guid isPermaLink="false">https://sozorablog.com/?p=10980</guid>

					<description><![CDATA[高性能なAIとして話題のChatGPT。誰もが手軽にAIとの対話を楽しめることで注目を集めており、瞬く間にユーザー数１億人オーバーという凄まじい状況になっています。 ChatGPTはAPIも提供されており、ラズベリーパイ [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">高性能なAIとして話題の<a href="https://openai.com/blog/chatgpt">ChatGPT</a>。誰もが手軽にAIとの対話を楽しめることで注目を集めており、瞬く間に<span class="sbd-text-red">ユーザー数１億人オーバー</span>という凄まじい状況になっています。</p>



<p class="wp-block-paragraph">ChatGPTはAPIも提供されており、<a href="https://sozorablog.com/what-is-raspberry-pi/">ラズベリーパイ</a>を用いたプログラミングにより、文章の生成などの処理を自動化できます。<a href="https://openai.com/blog/introducing-chatgpt-and-whisper-apis">ChatGPT API</a>を駆使すれば、ラズパイのようなコンパクトなデバイスにAI機能を組み込むことが可能です。</p>



<p class="wp-block-paragraph">たとえば、天気予報の情報を取得し、それをChatGPT APIに渡して<span class="sbd-text-bg-yellow">ポジティブな文章に変換</span>して表示するといった使い方もできます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="955" src="https://sozorablog.com/wp-content/uploads/2023/04/IMG_8708.jpeg" alt="" class="wp-image-14207" style="width:465px;height:auto"/><figcaption class="wp-element-caption">どんな天気もポジティブに伝える「AI天気予報パネル」</figcaption></figure>



<p class="wp-block-paragraph">本記事ではラズパイとChatGPTを活用した斬新な電子工作作品を紹介します。最後までお読みいただくことで、これまでにない<span class="sbd-text-bg-yellow">ワクワクするような楽しい作品のアイデア</span>に出会えることでしょう。</p>



<h2 class="wp-block-heading">ChatGPTは文章生成AI</h2>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="450" src="https://sozorablog.com/wp-content/uploads/2023/04/ラズベリーパイの選び方-39.jpg" alt="" class="wp-image-11026" srcset="https://sozorablog.com/wp-content/uploads/2023/04/ラズベリーパイの選び方-39.jpg 800w, https://sozorablog.com/wp-content/uploads/2023/04/ラズベリーパイの選び方-39-300x169.jpg 300w, https://sozorablog.com/wp-content/uploads/2023/04/ラズベリーパイの選び方-39-768x432.jpg 768w, https://sozorablog.com/wp-content/uploads/2023/04/ラズベリーパイの選び方-39-320x180.jpg 320w, https://sozorablog.com/wp-content/uploads/2023/04/ラズベリーパイの選び方-39-224x126.jpg 224w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<p class="wp-block-paragraph"><a href="https://openai.com/blog/chatgpt">ChatGPT</a>は人工知能（AI）の一種で、コンピューターが人間と同じように<span class="sbd-text-red">自然な文章</span>を作成することができる技術です。例えば、何かしらの質問に答えたり、指示された文章を作成したりすることができます。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="450" src="https://sozorablog.com/wp-content/uploads/2023/03/picoW-chatGPT1.jpg" alt="" class="wp-image-10873" srcset="https://sozorablog.com/wp-content/uploads/2023/03/picoW-chatGPT1.jpg 800w, https://sozorablog.com/wp-content/uploads/2023/03/picoW-chatGPT1-300x169.jpg 300w, https://sozorablog.com/wp-content/uploads/2023/03/picoW-chatGPT1-768x432.jpg 768w, https://sozorablog.com/wp-content/uploads/2023/03/picoW-chatGPT1-320x180.jpg 320w, https://sozorablog.com/wp-content/uploads/2023/03/picoW-chatGPT1-224x126.jpg 224w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<p class="wp-block-paragraph">まるでロボットに話しかけているような感覚で、コンピューターと会話ができます。</p>



<h3 class="wp-block-heading">APIを使えばプログラミングでChatGPTが利用可能</h3>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="450" src="https://sozorablog.com/wp-content/uploads/2023/04/ラズベリーパイの選び方-40.png" alt="" class="wp-image-11028" srcset="https://sozorablog.com/wp-content/uploads/2023/04/ラズベリーパイの選び方-40.png 800w, https://sozorablog.com/wp-content/uploads/2023/04/ラズベリーパイの選び方-40-300x169.png 300w, https://sozorablog.com/wp-content/uploads/2023/04/ラズベリーパイの選び方-40-768x432.png 768w, https://sozorablog.com/wp-content/uploads/2023/04/ラズベリーパイの選び方-40-320x180.png 320w, https://sozorablog.com/wp-content/uploads/2023/04/ラズベリーパイの選び方-40-224x126.png 224w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<p class="wp-block-paragraph">APIとは、Application Programming Interfaceの略称で、プログラムの機能を外部に公開するためのインターフェースのことです。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="567" height="275" src="https://sozorablog.com/wp-content/uploads/2023/04/ChatGPT-1.png" alt="" class="wp-image-11056" srcset="https://sozorablog.com/wp-content/uploads/2023/04/ChatGPT-1.png 567w, https://sozorablog.com/wp-content/uploads/2023/04/ChatGPT-1-300x146.png 300w" sizes="(max-width: 567px) 100vw, 567px" /><figcaption class="wp-element-caption">ChatGPT APIを利用するPythonスクリプトの一部</figcaption></figure>



<p class="wp-block-paragraph">ChatGPT APIは、プログラムから文章を生成したり、文章を理解したりすることができます。これをRaspberry Piで利用することにより、<span class="sbd-text-red">自動でChatGPTに質問を送り、応答を受け取ることが可能です</span>。</p>



<h3 class="wp-block-heading">ChatGPT APIは有料</h3>



<p class="wp-block-paragraph">2023年3月時点でのChatGPT API使用料金は以下の通りです。トークンとは単語数を計測する単位のことで、日本語の場合1000トークンで約750文字となります。</p>



<figure class="wp-block-table wp-block-sbd-table wp-block-sbd-table-vertical sbd-table--scroll"><table class="has-fixed-layout"><thead><tr><th>モデル</th><th>料金</th><th>備考</th></tr></thead><tbody><tr><td>GPT-4<br>8K context</td><td>入力：$0.03&nbsp;/ 1000トークン<br>出力：$0.06&nbsp;/ 1000トークン</td><td>8000トークンまで使えるプラン</td></tr><tr><td>GPT-4<br>32K context</td><td>入力：$0.06&nbsp;/ 1000トークン<br>出力：$0.12&nbsp;/ 1000トークン</td><td>32000トークンまで使えるプラン</td></tr><tr><td>gpt-3.5-turbo</td><td>$0.002 / 1000トークン</td><td>－</td></tr><tr><td>Davinci</td><td>$0.0200&nbsp;/ 1000トークン</td><td>－</td></tr></tbody></table><figcaption class="wp-element-caption">価格の詳細：<a href="https://openai.com/pricing">公式ページ</a></figcaption></figure>



<p class="wp-block-paragraph">ChatGPT APIは使用量に応じて、利用料金が発生します。料金の詳細は<a href="https://zenn.dev/umi_mori/books/chatbot-chatgpt/viewer/how_to_calculate_openai_api_prices">こちらのサイト</a>で詳しく解説されています。<br></p>



<h2 class="wp-block-heading">APIキーを発行する</h2>



<figure class="wp-block-image size-full"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2023/03/picoW-chatGPT16.jpg" alt=""/></figure>



<p class="wp-block-paragraph">ChatGPT APIを利用するにはAPIキーが必要です。APIキーはWeb APIを使用するために必要な<span class="sbd-text-red">パスワードのようなもの</span>です。</p>



<p class="wp-block-paragraph">APIキーを発行する方法は以下のサイトが参考になります。<br><a href="https://programming-zero.net/openai-api-key/">【画像付き】OpenAI（ChatGPT）のAPIキー取得手順</a></p>



<div class="wp-block-sbd-checkpoint-block"><p class="sbd-checkpoint-title">チェックポイント</p><div class="sbd-checkpoint-content sbd-inner-block-init"><p>APIキーの取り扱いには注意が必要です。第三者に悪用されると、課金額が増加する可能性があります。</p></div></div>



<h2 class="wp-block-heading">ChatGPT APIを利用する方法</h2>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="601" src="https://sozorablog.com/wp-content/uploads/2023/04/ChatGPT2.jpg" alt="" class="wp-image-11058" srcset="https://sozorablog.com/wp-content/uploads/2023/04/ChatGPT2.jpg 800w, https://sozorablog.com/wp-content/uploads/2023/04/ChatGPT2-300x225.jpg 300w, https://sozorablog.com/wp-content/uploads/2023/04/ChatGPT2-768x577.jpg 768w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<h3 class="wp-block-heading">OpenAIライブラリをインストールする</h3>



<p class="wp-block-paragraph">OpenAIライブラリをインストールすると、PythonスクリプトからChatGPT APIを操作できるようになります。</p>



<p class="wp-block-paragraph">ターミナルを開いて以下のコマンドを実行します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>pip3 install openai</code></pre></div>



<figure class="wp-block-image size-full"><img decoding="async" width="447" height="257" src="https://sozorablog.com/wp-content/uploads/2023/04/raspberrypi-chatgpt2.png" alt="" class="wp-image-11046" srcset="https://sozorablog.com/wp-content/uploads/2023/04/raspberrypi-chatgpt2.png 447w, https://sozorablog.com/wp-content/uploads/2023/04/raspberrypi-chatgpt2-300x172.png 300w" sizes="(max-width: 447px) 100vw, 447px" /></figure>



<h3 class="wp-block-heading">ChatGPT APIにアクセスするコード</h3>



<p class="wp-block-paragraph">以下のコードはOpenAIのAPIを使用してチャットを行うためのものです。コードを実行すると、「あなたは誰？」に対する返信が出力されます。</p>



<div class="wp-block-sbd-checkpoint-block"><p class="sbd-checkpoint-title">チェックポイント</p><div class="sbd-checkpoint-content sbd-inner-block-init"><p>5行目の&#8221;YOUR OpenAI API key&#8221;の部分にAPIキーを入力してください。</p></div></div>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code># OpenAIのライブラリをインポート
import openai

# APIキーを設定
openai.api_key = &quot;YOUR OpenAI API key&quot; # 前述で発行したAPIキーに置き換えてください

# クライアントを初期化
client = openai.OpenAI(api_key=openai.api_key)

# GPT-3.5-turboモデルを使ってチャットの回答を生成するリクエストを作成
response = client.chat.completions.create(
    model=&quot;gpt-3.5-turbo&quot;,  # 使用するモデルを指定
    messages=[  # メッセージのリスト
        {
            &quot;role&quot;: &quot;user&quot;,  # ユーザーの役割
            &quot;content&quot;: &quot;あなたは誰？&quot;  # ユーザーからの質問
        },
    ]
)

# 返信のみを取得して変数に格納
c_res = response.choices[0].message.content

# 返信を出力
print(c_res)</code></pre></div>



<p class="wp-block-paragraph">以下のように返信されました。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="660" height="223" src="https://sozorablog.com/wp-content/uploads/2023/04/raspberrypi-chatgpt1.png" alt="" class="wp-image-11042" srcset="https://sozorablog.com/wp-content/uploads/2023/04/raspberrypi-chatgpt1.png 660w, https://sozorablog.com/wp-content/uploads/2023/04/raspberrypi-chatgpt1-300x101.png 300w" sizes="(max-width: 660px) 100vw, 660px" /></figure>



<p class="wp-block-paragraph">13行目の質問の文章を適切に設定することにより、AIにさまざまなことをしゃべらせることができます。</p>



<h2 class="wp-block-heading">ChatGPTを使った作品（Raspberry Pi）</h2>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="450" src="https://sozorablog.com/wp-content/uploads/2023/04/ラズベリーパイの選び方-3.png" alt="" class="wp-image-11051" srcset="https://sozorablog.com/wp-content/uploads/2023/04/ラズベリーパイの選び方-3.png 800w, https://sozorablog.com/wp-content/uploads/2023/04/ラズベリーパイの選び方-3-300x169.png 300w, https://sozorablog.com/wp-content/uploads/2023/04/ラズベリーパイの選び方-3-768x432.png 768w, https://sozorablog.com/wp-content/uploads/2023/04/ラズベリーパイの選び方-3-320x180.png 320w, https://sozorablog.com/wp-content/uploads/2023/04/ラズベリーパイの選び方-3-224x126.png 224w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<p class="wp-block-paragraph">ラズベリーパイは入出力端子が豊富で、さまざまなハードウェアを接続できます。センサーやカメラなどを組み合わせて、自動でChatGPTを呼び出すことが可能です。</p>



<h3 class="wp-block-heading">透明OLEDへ表示</h3>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="534" src="https://sozorablog.com/wp-content/uploads/2023/04/image_67202049.jpg" alt="" class="wp-image-11097" srcset="https://sozorablog.com/wp-content/uploads/2023/04/image_67202049.jpg 800w, https://sozorablog.com/wp-content/uploads/2023/04/image_67202049-300x200.jpg 300w, https://sozorablog.com/wp-content/uploads/2023/04/image_67202049-768x513.jpg 768w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<p class="wp-block-paragraph"><a href="https://www.switch-science.com/products/8315?variant=42383969812678">透明OLED</a>とは、有機発光ダイオード（OLED）技術を用いた透明なディスプレイのことです。画面が透明なため、ディスプレイの背後にある物体などが見える<span class="sbd-text-red">近未来的なデザイン</span>が魅力です。</p>



<figure class="wp-block-embed is-type-rich is-provider-twitter wp-block-embed-twitter"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="500" data-dnt="true"><p lang="ja" dir="ltr">ChatGPT APIを使って、今日の気候に最適な服装を提案する装置を作ってみた。<br><br>ラズパイで天気と気温をインターネットから自動で取得して、ChatGPTに質問した回答を表示させる仕組み。<br><br>服装選びに迷いがちな今の時期に、快適さをプラス。 <a href="https://t.co/uE9KwvOoo4">pic.twitter.com/uE9KwvOoo4</a></p>&mdash; そぞら@Raspberry Pi 電子工作 (@sozoraemon) <a href="https://twitter.com/sozoraemon/status/1634028045953818624?ref_src=twsrc%5Etfw">March 10, 2023</a></blockquote><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</div></figure>



<p class="wp-block-paragraph">ChatGPTにメッセージを投げかけるときには<span class="sbd-text-red">毎日変わる要素</span>を追加するのがポイントです。上記の例では天気予報サイトからスクレイピングした情報をメッセージに追加して質問を投げています。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>response = client.chat.completions.create(
    model=&quot;gpt-3.5-turbo&quot;,
    messages=[
        {&quot;role&quot;: &quot;user&quot;,
         &quot;content&quot;: &quot;最低気温&quot;+temp_min+&quot;℃、最高気温&quot;+temp_max+&quot;℃、&quot;+tenki+&quot;の天気に適した30代男性の服装を50文字以内で教えて。気温や天気は不要です。&quot;}, #※1後述
    ]
)</code></pre></div>



<figure class="wp-block-embed is-type-rich is-provider-twitter wp-block-embed-twitter"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="500" data-dnt="true"><p lang="ja" dir="ltr">ラズパイとChatGPT APIを使って、ユーザーに話しかけるロボットを作りました。<br><br>AIカメラが人物を認識したとき、現在時刻や天候に合った「声かけ」をする仕組みです。<br><br>次は音声合成で、テキストをしゃべらせてみます。 <a href="https://t.co/1xTWSGEEfL">pic.twitter.com/1xTWSGEEfL</a></p>&mdash; そぞら@Raspberry Pi 電子工作 (@sozoraemon) <a href="https://twitter.com/sozoraemon/status/1634743842149928966?ref_src=twsrc%5Etfw">March 12, 2023</a></blockquote><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</div></figure>



<h3 class="wp-block-heading">音声合成でラズパイをしゃべらせる</h3>



<p class="wp-block-paragraph"><a href="https://monomonotech.jp/kurage/raspberrypi/raspi_speech_synthesis.html">Open JTalk</a>という日本語のテキストを音声に変換するオープンソースの音声合成エンジンを使用して、ChatGPTの生成したテキストをしゃべらせています。</p>



<figure class="wp-block-embed is-type-rich is-provider-twitter wp-block-embed-twitter"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="500" data-dnt="true"><p lang="ja" dir="ltr">ラズパイとChatGPT APIを使って、ユーザーに話しかけるロボットを作りました。<br><br>カメラが人物を認識したとき、現在時刻や天候に合った「声かけ」をする仕組みです。<br><br> ChatGPTの登場で「おしゃべりロボット」を作るハードルが大幅に下がっています。 <a href="https://t.co/ABCUAAADBN">pic.twitter.com/ABCUAAADBN</a></p>&mdash; そぞら@Raspberry Pi 電子工作 (@sozoraemon) <a href="https://twitter.com/sozoraemon/status/1634830619728580608?ref_src=twsrc%5Etfw">March 12, 2023</a></blockquote><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</div></figure>



<p class="wp-block-paragraph"><a href="https://www.pc-koubou.jp/magazine/19743">Julius</a>というオープンソースの音声認識エンジンを使えば、日本語の音声認識ができます。ただ、Juliusの認識制度はそれほど高くありません。長い文章や複雑な文章の認識は不可能です。このため、Raspberry Piにつないだ<a href="https://www.amazon.co.jp/SunFounder-USB%E3%83%9F%E3%83%8B%E3%83%9E%E3%82%A4%E3%82%AF-%E3%83%89%E3%83%A9%E3%82%A4%E3%83%90%E3%83%BC%E4%B8%8D%E8%A6%81-VOIP%E9%9F%B3%E5%A3%B0%E8%AA%8D%E8%AD%98%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2-Raspberry/dp/B08K9348F6/ref=sr_1_5?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&amp;crid=290RCXO8S2YDS&amp;keywords=SunFounder+%E8%B6%85%E5%B0%8F%E5%9E%8B+USB%E3%83%9F%E3%83%8B%E3%83%9E%E3%82%A4%E3%82%AF&amp;qid=1665344180&amp;sprefix=sunfounder+%E8%B6%85%E5%B0%8F%E5%9E%8B+usb%E3%83%9F%E3%83%8B%E3%83%9E%E3%82%A4%E3%82%AF%2Caps%2C161&amp;sr=8-5">マイク</a>で特定の短い単語を認識したときにプログラムを実行する仕組みとしました。</p>



<figure class="wp-block-embed is-type-rich is-provider-twitter wp-block-embed-twitter"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="500" data-dnt="true"><p lang="ja" dir="ltr">ChatGPT APIを使って、ラズパイとおしゃべりできる装置を作ってみた。<br><br>「おはよう」と声をかけると、天気予報を調べて、天候に合った返事をしてくれます。 <a href="https://t.co/NJ5cYo9OIh">pic.twitter.com/NJ5cYo9OIh</a></p>&mdash; そぞら@Raspberry Pi 電子工作 (@sozoraemon) <a href="https://twitter.com/sozoraemon/status/1635582904159047684?ref_src=twsrc%5Etfw">March 14, 2023</a></blockquote><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</div></figure>



<h3 class="wp-block-heading">電子ペーパーへ表示</h3>



<p class="wp-block-paragraph">Raspberry Piは<a href="https://www.sengoku.co.jp/mod/sgk_cart/detail.php?code=EEHD-58WK">電子ペーパー</a>を制御できます。電子ペーパーとは電子インク技術を利用した表示デバイスのことです。紙のような見た目で、省エネルギーで動作する特徴があります。</p>



<!-- START MoshimoAffiliateEasyLink -->
<script type="text/javascript">
(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;
b[a]=b[a]||function(){arguments.currentScript=c.currentScript
||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};
c.getElementById(a)||(d=c.createElement(f),d.src=g,
d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})
(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");
msmaflink({"n":"2.7インチ SPI 電子ペーパー モジュール E-inK ディスプレイ HAT スターターキット for RPI Raspberry Pi Zero 2 W 2W WH 拡張ボード ラズパイゼロ ユニバーサル基板 ラズベリーパイゼロ 2W 互換 3 Model B 4 スターターセット","b":"","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/412WMzfoDEL._SL500_.jpg","\/41P7VxgbsVL._SL500_.jpg","\/51A-FDpA5LL._SL500_.jpg","\/41o5vF6SqUL._SL500_.jpg","\/51j-pd1XbbL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/B0BKWJ5123","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":3,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/B0BKWJ5123","a_id":3038653,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1}],"eid":"XM6a0","s":"s"});
</script>
<div id="msmaflink-XM6a0">リンク</div>
<!-- MoshimoAffiliateEasyLink END -->



<p class="wp-block-paragraph">電子ペーパーを使用するメリットは以下の通りです。</p>



<div class="wp-block-sbd-list"><ul class="sbd-list sbd-list-border"><li>省エネルギー</li><li>視認性が高い</li><li>目に優しい</li><li>軽量・薄型</li></ul></div>



<figure class="wp-block-embed is-type-rich is-provider-twitter wp-block-embed-twitter"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="500" data-dnt="true"><p lang="ja" dir="ltr">ChatGPTからメッセージが届く自作ガジェット。<br><br>「伝説の占い師」になりきったAIが今日の運勢を教えてくれます。 <a href="https://t.co/NA5k3JDUFT">pic.twitter.com/NA5k3JDUFT</a></p>&mdash; そぞら@Raspberry Pi 電子工作 (@sozoraemon) <a href="https://twitter.com/sozoraemon/status/1641398727167598595?ref_src=twsrc%5Etfw">March 30, 2023</a></blockquote><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</div></figure>



<figure class="wp-block-embed is-type-rich is-provider-twitter wp-block-embed-twitter"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="500" data-dnt="true"><p lang="ja" dir="ltr">ChatGPTからメッセージが届く自作ガジェット。<br><br>今日は「ChatGPT犬」に変身してもらいました。日替わりでランダムに人格を切替えるプログラムを組むのも面白そう。 <a href="https://t.co/Q5od86KMYS">pic.twitter.com/Q5od86KMYS</a></p>&mdash; そぞら@Raspberry Pi 電子工作 (@sozoraemon) <a href="https://twitter.com/sozoraemon/status/1640910053124497409?ref_src=twsrc%5Etfw">March 29, 2023</a></blockquote><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</div></figure>



<figure class="wp-block-embed is-type-rich is-provider-twitter wp-block-embed-twitter"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="500" data-dnt="true"><p lang="ja" dir="ltr">毎朝ChatGPTから「気合いの入るメッセージ」が届く自作ガジェット。<br><br>人格を変更することで、テイストの違ったメッセージを表示可能。今回、指定した人格は「熱血教師」です。 <a href="https://t.co/A56HEViRew">pic.twitter.com/A56HEViRew</a></p>&mdash; そぞら@Raspberry Pi 電子工作 (@sozoraemon) <a href="https://twitter.com/sozoraemon/status/1640558253196349440?ref_src=twsrc%5Etfw">March 28, 2023</a></blockquote><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</div></figure>



<figure class="wp-block-embed is-type-rich is-provider-twitter wp-block-embed-twitter"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="500" data-dnt="true"><p lang="ja" dir="ltr">ChatGPTからのメッセージが届く自作ガジェット。<br><br>エイプリルフールにちなんで、AIに「ウソ」をついてもらいました。突拍子のないウソが良い感じ。 <a href="https://t.co/Yz3YTbIkjy">pic.twitter.com/Yz3YTbIkjy</a></p>&mdash; そぞら@Raspberry Pi 電子工作 (@sozoraemon) <a href="https://twitter.com/sozoraemon/status/1642754975863558144?ref_src=twsrc%5Etfw">April 3, 2023</a></blockquote><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</div></figure>



<h3 class="wp-block-heading">診断装置</h3>



<p class="wp-block-paragraph">ChatGPTに質問を複数生成してもらい、それに回答していくことで何らかの診断をしてもらうことが可能です。</p>



<figure class="wp-block-embed is-type-rich is-provider-twitter wp-block-embed-twitter"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="500" data-dnt="true"><p lang="ja" dir="ltr">ChatGPTと電子工作を組み合わせて、「骨格診断装置」を作りました。<br><br>骨格診断のスペシャリストになりきったChatGPTが、自動で生成する2択の質問に対して、AボタンまたはBボタンで回答していく仕組み。<br><br>7つの質問に回答した結果、自分の骨格タイプは「ストレート」であることが判明しました。 <a href="https://t.co/AH76F9wGl9">pic.twitter.com/AH76F9wGl9</a></p>&mdash; そぞら@Raspberry Pi 電子工作 (@sozoraemon) <a href="https://twitter.com/sozoraemon/status/1639828174707240960?ref_src=twsrc%5Etfw">March 26, 2023</a></blockquote><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</div></figure>



<p class="wp-block-paragraph">Aのボタンが押されたら「A」という回答を送り、Bのボタンが押されたら「B」という回答を送るプログラムを組みました。質問文は以下のように記述しています。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>user = &#39;&#39;&#39;
あなたは骨格診断のスペシャリストです。
これから私にさまざまな質問をしながら骨格診断をして、私の骨格のタイプを教えて。

#質問のルール
・質問形式は全てAとBの2択で答えられるようにしてください。
・質問数は最大7回まで。
・最後の質問に答えたあとに診断結果を出してください。
・最初の質問で,AとBの2択で性別を選択させること。
・質問は必ず１つずつ出力してください。
・質問文は簡潔にすること。
・診断結果は簡潔にすること。
・「了解しました。」や「次の質問です。」は書かないこと。

それでは質問を開始してください。&#39;&#39;&#39;</code></pre></div>



<figure class="wp-block-embed is-type-rich is-provider-twitter wp-block-embed-twitter"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="500" data-dnt="true"><p lang="ja" dir="ltr">ChatGPTとラズパイを使って「性格診断装置」を作りました。<br><br>ChatGPTが生成する選択形式の質問に、ボタン操作で回答していく仕組み。<br><br>数問程度の質問に答えただけなのに、診断結果がわりと当たってる気がして、普通にすごい。 <a href="https://t.co/VkalorzxG8">pic.twitter.com/VkalorzxG8</a></p>&mdash; そぞら@Raspberry Pi 電子工作 (@sozoraemon) <a href="https://twitter.com/sozoraemon/status/1640191693768241155?ref_src=twsrc%5Etfw">March 27, 2023</a></blockquote><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</div></figure>



<h2 class="wp-block-heading">ChatGPTを使った作品（Raspberry Pi Pico W）</h2>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="450" src="https://sozorablog.com/wp-content/uploads/2023/03/picoW-chatGPT11.png" alt="" class="wp-image-10900" srcset="https://sozorablog.com/wp-content/uploads/2023/03/picoW-chatGPT11.png 800w, https://sozorablog.com/wp-content/uploads/2023/03/picoW-chatGPT11-300x169.png 300w, https://sozorablog.com/wp-content/uploads/2023/03/picoW-chatGPT11-768x432.png 768w, https://sozorablog.com/wp-content/uploads/2023/03/picoW-chatGPT11-320x180.png 320w, https://sozorablog.com/wp-content/uploads/2023/03/picoW-chatGPT11-224x126.png 224w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<p class="wp-block-paragraph">2023年3月に発売された<a href="https://sozorablog.com/raspberry-pi-pico-w-review/">Raspberry Pi Pico W</a>を使った作品を紹介します。Pico Wは無線LANが使えるマイコンです。ラズパイよりも低スペックなため、できることは限られますが、低価格でシステムが組めるというメリットがあります。</p>



<div class="wp-block-sbd-background-block sbd-bg-color sbd-inner-block-init is-style-yellow">
<p class="wp-block-paragraph">Raspberry Pi Pico WでChatGPTを使う方法は、以下の記事で詳しく解説しています。<br><span class="sbd-text-bold"><a href="https://sozorablog.com/raspberry-pi-pico-w-chatgpt/">≫ AIと電子工作の融合！Raspberry Pi Pico WでChatGPT APIを使用する方法</a></span></p>
</div>



<figure class="wp-block-embed is-type-rich is-provider-twitter wp-block-embed-twitter"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="500" data-dnt="true"><p lang="ja" dir="ltr">ChatGPTにスタイリストをしてもらう装置ができた。<br><br>当日の最高気温と最低気温、降水確率を自動で取得して、天気に適した「モテる服」をAIに提案してもらい、表示させる仕組み。<br><br>PCやスマホを使わずに、1200円のマイコンで動作させてます。… <a href="https://t.co/4kUPulSEp7">pic.twitter.com/4kUPulSEp7</a></p>&mdash; そぞら@Raspberry Pi 電子工作 (@sozoraemon) <a href="https://twitter.com/sozoraemon/status/1637402889474945030?ref_src=twsrc%5Etfw">March 19, 2023</a></blockquote><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</div></figure>



<figure class="wp-block-embed is-type-rich is-provider-twitter wp-block-embed-twitter"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="500" data-dnt="true"><p lang="ja" dir="ltr">ChatGPTで「AIペット」を作りました。<br><br>人感センサーの信号をキャッチすると、ネコになりきって、生成したメッセージを表示する仕組み。<br><br>現在時刻をプロンプト（指示）に渡しているので、毎回違うメッセージが楽しめます。 <a href="https://t.co/csdcSvltfk">pic.twitter.com/csdcSvltfk</a></p>&mdash; そぞら@Raspberry Pi 電子工作 (@sozoraemon) <a href="https://twitter.com/sozoraemon/status/1638020354592632832?ref_src=twsrc%5Etfw">March 21, 2023</a></blockquote><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</div></figure>



<figure class="wp-block-embed is-type-rich is-provider-twitter wp-block-embed-twitter"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="500" data-dnt="true"><p lang="ja" dir="ltr">ChatGPTを自動で呼び出す装置を作ってみた。<br><br>人感センサーの信号をキャッチして、現在時刻に合ったメッセージを生成、表示する仕組み。<br><br>使っているのは、1200円程度のマイコン。低予算でも、高性能なAIで遊べることが本当にありがたい。 <a href="https://t.co/Gr8SxMfcOW">pic.twitter.com/Gr8SxMfcOW</a></p>&mdash; そぞら@Raspberry Pi 電子工作 (@sozoraemon) <a href="https://twitter.com/sozoraemon/status/1636972083036188673?ref_src=twsrc%5Etfw">March 18, 2023</a></blockquote><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</div></figure>
]]></content:encoded>
					
					<wfw:commentRss>https://sozorablog.com/raspberry-pi-chatgpt/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【Raspberry Pi】カメラモジュールV3の使い方｜Pythonで撮影・画像認識</title>
		<link>https://sozorablog.com/camera-module-v3/</link>
					<comments>https://sozorablog.com/camera-module-v3/#comments</comments>
		
		<dc:creator><![CDATA[そぞら]]></dc:creator>
		<pubDate>Mon, 16 Jan 2023 05:55:27 +0000</pubDate>
				<category><![CDATA[使い方]]></category>
		<guid isPermaLink="false">https://sozorablog.com/?p=10255</guid>

					<description><![CDATA[ラズベリーパイの代表的なオプションパーツであるカメラモジュール。現行モデルのCamera Module 3（V3）は、オートフォーカス機能を搭載し、画素数も従来の800万画素から1200万画素へ向上しました。 画素数も8 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><a href="https://sozorablog.com/what-is-raspberry-pi/">ラズベリーパイ</a>の代表的なオプションパーツであるカメラモジュール。現行モデルの<strong>Camera Module 3（V3）</strong>は、オートフォーカス機能を搭載し、画素数も従来の800万画素から1200万画素へ向上しました。</p>



<figure class="wp-block-embed is-type-rich is-provider-x wp-block-embed-x"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="500" data-dnt="true"><p lang="ja" dir="ltr">おー！動いてる。<br><br>オートフォーカス機能付きのラズパイカメラV3。レンズがしっかり上下しているのが確認できます。先代のカメラモジュールと同じく、SONY製のカメラセンサーが採用されています。 <a href="https://t.co/UJvKaYgWAi">pic.twitter.com/UJvKaYgWAi</a></p>&mdash; そぞら@Raspberry Pi 電子工作 (@sozoraemon) <a href="https://x.com/sozoraemon/status/1614044339281485826?ref_src=twsrc%5Etfw">January 13, 2023</a></blockquote><script async src="https://platform.x.com/widgets.js" charset="utf-8"></script>
</div></figure>



<p class="wp-block-paragraph">画素数も800万画素から<span class="sbd-text-red">1200万画素</span>になり、HDR（High Dynamic Range）モードも利用できます。先代モデルのCamera Module 2と比べて価格は高くなっていますが、その分、機能と性能が強化されたモデルです。</p>



<figure class="wp-block-table wp-block-sbd-table wp-block-sbd-table-vertical sbd-table--scroll"><table class="has-fixed-layout"><thead><tr><th></th><th><img decoding="async" width="115" height="108" class="wp-image-10310" style="width: 115px;" src="https://sozorablog.com/wp-content/uploads/2023/01/camera_v2.jpg" alt="" srcset="https://sozorablog.com/wp-content/uploads/2023/01/camera_v2.jpg 472w, https://sozorablog.com/wp-content/uploads/2023/01/camera_v2-300x281.jpg 300w" sizes="(max-width: 115px) 100vw, 115px" /><br>Camera Module V2</th><th><img decoding="async" width="112" height="107" class="wp-image-10309" style="width: 112px;" src="https://sozorablog.com/wp-content/uploads/2023/01/タイトルなし1.png" alt=""><br>Camera Module V3</th></tr></thead><tbody><tr><td>画素数</td><td>800万画素<br>(3280 × 2464)&nbsp;</td><td><span class="sbd-table-bg-circle">1200万画素<br>(4608 x 2592)</span></td></tr><tr><td>センサー</td><td>Sony IMX219</td><td>Sony IMX708</td></tr><tr><td>フォーカス</td><td>手動調節式<br>（固定フォーカス）</td><td><span class="sbd-table-bg-double-circle">モーター駆動<br>（オートフォーカス）</span></td></tr><tr><td>HDR対応</td><td>なし</td><td><span class="sbd-table-bg-circle">あり</span></td></tr><tr><td>価格</td><td>3,300円</td><td>5,940円</td></tr><tr><td>詳細</td><td><span class="sbd-table-btn"><a href="https://akizukidenshi.com/catalog/g/g110518/">詳細を見る</a></span></td><td><span class="sbd-table-btn"><a href="https://akizukidenshi.com/catalog/g/g130078/">詳細を見る</a></span></td></tr></tbody></table></figure>



<p class="wp-block-paragraph">この記事ではPythonプログラムを使い、カメラモジュールV3を操作する方法を解説します。静止画や動画の撮影から、<span class="sbd-text-red">顔認識</span>や<span class="sbd-text-red">物体認識</span>まで、幅広い活用方法を紹介しています。カメラモジュールV2の操作方法は、以下の記事をご覧ください。<br><strong><a href="https://sozorablog.com/camera_shooting/">≫【ラズベリーパイ】監視カメラの作り方｜PythonでカメラモジュールV2を自在に操作</a></strong></p>



<h2 class="wp-block-heading">使用準備</h2>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="600" src="https://sozorablog.com/wp-content/uploads/2023/01/camera-m3-5.jpg" alt="" class="wp-image-10274" srcset="https://sozorablog.com/wp-content/uploads/2023/01/camera-m3-5.jpg 800w, https://sozorablog.com/wp-content/uploads/2023/01/camera-m3-5-300x225.jpg 300w, https://sozorablog.com/wp-content/uploads/2023/01/camera-m3-5-768x576.jpg 768w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<h3 class="wp-block-heading">環境の確認</h3>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="226" src="https://sozorablog.com/wp-content/uploads/2021/09/スクリーンショット-2026-06-20-11.02.20-1.png" alt="" class="wp-image-17281" style="width:840px;height:auto"/><figcaption class="wp-element-caption">使用したOS</figcaption></figure>



<p class="wp-block-paragraph">この記事で使用しているOSはRaspberry Pi OS(64-bit)Trixieです。OSの準備方法は以下の記事で解説しています。なお、後半で紹介しているMediaPipeを使用した物体検出は、Trixieでは動作しないためご注意ください。<br><span class="sbd-text-bold"><a href="https://sozorablog.com/raspberrypi_initial_setting/">≫【2026年最新版】OSインストールから初期設定まで｜開始手順のすべて</a></span></p>



<h3 class="wp-block-heading">カメラモジュールの接続</h3>



<div class="wp-block-sbd-list"><ol class="sbd-list sbd-list-border"><li>黒いロックを持ち上げる。</li><li>リボンケーブルを挿入する</li><li>ロックを下に押し込んで固定する</li></ol></div>



<p class="wp-block-paragraph">まず、カメラポートの黒いロック部分を上に持ち上げます。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="450" src="https://sozorablog.com/wp-content/uploads/2021/12/camera-connect.jpg" alt="カメラポートのロック解除方法" class="wp-image-3198" srcset="https://sozorablog.com/wp-content/uploads/2021/12/camera-connect.jpg 800w, https://sozorablog.com/wp-content/uploads/2021/12/camera-connect-300x169.jpg 300w, https://sozorablog.com/wp-content/uploads/2021/12/camera-connect-768x432.jpg 768w, https://sozorablog.com/wp-content/uploads/2021/12/camera-connect-120x68.jpg 120w, https://sozorablog.com/wp-content/uploads/2021/12/camera-connect-160x90.jpg 160w, https://sozorablog.com/wp-content/uploads/2021/12/camera-connect-320x180.jpg 320w" sizes="(max-width: 800px) 100vw, 800px" /><figcaption class="wp-element-caption">カメラ接続</figcaption></figure>



<p class="wp-block-paragraph">リボンケーブルを差し込みます。Raspberry Pi 4以前のモデルでは、<span class="sbd-text-red">端子部分がHDMIコネクタ側にを向くように接続</span>します。Raspberry Pi 5にはカメラコネクタが2つ搭載されています。どちらのコネクタも使用できますが、Raspberry Pi 5では、<span class="sbd-text-red">端子部分がLANコネクタ側を向くように接続</span>してください。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="967" src="https://sozorablog.com/wp-content/uploads/2021/12/raspberry-pi-camera-v2-2-2.jpg" alt="リボンケーブルの差し込み方" class="wp-image-3435" style="width:336px;height:406px" srcset="https://sozorablog.com/wp-content/uploads/2021/12/raspberry-pi-camera-v2-2-2.jpg 800w, https://sozorablog.com/wp-content/uploads/2021/12/raspberry-pi-camera-v2-2-2-248x300.jpg 248w, https://sozorablog.com/wp-content/uploads/2021/12/raspberry-pi-camera-v2-2-2-768x928.jpg 768w" sizes="(max-width: 800px) 100vw, 800px" /><figcaption class="wp-element-caption">Pi 4の場合のリボンケーブルの向き</figcaption></figure>



<p class="wp-block-paragraph">黒いロック部分を押して固定します。</p>



<figure class="wp-block-image size-large is-resized"><img decoding="async" width="659" height="1024" src="https://sozorablog.com/wp-content/uploads/2021/12/raspberry-pi-camera-v2-1-2-659x1024.jpg" alt="リボンケーブルのロック方法" class="wp-image-3436" style="width:336px;height:521px" srcset="https://sozorablog.com/wp-content/uploads/2021/12/raspberry-pi-camera-v2-1-2-659x1024.jpg 659w, https://sozorablog.com/wp-content/uploads/2021/12/raspberry-pi-camera-v2-1-2-193x300.jpg 193w, https://sozorablog.com/wp-content/uploads/2021/12/raspberry-pi-camera-v2-1-2-768x1193.jpg 768w, https://sozorablog.com/wp-content/uploads/2021/12/raspberry-pi-camera-v2-1-2.jpg 800w" sizes="(max-width: 659px) 100vw, 659px" /><figcaption class="wp-element-caption">ケーブルのロック</figcaption></figure>



<p class="wp-block-paragraph">ケーブルを軽く引っ張って外れないことを確認します。</p>



<h3 class="wp-block-heading">ライブラリのインストール</h3>



<p class="wp-block-paragraph">Pythonで画像を扱うためのライブラリである<strong>OpenCV</strong>をラズパイにインストールします。ライブラリとは<strong>よく使う機能をまとめて保管している箱</strong>のようなものです。OpenCVをインストールすると、「カメラの画像を表示する」などの機能を「箱」から取り出して使えるようになります。</p>



<p class="wp-block-paragraph">ターミナルを開いて、コマンドを一行ずつ実行していきます。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="450" src="https://sozorablog.com/wp-content/uploads/2021/09/pico-1-1.jpg" alt="" class="wp-image-17371" srcset="https://sozorablog.com/wp-content/uploads/2021/09/pico-1-1.jpg 800w, https://sozorablog.com/wp-content/uploads/2021/09/pico-1-1-320x180.jpg 320w, https://sozorablog.com/wp-content/uploads/2021/09/pico-1-1-224x126.jpg 224w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<p class="wp-block-paragraph">まず、インストールできるソフトウェアの情報を最新の状態に更新します。下記のコマンドをターミナルに入力してEnterキーを押してください。</p>



<div class="wp-block-sbd-balloon sbd-balloon sbd-balloon--id-4 sbd-balloon--flat sbd-balloon--l sbd-balloon--green block-box"><div class="sbd-balloon__profile"><figure class="sbd-balloon__icon"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/09/アイコン.jpg" alt="そぞら" class="sbd-balloon__img"/></figure><div class="sbd-balloon__name">そぞら</div></div><div class="sbd-balloon__text-box sbd-inner-block-init">
<p class="wp-block-paragraph"><span class="sbd-text-red">sudo</span>は<strong>管理者権限</strong>で実行するときに使います。</p>
</div></div>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo apt update</code></pre></div>



<p class="wp-block-paragraph">sudoは管理者モードで実行する命令であり、安全確認として<span class="sbd-text-red">パスワード入力</span>が求められます。ラズベリーパイにログインするときのパスワードを入力後にEnterキーを押してください。</p>



<p class="wp-block-paragraph"><code>OpenCV</code>をインストールします。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo apt install -y python3-opencv</code></pre></div>



<p class="wp-block-paragraph">以上でカメラを使用するための準備は完了です。</p>



<h2 class="wp-block-heading">カメラの動作確認</h2>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="609" src="https://sozorablog.com/wp-content/uploads/2023/01/paicam12.jpg" alt="" class="wp-image-13706"/><figcaption class="wp-element-caption">プレビュー画面を表示した様子</figcaption></figure>



<p class="wp-block-paragraph">Raspberry Pi OSには<span class="sbd-text-bg-yellow">rpicam-apps</span>が標準でインストールされています。以下のコマンドを実行すると、カメラのプレビュー画面を表示できます。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>rpicam-hello --timeout 0</code></pre></div>



<p class="wp-block-paragraph">&#8211;timeout オプションに0 を指定すると、プレビューは手動で終了するまでずっと続きます。終了するには<span class="sbd-text-red">Ctrl + C</span>を押してください。</p>



<h2 class="wp-block-heading">Pythonプログラムで撮影する</h2>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="533" src="https://sozorablog.com/wp-content/uploads/2023/01/camera-m3-5-1.jpg" alt="" class="wp-image-10300" srcset="https://sozorablog.com/wp-content/uploads/2023/01/camera-m3-5-1.jpg 800w, https://sozorablog.com/wp-content/uploads/2023/01/camera-m3-5-1-300x200.jpg 300w, https://sozorablog.com/wp-content/uploads/2023/01/camera-m3-5-1-768x512.jpg 768w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<p class="wp-block-paragraph">まずは基本的な操作方法を解説します。</p>



<h3 class="wp-block-heading">静止画の撮影（保存）</h3>



<p class="wp-block-paragraph">スタートメニューのプログラミングからThonnyを開きます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2026/04/pico-2.jpg" alt="" style="width:608px;height:auto"/></figure>



<p class="wp-block-paragraph">以下のプログラムをコピーペーストします。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>from picamera2 import Picamera2

picam2 = Picamera2()

# フル解像度で画像を取得するための設定
capture_config = picam2.create_still_configuration(
    main={&quot;size&quot;: picam2.camera_properties[&#39;PixelArraySize&#39;]}  # センサーのフル解像度を指定
)

# 設定の適用
picam2.configure(capture_config)

# カメラの開始
picam2.start()

# 画像のキャプチャ
picam2.capture_file(&quot;test.jpg&quot;)

# カメラの停止
picam2.stop()

</code></pre></div>



<p class="wp-block-paragraph">プログラムを保存して実行します。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="450" src="https://sozorablog.com/wp-content/uploads/2023/01/thonny_open2-2.png" alt="" class="wp-image-10353" srcset="https://sozorablog.com/wp-content/uploads/2023/01/thonny_open2-2.png 800w, https://sozorablog.com/wp-content/uploads/2023/01/thonny_open2-2-300x169.png 300w, https://sozorablog.com/wp-content/uploads/2023/01/thonny_open2-2-768x432.png 768w, https://sozorablog.com/wp-content/uploads/2023/01/thonny_open2-2-320x180.png 320w, https://sozorablog.com/wp-content/uploads/2023/01/thonny_open2-2-224x126.png 224w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<p class="wp-block-paragraph">プログラムを実行すると、test.jpgというファイル名で画像が保存されます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="528" src="https://sozorablog.com/wp-content/uploads/2024/03/pico-52.png" alt="" class="wp-image-12128" style="width:759px;height:auto"/></figure>



<p class="wp-block-paragraph">test.jpgという固定のファイル名にすると、撮影するたびに画像が<strong>上書き</strong>されてしまいます。そこで以下のように撮影した時刻をファイル名にすることで、<span class="sbd-text-red">過去の画像を残しつつ新しい画像を保存できます</span>。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>from picamera2 import Picamera2
import datetime

# 現在の日時を取得し、ファイル名に使用する
dt_now = datetime.datetime.now()
file_name = dt_now.strftime(&#39;%Y%m%d_%H%M%S&#39;)

picam2 = Picamera2()

# フル解像度で画像を取得するための設定
capture_config = picam2.create_still_configuration(
    main={&quot;size&quot;: picam2.camera_properties[&#39;PixelArraySize&#39;]}  # センサーのフル解像度を指定
)

# 設定の適用
picam2.configure(capture_config)

# カメラの開始
picam2.start()

# 画像のキャプチャ
picam2.capture_file(file_name + &#39;.jpg&#39;)

# カメラの停止
picam2.stop()


</code></pre></div>



<h3 class="wp-block-heading">動画の撮影（保存）</h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>from picamera2 import Picamera2

picam2 = Picamera2()

# 解像度を1920x1080に設定
video_config = picam2.create_video_configuration(
    main={&quot;size&quot;: (1920, 1080)}  # フルHDに変更
)

# 設定の適用
picam2.configure(video_config)

# 動画撮影の開始と5秒後の自動停止
picam2.start_and_record_video(&quot;test.mp4&quot;, duration=5)

# カメラの停止
picam2.stop()

</code></pre></div>



<p class="wp-block-paragraph">上のプログラムを実行すると、test.mp4というファイル名で5秒間の動画が保存されます。フル解像度（4608&#215;2592）でのエンコードは、負荷が高くエラーが出たため解像度を1920&#215;1080に下げました。</p>



<h2 class="wp-block-heading">Pythonプログラムでカメラ映像（動画）を表示する</h2>



<p class="wp-block-paragraph">以下のプログラムは、カメラの映像をリアルタイムで画面に表示するものです。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>import cv2
from picamera2 import Picamera2
from libcamera import controls

picam2 = Picamera2()
picam2.configure(picam2.create_preview_configuration(main={&quot;format&quot;: &#39;XRGB8888&#39;, &quot;size&quot;: (640, 480)}))
picam2.start()
#カメラを連続オートフォーカスモードにする
picam2.set_controls({&quot;AfMode&quot;: controls.AfModeEnum.Continuous})

while True:
  im = picam2.capture_array()
  cv2.imshow(&quot;Camera&quot;, im)
 
  key = cv2.waitKey(1)
  # Escキーを入力されたら画面を閉じる
  if key == 27:
    break

picam2.stop()
cv2.destroyAllWindows()</code></pre></div>



<p class="wp-block-paragraph">12行目の「picam2.capture_array()」 は、現在のカメラ映像を NumPy配列として取得する関数です。この配列は画像データを含み、「cv2.imshow()」 でそのまま表示できます。</p>



<p class="wp-block-paragraph">プログラムを実行するとカメラの映像が立ち上がります。オートフォーカス機能も有効になっているので、近くの映像も鮮明に撮影できます。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="530" src="https://sozorablog.com/wp-content/uploads/2023/01/camera-m3-3.jpg" alt="" class="wp-image-10267" srcset="https://sozorablog.com/wp-content/uploads/2023/01/camera-m3-3.jpg 800w, https://sozorablog.com/wp-content/uploads/2023/01/camera-m3-3-300x199.jpg 300w, https://sozorablog.com/wp-content/uploads/2023/01/camera-m3-3-768x509.jpg 768w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<p class="wp-block-paragraph">オートフォーカスの速度を早くしたいときは、プログラムの9行目を以下のように変更します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>picam2.set_controls({&quot;AfMode&quot;: controls.AfModeEnum.Continuous, &quot;AfSpeed&quot;: controls.AfSpeedEnum.Fast})</code></pre></div>



<h4 class="wp-block-heading">HDRモードで表示する</h4>



<p class="wp-block-paragraph">HDR（High Dynamic Range）モードにすると、明るい部分と暗い部分がどちらも鮮明に表現できます。明るさの異なる複数枚の画像を合成して、1枚の画像を生成する仕組みです。</p>



<p class="wp-block-paragraph">本来、HDRをオンにするときはコマンドを入力する必要があります。以下のプログラムではos.systemを使い、<span class="sbd-text-red">プログラム中でHDRをオンにするコマンドを実行しています</span>。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>import cv2
from picamera2 import Picamera2
from libcamera import controls
import os

picam2 = Picamera2()

#HDRをオンにする
os.system(&quot;v4l2-ctl --set-ctrl wide_dynamic_range=1 -d /dev/v4l-subdev0&quot;)
print(&quot;Setting HDR to ON&quot;)

picam2.configure(picam2.create_preview_configuration(main={&quot;format&quot;: &#39;XRGB8888&#39;, &quot;size&quot;: (640, 480)}))
picam2.start()
#カメラを連続オートフォーカスモードにする
picam2.set_controls({&quot;AfMode&quot;: controls.AfModeEnum.Continuous, &quot;AfSpeed&quot;: controls.AfSpeedEnum.Fast})

while True:
  im = picam2.capture_array()
  cv2.imshow(&quot;Camera&quot;, im)
 
  key = cv2.waitKey(1)
  # Escキーを入力されたら画面を閉じる
  if key == 27:
    break

picam2.stop()
cv2.destroyAllWindows()

#HDRをオフにする
os.system(&quot;v4l2-ctl --set-ctrl wide_dynamic_range=0 -d /dev/v4l-subdev0&quot;)
print(&quot;Setting HDR to OFF&quot;)</code></pre></div>



<h2 class="wp-block-heading">OpenCVを使用すれば顔認識もできる</h2>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="362" src="https://sozorablog.com/wp-content/uploads/2021/09/raspberry-pi-opencv-haar-cascade-face-detection-1.jpg" alt="" class="wp-image-17353"/></figure>



<p class="wp-block-paragraph">OpenCVには、顔を検出するための機能が用意されています。ここでは、カメラに映った顔を検出するプログラムを作成してみましょう。</p>



<p class="wp-block-paragraph">まずは、顔を見つけるための学習データ（Haar Cascade）をインストールします。ターミナルを開き、以下のコマンドを実行してください。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo apt install opencv-data</code></pre></div>



<h3 class="wp-block-heading">リアルタイムで顔を検出する</h3>



<p class="wp-block-paragraph">カメラ映像からリアルタイムで人の顔を探し出して、四角で囲むプログラムは以下の通りです。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>import cv2
from picamera2 import Picamera2
from libcamera import controls

# Haar Cascadeのファイルパス
HAAR_FILE = (
    &quot;/usr/share/opencv4/haarcascades/&quot;
    &quot;haarcascade_frontalface_default.xml&quot;
)
face_detector = cv2.CascadeClassifier(HAAR_FILE)

cv2.startWindowThread()

picam2 = Picamera2()
picam2.configure(picam2.create_preview_configuration(main={&quot;format&quot;: &#39;XRGB8888&#39;, &quot;size&quot;: (640, 480)}))
picam2.start()
#カメラを連続オートフォーカスモードにする
picam2.set_controls({&quot;AfMode&quot;: controls.AfModeEnum.Continuous})

while True:
    im = picam2.capture_array()

    grey = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
    faces = face_detector.detectMultiScale(grey, 1.1, 5)

    for (x, y, w, h) in faces:
        cv2.rectangle(im, (x, y), (x + w, y + h), (0, 255, 0))

    cv2.imshow(&quot;Camera&quot;, im)
   
    key = cv2.waitKey(1)
    # Escキーを入力されたら画面を閉じる
    if key == 27:
        break

picam2.stop()
cv2.destroyAllWindows()</code></pre></div>



<p class="wp-block-paragraph">映像の中から顔が検出されると、緑の枠で囲まれます。顔の部分は後から加工して消しています。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="450" src="https://sozorablog.com/wp-content/uploads/2023/01/3333.jpg" alt="" class="wp-image-10268" srcset="https://sozorablog.com/wp-content/uploads/2023/01/3333.jpg 800w, https://sozorablog.com/wp-content/uploads/2023/01/3333-300x169.jpg 300w, https://sozorablog.com/wp-content/uploads/2023/01/3333-768x432.jpg 768w, https://sozorablog.com/wp-content/uploads/2023/01/3333-320x180.jpg 320w, https://sozorablog.com/wp-content/uploads/2023/01/3333-224x126.jpg 224w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<h2 class="wp-block-heading">リアルタイム物体認識に挑戦</h2>



<figure class="wp-block-image size-full"><img decoding="async" width="792" height="206" src="https://sozorablog.com/wp-content/uploads/2021/09/スクリーンショット-2026-06-20-13.17.25.png" alt="" class="wp-image-17312"/><figcaption class="wp-element-caption">使用したOS</figcaption></figure>



<p class="wp-block-paragraph">ここから先のコードを実行するには、<span class="sbd-text-bg-yellow">64ビット版のRaspberry Pi OS</span>（Lgacy）が必要です。最新のOS「Trixie」では動作しない点に注意が必要です。</p>



<p class="wp-block-paragraph">顔だけではなく、さまざまな物体を検出する方法を紹介します。Raspberry PiとカメラモジュールV3を使い、MediaPipeを活用した物体検出を試してみましょう。</p>



<p class="wp-block-paragraph">MediaPipeはGoogleが提供するマルチプラットフォーム対応の機械学習ライブラリで、TensorFlow Lite（<em>軽量版の機械学習ライブラリ</em>）を活用してリアルタイムの映像処理やモデル推論を効率的に行います。</p>



<p class="wp-block-paragraph">物体認識の環境を作成するには、ターミナルを開き、以下のコマンドを順に実行します。インストールできるソフトウェアの一覧を最新の状態に更新します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo apt update</code></pre></div>



<p class="wp-block-paragraph">カメラ制御に必要な&nbsp;<code>libcap</code>&nbsp;ライブラリの開発用ヘッダーをインストールします。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sudo apt install libcap-dev</code></pre></div>



<p class="wp-block-paragraph">mpという名前のPython仮想環境を作成します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>python3 -m venv ~/mp --system-site-packages</code></pre></div>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="450" src="https://sozorablog.com/wp-content/uploads/2023/01/pico-2025-01-11T115631.082.png" alt="" class="wp-image-13713" style="width:603px;height:auto" srcset="https://sozorablog.com/wp-content/uploads/2023/01/pico-2025-01-11T115631.082.png 800w, https://sozorablog.com/wp-content/uploads/2023/01/pico-2025-01-11T115631.082-320x180.png 320w, https://sozorablog.com/wp-content/uploads/2023/01/pico-2025-01-11T115631.082-224x126.png 224w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<div class="wp-block-sbd-checkpoint-block"><p class="sbd-checkpoint-title">チェックポイント</p><div class="sbd-checkpoint-content sbd-inner-block-init"><p>仮想環境とは、Python用の専用作業スペースのようなものです。Raspberry Pi本体のPython環境とは分離されているため、他のプログラムに影響を与えずにライブラリをインストールできます。</p><p><br>Bookworm以降のRaspberry Pi OSでは、システム領域へのPythonライブラリの直接インストールが制限されています。そのため、MediaPipeを利用するには仮想環境の使用が必要です。</p><p><br>コマンドが完了すると、「mp」フォルダが作成され、その中に専用のPython実行環境が用意されます。</p></div></div>



<p class="wp-block-paragraph">仮想環境を有効化します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>source ~/mp/bin/activate</code></pre></div>



<p class="wp-block-paragraph">MediaPipeのサンプルコード一式をRaspberry Piにコピーします。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>git clone https://github.com/googlesamples/mediapipe.git</code></pre></div>



<p class="wp-block-paragraph">Raspberry Pi用のオブジェクト検出のサンプルコードがあるディレクトリに移動します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>cd mediapipe/examples/object_detection/raspberry_pi</code></pre></div>



<p class="wp-block-paragraph">必要な依存パッケージのインストールと環境のセットアップをします。32ビット版のRaspberry Pi OSでは、この段階でエラーが発生する場合があります。この場合は64ビット版の使用を推奨します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>sh setup.sh</code></pre></div>



<h3 class="wp-block-heading">Thonnyを仮想環境に切り替える</h3>



<p class="wp-block-paragraph">Thonnyは初期設定のままだと、Raspberry Pi標準のPython環境（/usr/bin/python3）を使用します。そのため、仮想環境内にインストールしたMediaPipeを読み込もうとすると、エラーが発生します。そこで、Thonnyが仮想環境内のPythonを使用するよう設定を変更します。</p>



<p class="wp-block-paragraph">Thonny画面右下の「Local Python 3 • /usr/bin/python3」をクリックして、表示されたメニューから「Configure interpreter…」をクリックします。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="450" src="https://sozorablog.com/wp-content/uploads/2026/04/pico.png" alt="" class="wp-image-16751" style="width:601px;height:auto" srcset="https://sozorablog.com/wp-content/uploads/2026/04/pico.png 800w, https://sozorablog.com/wp-content/uploads/2026/04/pico-320x180.png 320w, https://sozorablog.com/wp-content/uploads/2026/04/pico-224x126.png 224w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<p class="wp-block-paragraph">「Python executable」の右側にある「…」ボタンをクリックして、「ホーム」、「mp」の順に選択します。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="248" src="https://sozorablog.com/wp-content/uploads/2021/09/pico-1.png" alt="" class="wp-image-17336" style="width:840px;height:auto"/></figure>



<p class="wp-block-paragraph">「bin」、「python」、「OK」の順にクリックします。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="226" src="https://sozorablog.com/wp-content/uploads/2021/09/pico.png" alt="" class="wp-image-17337" style="width:840px;height:auto"/></figure>



<h3 class="wp-block-heading">検出した物体を表示する</h3>



<p class="wp-block-paragraph">以下のコードを、/home/pi/mediapipe/examples/object_detection/raspberry_piに保存します。プログラムの保存場所が異なると、モジュールの読み込み時にエラーが発生するので注意が必要です。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code># Copyright 2023 The MediaPipe Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import argparse
import sys
import time
import cv2
import mediapipe as mp
from picamera2 import Picamera2
from libcamera import controls
from mediapipe.tasks import python
from mediapipe.tasks.python import vision
from utils import visualize

# Initial configuration of the camera
picam2 = Picamera2()
picam2.configure(picam2.create_preview_configuration(
    main={&quot;format&quot;: &#39;XRGB8888&#39;, &quot;size&quot;: (640, 480)}))
picam2.start()
picam2.set_controls({&quot;AfMode&quot;: controls.AfModeEnum.Continuous})

# Global variables to calculate FPS
COUNTER, FPS = 0, 0
START_TIME = time.time()

def run(model: str, max_results: int, score_threshold: float,
        width: int, height: int) -&gt; None:
            
    global is_inference_in_flight
    global latest_detection_result

    # Initialize global variables here
    is_inference_in_flight = False
    latest_detection_result = None            

    def save_result(result: vision.ObjectDetectorResult,
                    unused_output_image: mp.Image,
                    timestamp_ms: int):
        &quot;&quot;&quot;Callback when the detection is done.&quot;&quot;&quot;
        global is_inference_in_flight, latest_detection_result, COUNTER, START_TIME, FPS

        # Mark that inference has finished, so we can send another frame
        is_inference_in_flight = False

        # Update FPS
        if COUNTER % fps_avg_frame_count == 0:
            current_time = time.time()
            FPS = fps_avg_frame_count / (current_time - START_TIME)
            START_TIME = current_time

        latest_detection_result = result
        COUNTER += 1

    # Initialize the object detection model
    base_options = python.BaseOptions(model_asset_path=model)
    options = vision.ObjectDetectorOptions(
        base_options=base_options,
        running_mode=vision.RunningMode.LIVE_STREAM,
        max_results=max_results,
        score_threshold=score_threshold,
        result_callback=save_result
    )
    detector = vision.ObjectDetector.create_from_options(options)

    # Visualization parameters
    row_size = 50  # pixels
    left_margin = 24  # pixels
    text_color = (0, 0, 0)  # black
    font_size = 1
    font_thickness = 1
    fps_avg_frame_count = 10

    # Create a window to display the detection results
    cv2.namedWindow(&#39;object_detection&#39;, cv2.WINDOW_NORMAL)
    cv2.resizeWindow(&#39;object_detection&#39;, 800, 600)

    while True:
        frame = picam2.capture_array()
        if frame is None:
            break

        # Resize and convert for inference
        image = cv2.resize(frame, (width, height))
        rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        mp_image = mp.Image(image_format=mp.ImageFormat.SRGB, data=rgb_image)

        # If the previous inference is done, start a new one
        if not is_inference_in_flight:
            detector.detect_async(mp_image, time.time_ns() // 1_000_000)
            is_inference_in_flight = True
        else:
            # If inference is still in flight,
            # we do NOT enqueue a new frame to avoid backlog
            pass

        # Draw FPS
        fps_text = &#39;FPS = {:.1f}&#39;.format(FPS)
        text_location = (left_margin, row_size)
        cv2.putText(image, fps_text, text_location, cv2.FONT_HERSHEY_DUPLEX,
                    font_size, text_color, font_thickness, cv2.LINE_AA)

        # Visualize the latest detection result (if it exists)
        if latest_detection_result is not None:
            image = visualize(image, latest_detection_result)

        cv2.imshow(&#39;object_detection&#39;, image)

        # Stop if ESC is pressed
        if cv2.waitKey(1) == 27:
            break

    detector.close()
    picam2.stop()
    cv2.destroyAllWindows()

def main():
    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument(&#39;--model&#39;, help=&#39;Path of the object detection model.&#39;,
                        required=False, default=&#39;efficientdet.tflite&#39;)
    parser.add_argument(&#39;--maxResults&#39;, help=&#39;Max number of detection results.&#39;,
                        required=False, default=5)
    parser.add_argument(&#39;--scoreThreshold&#39;,
                        help=&#39;The score threshold of detection results.&#39;,
                        required=False, type=float, default=0.25)
    parser.add_argument(&#39;--cameraId&#39;, help=&#39;Id of camera.&#39;,
                        required=False, type=int, default=0)
    parser.add_argument(&#39;--frameWidth&#39;,
                        help=&#39;Width of frame to capture from camera.&#39;,
                        required=False, type=int, default=1280)
    parser.add_argument(&#39;--frameHeight&#39;,
                        help=&#39;Height of frame to capture from camera.&#39;,
                        required=False, type=int, default=720)
    args = parser.parse_args()

    run(args.model, int(args.maxResults), args.scoreThreshold,
        args.frameWidth, args.frameHeight)

if __name__ == &#39;__main__&#39;:
    main()</code></pre></div>



<p class="wp-block-paragraph">上記のコードは、Raspberry Piカメラモジュールを使用してリアルタイムで物体検出を行い、検出結果を表示するものです。TFLite（<a href="https://www.tensorflow.org/lite/guide?hl=ja">TensorFlow Lite</a>）モデルを使用して物体を検出し、画面上に検出された物体とFPSを描画します。TFLiteは軽量かつ効率的な機械学習モデルを動作させるためのプラットフォームで、Raspberry Piのようなリソースの限られた環境での使用に最適化されています。</p>



<p class="wp-block-paragraph">このプログラムは、サンプルコードとして提供されている<code>detect.py</code>を改良したものです。元の<code>detect.py</code>は処理が重く、フリーズしてしまう問題がありました。そこで、「推論中に新しい推論を開始しない」という制御を追加することで、安定した動作を実現しています。</p>



<p class="wp-block-paragraph">プログラムを実行すると、以下のように表示されます。car、bottle 、cupを検出できました。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="793" height="447" src="https://sozorablog.com/wp-content/uploads/2023/01/paicam9.jpg" alt="" class="wp-image-13586" style="width:840px;height:auto" srcset="https://sozorablog.com/wp-content/uploads/2023/01/paicam9.jpg 793w, https://sozorablog.com/wp-content/uploads/2023/01/paicam9-320x180.jpg 320w, https://sozorablog.com/wp-content/uploads/2023/01/paicam9-224x126.jpg 224w" sizes="(max-width: 793px) 100vw, 793px" /></figure>



<h3 class="wp-block-heading">検出した物体をカウントする</h3>



<p class="wp-block-paragraph">特定の物体を検出した場合にその数をカウントすることもできます。以下のコードを、/home/pi/mediapipe/examples/object_detection/raspberry_piに保存します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code># Copyright 2023 The MediaPipe Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import argparse
import sys
import time
import cv2
import mediapipe as mp
from picamera2 import Picamera2
from libcamera import controls
from mediapipe.tasks import python
from mediapipe.tasks.python import vision
from utils import visualize

# 任意の物体名を指定する変数（ここで変更可能）
target_object = &quot;person&quot;  # ここを好きな物体名に変更できる

# カメラの初期設定
picam2 = Picamera2()
picam2.configure(picam2.create_preview_configuration(
    main={&quot;format&quot;: &#39;XRGB8888&#39;, &quot;size&quot;: (640, 480)}))
picam2.start()
picam2.set_controls({&quot;AfMode&quot;: controls.AfModeEnum.Continuous})

# FPS計算用のグローバル変数
COUNTER, FPS = 0, 0
START_TIME = time.time()
is_inference_in_flight = False
latest_detection_result = None
fps_avg_frame_count = 10

def save_result(result: vision.ObjectDetectorResult,
                unused_output_image: mp.Image,
                timestamp_ms: int):
    &quot;&quot;&quot;検出が完了したときに呼び出されるコールバック関数&quot;&quot;&quot;
    global is_inference_in_flight, latest_detection_result, COUNTER, START_TIME, FPS

    # 推論が終了したことをマークし、新しいフレームを送信できるようにする
    is_inference_in_flight = False

    # 検出結果から指定した物体の数をカウントする
    object_count = sum(1 for detection in result.detections if detection.categories[0].category_name == target_object)
    
    # 検出された物体の数をコンソールに出力
    print(f&quot;検出された {target_object} の数: {object_count}&quot;)

    # FPSを更新
    if COUNTER % fps_avg_frame_count == 0:
        current_time = time.time()
        FPS = fps_avg_frame_count / (current_time - START_TIME)
        START_TIME = current_time

    latest_detection_result = result
    COUNTER += 1

    # 画像上に検出された物体の数を描画
    object_text = f&#39;{target_object.capitalize()}: {object_count}&#39;
    image_copy = unused_output_image.numpy_view().copy()  # 書き込み可能なコピーを作成
    cv2.putText(image_copy, object_text, (24, 100),
                cv2.FONT_HERSHEY_DUPLEX, 1, (0, 0, 255), 1, cv2.LINE_AA)

def run(model: str, max_results: int, score_threshold: float,
        width: int, height: int) -&gt; None:
    global is_inference_in_flight

    # オブジェクト検出モデルを初期化
    base_options = python.BaseOptions(model_asset_path=model)
    options = vision.ObjectDetectorOptions(
        base_options=base_options,
        running_mode=vision.RunningMode.LIVE_STREAM,
        max_results=max_results,
        score_threshold=score_threshold,
        result_callback=save_result
    )
    detector = vision.ObjectDetector.create_from_options(options)

    # 表示に関するパラメータ
    row_size = 50  # ピクセル
    left_margin = 24  # ピクセル
    text_color = (0, 0, 0)  # 黒
    font_size = 1
    font_thickness = 1

    # 検出結果を表示するウィンドウを作成
    cv2.namedWindow(&#39;object_detection&#39;, cv2.WINDOW_NORMAL)
    cv2.resizeWindow(&#39;object_detection&#39;, 800, 600)

    while True:
        frame = picam2.capture_array()
        if frame is None:
            break

        # フレームをリサイズし、推論用に変換
        image = cv2.resize(frame, (width, height))
        rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        mp_image = mp.Image(image_format=mp.ImageFormat.SRGB, data=rgb_image)

        # 前回の推論が終了していれば、新しい推論を開始
        if not is_inference_in_flight:
            detector.detect_async(mp_image, time.time_ns() // 1_000_000)
            is_inference_in_flight = True

        # FPSを画像上に描画
        fps_text = &#39;FPS = {:.1f}&#39;.format(FPS)
        text_location = (left_margin, row_size)
        cv2.putText(image, fps_text, text_location, cv2.FONT_HERSHEY_DUPLEX,
                    font_size, text_color, font_thickness, cv2.LINE_AA)

        # 最新の検出結果が存在する場合は画像に描画
        if latest_detection_result is not None:
            image = visualize(image, latest_detection_result)

            # 画像上に検出された物体の数を描画
            object_count = sum(1 for detection in latest_detection_result.detections if detection.categories[0].category_name == target_object)
            object_text = f&#39;{target_object.capitalize()}: {object_count}&#39;
            cv2.putText(image, object_text, (24, 100), cv2.FONT_HERSHEY_DUPLEX,
                        font_size, text_color, font_thickness, cv2.LINE_AA)

        cv2.imshow(&#39;object_detection&#39;, image)

        # ESCキーが押されたら終了
        if cv2.waitKey(1) == 27:
            break

    detector.close()
    picam2.stop()
    cv2.destroyAllWindows()

def main():
    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument(&#39;--model&#39;, help=&#39;オブジェクト検出モデルのパス&#39;,
                        required=False, default=&#39;efficientdet.tflite&#39;)
    parser.add_argument(&#39;--maxResults&#39;, help=&#39;検出結果の最大数&#39;,
                        required=False, default=5)
    parser.add_argument(&#39;--scoreThreshold&#39;,
                        help=&#39;検出結果のスコア閾値&#39;,
                        required=False, type=float, default=0.25)
    parser.add_argument(&#39;--cameraId&#39;, help=&#39;カメラID&#39;,
                        required=False, type=int, default=0)
    parser.add_argument(&#39;--frameWidth&#39;,
                        help=&#39;カメラからキャプチャするフレームの幅&#39;,
                        required=False, type=int, default=1280)
    parser.add_argument(&#39;--frameHeight&#39;,
                        help=&#39;カメラからキャプチャするフレームの高さ&#39;,
                        required=False, type=int, default=720)
    args = parser.parse_args()

    run(args.model, int(args.maxResults), args.scoreThreshold,
        args.frameWidth, args.frameHeight)

if __name__ == &#39;__main__&#39;:
    main()


</code></pre></div>



<p class="wp-block-paragraph">このコードはRaspberry Piに接続されたカメラを使い、リアルタイムで指定した物体を認識し、その数をカウントして画面に表示するものです。</p>



<p class="wp-block-paragraph">26行目の<code>target_object</code>という変数にはカウントしたい物体の名前を指定します。初期値は&#8221;person&#8221;となっていますが、ここを変更することで&#8221;car&#8221;や&#8221;bottle&#8221;など、別の物体をカウントできます。</p>



<p class="wp-block-paragraph">物体が検出されると、<code>save_result</code>という関数が呼び出されます。この関数では、検出された物体の中から、<code>target_object</code>で指定した物体をカウントします。</p>



<p class="wp-block-paragraph">以下は<code>target_object</code>に「car」を指定してプログラムを実行した際の結果です。画面の左上に「Cars: 5」と表示されています。ミニカーですが、5台しっかりとカウントできています。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="785" height="442" src="https://sozorablog.com/wp-content/uploads/2023/01/paicam10.jpg" alt="" class="wp-image-13589" srcset="https://sozorablog.com/wp-content/uploads/2023/01/paicam10.jpg 785w, https://sozorablog.com/wp-content/uploads/2023/01/paicam10-320x180.jpg 320w, https://sozorablog.com/wp-content/uploads/2023/01/paicam10-224x126.jpg 224w" sizes="(max-width: 785px) 100vw, 785px" /></figure>
]]></content:encoded>
					
					<wfw:commentRss>https://sozorablog.com/camera-module-v3/feed/</wfw:commentRss>
			<slash:comments>14</slash:comments>
		
		
			</item>
		<item>
		<title>ラズベリーパイおすすめの本5選｜目的やレベル別の選び方ガイド</title>
		<link>https://sozorablog.com/raspberrypi_book/</link>
					<comments>https://sozorablog.com/raspberrypi_book/#respond</comments>
		
		<dc:creator><![CDATA[そぞら]]></dc:creator>
		<pubDate>Sun, 06 Mar 2022 05:46:37 +0000</pubDate>
				<category><![CDATA[Raspberry Pi]]></category>
		<category><![CDATA[ラズパイ基礎]]></category>
		<category><![CDATA[使い方]]></category>
		<guid isPermaLink="false">https://sozorablog.com/?p=2501</guid>

					<description><![CDATA[ラズベリーパイに関する情報はネット上にも多くありますが、より広く深く学びたい方には書籍での学習をおすすめします。ブログやYouTubeの情報は個人が趣味の範囲で発信しているものが多く、情報の量と質が本に比べて劣ることが多 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><a href="https://sozorablog.com/raspberry-pi/">ラズベリーパイ</a>に関する情報はネット上にも多くありますが、より<span class="sbd-text-red">広く深く学びたい</span>方には書籍での学習をおすすめします。ブログやYouTubeの情報は個人が趣味の範囲で発信しているものが多く、情報の量と質が本に比べて劣ることが多いからです。</p>



<div class="wp-block-sbd-balloon sbd-balloon sbd-balloon--id-4 sbd-balloon--flat sbd-balloon--l sbd-balloon--green block-box"><div class="sbd-balloon__profile"><figure class="sbd-balloon__icon"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/09/アイコン.jpg" alt="そぞら" class="sbd-balloon__img"/></figure><div class="sbd-balloon__name">そぞら</div></div><div class="sbd-balloon__text-box sbd-inner-block-init">
<p class="wp-block-paragraph">仕事でラズベリーパイを使ったのがきっかけで、家でも電子工作を楽しんでいる僕が<span class="sbd-text-bold">おすすめの本</span>を紹介します。</p>
</div></div>



<p class="wp-block-paragraph">この記事を読めば自分にぴったりの一冊が見つかるはずです。</p>



<figure class="wp-block-table wp-block-sbd-table wp-block-sbd-table-vertical sbd-table--scroll sbd-table--fixed"><table><thead><tr><th></th><th>詳細</th><th>商品名</th><th>価格</th><th>発売日</th><th>ページ数</th><th>特徴</th></tr></thead><tbody><tr><td><img decoding="async" width="150" height="193" class="wp-image-14411" style="width: 150px;" src="https://sozorablog.com/wp-content/uploads/2022/03/kanzen.jpg" alt=""></td><td><span class="sbd-table-btn"><a href="#pi5">詳細を見る</a></span></td><td>電子工作＆サーバー構築徹底解説！ ラズパイ５完全ガイド<br></td><td>3,960円</td><td>2024/5/20</td><td>504ページ</td><td>Raspberry Pi 5対応</td></tr><tr><td><img decoding="async" width="150" height="200" class="wp-image-5464" style="width: 150px;" src="https://sozorablog.com/wp-content/uploads/2022/03/ラズベリーパイ超入門.jpg" alt="" srcset="https://sozorablog.com/wp-content/uploads/2022/03/ラズベリーパイ超入門.jpg 800w, https://sozorablog.com/wp-content/uploads/2022/03/ラズベリーパイ超入門-225x300.jpg 225w, https://sozorablog.com/wp-content/uploads/2022/03/ラズベリーパイ超入門-768x1024.jpg 768w" sizes="(max-width: 150px) 100vw, 150px" /></td><td><span class="sbd-table-btn"><a href="#超入門">詳細を見る</a></span></td><td>これ１冊でできる！<br>ラズベリーパイ超入門</td><td>3,025円</td><td>2022/3/19</td><td>288ページ</td><td>超初心者向き</td></tr><tr><td><img decoding="async" width="150" height="188" class="wp-image-5409" style="width: 150px;" src="https://sozorablog.com/wp-content/uploads/2022/03/電子工作パーツ制御完全攻略-2.jpg" alt="" srcset="https://sozorablog.com/wp-content/uploads/2022/03/電子工作パーツ制御完全攻略-2.jpg 800w, https://sozorablog.com/wp-content/uploads/2022/03/電子工作パーツ制御完全攻略-2-239x300.jpg 239w, https://sozorablog.com/wp-content/uploads/2022/03/電子工作パーツ制御完全攻略-2-768x965.jpg 768w" sizes="(max-width: 150px) 100vw, 150px" /></td><td><span class="sbd-table-btn"><a href="#自由自在">詳細を見る</a></span></td><td>ラズパイ自由自在 電子工作パーツ制御完全攻略</td><td>3,190円</td><td>2022/3/18</td><td>288ページ</td><td>電子工作マスター</td></tr><tr><td><img decoding="async" width="150" height="206" class="wp-image-5104" style="width: 150px;" src="https://sozorablog.com/wp-content/uploads/2022/03/IoTシステム開発実習.jpg" alt="" srcset="https://sozorablog.com/wp-content/uploads/2022/03/IoTシステム開発実習.jpg 800w, https://sozorablog.com/wp-content/uploads/2022/03/IoTシステム開発実習-219x300.jpg 219w, https://sozorablog.com/wp-content/uploads/2022/03/IoTシステム開発実習-747x1024.jpg 747w, https://sozorablog.com/wp-content/uploads/2022/03/IoTシステム開発実習-768x1053.jpg 768w" sizes="(max-width: 150px) 100vw, 150px" /></td><td><span class="sbd-table-btn"><a href="#システム">詳細を見る</a></span></td><td>Raspberry Piによる<br>IoTシステム開発実習</td><td>2,750円</td><td>2020/10/27</td><td>200ページ</td><td>センサーのデータ収集</td></tr></tbody></table></figure>



<h2 class="wp-block-heading" id="pi5">ラズパイ5ユーザー必携（ラズパイ５完全ガイド）</h2>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="732" src="https://sozorablog.com/wp-content/uploads/2022/03/IMG_8778.jpeg" alt="" class="wp-image-14412" style="width:793px;height:auto"/><figcaption class="wp-element-caption">504ページのボリューム</figcaption></figure>



<p class="wp-block-paragraph">本書は<a href="https://www.nikkeibp.co.jp/index.html">日経BP</a>様より献本いただきました。</p>



<p class="wp-block-paragraph">「電子工作＆サーバー構築徹底解説！ ラズパイ５完全ガイド」は、最新の<a href="https://sozorablog.com/pi5/">Raspberry Pi 5</a>と新OS「Bookworm」を使いこなしたい方にぴったりの一冊です。</p>



<div class="wp-block-sbd-balloon sbd-balloon sbd-balloon--id-4 sbd-balloon--flat sbd-balloon--l sbd-balloon--green block-box"><div class="sbd-balloon__profile"><figure class="sbd-balloon__icon"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/09/アイコン.jpg" alt="そぞら" class="sbd-balloon__img"/></figure><div class="sbd-balloon__name">そぞら</div></div><div class="sbd-balloon__text-box sbd-inner-block-init">
<p class="wp-block-paragraph">Pi 5は従来のOSが使えず、「Bookworm」専用となっており、これまでの使い方とは異なります。</p>
</div></div>



<p class="wp-block-paragraph">さらに、一部のGPIOライブラリが非対応のため、ネットの情報だけでは詰まりやすく、正しい知識が欠かせません。今後は従来のOSのサポートも終了するため、Pi 5ユーザーだけでなく、今後のラズパイ活用を見据えるすべてのユーザーにおすすめです。</p>



<figure class="wp-block-table wp-block-sbd-table wp-block-sbd-table-vertical"><table class="has-fixed-layout"><tbody><tr><td>読みやすさ</td><td><div class="sbd-rate"><div class="sbd-rate__star"><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span></div><div class="sbd-rate__num">(5 / 5.0)</div></div></td></tr><tr><td>情報量</td><td><div class="sbd-rate"><div class="sbd-rate__star"><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-off"></span></div><div class="sbd-rate__num">(4 / 5.0)</div></div></td></tr><tr><td>値段</td><td><div class="sbd-rate"><div class="sbd-rate__star"><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-off"></span><span class="sbd-icon-star-off"></span></div><div class="sbd-rate__num">(3 / 5.0)</div></div></td></tr><tr><td>初心者向き</td><td><div class="sbd-rate"><div class="sbd-rate__star"><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span></div><div class="sbd-rate__num">(5 / 5.0)</div></div></td></tr><tr><td>新しさ</td><td><div class="sbd-rate"><div class="sbd-rate__star"><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-off"></span></div><div class="sbd-rate__num">(4 / 5.0)</div></div></td></tr><tr><td>満足度</td><td><div class="sbd-rate"><div class="sbd-rate__star"><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-off"></span></div><div class="sbd-rate__num">(4 / 5.0)</div></div></td></tr></tbody></table></figure>



<h2 class="wp-block-heading" id="超入門">最新情報を知りたい超初心者向き（これ1冊でできる！ラズベリーパイ超入門）</h2>



<figure class="wp-block-image size-large is-resized"><img decoding="async" width="768" height="1024" src="https://sozorablog.com/wp-content/uploads/2022/03/ラズベリーパイ超入門-768x1024.jpg" alt="" class="wp-image-5464" style="width:359px;height:475px" srcset="https://sozorablog.com/wp-content/uploads/2022/03/ラズベリーパイ超入門-768x1024.jpg 768w, https://sozorablog.com/wp-content/uploads/2022/03/ラズベリーパイ超入門-225x300.jpg 225w, https://sozorablog.com/wp-content/uploads/2022/03/ラズベリーパイ超入門.jpg 800w" sizes="(max-width: 768px) 100vw, 768px" /></figure>



<div class="wp-block-sbd-balloon sbd-balloon sbd-balloon--id-5 sbd-balloon--flat sbd-balloon--l sbd-balloon--green block-box"><div class="sbd-balloon__profile"><figure class="sbd-balloon__icon"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/11/7-2.png" alt="" class="sbd-balloon__img"/></figure><div class="sbd-balloon__name"></div></div><div class="sbd-balloon__text-box sbd-inner-block-init">
<p class="wp-block-paragraph">・初心者だけどラズパイをガッツリ学びたい</p>



<p class="wp-block-paragraph">・電子工作をやってみたい</p>
</div></div>



<p class="wp-block-paragraph">このような方におすすめです。</p>



<p class="wp-block-paragraph">本書では2022年3月現在販売されている<span class="sbd-text-bg-yellow">すべてのモデル</span>について、各種ケーブルの接続方法をカラー写真で詳しく解説しています。キーボード一体型の<a href="https://sozorablog.com/raspberry-pi-400-explanation/">Raspberry Pi 400</a>にも対応している本は珍しいです。</p>



<p class="wp-block-paragraph">本文中では<span class="sbd-text-bg-yellow">注意すべきポイント</span>や<span class="sbd-text-bg-yellow">専門用語の解説</span>が適宜組み込まれていて、<span class="sbd-text-red">初心者が置き去りにならない工夫</span>が凝らされています。</p>



<figure class="wp-block-table wp-block-sbd-table wp-block-sbd-table-vertical"><table class="has-fixed-layout"><tbody><tr><td>読みやすさ</td><td><div class="sbd-rate"><div class="sbd-rate__star"><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-half"></span></div><div class="sbd-rate__num">(4.5 / 5.0)</div></div></td></tr><tr><td>情報量</td><td><div class="sbd-rate"><div class="sbd-rate__star"><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-off"></span></div><div class="sbd-rate__num">(4 / 5.0)</div></div></td></tr><tr><td>値段</td><td><div class="sbd-rate"><div class="sbd-rate__star"><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-half"></span><span class="sbd-icon-star-off"></span></div><div class="sbd-rate__num">(3.5 / 5.0)</div></div></td></tr><tr><td>初心者向き</td><td><div class="sbd-rate"><div class="sbd-rate__star"><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span></div><div class="sbd-rate__num">(5 / 5.0)</div></div></td></tr><tr><td>新しさ</td><td><div class="sbd-rate"><div class="sbd-rate__star"><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span></div><div class="sbd-rate__num">(5 / 5.0)</div></div></td></tr><tr><td>満足度</td><td><div class="sbd-rate"><div class="sbd-rate__star"><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-half"></span></div><div class="sbd-rate__num">(4.5 / 5.0)</div></div></td></tr></tbody></table></figure>



<figure class="wp-block-embed is-type-rich is-provider-twitter wp-block-embed-twitter"><div class="wp-block-embed__wrapper">
https://twitter.com/sotechsha_hanbi/status/1502210876811931648
</div></figure>



<!-- START MoshimoAffiliateEasyLink -->
<script type="text/javascript">
(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;
b[a]=b[a]||function(){arguments.currentScript=c.currentScript
||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};
c.getElementById(a)||(d=c.createElement(f),d.src=g,
d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})
(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20210203","msmaflink");
msmaflink({"n":"これ1冊でできる! ラズベリー・パイ 超入門 改訂第7版 Raspberry Pi 1+\/2\/3\/4\/400\/Zero\/Zero W\/Zero 2 W 対応","b":"","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/511c0cO9XiL._SL500_.jpg","\/41W7KFmLR0L._SL500_.jpg","\/41d4BPk1TdL._SL500_.jpg","\/41GkfBMowFL._SL500_.jpg","\/41B70zEvaDL._SL500_.jpg","\/41sd5odD5BL._SL500_.jpg","\/41SoIymXEEL._SL500_.jpg","\/41anX-jajKL._SL500_.jpg","\/41gjAgholwL._SL500_.jpg","\/41uX3wQN2PL._SL500_.jpg","\/41yJCqlWRHL._SL500_.jpg","\/41pmWsYT6KL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4800712971","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4800712971","a_id":3038653,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/%E3%81%93%E3%82%8C1%E5%86%8A%E3%81%A7%E3%81%A7%E3%81%8D%E3%82%8B!%20%E3%83%A9%E3%82%BA%E3%83%99%E3%83%AA%E3%83%BC%E3%83%BB%E3%83%91%E3%82%A4%20%E8%B6%85%E5%85%A5%E9%96%80%20%E6%94%B9%E8%A8%82%E7%AC%AC7%E7%89%88%20Raspberry%20Pi%201%2B%2F2%2F3%2F4%2F400%2FZero%2FZero%20W%2FZero%202%20W%20%E5%AF%BE%E5%BF%9C\/","a_id":3038654,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2}],"eid":"mDV5u","s":"s"});
</script>
<div id="msmaflink-mDV5u">リンク</div>
<!-- MoshimoAffiliateEasyLink END -->



<h2 class="wp-block-heading" id="自由自在">電子工作を極めたい人向け（ラズパイ自由自在 電子工作パーツ制御完全攻略）</h2>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="1005" src="https://sozorablog.com/wp-content/uploads/2022/03/電子工作パーツ制御完全攻略-2.jpg" alt="" class="wp-image-5409" style="width:377px;height:470px" srcset="https://sozorablog.com/wp-content/uploads/2022/03/電子工作パーツ制御完全攻略-2.jpg 800w, https://sozorablog.com/wp-content/uploads/2022/03/電子工作パーツ制御完全攻略-2-239x300.jpg 239w, https://sozorablog.com/wp-content/uploads/2022/03/電子工作パーツ制御完全攻略-2-768x965.jpg 768w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<div class="wp-block-sbd-balloon sbd-balloon sbd-balloon--id-5 sbd-balloon--flat sbd-balloon--l sbd-balloon--green block-box"><div class="sbd-balloon__profile"><figure class="sbd-balloon__icon"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/11/7-2.png" alt="" class="sbd-balloon__img"/></figure><div class="sbd-balloon__name"></div></div><div class="sbd-balloon__text-box sbd-inner-block-init">
<p class="wp-block-paragraph">・電子パーツの仕組みを詳しく知りたい</p>



<p class="wp-block-paragraph">・電子工作スキルをレベルアップしたい</p>



<p class="wp-block-paragraph">・用途に合った電子パーツの選び方が知りたい</p>
</div></div>



<p class="wp-block-paragraph">このような方におすすめです。</p>



<p class="wp-block-paragraph">前半では電子パーツの仕組みや特性・使い方を詳しく解説しています。</p>



<div class="wp-block-sbd-checkpoint-block"><p class="sbd-checkpoint-title">チェックポイント</p><div class="sbd-checkpoint-content sbd-inner-block-init"><p><span class="sbd-text-red">実験結果</span>や<span class="sbd-text-red">分解画像</span>を交えて、複数のパーツの比較をしている点がこの本の特徴です。</p></div></div>



<p class="wp-block-paragraph">例えば「距離センサー」のパートにおいて、５種類のセンサーをさまざまな条件下で使用して測定結果を比較しています。屋外での測定に向いているセンサーはどれかなど実用的な知識が学べます。</p>



<p class="wp-block-paragraph">後半ではラズベリーパイの汎用入出力端子（GPIOピン）についての専門的な知識を解説しています。</p>



<div class="wp-block-sbd-list"><ul class="sbd-list sbd-list-border"><li>デジタル入出力</li><li>PWM出力</li><li>I²C</li><li>SPI</li><li>UART</li></ul></div>



<p class="wp-block-paragraph">上記についての仕組みや読み取るためのPythonプログラムを詳しく学べます。この本で学習すれば、電子パーツの<span class="sbd-text-bold">データシート</span>を見て<span class="sbd-text-red">自力でパーツを使いこなす</span>ことが可能になります。</p>



<div class="wp-block-sbd-background-block-title sbd-bg-color sbd-inner-block-init is-style-yellow">
<div class="wp-block-sbd-heading"><p>参考情報</p></div>



<p class="wp-block-paragraph">3軸加速度センサー（ＡＤＸＬ３４５）の<a rel="noreferrer noopener" href="https://akizukidenshi.com/download/ds/freescale/ADXL345_jp.pdf" target="_blank">データシート</a></p>
</div>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="640" height="480" src="https://sozorablog.com/wp-content/uploads/2022/03/加速度センサー.jpg" alt="3軸加速度センサー（ＡＤＸＬ３４５）" class="wp-image-5424" style="width:198px;height:137px" srcset="https://sozorablog.com/wp-content/uploads/2022/03/加速度センサー.jpg 640w, https://sozorablog.com/wp-content/uploads/2022/03/加速度センサー-300x225.jpg 300w" sizes="(max-width: 640px) 100vw, 640px" /><figcaption class="wp-element-caption">出典：<a href="https://akizukidenshi.com/catalog/g/gM-06724/" target="_blank" rel="noreferrer noopener">秋月電子通商</a></figcaption></figure>



<p class="wp-block-paragraph">本書は<span class="sbd-text-bg-yellow">完全初心者向きではありません</span>。ラズベリーパイ本体の基本的な使い方や、ブレッドボードや抵抗など電子工作の基礎的な説明は省略されています。その分、パーツを分解して仕組みを内部から解説している点など、<span class="sbd-text-red">本書でしか学べない情報</span>が多数あります。電子工作をやったことはあるけど、もっと深い知識を身に付けたい方に最適な一冊です。</p>



<figure class="wp-block-table wp-block-sbd-table wp-block-sbd-table-vertical"><table class="has-fixed-layout"><tbody><tr><td>読みやすさ</td><td><div class="sbd-rate"><div class="sbd-rate__star"><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-off"></span></div><div class="sbd-rate__num">(4 / 5.0)</div></div></td></tr><tr><td>情報量</td><td><div class="sbd-rate"><div class="sbd-rate__star"><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-off"></span></div><div class="sbd-rate__num">(4 / 5.0)</div></div></td></tr><tr><td>値段</td><td><div class="sbd-rate"><div class="sbd-rate__star"><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-half"></span><span class="sbd-icon-star-off"></span></div><div class="sbd-rate__num">(3.5 / 5.0)</div></div></td></tr><tr><td>初心者向き</td><td><div class="sbd-rate"><div class="sbd-rate__star"><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-off"></span><span class="sbd-icon-star-off"></span></div><div class="sbd-rate__num">(3 / 5.0)</div></div></td></tr><tr><td>新しさ</td><td><div class="sbd-rate"><div class="sbd-rate__star"><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span></div><div class="sbd-rate__num">(5 / 5.0)</div></div></td></tr><tr><td>満足度</td><td><div class="sbd-rate"><div class="sbd-rate__star"><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span></div><div class="sbd-rate__num">(5 / 5.0)</div></div></td></tr></tbody></table></figure>



<figure class="wp-block-embed is-type-rich is-provider-twitter wp-block-embed-twitter"><div class="wp-block-embed__wrapper">
https://twitter.com/ciniml/status/1505576050352279556
</div></figure>



<p class="wp-block-paragraph">以下の動画にて、著者である松岡貴志さんが本誌の魅力を解説されています。</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="著者から直接聞いちゃおう！『ラズパイ自由自在 電子工作パーツ制御完全攻略本』の歩き方！" width="500" height="281" src="https://www.youtube.com/embed/IWCO0B51Vfo?start=1620&#038;feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<!-- START MoshimoAffiliateEasyLink -->
<script type="text/javascript">
(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;
b[a]=b[a]||function(){arguments.currentScript=c.currentScript
||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};
c.getElementById(a)||(d=c.createElement(f),d.src=g,
d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})
(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20210203","msmaflink");
msmaflink({"n":"ラズパイ自由自在　電子工作パーツ制御完全攻略","b":"","t":"","d":"https:\/\/m.media-amazon.com","c_p":"","p":["\/images\/I\/51Z-ZkTVQsL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/B09VKM6XHW","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/B09VKM6XHW","a_id":3038653,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/%E3%83%A9%E3%82%BA%E3%83%91%E3%82%A4%E8%87%AA%E7%94%B1%E8%87%AA%E5%9C%A8%E3%80%80%E9%9B%BB%E5%AD%90%E5%B7%A5%E4%BD%9C%E3%83%91%E3%83%BC%E3%83%84%E5%88%B6%E5%BE%A1%E5%AE%8C%E5%85%A8%E6%94%BB%E7%95%A5\/","a_id":3038654,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2}],"eid":"jqm6y","s":"s"});
</script>
<div id="msmaflink-jqm6y">リンク</div>
<!-- MoshimoAffiliateEasyLink END -->



<h2 class="wp-block-heading" id="システム">実務で使いたい人向け（Raspberry PiによるIoTシステム開発実習）</h2>



<figure class="wp-block-image size-large is-resized"><img decoding="async" width="747" height="1024" src="https://sozorablog.com/wp-content/uploads/2022/03/IoTシステム開発実習-747x1024.jpg" alt="" class="wp-image-5104" style="width:362px;height:481px" srcset="https://sozorablog.com/wp-content/uploads/2022/03/IoTシステム開発実習-747x1024.jpg 747w, https://sozorablog.com/wp-content/uploads/2022/03/IoTシステム開発実習-219x300.jpg 219w, https://sozorablog.com/wp-content/uploads/2022/03/IoTシステム開発実習-768x1053.jpg 768w, https://sozorablog.com/wp-content/uploads/2022/03/IoTシステム開発実習.jpg 800w" sizes="(max-width: 747px) 100vw, 747px" /></figure>



<div class="wp-block-sbd-balloon sbd-balloon sbd-balloon--id-5 sbd-balloon--flat sbd-balloon--l sbd-balloon--green block-box"><div class="sbd-balloon__profile"><figure class="sbd-balloon__icon"><img decoding="async" src="https://sozorablog.com/wp-content/uploads/2021/11/7-2.png" alt="" class="sbd-balloon__img"/></figure><div class="sbd-balloon__name"></div></div><div class="sbd-balloon__text-box sbd-inner-block-init">
<p class="wp-block-paragraph">・ラズパイでIoTシステムを作りたい</p>



<p class="wp-block-paragraph">・センサーのデータを無線で収集したい</p>
</div></div>



<p class="wp-block-paragraph">このような方におすすめです。</p>



<p class="wp-block-paragraph">前半ではラズベリーパイのセットアップからセンサーの基礎、無線モジュールの使い方までを解説。後半ではラズベリーパイとセンサーと無線マイコンモジュールを用いた<span class="sbd-text-red">データ監視システムの構築</span>について解説されています。</p>



<p class="wp-block-paragraph">本書で使い方が紹介されている機器の一例を以下に示します。</p>



<figure class="wp-block-image size-full is-style-default"><img decoding="async" width="800" height="339" src="https://sozorablog.com/wp-content/uploads/2022/03/TEELITE-DIP.png" alt="" class="wp-image-5110" srcset="https://sozorablog.com/wp-content/uploads/2022/03/TEELITE-DIP.png 800w, https://sozorablog.com/wp-content/uploads/2022/03/TEELITE-DIP-300x127.png 300w, https://sozorablog.com/wp-content/uploads/2022/03/TEELITE-DIP-768x325.png 768w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<p class="wp-block-paragraph">上記の機器とラズベリーパイを使って、センサーの情報を<span class="sbd-text-bg-yellow">無線</span>で収集する方法を本書では学べます。</p>



<p class="wp-block-paragraph">本のタイトルや表紙のイメージ通りで、かなり<span class="sbd-text-red">専門的な内容</span>になっているため<span class="sbd-text-bg-yellow">初心者向きではありません</span>。ところどころで演習問題が入っており、学校の教科書のような雰囲気があります。しかし、IoTシステム開発の分野にはかなり踏み込んでいて、実務でラズベリーパイを活用したい方にとって大変有益な内容となっています。</p>



<figure class="wp-block-table wp-block-sbd-table wp-block-sbd-table-vertical"><table class="has-fixed-layout"><tbody><tr><td>読みやすさ</td><td><div class="sbd-rate"><div class="sbd-rate__star"><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-off"></span><span class="sbd-icon-star-off"></span></div><div class="sbd-rate__num">(3 / 5.0)</div></div></td></tr><tr><td>情報量</td><td><div class="sbd-rate"><div class="sbd-rate__star"><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span></div><div class="sbd-rate__num">(5 / 5.0)</div></div></td></tr><tr><td>値段</td><td><div class="sbd-rate"><div class="sbd-rate__star"><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-off"></span></div><div class="sbd-rate__num">(4 / 5.0)</div></div></td></tr><tr><td>初心者向き</td><td><div class="sbd-rate"><div class="sbd-rate__star"><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-off"></span><span class="sbd-icon-star-off"></span><span class="sbd-icon-star-off"></span></div><div class="sbd-rate__num">(2 / 5.0)</div></div></td></tr><tr><td>新しさ</td><td><div class="sbd-rate"><div class="sbd-rate__star"><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-half"></span><span class="sbd-icon-star-off"></span></div><div class="sbd-rate__num">(3.5 / 5.0)</div></div></td></tr><tr><td>満足度</td><td><div class="sbd-rate"><div class="sbd-rate__star"><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-full"></span><span class="sbd-icon-star-off"></span></div><div class="sbd-rate__num">(4 / 5.0)</div></div></td></tr></tbody></table></figure>



<!-- START MoshimoAffiliateEasyLink -->
<script type="text/javascript">
(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;
b[a]=b[a]||function(){arguments.currentScript=c.currentScript
||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};
c.getElementById(a)||(d=c.createElement(f),d.src=g,
d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})
(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20210203","msmaflink");
msmaflink({"n":"Raspberry PiによるIoTシステム開発実習:センサネットワーク構築からwebサービス実装まで","b":"森北出版","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/51bSvD4PQiL._SL500_.jpg","\/51bNW0QMO4L._SL500_.jpg","\/41DOgzNheqL._SL500_.jpg","\/51bt22yAtEL._SL500_.jpg","\/415axmCUxQL._SL500_.jpg","\/41r4Lgi3QyL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4627855710","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4627855710","a_id":3038653,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/Raspberry%20Pi%E3%81%AB%E3%82%88%E3%82%8BIoT%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E9%96%8B%E7%99%BA%E5%AE%9F%E7%BF%92%3A%E3%82%BB%E3%83%B3%E3%82%B5%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E6%A7%8B%E7%AF%89%E3%81%8B%E3%82%89web%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E5%AE%9F%E8%A3%85%E3%81%BE%E3%81%A7\/","a_id":3038654,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2}],"eid":"byG1h","s":"s"});
</script>
<div id="msmaflink-byG1h">リンク</div>
<!-- MoshimoAffiliateEasyLink END -->



<h2 class="wp-block-heading">実は私も出版しています</h2>



<figure class="wp-block-image size-full"><img decoding="async" width="800" height="772" src="https://sozorablog.com/wp-content/uploads/2024/05/IMG_6826.jpeg" alt="" class="wp-image-12508"/></figure>



<p class="wp-block-paragraph">手前みそではありますが、<a href="https://sozorablog.com/raspberry-pi-pico-w-review/">Raspberry Pi Pico W</a>に特化した本をお探しの方は「ラズパイPico WかんたんIoT電子工作レシピ」がおすすめです。Raspberry Pi Pico Wは無線チップ搭載のマイコンボードで、普通のラズパイのようにOSを動かすことはできませんが、インターネットに接続した電子工作を楽しめます。</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="800" height="450" src="https://sozorablog.com/wp-content/uploads/2022/03/pico-1.jpg" alt="" class="wp-image-14426" style="width:840px;height:auto" srcset="https://sozorablog.com/wp-content/uploads/2022/03/pico-1.jpg 800w, https://sozorablog.com/wp-content/uploads/2022/03/pico-1-320x180.jpg 320w, https://sozorablog.com/wp-content/uploads/2022/03/pico-1-224x126.jpg 224w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<p class="wp-block-paragraph">これから電子工作をはじめる人や、ラズパイは使ったことがあるけどPico Wは初めてという方に向けて書きました。あまり難しい技術には触れず、<strong>応用しやすいシンプルなテクニックを多数紹介</strong>しています。</p>



<div class="wp-block-sbd-background-block sbd-bg-color sbd-inner-block-init is-style-yellow">
<p class="wp-block-paragraph">書籍の詳細は以下の記事にまとめました。<br><strong><a href="https://sozorablog.com/picowbook/">≫初著書「ラズパイPico WかんたんIoT電子工作レシピ」技術評論社より発売決定！</a></strong></p>
</div>



<!-- START MoshimoAffiliateEasyLink -->
<script type="text/javascript">
(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;
b[a]=b[a]||function(){arguments.currentScript=c.currentScript
||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};
c.getElementById(a)||(d=c.createElement(f),d.src=g,
d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})
(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");
msmaflink({"n":"ラズパイPico W　かんたんIoT電子工作レシピ","b":"技術評論社","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/51U8-tEqGGL._SL500_.jpg","\/41r8cUik+SL._SL500_.jpg","\/51GudZEc1KL._SL500_.jpg","\/41B4Fm-d8oL._SL500_.jpg","\/41bSWrjTb2L._SL500_.jpg","\/41p0KrleyXL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4297141825","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4297141825","a_id":3038653,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":3,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/%E3%83%A9%E3%82%BA%E3%83%91%E3%82%A4Pico%20W%E3%80%80%E3%81%8B%E3%82%93%E3%81%9F%E3%82%93IoT%E9%9B%BB%E5%AD%90%E5%B7%A5%E4%BD%9C%E3%83%AC%E3%82%B7%E3%83%94\/","a_id":3038654,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2}],"eid":"bowZM","s":"s"});
</script>
<div id="msmaflink-bowZM">リンク</div>
<!-- MoshimoAffiliateEasyLink END -->
]]></content:encoded>
					
					<wfw:commentRss>https://sozorablog.com/raspberrypi_book/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
