Shujima Blog

Apple製品,技術系の話をするブログ

macOS Mojave betaに STM32CubeMXをインストールする

なぜかはわからないけどできた。他のソフトウェアにも応用できるかも。

環境

症状

ダウンロードしてきたパッケージ「SetupSTM32CubeMX-4.26.0.app」をクリックしても起動しなかった。 右クリック→Option押しながら「開く」も試したが変わらず。

解決策

コマンド3行打つだけです。

1行目

ターミナルを起動し、まず3文字打つ(確定しない)

$ cd 
  • (続きがあるのでまだエンターキーを押さない)
  • ($は打たなくてよい)
  • (c+d+空白)

続けてダウンロードしてきた「Setup....app」を画像のようにドラッグアンドドロップする。

f:id:masa_flyu:20180719092814j:plain 多くの人は $ cd /Users/USERNAME/Downloads/en/SetupSTM32CubeMX-4.26.0.app のようになるはず。

(私はダウンロードを2回繰り返したため、画像中ではenではなくen-2になっています)

ここで一旦確定(エンター)する。

2行目

またcdコマンドで以下のように入力して確定する。コピペでOK。

$ cd ./Contents/MacOs/
  • ($は打たなくてよい)
  • 改行して確定

3行目

以下のコマンドでアプリケーションを実行する。

$ sudo ./SetupSTM32CubeMX-4_26_0_macos 
  • ($は打たなくてよい)
  • 改行して確定

バージョンが4.26.0ならばコピペでOK。 そうでない人は$ sudo ./Sまで打ってタブキーを押せば勝手に入力してくれる。

f:id:masa_flyu:20180719093951j:plain

すると、セットアップアプリケーションが普通に起動しました。

f:id:masa_flyu:20180719093956j:plain

その後

インストーラを完了させると、 アプリケーションフォルダ/STMicroelectronics/ に、STM32CubeMXがインストールされています。

Raspbery PiとEthenet(有線LAN)で通信する

1. IPアドレスを確認

Raspberry Pi上のターミナル(LXTerminal)でIPアドレスを確認

($は打つ必要が無い)

$  ifconfig

すると、以下のような文字列が一気に出てくる。

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
inet xxx.xxx.xxx.xxx  netmask xxx.xxx.xxx.xxx  broadcast xxx.xxx.xxx.xxx
(省略)

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
(省略)

wlan0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
(省略)

この中のeth0の項目にある、inet以降の数字列(xxx.xxx.xxx.xxxのようなドットで区切られた数値4つ)が有線LAN(Ethernet)のIPアドレス。 これを以降で使用する。 netmask(サブネットマスク)やbroadcast(ブロードキャストアドレス)は今回は必要ではない。

2. 物理的に接続

LANケーブル(ストレートケーブルでOK)でRaspberry Piどうしを直接接続する。

3. 通信の確認

どちらかからpingを飛ばす。xxx.xxx.xxx.xxxには相手のIPアドレスを入力する。

($は打つ必要が無い)

$  ping xxx.xxx.xxx.xxx

成功すると、

$  ping xxx.xxx.xxx.xxx
64 bytes from xxx.xxx.xxx.xxx: icmp_seq=1 ttl=64 time=0.396 ms
(こんな感じの文字が1秒毎に出てくる。)

Ctrl+Cを押すと止まる 。

失敗すると、

$  ping xxx.xxx.xxx.xxx
Request timeout for icmp_seq 0
(こんな感じの文字が1秒毎に出てくる。)

Ctrl+Cを押すと止まる 。

  • 失敗するときは
    • 追加でインストールしたものは無いため、純粋にIPアドレスか物理環境の問題
    • IPアドレスが間違っていないか確認する
    • LANケーブルなどを交換する
    • その他の方法で通信ができているか確認する

Raspberry Pi 3 Model B V1.2 (日本製) 国内正規代理店品

Raspberry Pi 3 Model B V1.2 (日本製) 国内正規代理店品

Raspberry PiどうしでUDPやりとり(Python 3)

Raspberry Pi 相互と言っているが、Pythonが実行できればパソコンでもMacでもなんでも良いです。 両者の操作を行ったり来たりするので、SSHでの遠隔操作が望ましいでしょう。

筆者の環境

  • Raspberry Pi 3 × 2
  • Raspbian 9.4( stretch )
  • Python 3.5.3

Raspberry Pi 3 Model B V1.2 (日本製) 国内正規代理店品

Raspberry Pi 3 Model B V1.2 (日本製) 国内正規代理店品

前提

  • Python3を実行できるRaspberry Piが2つある

目次

Pythonのプログラムが見たい方は5節まで飛ばしてください。

1. ネットワーク接続

Raspberry PiどうしをLANケーブルで直接接続します。

f:id:masa_flyu:20180716033616p:plain

または、下図のようにハブを使って接続することもできます。ただし、うまく動作しないなどのトラブルは増えるかもしれません。

f:id:masa_flyu:20180716034706p:plain

接続したら、お互いのIPアドレスなどをチェックします。 下記記事を参照してください。

masa-flyu.hatenablog.com

ただのチェックなので、IPアドレスなどがすでに分かっている場合には飛ばして問題ありません。

2. UDP送受信チェック

次の送信の工程がうまくいくことを確認するのに必要です。 厳密には不要な工程ですが、失敗した時の原因を見極めるのに役立ちます。 面倒ならば飛ばしてください。 この節ではaptパッケージ

  • tcpdump
  • hping3

をインストールします。これらは次節以降のPythonプログラムの実行には直接関係しません。

tcpdumpをインストール[受信側]

以下のコマンドでtcpdumpをインストールします。

$ sudo apt-get install tcpdump

tcpdumpを受信状態にする[受信側]

以下のコマンドを打ちます

$ sudo tcpdump -A -n udp port 60000

すると2〜3行の

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes

のような文字列がでます。これ以降、自分のIPアドレス宛に届いた60000番のUDPパケットを受信し、ターミナル上に表示する状態となります。 60000に特に意味はありません。 0〜65535であればなんでもよいです。ただし0〜49151は決まった利用目的が決められているため、この先の工程でインターネットに接続する時には、自由に使える49152〜65535をおすすめします。 この記事では60000に統一しています。

なお、受信を停止するには、Ctrl + Cを押します。

hping3をインストール[送信側]

以下のコマンドでhping3をインストールします。

$ sudo apt-get install hping3

ポートを指定してpingする[送信側]

以下のコマンドで、高度なpingを打ちます。

$ sudo hping3 -2 -p 60000 xxx.xxx.xxx.xxx

すると、tcpdumpを受信状態にしておいた受信側のターミナルに、こんなのが1秒ごとに表示されるはずです。

xx:xx:xx.xxxxxx IP xxx.xxx.xxx.xxx.xxxxx > xxx.xxx.xxx.xxx.60000: UDP, length 0
<...!..'.5....E.......@.`.......@..&.`......................

60000とUDPが確認できれば、あとはどうでもいいです。

f:id:masa_flyu:20181119211325j:plain

3. Pythonで送信プログラム

送信側のプログラムを書きます。

文字列送信プログラム[送信側]

ソースは以下より引用し、一部改変しています。

rikoubou.hatenablog.com

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import socket #UDP送信
import time #待機時間用
from contextlib import closing #with用

host = '169.254.169.5' # IPアドレス(変更する!)
port = 60000 # ポート番号
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) #ソケットの設定
with closing(sock): #プログラム終了時にソケットを自動的に閉じる
  while True: #無限ループ
    message = 'Hello via UDP'.encode('utf-8') #送信する文字列の設定
    print("send: ", message) #送信した文字列を送信側に表示
    sock.sendto(message, (host, port)) #ソケットにUDP送信
    time.sleep(1) #1秒待機

IPアドレスは受信側のものを入力してください。

以上のpythonプログラムを"udpsend.py"のような名前でどこかに保存します。 そして

$ cd (pythonプログラムのディレクトリ)
$ sudo python3 ./udpsend.py

で実行します。

すると、tcpdumpを受信状態にしておいた受信側のターミナルに

xx:xx:xx.xxxxxx IP xxx.xxx.xxx.xxx.xxxxx > xxx.xxx.xxx.xxx.60000: UDP, length 13
E..)tf....  ...@...... .`..t.Hello via UDP.....

のように表示されます。関係ない文字列が前後にありますが、「Hello via UDP」の文字列が送られていることがわかります。

数値送信プログラム[送信側]

上記のソースをさらに改変します。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import socket #UDP送信
import time #待機時間用
import struct #数値→バイト列変換用
from contextlib import closing #with用

host = '169.254.169.5' # IPアドレス(変更する!)
port = 60000 # ポート番号
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) #ソケットの設定
with closing(sock): #プログラム終了時にソケットを自動的に閉じる
  while True: #無限ループ
    d = 4.675208021 #適当な数値
    ds = struct.pack('>d', d ) #ビッグエンディアンのバイト列に変換
    print("send: ", ds) #送信したバイト列を送信側に表示
    sock.sendto(ds, (host, port)) #ソケットにUDP送信
    time.sleep(1) #1秒待機

文字列送信プログラムから数行だけ変えています。 新たにstructをインポートする必要があります。

これを実行すると

xx:xx:xx.xxxxxx IP xxx.xxx.xxx.xxx.xxxxx > xxx.xxx.xxx.xxx.60000: UDP, length 8
E..$3.....J...@........`....@..i.@.}..........

受信側に表示されます。先ほどと違い、実行結果が入力と一致しません。 これは、バイト列を数値に戻していないためです。 そのためには受信プログラムが必要です。

4. Pythonで受信プログラム

受信側のプログラムを書きます。

数値を受信する[受信側]

ソースは以下より引用し、一部改変しています。

qiita.com

import socket #UDP送信
import struct #数値→バイト列変換用
from contextlib import closing #with用

UDP_IP = "" #このままでいい
UDP_PORT = 60000 #ポート番号

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) #ソケットの生成
sock.bind((UDP_IP, UDP_PORT)) #ソケットを登録する
with closing(sock): #プログラム終了時にソケットを自動的に閉じる
  while True: #無限ループ
    data, addr = sock.recvfrom(1024) #受信する
    print ( "bytes:", data ) #バイト列をそのまま表示
    print ( str( struct.unpack('>d' , data)[0] )) #数値に変換して表示

送信側は先ほどのプログラム、受信側はこちらのプログラムを共に実行すると、受信側で

bytes: b'@\x12\xb3i\xbb@\xc4}'
4.675208021

が1秒ごとに表示されます。

下段の数値をプログラム内で利用することもできます。

5. お互いに送受信するプログラム

いよいよお互いに送受信させます。

シチュエーション

今までのプログラムを元に、Raspberry Piどうしでの値のやりとりを想定します。

今回は以下のようなシチュエーションとしました。

  1. 片方(クライアント側と呼称)から数値を送る
  2. もう片方(サーバ側)で受け取る
  3. サーバ側は値を元に計算する
  4. 計算結果を送る
  5. クライアント側で計算結果を表示する

以下のプログラムはクライアント側から数値を1秒毎に送ります。 パッケージの追加は必要ないはずです。

クライアント側のプログラム

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import socket #UDP送信
import time #待機時間用
import struct #数値→バイト列変換用
from contextlib import closing #with用
import ipaddress #入力IPアドレスの形式確認用

#IPアドレスの入力関係
print("Destination IP address:")
while True:
  try:
    print(">",end="") #>を改行無しで表示
    inputip = input() #入力させる
    ipaddress.ip_address(inputip) #入力が誤った形式だとエラーを吐く
  except KeyboardInterrupt:
    exit() #Ctrl+Cが入力されたらプログラムを抜ける
  except:
    print("Incorrect IP address. input IP address again.(xxx.xxx.xxx.xxx)")
  else:
    break #正しいIPアドレスだったらwhileを抜ける
        
#送信の設定
host = inputip # 送信先(相手)IPアドレス
send_port = 60000 # 送信ポート番号
#受信の設定
recv_ip = "" #このままでいい
recv_port = 60000 #ポート番号

#2つのsocketを設定
socksend = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) #送信ソケットの設定
sockrecv = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) #受信ソケットの生成
sockrecv.bind((recv_ip, recv_port)) #ソケットを登録する
sockrecv.setblocking(0) #ノンブロッキング受信に設定

print("OK") #準備完了であることを示す
sum = 0.0
s = 1

#送受信
with closing(socksend), closing(sockrecv): #プログラム終了時にソケットを自動的に閉じる
  while True: #無限ループ
    #送信
    # 1秒ごとに一方的に送信する
    print("send: ", str( s )) #送信する数値を送信側に表示
    ss = struct.pack('>i', s ) #バイト列に変換
    socksend.sendto(ss, (host, send_port)) #ソケットにUDP送信

    #待機
    time.sleep(1) #1秒待機
    
    #受信
    # パケットを受信した場合のみ、結果を表示する。それ以外は何もせずスルーする
    try: #try構文内でエラーが起こるとexceptに飛ぶ、なければelseへ
      sr, addr = sockrecv.recvfrom(1024) #受信する
    except socket.error: #受信していなければなにもしない
      pass
    else: #受信していたら表示
      r = struct.unpack('>d' , sr)[0] #バイト列を数値に変換
      print ( "receive: " , str( r )) #数値に変換して表示
      #処理
      sum += r
      print(s , ": pi = " , sum * 4 )
      s += 1

サーバ側

こちらもパッケージの追加は必要ないはずです。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import socket #UDP送信
import time #待機時間用
import struct #数値→バイト列変換用
from contextlib import closing #with用
import ipaddress #入力IPアドレスの形式確認用

#IPアドレスの入力関係
print("Destination IP address:")
while True:
  try:
    print(">",end="") #>を改行無しで表示
    inputip = input() #入力させる
    ipaddress.ip_address(inputip) #入力が誤った形式だとエラーを吐く
  except KeyboardInterrupt:
    exit() #Ctrl+Cが入力されたらプログラムを抜ける
  except:
    print("Incorrect IP address. input IP address again.(xxx.xxx.xxx.xxx)")
  else:
    break #正しいIPアドレスだったらwhileを抜ける

#送信の設定
host = inputip # 送信先(相手)IPアドレス
send_port = 60000 # 送信ポート番号
#受信の設定
recv_ip = "" #このままでいい
recv_port = 60000 #ポート番号

#2つのsocketを設定
socksend = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) #送信ソケットの設定
sockrecv = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) #受信ソケットの生成
sockrecv.bind((recv_ip, recv_port)) #ソケットを登録する

#送受信
with closing(socksend), closing(sockrecv): #プログラム終了時にソケットを自動的に閉じる
  while True: #無限ループ
  
    #受信
    print("Waiting for receive...") #受信待機中であることを示す
    # 受信を待機する
    sr, addr = sockrecv.recvfrom(1024) #受信する
    #--受信していない間はここで止まる--
    r = struct.unpack('>i' , sr)[0] #受信したバイト列を数値に変換
    print ( "receive: " , str( r )) #数値に変換して表示
    
    #処理
    s = 1.0 / ( 2.0 * r - 1.0 )
    if r % 2 == 0 :
      s = -s

    #送信
    # 受信があったときのみ送信する
    print("send: ", str( s )) #送信するバイト列を自分側に表示
    ss = struct.pack('>d', s ) #計算結果をバイト列に変換
    socksend.sendto(ss, (host, send_port)) #ソケットにUDP送信

実行結果

以下の画像のようにマスタとスレーブで通信していることがわかります。 以下の画像はMacからSSHで2台のRaspberry Piに接続しているようすです。 f:id:masa_flyu:20180716020327p:plain

クライアント側の解説

7~19行目

IPアドレスをキーボードで入力させます。「xxx.xxx.xxx.xxx」の形式になっているかを確認するためにipaddressパッケージを用いています。

21~32行目

送信用と受信用のソケットをそれぞれ設定しています。 ポート番号はそれぞれ異なっていても問題ありません。 32行目の

sockrecv.setblocking(0)

でマスタの受信側ソケットをノンブロッキングに設定しています。この設定を行わないと、recvfrom()するたびになにかを受信するまでプログラムを停止してしまうため、定期的な送信ができなくなってしまいます。

39行目

with文を使用し、プログラム終了時に確実にソケットを閉じるようにします。

41~45行目

UDPパケットを送信します。

50~62行目

53行目のrecvfrom()でUDPパケットを受信します。(直近1秒間に受信した)未処理のパケットがある場合は受信して、結果がsrに格納されますが、無い場合は例外(エラー)をだしてしまいます。 そこでtry文を使ってエラーを無視するようにしています。 受信していた場合は数値化の上処理を行います。

サーバ側の解説

こちらはクライアント側よりも単純です。

7~19行目

IPアドレスをキーボードで入力させます。「xxx.xxx.xxx.xxx」の形式になっているかを確認するためにipaddressパッケージを用いています。

21~31行目

送信用と受信用のソケットをそれぞれ設定しています。 ポート番号はそれぞれ異なっていても問題ありません。 マスタ側と異なり、ノンブロッキングの設定を行いません。 ブロッキングのままで使用することで、recvfrom()でパケット受信後即時応答することが可能です。

34行目

with文を使用し、プログラム終了時に確実にソケットを閉じるようにします。

37~43行目

ノンブロッキング設定をしていないので、受信するまでrecvfrom()で実行を停止します。受診後はそれを数値化します。

46~48行目

デモ用の計算です。

50~54行目

計算結果をUDPパケットとして送ります。

プログラム全体の解説(おまけ)

本題とはややそれますが、このプログラムではマスタ側に円周率に漸近していく値が表示されます。 クライアントが数値nを送ると、サーバがライプニッツの公式のn項を返します。 それを加算していくことで、円周率を求めています。 ライプニッツの公式 - Wikipedia

整数と小数を送り合うデモのために作ってみましたが、パケット往復に1秒以上かかると値が狂ってしまいます。

6. インターネットを経由する

インターネットを経由する場合にはなにかしらの工夫が必要です. 例えばこちらなどを参照してください.

www.shujima.work

MacBook,Air,Proと一緒に買うUSB Type-Cアダプタ・製品オススメ

どんなものを買わなきゃいけない?

  • USB-Aを含む周辺機器との変換アダプタすべて
  • ディスプレイや多機能ドックなど、USB-Cならではのものもある

今までのアダプタは使える?

  • 旧来のMacBook等に使っていたアダプタの再利用は面倒臭い
  • 基本的にすべて買い直すことをお勧めする

マルチアダプタ

ポイント:

  • ポートの少なさを補う必須アイテム
  • 基本的にMacBook用もMacBook Pro用も変わらない
  • 性能も特に変わらない(USB3.1 Gen1ばかり)

購入時の注意点:

  • 基本的にどの製品でも使用できる
  • 故障のリスクを考えると多機能すぎてもよくないかも

製品例:NOVOO USB-C ハブ

  • USB3-A ×2 , HDMI , SD , microSD.
  • MacBook Air / Proにお勧め
  • MacBookの場合、使用中に充電できない
  • 筆者が実際に購入
  • オススメ度:★★★★☆

今のMacBook Proに無くて以前のMacBook Proにあったポートをすべて復活させるアダプタ。外装が分厚いアルミで高級感があり、かつ小型。

ドック

ポイント:

  • USB-Cならではの機器、これをきっかけに導入してみては
  • 据え置き時に様々なデバイスを同時に接続できる
  • 外部ディスプレイの接続やTime Machine HDD、充電器などを1本で接続できる

購入時の注意点:

  • USB-PD(充電機能)が無いものがある
  • USB-PDは60Wまでのものが大半だが、MacBook Pro15インチも一応充電できる
  • Thunderbolt 3 (40Gbps)に対応しているものとそうでないもの( USB3.1 Gen.1 = 5Gbps)のものがある
  • 4K映像はUSB3.1では30fpsまでしかでない
  • Thunderbolt 3じゃないのに「5K対応」はウソ
  • 価格の変動が大きい

製品例:StarTech.com USB-Cドック

  • USB3-A ×3 , HDMI , Display Port , Ethernet(有線LAN) , アナログオーディオ入出力 , USB-PD 60W.
  • MacBook / Air / Proにお勧め
  • MacBook Pro 15インチの場合、充電速度が遅くなる
  • 付属のケーブルが短いので買い直すべき
  • 筆者が実際に購入
  • オススメ度:★★★★★

個別のアダプタ:

ポイント

  • 基本的にMacBook用もMacBook Pro用も変わらない
  • USB-Aとの変換はいざという時のため個別でも用意しておくべき
  • 面倒くさければAmazonベーシックで揃えてしまえばよい

注意点

  • Thunderbolt3→2アダプタを使っても今までの映像用アダプタは利用できない

製品例: Amazonベーシック USB3.1タイプC - イーサネットアダプター

  • Ethernet 1Gbps
  • MacBook Air / Proにオススメ
  • 筆者が実際に購入
  • オススメ度:★★★★☆

製品例: Amazonベーシック USB3.1タイプC - VGAアダプター

  • VGA
  • MacBook Air / Proにオススメ
  • 筆者が実際に購入
  • オススメ度:★★★★☆

製品例: Amazonベーシック USB3.1タイプC - HDMIアダプター

ディスプレイ

製品例: LG モニター ディスプレイ 27UK850-W

  • USB-C入力に対応

ケーブル

ポイント

  • PD対応や流せる信号の種類など非常に複雑
  • ポイントは「USBの速度」、「USB以外の信号」、「電流」
  • 付属品のUSB-Cケーブルは短いので、ドックやディスプレイとセットで長いケーブルがオススメ

購入時の注意点:

  • 1000円以下は偽物が多い
  • 安いものは低速にしか対応していないものが多い
  • MacBook Pro付属のケーブルは「充電ケーブル」

製品例: Cable Matters Thunderbolt 3 ケーブル 2m

  • USB3.1Gen.2(10Gbps) , Thunderbolt3 (20Gbpsまで) , Displayportを含むAlt-Modeに対応 , 3A60Wまでの給電.
  • MacBook / MacBook Proにオススメ
  • MacBook Pro 15インチの場合、充電速度が遅くなる
  • 5Kディスプレイは60Hzで使用できない
  • 筆者が実際に購入
  • オススメ度:★★★★★

Mac/LinuxでmicroSDのRaspberry Piイメージを丸ごとコピーしてバックアップ

Raspberry Piといえど,長く使っていれば,いろんな設定,いろんなパッケージの導入など,簡単に再構築できない状態になっていきます.

そんなRaspberry Piのイメージ全体をバックアップすることで,いざという時に備えておくことをお勧めします.

この記事では,バックアップをMac(Linuxも可)で行う手順を示します.

  • microSDの確認
  • micro SDからMac/PCにコピーする
    • コマンドの解説
  • Mac/PCからmicroSDにコピーする(同じSDの場合)
    • 以降書きかけです
  • micro SDからMac/PCにコピーする(別のSDに移す用)
    • GPartedで縮小する
    • microSDの接続
    • Ubuntuソフトウェアセンターで「GParted」を検索してインストール
続きを読む
当ブログをご利用いただく際には免責事項をお読みください。