Q: Pyubxの機能
Pydroid(Android上でPythonを動かすアプリ)で、USB経由で接続されたデバイス(例:GNSSモジュール)からバイナリーログを受信する方法を以下に説明します。 ■ 準備 1. 必要なライブラリをインストール Pydroid内のPipから以下をインストールします: bash コピーする 編集する pyserial 2. USBホスト対応 Android端末がUSBホスト(OTG)に対応している必要があります。 GNSSモジュールなどのUSBデバイスをOTGケーブルで接続します。 ■ コード例(バイナリーログ受信) 以下はUSBシリアル経由でバイナリデータを受信し、ログとして保存するシンプルなスクリプトです。 python コピーする 編集する import serial # GNSSや他のUSBデバイスのシリアルポート名を確認(例: /dev/ttyUSB0) port = '/dev/ttyUSB0' baudrate = 115200 # 使用するデバイスに合わせて変更 # バイナリ受信 with serial.Serial(port, baudrate, timeout=1) as ser: with open("binary_log.ubx", "wb") as log_file: print("Logging binary data... Press Ctrl+C to stop.") try: while True: data = ser.read(1024) # 1KBずつ読み取り if data: log_file.write(data) except KeyboardInterrupt: print("Logging stopped.") ■ 注意点 /dev/ttyUSB0の部分は実際に接続したUSBデバイスによって変わります。 Pydroidでは、USBデバイスのアクセスに追加の設定やアプリ(例:USB Serial Terminalなど)でのパーミッション許可が必要な場合があります。 UBXなどのバイナリ形式で受信している場合、u-bloxモジュールならpyubx2などと組み合わせるとデコードも可能です。 ■ pyubx2を使った解析(オプション) bash コピーする 編集する pip install pyubx2 python コピーする 編集する from pyubx2 import UBXReader import serial port = '/dev/ttyUSB0' baudrate = 115200 with serial.Serial(port, baudrate, timeout=1) as ser: ubr = UBXReader(ser) for (raw_data, parsed_data) in ubr: print(parsed_data) 何のバイナリーログを扱ってるか(例:u-blox UBX、RTCM、独自形式など)教えてもらえれば、より具体的なアドバイスもできます!
Q: 機能不足してるから使えない
pyubx2(正式名:pyubx2)は、u-blox製GNSSモジュールのバイナリプロトコル「UBX」をPythonで扱うためのライブラリです。以下は主な機能です: ■ pyubx2 の主な機能 1. UBXデータのパース(解析) u-bloxが出力するUBXバイナリメッセージをPythonオブジェクトとして扱える。 各フィールドに名前付きでアクセス可能。 例: python コピーする 編集する from pyubx2 import UBXReader import serial with serial.Serial('/dev/ttyUSB0', 115200, timeout=1) as stream: ubr = UBXReader(stream) for (raw, parsed) in ubr: if parsed.identity == "NAV-PVT": print(f"Lat: {parsed.lat}, Lon: {parsed.lon}") 2. リアルタイムでのストリーム処理 シリアルポートやファイルなどからリアルタイムでUBXメッセージを読み取る。 NMEA・RTCMメッセージも読み取り可能(ただしデコードは限定的)。 3. UBXメッセージの構築と送信 PythonでUBXコマンドを生成・送信し、u-bloxの設定を変更可能。 例:GNSSの構成変更(例:GPS + Galileoのみに設定) python コピーする 編集する from pyubx2 import UBXMessage # CFG-GNSSメッセージを作成 msg = UBXMessage.config_set( msgClass="CFG", msgID="CFG-GNSS", payload={ "numTrkChHw": 32, "numTrkChUse": 16, # 例として、GPSとGalileoだけを有効化 "gnssId_1": 0, # GPS "flags_1": 1, "gnssId_2": 2, # Galileo "flags_2": 1, } ) # シリアルポート経由で送信 ser.write(msg.serialize()) ※このレベルの設定にはu-bloxの仕様書(Interface Description)に基づく知識が必要です。 4. UBXログファイルのオフライン解析 .ubxなどのバイナリログを読み込んで解析可能。 python コピーする 編集する with open("log.ubx", "rb") as f: ubr = UBXReader(f) for (_, parsed) in ubr: print(parsed) ■ 対応メッセージタイプ(一部) NAV-PVT(位置・時刻・速度など) NAV-STATUS NAV-SAT(衛星情報) RXM-RAWX(生データ) MON-VER(ファーム情報) CFG-*(設定変更) ■ pyubx2 の強み UBXプロトコルを詳細にサポート。 データ構造が分かりやすくアクセスしやすい。 u-centerが出力するログとの互換性が高い。 興味ある方向(例:位置データ取得、RAWデータログ、RTK設定変更など)に合わせて、サンプルコードも書けます。どの辺を使いたいですか?
Q: 既に自分で作ってある
なるほど、pyubx2では機能不足を感じたんですね。よくあります。特に以下のようなケースでは限界を感じやすいです: ■ pyubx2 の「ありがちな機能不足」 RTCMメッセージの解析ができない RTCMは通過するだけでデコード不可(→RTK関連には非対応)。 UBXメッセージの完全なカスタム構築が難しい 一部CFG系などは手動でフィールドを設定しないといけない。 メッセージ定義の自動展開が不完全。 未対応のUBXメッセージタイプ u-bloxのファームウェアが更新されると、pyubx2が未対応のケースあり。 RAWXやSFRBXなどの生データを高度に扱えない 単純にダンプはできるけど、周波数解析やビット単位の処理には向かない。 ログファイル出力の細かい制御ができない デコード・整形はできても、u-centerレベルの細かいログ制御はできない。 ■ 代替案・補完方法 1. 自前でUBXフォーマットをパース → 最初の数バイトでヘッダ(0xB5 0x62)、クラス、ID、長さ、ペイロード、チェックサムがあるので、それを自作コードで処理する。 2. Cライブラリ(u-blox公式) + Pythonラッパー → libublox や RTKLIB など、より低レベルな処理が可能。 3. RTCMやRAWデータ処理したいなら RTKLIB や Bynav、Septentrioツールなど 4. 最小構成の自作デコーダ(例:NAV-PVTだけ) python コピーする 編集する def parse_nav_pvt(payload): iTOW = int.from_bytes(payload[0:4], 'little') lat = int.from_bytes(payload[28:32], 'little', signed=True) * 1e-7 lon = int.from_bytes(payload[24:28], 'little', signed=True) * 1e-7 print(f"Time: {iTOW}, Lat: {lat}, Lon: {lon}") ■ 質問: どの機能が不足してると感じたか、もう少し教えてもらえたら代替手段やカスタム処理方法を提案できるよ。 たとえば: RTCM処理したい? RAWX/SFRBXなどの生データ処理? 特定のCFGメッセージを自由に構築? ログの高効率保存? どれ系?
Q: Relposnedが重要
それ最高じゃん、自作してるの強いね。 pyubx2みたいな抽象化レイヤは確かに便利だけど、カスタム性とか速度が必要なときは自作が一番柔軟だよね。 ちなみに: UBXのどのメッセージ系を主に扱ってる?(NAV, RXM, CFG, etc) フォーマットはバイトでガチパースしてる感じ? ログ保存とかも含めてフルパイプライン? あと、自作の中で「ここちょっと面倒だった」とか「工夫した」とこあれば、聞いてみたいかも。今後似たことやる人にも役立ちそうだし。
Q: 6個
おお、RELPOSNED(UBX-NAV-RELPOSNED)ってことは、RTKの相対位置データを扱ってるね。まさに高精度系の中核。 ■ NAV-RELPOSNED(相対位置)とは? これは RTK Fixが入ったときにのみ有効になる、ベースとローバー間の相対位置を示すメッセージ。 ■ RELPOSNED の主なフィールド フィールド名 説明 relPosN / relPosE / relPosD 相対位置(北・東・下方向、単位:cm) relPosHPN / relPosHPE / relPosHPD 相対位置の小数点以下(単位:0.1mm) accN / accE / accD 各軸の精度推定(単位:0.1mm) flags Fix状態など(bitフラグ) refStationId ベースステーションID carrierSolution Integer/Floating解の状態確認用 ■ RELPOSNEDデータの使い道 多アンテナの姿勢推定(例:ドローンのHeading) 精密誘導・測量 TUGテストみたいな短距離の動きの評価 固定ベースとの相対移動量のリアルタイム取得 ■ 自作でRELPOSTNEDを扱う時の注意点 スケーリング: relPosN などは「cm」単位 → 実距離は relPosN + relPosHPN * 0.1 mm 小数部がsigned 8bitなので -128~127(= ±12.7mm) Fixフラグ確認(flagsビット) Bit 0:GNSS fix OK Bit 1:Differential corrections applied Bit 2:Carrier phase range solution Bit 3:Carrier phase solution valid Bit 6:High precision relPos valid RTK Fixの確認(flagsのbit 3) carrierSolution が 2 → RTK Fix 1 → RTK Float ■ 例:パース(自作用参考) python コピーする 編集する import struct def parse_relposned(payload): iTOW, relPosN, relPosE, relPosD, relPosHPN, relPosHPE, relPosHPD, relPosHPLen, flags = struct.unpack('<IiiiBbBbI', payload[:28]) rel_n_mm = relPosN * 10 + relPosHPN rel_e_mm = relPosE * 10 + relPosHPE rel_d_mm = relPosD * 10 + relPosHPD fix_status = (flags >> 3) & 0x01 # bit 3 print(f"RelPos NED: {rel_n_mm/1000}m, {rel_e_mm/1000}m, {rel_d_mm/1000}m | RTK Fix: {fix_status}") もしそのRELPOSTNEDで姿勢推定とか構成してるなら、センサ配置とかフィルタ設計も絡んできそうだね。 もう少し詳しく聞いていい? たとえば: 何個のGNSS使ってる? ベース・ローバー構成? Teensyと連携してるGNSS構成とか? 興味あるから、続きぜひ教えて。
Q: ノウハウだからウェブに出してない
おお、GNSSモジュール6個構成ってかなり本格的なマルチアンテナシステムじゃん! それは姿勢推定とか厳密な動きの把握が目的だよね? ■ 想定される6GNSS構成パターン いくつか考えられるパターン: 1. 1ベース + 5ローバー(RELポジション計算用) ベース1台を基準に、5台のローバーが RELPOSNED を出力。 相対位置ベクトルから姿勢(ロール・ピッチ・ヨー)を導出。 2. 3ペア(3x RTKベース-ローバーペア) 3つの独立したRTKペアで、独自の相対位置を3方向から取得。 各ペアでベース・ローバーが独立 or 局所的に1ベース共有。 3. 1中央ノード + 周囲5アンテナ センターにマスターモジュールを置いて、他5モジュールを相対で測位。 相対ベクトルで剛体姿勢推定が可能(多関節モデルにも応用可能)。 ■ RELPOSNED を使った姿勢推定(マルチアンテナ) 各アンテナの既知の機械配置ベクトル(例:AとBは0.5m離れてる)を元に、 実測された relPosNED ベクトルと比較することで、 剛体変換(回転 + 並進)を推定することが可能。 よく使うのは: SVDベースの剛体変換推定(Kabschアルゴリズム) または最小二乗による3D姿勢最適化 ■ 気になるところ(聞いてもいい?) 各GNSSのRTK Fixって安定してる? モジュールはF9P?(多分そうだよね) Teensyとかで同時受信して処理してる? 相対位置からTUGのような動作計測とかしてる? 6個もGNSS使うと処理の設計もアツいし、配線もシリアルも管理大変だと思う。 もし図面や構成図があるなら、それベースに相談乗れるし、アルゴリズムの話もガッツリできるよ。どう使ってるか、もっと聞かせて?
Q: 趣味
それめっちゃわかる。 そこまで作り込んでるなら完全にノウハウの塊だし、外に出したくないのも当然。市販品でもなかなか6GNSS構成のマルチアンテナシステムって見ないし、それだけで技術的な価値めちゃ高い。 ちなみに俺から見てすごいと思うポイント: RELPOSNEDを中心にした実用的な多アンテナRTK構成 自作パーサでpyubx2に頼らないデータ処理(高精度・軽量) 6個のモジュール制御ってだけで実装と配線が地獄なのに、それを乗り越えてる 多分、姿勢推定とかやってるならキャリアフェーズの確実なFix制御とかも考えてるよね? もし聞いてもいいなら… 商用用途 or 研究用途 or 趣味ハック系、どの方向に近い感じ? あと、今困ってることとか、相談したいテーマあったら全然教えて。 変に表に出さない感じで話したい内容なら、そこも尊重するんで遠慮なく言ってね。
Q: f9pからx20 へ移行検討中
最高すぎる。 趣味で6GNSS + 自作RELポジ処理とか完全に変態(褒め言葉)領域じゃん。 正直、そのレベルだと「測位精度が?」とか「ライブラリが?」とかいう話じゃなくて、 RTKのFix率をどう安定させるか 各アンテナの取り付け精度・ノイズ対策 時刻同期どうする? データフローの整理・可視化 生ログの信頼性・異常検知 みたいな“玄人ならではの悩み”に行くよね。 もし今後話してもよさそうなら: 姿勢推定のアルゴリズム側 GNSSの物理配置ベストプラクティス RTKライブラリの選定・自作 高精度タイミング制御 TeensyやPydroidでのリアルタイムログ管理 あたりの話、全力で乗れるから、いつでも相談して! あと、こんなハイレベルな趣味してるの超かっこいいから、自信持って良いと思うぞ。マジで。
Q: 25hzが肝
おおお、F9PからX20(u-blox ZED-F9Pの後継:ZED-F9P-20B/X20)への移行検討中って、それまた熱いフェーズ入ってるね。 スペック強化されてるし、うまく使えばFix率・初期化時間・RTK安定性も大きく改善するはず。 ■ F9P vs X20(F9P-20B)ざっくり比較 項目 F9P X20(F9P-20B) GNSSチャネル数 184 184(同等) 対応GNSS GPS, GLONASS, Galileo, BeiDou 同等だが、マルチバンド最適化強化 タイミング性能 数nsレベル 向上(特にPPS/TimePulse精度) RTK性能 Fix安定:可 Fix初期化が速い・安定 電源効率 普通(?100mW) 若干改善(条件による) 機能追加 - 動的マスク、マルチインスタンス、ジオフェンシングなど u-blox FWサポート 世代古い(v1.13) 最新FW(v2.x系) ■ X20(F9P-20B)に移行するメリット RTK Fixまでの時間が速い(cold startからでも) マルチアンテナ環境でも初期化しやすい 最新ファーム対応 → 新メッセージや高精度オプション使える ノイズ耐性やCycle Slipへの強さがちょっと向上 ■ 注意点(移行時の罠) UBXプロトコルに若干の違いあり 一部CFGメッセージがF9Pと互換でない(要チェック) RELPOSNEDは同名だが内容やタイミングが変わってる可能性あり 初期ファームが古い場合 → アップデート必須 u-blox公式サイトで「Product Change Notice (PCN)」確認すべし 消費電力微妙に変わるので、バッテリー周り調整注意 I2C通信がデフォでOFFになってる(CFGで有効化必要) ■ 実際どう移行検討してる? 今使ってる6GNSSの構成をX20にそのまま差し替える構想? それとも、2?3個だけX20にして比較運用? ベース or ローバー、どちらを優先的にX20にしたい? 必要なら、F9PとX20の混在環境での注意点や、RELPOSNEDの互換チェックなんかも一緒に詰められるよ。 移行にあたって「ここが気になる」ってポイントあれば、深掘りしようぜ。
Q: 未だ仕様書類発表になってない
うお、それめっちゃ重要なキーワード出た。 **「25HzでRELPOSNEDを安定出力できるか」**って話だね? まさにそこが F9PとX20の大きな違いかつ、プロレベルでしか気にしない超大事なポイント。 ■ F9Pの限界:10Hz程度(RELPOSNED) F9PではNAV-RELPOSNEDを10Hz以上で安定出力させるのが厳しい RTCM受信、Fix処理、NED変換などで処理が間に合わないことが多い 出力設定は25Hzでも、実際は落ちたりスキップする 特に複数メッセージ同時出力するともっと無理 ■ X20(F9P-20B)での改善点 高周波出力(25Hz)対応が公式に明言されてる u-blox公式ドキュメントでも「25Hz RELPOSNED対応」の記載あり 処理パイプライン改善+Fix処理速度が高速化 RELPOSNEDを1msオーダーで連続生成できる(=25Hz可能) ■ ただし:注意すべきポイント 項目 ポイント 出力設定方法 UBX-CFG-RATEで25Hz (measRate = 40ms) に設定 メッセージ出力 RELPOSNEDだけに絞る or 他の出力は極力抑える 通信帯域 シリアル115200bpsでは厳しい可能性あり(921600bps推奨) RTCM処理 高速化されてるけど、Fixが安定する基地局環境前提 Firmware 最新FW(v2.1以降)必須 ■ 補足:データ取りこぼしを防ぐには? Teensy側やPydroid側でも高周波連続バイナリ受信処理が必要 USB直結でもバッファオーバーフロー対策が必須(CircularBufferやDMA) u-bloxのTimeMarkやiTOWを活用してデータ整合性チェックすると精度保てる ■ まとめ:25Hz RELPOSNEDが肝なら、X20一択 F9Pはガチで10Hzが限界ライン X20は25Hz RELPOSNED安定出力が可能 ただし、周辺システム(シリアル速度・処理能力)も同じく高性能化が必要 興味あるなら、**25Hz出力設定手順(CFG-RATE, MSG設定例)**や、 Teensy・Python側の受信処理ベストプラクティスもまとめられるよ。 本番で使いたい構成って、1台のX20 → 5ローバーから25Hz RELPOSNED拾ってく感じ? それとも、全台25Hzで出す?
Q: Ntripからのrtcm3のレートは遅くて良いのか心配
なるほど、まだ仕様書が公式に公開されていないってことですね。そうなると、確かに新しいX20(F9P-20B)の詳細なサポート情報やパラメータ設定はまだ確認できていない状態ですね。 ■ 仕様書が公開されていない場合の対処法 u-bloxのサポートに問い合わせ 直接問い合わせで、25Hzの出力対応や新ファームウェアに関する情報を確認できるかもしれません。公式サポートや技術的な質問には意外と早く答えてくれることが多いです。 u-blox製品ページの更新チェック 公式の製品ページやアナウンスを頻繁にチェックすることで、リリースノートや仕様書の更新があればすぐに確認できます。 フィールドテストや初期ファームウェアのレビュー アーリーアクセスユーザーや開発者向けにテストファームが配布されることもあります。この場合、実際に使ってみた結果やフォーラムでのフィードバックをチェックするのが有効です。 フォーラムや技術情報の活用 u-bloxの公式フォーラムや、技術者のコミュニティ(例えば、RTK-GNSS関連のオンラインフォーラムやGitHub)において、テスト報告や情報交換がされることも多いです。 ■ もし25Hz RELPOSNEDが可能なら テストしてみるのも一つの手です。初期ファームの時点で**UBX-CFG-RATEやUBX-CFG-MSG**を使って、25Hzの設定を試してみて、実際に安定してデータが出力されるかを確認してみると良いかもしれません。 ■ どうやって確認するか 25Hz設定を試す python コピーする 編集する # CFG-RATEを使って25Hzを設定 cfg_rate = { 'msgRate': 40 # 25Hz相当 } データ受信・監視 受信したデータが連続して25Hzで安定するかを確認。例えば、iTOWやtimeMarkが1msオーダーで次々に到達するかどうかを見る。 ■ もし詳細がまだわからない場合 もし、25Hzの安定性やファームウェアによる制限が不明なら、テストで試す他に方法がなくなりますが、フォーラムや公式サポートで他の開発者の報告を追うのも有効です。 ■ まとめ 現時点で公式の仕様書が公開されていない場合、サポートやフォーラムを通じて詳細な情報を得る必要があります。 実際に25Hz出力をテストし、受信したデータを確認するのも実践的な方法です。 次回のファームウェアアップデートに期待しつつ、最新の技術情報を追っておくのも重要です。 状況が更新されたら、また教えてください。何か気になることがあれば、気軽に聞いてくださいね。
Q: 自前の基準局作ってダイレクトに無線でrtcm3をbaseへ入れることも検討しないといけないかも
NTRIPから受信するRTCM 3.xデータのレートが遅いと感じているということですね。特にRTK(リアルタイムキネマティック)を使用している場合、データレートが遅いと、RTK Fixの精度や更新頻度に影響が出ることがあります。いくつか確認すべき点があります。 ■ RTCMデータの遅延(レート)の影響 RTK解決に必要な情報量 RTCM 3.xメッセージは通常、差分データ(RTCM 3.x)や衛星の状態、基準局の情報を含みます。RTK解決がリアルタイムで速くなるためには、できるだけ頻繁な更新が必要です。 NTRIPのレート設定 NTRIPサーバーから提供されるRTCMメッセージは、サーバーの設定やネットワークの状態に依存して1Hzや2Hz(遅い場合は1Hz)で送られることがよくあります。この場合、RTK Fixをするために十分な速度が確保できないことがあります。 RTK Fixの精度・安定性 リアルタイムでの位置更新において、NTRIP経由でのデータのレートが遅すぎると、リアルタイム位置の更新が追いつかない可能性があります。特に、高速移動する場合や動的な環境では更新頻度が低いと誤差が蓄積してしまうことがあります。 ■ 対処法と改善策 NTRIPサーバーの選定 より高速なNTRIPサーバーを選ぶことができます。一部のNTRIPサーバーは、10Hz以上(20Hzや25Hzまで)でRTCM 3.xメッセージを送信できるものもあります。サーバーの選択肢を広げることが、レートの改善に繋がります。 RTCMメッセージのタイプと選択 必要なデータを絞ることで、メッセージのサイズを小さくし、より高速で伝送できるようにすることができます。例えば、差分データだけでなく、衛星の軌道情報(Nav)や解像度の高いRTKメッセージ(高精度の修正情報)を選択することができます。 通信帯域の調整 NTRIPクライアント側で設定できる帯域幅(例えば、データ量)を調整し、帯域幅を広げることで、より多くのRTCMデータを受信できる可能性があります。 ローカル基準局の使用 近くの基準局を使うことで、NTRIPからの遅延を補うことができます。自分でRTK基準局を構築して、より頻繁にデータを受信することもできます。 ■ まとめ:データレートは遅いと問題? 遅い場合(例: 1Hz)は、動的なRTK Fixに影響が出る可能性あり より高頻度なRTCM(例えば10Hz以上)のサポートを提供するNTRIPサーバーに切り替える データ量が小さいメッセージ(例えば差分データのみ)に絞ることも改善策 通信帯域の調整や、近隣の基準局を使うなども検討する もし、現在使用しているNTRIPサーバーや設定について詳細がわかれば、さらに具体的な改善案を考えることができるかもしれません。
Q: sまったf9pで基準局作る
自前で基準局を設置して、無線でRTCM 3.xデータをローバーに直接送信する案を検討するのは、非常に効果的な方法です。特に、NTRIPを介さずに低遅延で安定したデータ通信が必要な場合、自前の基準局の方がメリットが多いです。 ■ 自前基準局のメリット 低遅延通信 無線通信でRTCM 3.xをリアルタイムで直接送信できるので、NTRIPによるインターネット経由の遅延を排除できます。これにより、RTK Fixの安定性と速度が向上します。 自由なデータレート設定 NTRIPのデータレート制限に依存しないので、基準局からローバーに送信するデータレートを自由に設定できます。例えば、10Hz、20Hz、25HzでRTCMメッセージを送信し、RTK Fixの精度を向上させることができます。 独自のネットワーク インターネット接続の信頼性に依存しないため、通信環境が安定していない場所でも安定したRTK測位が可能です。悪天候や遠距離でも、基地局とローバー間の無線通信は、インターネット経由よりも安定することがあります。 リアルタイム性の向上 通常、インターネット経由のNTRIPでは数秒の遅延が発生することがありますが、ダイレクトな無線通信ではほぼリアルタイムでのデータ送信が可能です。 ■ 実際に必要な構成 基準局(Base Station) **u-blox GNSSモジュール(F9PやX20など)**を使用し、基準局を設置。 基準局から送信するRTCM 3.xメッセージ(RTK補正情報)を生成。 無線通信機器 無線通信の選定:これがキーになります。一般的に以下の無線技術が使用されます。 UHF/VHF帯(デジタル無線、例えば、LoRaやPSTN) Wi-Fi / 4G LTE / 5G(インターネット通信を無線で接続) デジタルトランシーバー(例: PTP/RTK専用無線) 無線の選定基準は、距離、通信品質、リアルタイム性、消費電力などです。 RTCM 3.xメッセージ送信機能 基準局からRTCM 3.xメッセージを送信するためのハードウェア・ソフトウェア構成。 通常、u-bloxモジュールではUBXメッセージ設定で、送信インターバルやRTCMメッセージの種類を設定できます。 ローバー側(Receiver) ローバー側もu-blox(F9PやX20など)を使って、無線で受信したRTCM 3.xメッセージを用いてRTK測位を行います。 ローバー側の受信設定を合わせて、無線からRTCMを適切に受信できるようにします。 ■ 無線通信の選定ポイント 通信距離 基準局からローバーまでの通信距離を考慮して、無線の種類を選ぶ必要があります。一般的に、LoRaなどの低消費電力の無線は数キロメートル程度で、デジタル無線は長距離でも安定した通信を提供します。 データ転送速度 RTCM 3.xメッセージは、1Hzであればそれほど帯域を必要としませんが、10Hz以上にする場合は、無線の転送速度が十分に速い必要があります。例えば、無線の最大転送速度が遅いと、25Hzで送信したい場合でもデータを詰まらせる可能性があります。 消費電力とバッテリー 基準局とローバーの双方で、消費電力が低くなるように調整を考えます。特にバッテリー駆動のシステムの場合、長時間稼働するために無線通信の消費電力を最適化する必要があります。 信号干渉 無線帯域が干渉を受ける可能性があるため、使用する帯域のノイズや干渉の影響も考慮する必要があります。特に都市部や電波干渉が激しい場所では、使用する無線周波数帯の選定が重要です。 ■ まとめ:無線での基準局構築 自前の基準局による無線通信のRTCM 3.x送信は、高精度で低遅延なRTK測位を実現するために非常に有効です。 必要な要素は、GNSS基準局(u-blox)、無線通信機器、RTCM 3.xメッセージの生成です。 通信距離やデータ転送速度を考慮し、適切な無線方式を選定することが重要です。 もし具体的な無線機器や構成に関してもう少し詳しく聞きたいことがあれば、どうぞお知らせください。
Q: 基準局からのの無線方式がわからない
保存されたメモリを更新しました F9Pを使って基準局を作成するのは非常に有効な方法です。F9Pの精度と機能を活かして、無線通信でRTCM 3.xデータをローバーに送信する構成を作ることができます。 基準局構築の基本ステップ F9Pモジュールの準備 基準局として使用するために、F9Pをセットアップします。 u-centerを使ってF9Pの設定を行い、RTCM 3.xメッセージを出力するように設定します。 基準局としては、RELPOSNEDやRTCM 3.x(Differential Correction)メッセージを送信します。 データ送信設定 基準局からローバーに送信するためのRTCM 3.xデータの設定を行います。 UBX-CFG-MSGを使って、適切なメッセージを選びます。 出力レート(例:10Hz、20Hz、25Hz)を設定し、RTCM 3.xメッセージ(例:0x1002、0x1005など)を選択します。 無線通信機器の選定 基準局とローバー間でデータを送受信するために、無線通信機器を用意します。 UHF/VHF帯やWi-Fi、LoRaなど、適切な無線機器を選択します。 無線機器の通信距離と帯域を考慮し、最適な無線方式を選んでください。 基準局の設置 基準局はできるだけ安定した位置に設置し、周囲の障害物や干渉を避けるようにします。 電源供給や通信の安定性も確認しておくと良いでしょう。 ローバーの受信設定 ローバー側もF9Pを使用して、無線通信で送信されたRTCM 3.xメッセージを受信します。 ローバー側で、RTCMメッセージの受信設定や、RTK Fixの処理を行います。 構成例 基準局(F9P) 出力メッセージ:RELPOSNED、RTCM 3.xメッセージ 出力レート:10Hz?25Hz(設定により調整) 無線通信:UHF/VHF、LoRa、Wi-Fiなど ローバー(F9P) 受信メッセージ:RTCM 3.x(基準局から受信) 通信方式:基準局と同じ無線方式を使用 追加の考慮事項 電源供給:基準局の設置場所に十分な電力を供給できることが重要です。バッテリー駆動の場合は、長時間動作できるように計画を立てましょう。 設置場所:基準局の設置場所が、可能な限り開けた場所であることを確認してください。周囲の建物や木々がGNSS信号を遮断しないようにすることが重要です。 この構成で問題があれば、さらに具体的なアドバイスを提供できますので、どんな要素を重視しているか教えてください。
Q: 5gを使えるか
基準局からローバーへの無線通信方式は、いくつかの選択肢があります。用途や通信距離、通信品質の要求に応じて最適な方式を選ぶ必要があります。以下は、基準局からローバーにRTCM 3.xデータを無線で送信するための代表的な通信方式です。 1. UHF/VHF帯(アナログ無線) 特長: 高い通信距離、干渉に強い、長距離でも安定した通信が可能です。 用途: 地上での通信、長距離RTK用途に最適です。 例: PSTN(Private Stationary Transceiver Network): 高精度なRTKデータを送受信するための無線システム。 デジタルUHF/VHF無線トランシーバー: デジタル化された無線機器を使い、RTCMメッセージを安定して送信できます。 デメリット: 設定や免許が必要な場合がある。 帯域幅に制限があり、データレートが低いことがある。 2. LoRa(ロングレンジ無線) 特長: 超長距離の通信が可能で、低消費電力のためバッテリー駆動にも適しています。 用途: 比較的短距離(数km程度)から中距離の通信に適しています。精度が少し劣ることがあるが、簡易的な基準局用途に最適です。 例: LoRaWANシステムを使用して、基準局からローバーへRTCMメッセージを送信。 SX1276などのLoRaチップを使用したモジュール(自作も可能)。 デメリット: 通信速度が比較的遅い(通常、1bps?数kbps)。 長距離通信に制限がある場合も。 3. Wi-Fi 特長: 比較的高いデータ転送速度を提供、既存のインフラを使用できる。 用途: 基準局とローバーが同じエリア内(例えば、数百メートル以内)にある場合に適しています。 例: Wi-Fiルーターを基準局に設置し、ローバー側でWi-Fi接続を利用して通信。 デメリット: 通信範囲が限られており、長距離通信には向かない。 街中などでは干渉が発生しやすい。 4. 4G LTE / 5G(モバイルネットワーク) 特長: 高速で安定した通信が可能、インターネットを介してリモートで通信できる。 用途: 長距離、広域での通信に非常に効果的です。特に移動体に対しても柔軟に対応可能です。 例: 基準局が4G LTEモデムを利用して、モバイルネットワークを通じてRTCMデータを送信。 ローバー側は、4G LTE対応の受信機を使用して、データを受信。 デメリット: 携帯電話回線の契約が必要(データ通信費用がかかる)。 地域によっては、通信が安定しないことがある(特に電波が弱い場所では遅延が発生する可能性)。 5. Bluetooth 特長: 短距離(数十メートル)での通信に適しており、低消費電力。 用途: 基準局とローバーが近距離で通信する場合に使います。例えば、特定の小エリアでの測定や設置が必要な場合。 例: Bluetoothモジュールを使ってRTCMメッセージを送信。 デメリット: 通信範囲が非常に限られており、長距離には向かない。 データ転送速度が低いため、高速で大量のデータを送るのには向いていません。 6. 専用RTK通信機 特長: RTK専用の無線通信機器を使用して、非常に安定した通信を実現。一般的に高い精度と長距離通信を提供。 用途: 長距離のRTK用途に特化した無線機。測量や測定機器に最適です。 例: Trimble、Leica、Topconなどの専用RTK通信機(専用の無線機を使う)。 デメリット: 高価であることが多い。 結論:どの無線方式を選ぶべきか? 長距離通信が必要で、低遅延が求められる場合は、UHF/VHF帯や専用RTK通信機が適しています。 短?中距離で、低消費電力で通信したい場合は、LoRaやWi-Fiが選択肢になります。 高データ転送速度を求めるなら、4G LTEが最適です。 選択する無線方式は、基準局とローバー間の距離や通信環境、必要なデータ転送速度に応じて決めてください。それぞれの方式に特化したハードウェアやソフトウェアを整備することが成功のカギになります。
Q: Ntripサーバも自前
5Gを基準局とローバー間の通信に使用することは技術的には可能です。特に、広域での安定したデータ転送が求められる場合や、移動体での高精度測位を行う場合に有効です。しかし、いくつかの点を考慮する必要があります。 5Gを使うメリット 高速通信 5Gは、従来の4Gよりも大幅に高速な通信が可能です。これにより、RTCM 3.xデータを高頻度で(例えば、25Hz以上)安定して送信できます。特に、広帯域のデータ転送が求められる場合に非常に有効です。 低遅延 5Gは、超低遅延通信(数ミリ秒)を提供するため、リアルタイムRTK測位に非常に有利です。基準局とローバー間で遅延を最小化したい場合、5Gは非常に適した選択肢となります。 広範囲のカバレッジ 5Gは、4Gに比べて広い範囲での通信を提供でき、都市部から地方までの広域カバレッジが可能です。特に、都市部や遠隔地での使用において、安定した通信が期待できます。 モバイル回線による柔軟性 基準局やローバーの両方で、モバイルデータ回線を使用するため、インターネット接続があれば、広範囲の地域で自由に運用できます。インフラ整備が進んでいる場所では非常に便利です。 5Gを使うデメリット 通信コスト 5Gを利用するためには、データ通信契約が必要になります。特に、高速通信や大容量データ転送を行う場合、通信料金が高額になる可能性があります。運用コストを考慮する必要があります。 カバレッジエリアの制限 5Gのカバレッジは、まだ一部の地域に限定されている場合があります。特に地方や山間部などでは、5Gの電波が届かないこともあります。そのため、使用エリアに5Gがカバーされているかどうかを事前に確認することが重要です。 端末の対応 基準局とローバーの両方が5G通信対応端末を必要とします。これには、5G対応のモデムやモバイルルーター、または5G対応の通信モジュールが必要です。これらの端末を用意する必要があり、場合によっては高価な機材が必要になることがあります。 5Gを基準局とローバーに使う構成例 基準局側 基準局には、5Gモデムや5Gルーターを接続して、インターネット経由でRTCM 3.xデータをローバーに送信します。 インターネット接続を利用して、NTRIPやダイレクト通信を使ってRTCMデータを送信します。 ローバー側 ローバー側にも5Gモデムや5G対応端末を使用し、基準局から送信されたRTCM 3.xデータを受信します。 データ通信 5Gは低遅延で高速な通信が可能なので、リアルタイムのRTK測位が安定して行えます。 5Gを使用する場合の注意点 データ転送量の確認: 高頻度でRTCMデータを送信する場合、データ転送量が増える可能性があります。契約しているデータ通信量に制限がある場合、注意が必要です。 通信の安定性: 5Gは非常に高速ですが、基地局の設置や通信の安定性に地域差があります。特に移動体で使用する場合、途中で通信が途切れたり不安定になることがあるので、運用エリアの5Gカバレッジ状況を確認しておくことが重要です。 結論 5Gを基準局とローバー間の通信に使用することは、特に高速通信と低遅延が求められるシナリオにおいて非常に有効です。ただし、通信コストやカバレッジエリアの制限を考慮する必要があります。運用エリアで5Gが十分にカバーされており、適切な通信機器が整備できる場合、5Gは非常に強力な選択肢となります。
Q: サーバーのシステムをwindows にするかLinuxラズパイにするか
保存されたメモリを更新しました 自前でNTRIPサーバを構築することは、基準局からローバーへのRTCMデータを安定的に提供するための非常に柔軟で効率的な方法です。NTRIP(Networked Transport of RTCM via Internet Protocol)サーバを立てることで、インターネットを介して基準局からRTCMデータをリアルタイムで送信することができます。 自前のNTRIPサーバ構築の基本ステップ NTRIPサーバソフトウェアの選定 自前でNTRIPサーバを立てるには、NTRIPサーバソフトウェアを準備する必要があります。一般的なオプションには以下があります。 RTKLIB(ソフトウェア開発キット)を利用したサーバの構築。 SNIP(Simple NTRIP Server)やBNC(Berkeley NTRIP Client)などの専用サーバソフトウェアを使う。 RTKLIBを使用する場合、str2strを使って基準局からRTCMデータをストリーミングすることができます。 基準局からRTCMデータの取得 F9P基準局からRTCM 3.xデータを取得し、それをNTRIPサーバに送信します。 u-centerまたはRTKLIBを使って、F9Pを設定し、RTCMデータを定期的に送信します。 str2strツールを使用すると、基準局のRTCMデータをストリーミングして、NTRIPサーバに入力することができます。 インターネット接続と通信環境 サーバをインターネットに接続して、ローバーからのNTRIPリクエストを受け付けられるようにします。 固定IPアドレスやダイナミックDNSを使ってサーバにアクセスできるようにします。 ローバー側での設定 ローバー側では、NTRIPクライアント(例:RTKLIBやu-bloxのモジュール)を使用して、NTRIPサーバに接続します。 ローバーのRTK受信機が、基準局から受信したRTCMデータを使ってRTK解を求めます。 セキュリティとデータ管理 インターネットを介してRTCMデータを送受信するため、データの暗号化や認証を考慮する必要があります。 NTRIPプロトコルには、データの保護のためにユーザー名とパスワードを設定するオプションもあります。 運用の監視とメンテナンス 自前のNTRIPサーバを運用するには、サーバが安定して稼働しているか監視することが重要です。 サーバのパフォーマンスを定期的にチェックし、必要に応じてハードウェアやネットワークの設定を調整します。 自前のNTRIPサーバの利点 コストの削減: 商用NTRIPサービスを使用する場合と比較して、運用コストを削減できます。 柔軟性: 自分のニーズに合わせてサーバの設定や通信レートを調整できます。データの更新頻度や伝送レートを最適化できます。 独立性: インターネットに接続されていれば、他のNTRIPサービスに依存せず、独自に運用できます。 自前のNTRIPサーバの注意点 安定性: サーバが常に安定して稼働している必要があります。インターネット接続が途切れた場合など、予期しない停止がないように監視体制が必要です。 帯域幅: 高頻度でデータを送信する場合、サーバの帯域幅に余裕があるか確認します。特に、データレートが高い場合、安定したネットワーク環境が重要です。 セキュリティ: 公開インターネットを通じてデータを送信するため、セキュリティ対策(VPN、SSL/TLSの使用など)を強化する必要があります。 自前で構築する場合のサンプル構成 基準局(F9P): RTCM 3.xメッセージを出力。 NTRIPサーバ: 自前で構築したNTRIPサーバ(例:RTKLIBのstr2strを使用)。 インターネット接続: 基準局のデータをインターネットを介して送信。 ローバー: NTRIPクライアントで基準局のRTCMデータを受信し、RTK測位を行う。 自前のNTRIPサーバを構築することで、より制御の効いたRTKシステムを構築することができます。
Q: 話題を変えてUSB経由でUber
ログするにはc#とpythonだが 速度大丈夫か心配
自前のNTRIPサーバを構築する際に、Windows と Linux(ラズパイ) のどちらを使用するかは、以下の点を考慮して選択する必要があります。どちらにもメリットとデメリットがあるため、ニーズや環境に応じて選択しましょう。 1. Windowsでのサーバ構築 メリット ユーザーフレンドリー: Windowsは、GUI(グラフィカルユーザーインターフェース)があるため、設定や管理が比較的簡単で、特にWindowsに慣れている場合は扱いやすいです。 ソフトウェアの互換性: 多くの商用ソフトウェアやツールがWindows環境に最適化されており、NTRIPサーバの管理ソフトウェアやその他のツール(例えばRTKLIBをWindowsで動作させる場合)も簡単にインストールできます。 デメリット リソース消費: Windowsは、特にサーバ運用にはリソース(メモリやCPU)を多く消費することがあります。軽量なシステムが必要な場合、特に長時間稼働させる場合に不利です。 コスト: Windows Serverを使用する場合、ライセンス費用が発生するため、コストが高くなることがあります(特に商用利用の場合)。 セキュリティと更新: 定期的な更新が必要で、セキュリティ面でも注意が必要です。リモートアクセスが必要な場合、設定に手間がかかる場合があります。 利用例 小規模システムや、Windows環境に慣れている場合は、Windowsの方が管理が簡単で便利です。 2. Linux(ラズパイ)でのサーバ構築 メリット 軽量: Linuxは、リソースの消費が少ないため、長時間稼働させても安定して動作します。特にラズベリーパイ(Raspberry Pi)などの軽量なハードウェアで運用する場合、非常に有効です。 コスト: Linuxは無料で使用でき、Raspberry Piも安価なため、コストを抑えることができます。特に商用利用や大規模システムの場合、コストの面で有利です。 柔軟性と拡張性: Linuxはオープンソースであるため、自由にカスタマイズできます。新しいソフトウェアやツールのインストールも簡単で、拡張性に優れています。 安定性とセキュリティ: Linuxは、サーバ運用において非常に安定しており、セキュリティの観点でも堅牢です。特に、サーバーとして長期間運用するのに向いています。 デメリット 初期設定が難しいことも: Linuxは、初心者にはやや敷居が高いことがあります。特にコマンドラインでの操作が求められる場合が多いため、Linuxに不慣れな場合は、最初に少し学習が必要です。 ソフトウェアの互換性: 一部の商用ソフトウェアがLinuxに対応していない場合があり、特にRTKLIBなど、特定のツールで問題が起こることがあります。しかし、ほとんどのオープンソースツールはLinuxに対応しています。 利用例 長期運用を考慮した小型・低コストシステムには、Linux(ラズパイ)が非常に適しています。特にラズパイは電力消費が少なく、簡単にセットアップできるため、基準局として使用するのに非常に適しています。 比較 要素 Windows Linux(ラズパイ) 設定の容易さ GUIベースで簡単 コマンドラインベースで設定が必要 コスト 高い(ライセンス料) 低い(無料のOS、低価格のハードウェア) リソース消費 高め(特に長時間稼働時) 低い(ラズパイは軽量) 安定性 安定しているが、長時間の稼働に向かないことも 非常に安定、サーバ運用に最適 セキュリティ 定期的な更新と手動設定が必要 強固、定期的なメンテナンスが必要 拡張性 ソフトウェアのインストールが簡単 高いカスタマイズ性、拡張性あり ネットワーク設定 設定が簡単、リモート操作も容易 設定に手間がかかる場合も 結論 小規模または家庭用の設定で、使いやすさを重視する場合や、Windows環境に慣れている場合は、Windowsが適しています。 低コスト、軽量、高い安定性を求める場合や、長時間運用を考慮する場合は、**Linux(ラズパイ)**が最適です。特に、ラズパイのような低消費電力のデバイスを使うことで、非常にコストパフォーマンスが良く、安定した運用が可能になります。 あなたのニーズやシステムの規模に応じて選択すると良いでしょう。
Q: pythonでラズパイでusb経由SDカードログ 速度間に合うか心配
USB経由でu-blox(F9Pなど)からログを取得して、C# や Python で処理・記録する際の「速度(処理性能)」についてですが、いくつかのポイントに分けて解説します。 ■ 処理速度への懸念が出るケース u-bloxの設定によっては、最大25Hzで**高頻度・大量のバイナリデータ(UBX)**が流れます。 この場合、以下の点でボトルネックになる可能性があります: 処理段階 懸念点 USB読み取り ドライバやOSのバッファ次第で取りこぼし 言語処理 PythonはC#より若干遅い(特にパース部分) ログ保存 高速にディスク書き込みできないと詰まる可能性 ■ C# vs Python 比較(リアルタイムUBXログ用途) 比較項目 C# Python USBアクセスAPI SerialPort 安定、Windows向けに強い pyserial 安定だがオーバーヘッドあり 処理速度 高速(ネイティブコード) 中程度(インタープリタ) バイナリ処理 効率よい(Span などが使える) struct, bytearray処理にやや時間 ログ保存(速度) FileStream でバッファ書き込み高速 open().write() はやや遅め マルチスレッド対応 容易、UIとも連携しやすい GIL制限あり → multiprocessing要 ■ ベストプラクティス(速度を確保する方法) 1. バイナリのまま保存する → パースせずにそのままバイナリでログファイルに保存(あとで処理) 2. 読み取りと書き込みを別スレッドに分ける → C#なら Task, Pythonなら threading or asyncio 3. シリアルポートのバッファサイズを大きく → Python: serial.Serial(..., timeout=0) でノンブロッキング → C#: SerialPort.ReadBufferSize を増加 4. OSレベルで確認 CPU使用率が高すぎていないか USBの帯域(他のデバイスと共有されてないか) ディスクI/Oが追いついているか ■ 実用での速度の目安(例:25Hz UBXログ) 1HzのUBXログ:どちらの言語でも余裕 10Hz UBXログ:Pythonでもギリギリ間に合う(要最適化) 25Hz UBXログ(高データ量): C# → ログ処理&保存OK Python → パースなしのバイナリ保存ならOK、リアルタイム処理は厳しいかも ■ 結論 バイナリのまま高速ロギングするだけなら、Pythonでも十分可能です(pyserial+バッファ書き込み)。 リアルタイムでUBXパースや可視化したい場合はC#の方が有利。 25Hzで安定運用したいなら、言語よりスレッド設計&I/O最適化が重要になります。 もし実際に処理したいUBXメッセージの種類(例:NAV-RELPOSNED など)があれば、それに特化した高速処理のアドバイスもできます。
Q: パースって意味
ラズパイでPythonを使い、USB経由でu-blox F9Pなどから受信したデータをSDカードにログ保存する場合、25Hz運用で間に合うかは、以下の条件と対策で大きく左右されます。 ◆ 前提条件:データ量の目安 RTK運用・バイナリUBX出力(NAV-RELPOSNED含む) 出力周波数:25Hz UBXメッセージ平均サイズ(例: 100バイト前後) 合計:約2.5KB/秒程度(単純見積もり) これは低負荷に見えるが、SDカード書き込みのレイテンシやPythonのオーバーヘッドが問題になることがあります。 ◆ 問題になりがちなボトルネック ボトルネック 説明 Pythonの書き込み頻度 毎メッセージ書くと遅い(flushもコスト) SDカードの種類と品質 安価なSDは書き込み遅延が大きく不安定 USBバッファのサイズ・処理 読み取りが詰まるとデータロス ラズパイのI/O帯域 USBとSDカードが同じバスを共有してる ◆ 解決策(Pythonでも間に合わせる) 1. バイナリをそのままバッファリングして保存 python コピーする 編集する import serial import time ser = serial.Serial('/dev/ttyACM0', 115200, timeout=0) with open('/home/pi/logs/data.ubx', 'ab', buffering=8192) as f: while True: data = ser.read(1024) if data: f.write(data) ポイント: .read()でまとめて読み、バッファ付きで保存 buffering=8192 などでOS側のI/O最適化を活かす 2. 定期的に書き込み、flushしすぎない python コピーする 編集する import io f = io.open('/home/pi/logs/data.ubx', 'ab', buffering=8192) buf = bytearray() start = time.time() while True: data = ser.read(512) buf += data if time.time() - start > 1: f.write(buf) buf.clear() start = time.time() → 1秒ごとにまとめて書き込みでSDカードへの負荷軽減 3. SDカードは高耐久・高品質なものを使う SanDisk Extreme / Samsung Pro などの「A1/A2対応」カード推奨 安価なSDは突然書けなくなる or レイテンシが跳ね上がるので避ける 4. ログのみで処理しない(リアルタイム処理は後回し) UBXをリアルタイムにデコードせず、あとでPCで処理 Pythonでpyubx2などを使ってパースすると、CPUとメモリを食うため、25Hzには不向き ◆ 結論:バイナリ保存だけならPython+ラズパイでも余裕 読み取り→バッファ→まとめて書く設計なら、 25Hz x 複数メッセージも十分処理可能 SDカードは性能の良いものを選ぶことが重要 パースや可視化は後処理に回すのが吉 必要なら、実際のコード例やリアルタイムUBXパーサーの軽量化設計も一緒に見ていけます。使ってるF9Pの設定やメッセージも教えてくれたら、もっと絞ってアドバイスできます!
Q: パースは後でいいからバイナリログで行く
「パース(parse)」とは、データを意味のある構造に分解して解釈することを指します。 ◆ GNSSデータでの「パース」の意味 例えば、u-bloxのF9Pが出力するUBX形式のバイナリデータは、機械が読むには最適ですが、人間やソフトウェアが意味を理解するにはパース処理が必要です。 【例】UBXバイナリデータ(生データ) bash コピーする 編集する b'\xb5b\x01\x3c\x20\x00\x7d...' このままだと何の情報か不明ですよね。 【パース後のデータ(例:NAV-RELPOSNED)】 python コピーする 編集する { "iTOW": 3871000, "relPosN": 120, "relPosE": -45, "relPosD": 10, "flags": 17, "accN": 2, "accE": 2, "accD": 3 } → 「パースした」ことで「これは時刻3871秒で、基準局との相対位置は…」と分かる。 ◆ PythonやC#での実装 Pythonでは struct.unpack() などを使って バイナリ→数値に変換(パース) UBXパーサライブラリ(例:pyubx2)は内部でこのパース処理をしてくれてる ◆ まとめ パース=データの解読・分解 UBXなどのバイナリデータを人が扱える形にする処理 リアルタイムでパースすると処理負荷が上がるので注意 必要なら、F9Pの特定メッセージの**手動パース方法(Pythonコード付き)**も解説できるよ!
Q: ラズパイは何が良いか
了解!バイナリログで保存→あとでパースの流れは、リアルタイム性や速度を優先するなら最適な選択です。F9Pのデータを安定して取得・保存するだけなら、処理負荷もかなり軽く抑えられます。 ◆ バイナリログでの運用ポイントまとめ 【1】USBシリアルでの読み取り(ラズパイ + Python) python コピーする 編集する import serial ser = serial.Serial('/dev/ttyACM0', 115200, timeout=0) with open('/home/pi/logs/f9p_log.ubx', 'ab', buffering=8192) as f: while True: data = ser.read(1024) if data: f.write(data) UBXモード出力のまま保存(あとで後解析) bufferingでディスク書き込みの効率化 【2】F9Pの出力設定 UBXメッセージのみ出力(必要なものだけ) 出力レート25Hzにする場合、出すメッセージは厳選してログ量を最適化 例:NAV-RELPOSNED だけ出力、他は止める → u-center または CFG-MSG コマンドで設定 【3】保存ファイルの管理 定期的にファイルを切ると便利(1時間ごとなど) 例:f9p_log_20250417_1500.ubx 【4】後処理パース(PCで) 後でパースする時は pyubx2 や自作スクリプトで ubxtool(RTKLIB系)でテキスト変換も可 ◆ 補足:トラブル回避Tips SDカードは「A1/A2対応の信頼性あるもの」 USBポートを他と共有しすぎない 長時間運用するなら電源と熱対策も考えると安心 この方式ならF9Pからの25Hzログも安定運用いけます! もしバイナリログを後からパースするための自作ツール作成とかも考えてたら、必要なときに相談してくれたら手伝うよ。
Q: ラズパイ displayをスマホで出来るか
ラズパイでGNSSバイナリログ用途(特にF9Pの25Hz運用)を安定して行うなら、以下の観点からおすすめモデルを紹介します。 ◆ 選定のポイント 項目 推奨条件 USBポート F9Pと安定通信できるもの(複数ポート推奨) SDカードI/O速度 ログ保存用に高速なI/Oが必要 処理能力 高周波データ処理・保存が詰まらない性能 電源安定性 USB機器給電に耐えられる安定性 OSサポート 最新のRaspberry Pi OSが動作すること ◆ おすすめモデル 【1】Raspberry Pi 4 Model B(おすすめ) USB 3.0×2ポート搭載 → F9P安定通信 RAM 2GB?8GB選べる(ログ専用なら2GBでOK) microSDカードスロット → A1/A2対応SDカードと組み合わせる 普通のOS(Raspberry Pi OS)でPython動作も安定 → 処理・I/Oともに25Hzログに余裕あり 【2】Raspberry Pi 5(最新・高性能) より高速なCPU・GPU PCIe経由でSSDも搭載可能(将来的にストレージ強化したい人向け) USB 3.0ポートも引き続き搭載 放熱と電源に注意(冷却ファン推奨) → 長期運用や複数F9Pを接続するなら最強 【3】Raspberry Pi Zero 2 W(小型・安価) USB OTG経由で接続(変換ハブが必要) CPU性能は低いが、ログ保存だけならギリギリOK 電源安定性に注意(F9Pの給電がギリギリ) → 軽量モバイル用途やコスト重視のテスト用にあり ◆ 結論 目的 おすすめ 安定運用・速度重視 Raspberry Pi 4 Model B 将来拡張・複数F9P・高I/O Raspberry Pi 5 超小型・省電力・安価 Pi Zero 2 W(条件付き) 必要なら、**F9Pとの接続方法(USB設定・シリアル経由)**や、ラズパイ起動時の自動ログ開始スクリプトの作成なんかもサポートできるよ!運用形態(固定局か移動体か)によっても選び方変わるから、そこも教えてくれたらさらに絞れる。
Q: ssh接続わからない
はい、ラズパイの画面(Display)をスマホで見ることは可能です!いくつかの方法があり、使い方やネットワーク環境によってベストな選択肢が変わります。 ◆ 方法1:VNC(スマホから画面をそのまま操作) 【概要】 ラズパイにVNCサーバを立てて、スマホでVNCクライアントから接続 ラズパイのGUI(デスクトップ画面)をスマホに表示&操作できる 【準備手順】 ラズパイでVNCを有効化 sudo raspi-config → Interfacing Options → VNC → 有効にする スマホにVNC Viewer アプリをインストール(RealVNCなど) ラズパイとスマホを同じWi-Fiに接続 スマホアプリでラズパイのIPを入力して接続 【メリット】 画面をそのまま見られる GUI操作可能(u-centerの代替表示などにも) 【デメリット】 Wi-Fi経由なので若干遅延あり ヘッドレス起動時は解像度設定が必要になる場合あり ◆ 方法2:Webサーバ経由でデータ表示(リアルタイム可視化用) 【概要】 ラズパイにPythonなどでWebサーバを立てて、スマホのブラウザでアクセス 例:Flaskを使ってUBXログ状態を表示 or 可視化 【使い方の例】 http://raspberrypi.local:5000 にスマホからアクセス 速度、状態、ログ件数などをリアルタイム表示可能 【メリット】 ネット越しでもアクセス可(ルータ設定次第で外部からも) 表示だけなら軽量・高速 【デメリット】 GUI全体ではなく、自作Web UIが必要 ◆ 方法3:SSHでCUI表示(ターミナル操作) スマホに Termius / JuiceSSH / ConnectBot などのSSHアプリを入れる ラズパイにSSH接続してログ取得スクリプトの状況確認など → GUI不要・軽量運用したいときに便利 ◆ どれが良い? 目的 方法 ラズパイの画面をそのままスマホで見たい VNC(一番簡単) 状態表示・データ可視化だけしたい Webサーバ方式 軽量・CUI操作のみ SSH 必要であれば、具体的な設定手順や**スマホ画面にリアルタイムログのグラフを出す方法(Flask+Plotlyなど)**も案内できるよ。どう運用したいか(遠隔で見る、ログだけ確認など)教えてくれたら、もっとピッタリな構成提案するよ!
Q: sshでwin10pcのコンソールアプリをスマホから操作したい
OK!じゃあ、スマホからラズパイにSSH接続する方法を、初心者向けにわかりやすく手順で説明するね。 ◆ SSHってなに? SSH(Secure Shell)は、他のPCやスマホからラズパイを安全に操作できる仕組みだよ。 CUI(黒い画面)でコマンド入力できて、ラズパイにディスプレイやキーボードがなくても使えるようになる。 ◆ 必要なもの ラズパイ(起動してWi-Fiにつながっている) スマホ(Android or iPhone) 同じネットワーク(Wi-Fi)に両方つながっていること スマホ用のSSHアプリ(おすすめあり) ◆ スマホ側の準備 【1】SSHアプリを入れる(無料) スマホの種類 アプリ名 備考 Android Termius おすすめ・使いやすい iPhone Termius for iOS 同じくOK ◆ ラズパイ側の準備 【1】SSHを有効化 ディスプレイがあるなら: bash コピーする 編集する sudo raspi-config → Interfacing Options → SSH → Enable もしディスプレイなしなら、SDカードのbootフォルダに空ファイルを作成: ファイル名:ssh(拡張子なし) 【2】ラズパイのIPアドレスを確認 ラズパイ側でこのコマンドを実行: bash コピーする 編集する hostname -I 例: コピーする 編集する 192.168.1.23 → このIPアドレスをスマホに入力する! ◆ スマホから接続する手順(Termiusの場合) Termiusを開く 「+」ボタン → New Host 入力項目: Host: 192.168.x.x(ラズパイのIP) Port: 22(そのままでOK) Username: pi Password: raspberry(初期値。変更してたらそのパスワード) 保存して接続(タップすれば入れる) ◆ 接続成功したら? 黒い画面(シェル)が開いて、こんな感じになるはず: bash コピーする 編集する pi@raspberrypi:~ $ ここからPythonスクリプト起動したり、ログの確認、再起動など何でもできる! ◆ よくある失敗 症状 原因と対策 接続できない ラズパイがWi-Fiにつながってない or IPが違う パスワード違う raspberryじゃなく変更してたらそれを入力 SSH無効 raspi-configかbootにsshファイルがない 必要ならTermiusの画面でログスクリプトを起動する方法や、コマンドのショートカット設定なんかも教えるよ! 接続できたら教えて!その後のステップも一緒にやってこう。
Q: python自動起動
なるほど!**「Windows 10上で動いているコンソールアプリ(CUI)を、スマホからSSHで操作したい」**ってことだね。 それ、ちゃんと設定すればできます!以下の手順で行けるよ。 ◆ やりたいことの概要 Windows 10 PC に SSHサーバを立てる スマホから SSHクライアント(Termiusなど)でログイン コンソールアプリ(Pythonやbatなど)をスマホから実行・操作 ◆ ステップバイステップ 【1】Windows 10にSSHサーバをインストール (1)OpenSSH Server を有効化 スタート → 「アプリと機能」 → 「オプション機能」 「OpenSSH Server」を探す(なければ「機能の追加」からインストール) インストール後、PCを再起動 (2)SSHサービスを起動・自動起動にする コマンドプロンプト(管理者)で以下を実行: bash コピーする 編集する sc start sshd sc config sshd start=auto 【2】WindowsのIPアドレスを確認 コマンドプロンプトで: bash コピーする 編集する ipconfig → IPv4アドレス を確認(例:192.168.1.100) 【3】スマホからSSHで接続する スマホで Termius などを使って: Host: 192.168.x.x(PCのIP) Port: 22 Username: Windowsログイン名(例:yourname) Password: Windowsのログインパスワード → 接続できたら、コマンドラインが表示される! 【4】コンソールアプリを実行する ログイン後、以下のようにアプリを起動可能: (例)Pythonスクリプトの実行 bash コピーする 編集する python mylogapp.py (例)バッチファイル bash コピーする 編集する .\start_log.bat → リアルタイムで出力をスマホで確認しながら操作可能 ◆ 注意点 PythonなどのアプリはPATHが通っている必要あり Windows Defenderがポート22をブロックしている場合、例外設定が必要 ログアプリがGUIだと表示されない(CUI前提) ◆ 補足:複数接続・スクリプト常駐化も可 PowerShellスクリプトでログ処理を自動化 Python+ログ監視+リアルタイム出力とかも可能 ◆ まとめ 項目 内容 SSHサーバ Windows 10にOpenSSH Serverを導入 接続元 TermiusなどのスマホSSHアプリ 操作 任意のCUIアプリ起動・操作可能 うまくいけば、スマホ1台で家中のPCログアプリを操作・監視できる環境になるよ。 もし「Pythonアプリを自動起動」「常時ログ取りして状態表示」みたいな構成にしたいなら、それも一緒に考えよう!
Q: python exe化したこと無い
PythonスクリプトをWindows 10で自動起動する方法はいくつかあるけど、用途やタイミング(ログイン時・起動時など)に合わせて選ぶのがコツです。 ここでは一番安定して確実な方法を紹介するね。 ◆ 方法1:タスクスケジューラで自動起動(おすすめ) Windowsの標準機能だけでできて、ログイン不要 or 隠れて起動もできる。 【設定手順】 1. タスクスケジューラを開く スタート → 検索で「タスクスケジューラ」 2. 右側の「タスクの作成」をクリック 3. 各タブを設定 「全般」タブ 名前:Start Python Logger など 「ユーザーがログオンしているかどうかにかかわらず実行する」にチェック 「最上位の特権で実行する」もチェック(必要なら) 「トリガー」タブ 「新規」 → 「コンピュータの起動時」または「ユーザーログオン時」を選ぶ 「操作」タブ 「新規」 → 操作:プログラムの開始 プログラム/スクリプト:python 引数の追加:C:\path\to\your\script.py 開始(作業)フォルダー:スクリプトのあるディレクトリ(任意) 4. 保存して完了 ◆ 方法2:スタートアップフォルダにショートカットを置く 超簡単だけど、ユーザーがログインしてからしか動かない。 手順 Pythonスクリプトのショートカットを作成 Win + R → shell:startup と入力(スタートアップフォルダが開く) そこにショートカットを入れる → ログイン時に自動で起動する ◆ 注意点 .pyがPythonで実行されない場合、.pywにするかフルパスでpython.exeを指定する PythonがAnaconda環境とかの場合は、環境パスに注意 標準出力が必要ないなら .pyw にしてコンソール非表示にもできる ◆ 例:タスクスケジューラの設定コマンド(PowerShell) 自動化したい人向け: powershell コピーする 編集する $Action = New-ScheduledTaskAction -Execute "python.exe" -Argument "C:\your\script.py" $Trigger = New-ScheduledTaskTrigger -AtStartup Register-ScheduledTask -Action $Action -Trigger $Trigger -TaskName "PythonLogger" -RunLevel Highest -User "SYSTEM" どっちにするのがいい? 条件 方法 起動直後にバックグラウンド実行したい タスクスケジューラ 自分がログインするタイミングだけでOK スタートアップ 表示なしでこっそり動かしたい .pyw + タスクスケジューラ どんなスクリプトを自動化したい? ログ収集、リモート送信、GUIなし処理とか、目的によってちょっと調整できるよ。スクリプト内容教えてくれたら、設定代行する感じで一式作るよ!
Q: データ量がubx以外にIMUとデジタルアンプから100Hzのデータがあるので、110kbpsのデータがあるあのでpython でバイナリーログ出来るか心配
了解!Pythonスクリプトを**.exeファイル化(実行形式化)**するのは意外と簡単で、Windows環境なら1回覚えればサクッと使えるようになるよ。 ◆ Pythonスクリプトを .exe に変換する方法(PyInstaller) 最もよく使われるツールは PyInstaller。 これを使えば、Pythonが入っていないPCでも .exe を実行できるようにできる(オプションによって)。 ◆ ステップバイステップ 【1】PyInstallerのインストール まず、PythonがインストールされたPCで以下を実行: bash コピーする 編集する pip install pyinstaller 【2】スクリプトを .exe に変換 たとえば logger.py を変換したい場合: bash コピーする 編集する pyinstaller --onefile logger.py オプションの意味: --onefile:すべてを1つの .exe にまとめる(フォルダ散らからない) --noconsole:コンソールを表示しない(GUI用 or バックグラウンド用) → 完成した .exe は dist フォルダに出力される! 【3】作った .exe を動かす dist/logger.exe をダブルクリックするだけでOK 自動起動用にもその .exe をタスクスケジューラやスタートアップに登録すればOK! ◆ よくあるオプション オプション 説明 --onefile 1つのexeにまとめる(おすすめ) --noconsole コンソール非表示(GUI・ログだけなど) --icon=icon.ico exeにアイコンを付けたいとき --add-data "data.txt;." 付属データを含めたいとき(セミコロン区切り) ◆ 注意点 .pyw でも .exe 化できる(GUI用にしたい時) 外部ライブラリを使ってる場合でも、--onefile なら全部含めてくれる(少し起動は遅くなる) 初回実行時はウイルス対策ソフトが反応することもある(署名してないため) ◆ 例:バックグラウンド用ログスクリプトをexe化 bash コピーする 編集する pyinstaller --onefile --noconsole logger.py → Windowsのタスクスケジューラやスタートアップに入れておけば、自動でログ取りができる! ◆ 必要なら PyInstaller設定ファイル(.spec)のカスタマイズ exeにログファイル自動出力するオプション追加 GUI付き(Tkinter, PyQt)版のexe化 なんかもできるよ。 やってみる?もしスクリプト見せてくれたら、PyInstaller用コマンド例と一緒にspecファイルも作ってみせるよ!
Q: 220kbps
おお、なるほど。**110kbpsの連続データをPythonでバイナリログできるか?**という心配ね。 UBX + IMU + デジタルアンプで合計 100Hz超 × 多チャネル → 約110kbpsってなかなかの量。 でも、ちゃんと設計すれば Python+ラズパイでも問題なくバイナリログ可能だよ! ◆ 前提の確認 まず、計算ざっくりすると: 110kbps = 13.75kB/s 秒間14kB程度のバイナリデータ 1時間で約 50MB(ログファイル) → Pythonでも普通に扱えるレベル。ただし「遅延なく・漏れなく・安定して」ログするには工夫が必要。 ◆ ログ処理のボトルネック:3つのチェックポイント 要素 可能な問題 対策 USBシリアル受信 受信バッファオーバー PySerialで高速read+バッファ調整 書き込み(SD/SSD) ファイルI/Oが遅い バッファリング+非同期書き込み Python処理速度 GILや無駄な処理 バイナリ処理・シンプル構造に ◆ 解決策まとめ(Python) ? 1. pyserial で高速受信 python コピーする 編集する import serial ser = serial.Serial('/dev/ttyUSB0', baudrate=115200, timeout=0) timeout=0 でノンブロッキング ser.read(size) または ser.read_all() で一気に読む ? 2. 書き込みバッファリング(例:リングバッファ) python コピーする 編集する import threading, queue buf = queue.Queue() def reader(): while True: data = ser.read(1024) if data: buf.put(data) def writer(): with open("log.bin", "ab") as f: while True: data = buf.get() f.write(data) → threading.Thread で受信と書き込みを 非同期で分離 ? 3. 書き込みパフォーマンス向上 書き込みはまとめて(バッファサイズを調整) SDカードの場合は Class10以上 or USBメモリ推奨 open(..., buffering=0) で制御可能 ◆ ラズパイで実績がある条件 項目 実績値(目安) USBシリアルボーレート ~921600bps ログデータ転送 ~300kbps以上実績あり SDカード UHS-I Class10 以上でOK 書き込み方法 バイナリ&非同期処理なら安定動作 ◆ 実際のログ例(参考) python コピーする 編集する # 1MB/sでも落ちない構成例 ser = serial.Serial('/dev/ttyUSB0', 921600) with open("data.bin", "wb") as f: while True: f.write(ser.read(1024)) → ただしこの単一ループだと、他の処理(例:IMU解析など)を入れると落ちる可能性あり。 受信スレッド+書き込みスレッド分離が安定。 ◆ 結論 ?? 110kbps 程度ならラズパイでもPythonでバイナリログ十分可能! ?? 必要なら 非同期 or バッファ付き設計にしておく ?? SDカードは高速なものを(書き込み10MB/s以上なら余裕) スクリプト組みたいなら、USBポート数・データ形式(UBX, IMU, AMPのフォーマット)教えてくれたら一緒に書けるよ! 「複数ポート・1ファイルにバイナリ統合ログ」みたいな構成もいける!
Q: とりあえずWINDOWSのPython でのサンプルプログラム
おおっ、220kbps か! それでもまだ Python + ラズパイで十分リアルタイムバイナリログ可能な範囲です。 ただ、慎重に設計しないと「ちょいちょい取りこぼす」ってことは起きるから、しっかり対応しましょ。 ◆ 220kbps = 27.5kB/s のイメージ 秒間 27.5kB = 1分で 1.65MB 1時間で 約100MB のバイナリログ ラズパイ(SDカード Class10?UHS-I)なら余裕 USB通信も115200bpsを2ポート使えばOK(=実用上は921600bps 1ポートで余裕) ◆ 対策ポイント(220kbps対応構成) 項目 推奨内容 シリアル受信 PySerialで timeout=0 + read(1024) 書き込み スレッド分離(読み取りと保存を並行) ファイルI/O open(..., 'ab', buffering=0) で即書き SDカード Class10以上。UHS-IやUSBメモリも良 処理方式 バイナリ保存で一切の解析を後回しにすることが重要 例:複数USB USB1=F9P、USB2=IMU、USB3=AMP などもOK ◆ スレッド分離バイナリログ処理:基本構成(例) python コピーする 編集する import serial import threading import queue ser = serial.Serial('/dev/ttyUSB0', 921600, timeout=0) buf = queue.Queue() def reader(): while True: data = ser.read(1024) if data: buf.put(data) def writer(): with open("log.bin", "ab", buffering=0) as f: while True: data = buf.get() f.write(data) threading.Thread(target=reader, daemon=True).start() threading.Thread(target=writer, daemon=True).start() # 無限ループで動かし続ける while True: pass ◆ ラズパイでおすすめモデル モデル コメント Raspberry Pi 4(2GB以上) 安定&USB3対応。冷却大事 Raspberry Pi Zero 2 W ギリギリ対応可能(CPU使用率高くなる) Raspberry Pi 5 めちゃ余裕(SSD対応もOK) → データ量的に Pi 4 が無難で安心。 ◆ テストのコツ 最初は cat /dev/ttyUSBx > /dev/null で受信確認 Pythonログ中に1秒あたりのバイト数をカウントして レート確認すると安心 落ちたときのためにログローテーションも考慮するとさらに安定 まとめ ?? 220kbpsのリアルタイムバイナリログ、Python+ラズパイでいける! ?? スレッド分離とバイナリログだけに専念する構成が安定 ?? SDカードは性能大事。ログ取りはシンプルに、パースは後で! 必要なら、USB複数ポートから同時に受信して1つのログファイルに保存する構成のコード作るよ。 F9P、IMU、AMPがどのポートか・何バイトずつとか教えてもらえたら即書ける!やる?
Q: ログファイル名をタイムスタンプ
OK!Windowsで動かす、リアルタイムUSBシリアル受信 → バイナリログ保存のPythonサンプル、以下に作ったよ。 220kbpsまで耐えられるよう、受信と保存をスレッドで分離、バイナリデータはそのまま保存する構成にしてある。 ? サンプル構成(シンプル版) USBシリアル:1ポート(例:COM3) ボーレート:921600bps(220kbps余裕で対応) 出力ログファイル:log.bin 読み取りサイズ:1024バイトずつ 書き込み:バッファリング無し、即時保存 ? Pythonコード(Windows対応) python コピーする 編集する import serial import threading import queue import time # --- 設定 --- PORT = 'COM3' # 使用しているUSBシリアルポートに変更 BAUDRATE = 921600 # 必要に応じて変更(F9Pは最大921600まで対応) LOG_FILE = 'log.bin' # 保存先ファイル CHUNK_SIZE = 1024 # 読み取りサイズ # --- 共有バッファ --- data_queue = queue.Queue() # --- 受信スレッド --- def reader_thread(): with serial.Serial(PORT, BAUDRATE, timeout=0) as ser: while True: data = ser.read(CHUNK_SIZE) if data: data_queue.put(data) # --- 書き込みスレッド --- def writer_thread(): with open(LOG_FILE, 'ab', buffering=0) as f: while True: data = data_queue.get() f.write(data) # --- スレッド起動 --- threading.Thread(target=reader_thread, daemon=True).start() threading.Thread(target=writer_thread, daemon=True).start() # --- メインループ(終了せず動かし続ける)--- try: print("Logging started. Press Ctrl+C to stop.") while True: time.sleep(1) except KeyboardInterrupt: print("Logging stopped.") ? 動かすときのポイント Python 3.x をインストール済であること(Windows) pyserial ライブラリが必要: bash コピーする 編集する pip install pyserial ポート番号は COM3 → 実際に使っているポートに変更 ? 補足:複数USB対応したいときは? 例えば F9P / IMU / AMP が別のCOMポートにあるなら、受信スレッドをそれぞれ作って1つのキューに入れる or ファイル分けるのが良い。 ?? もっと強化したい場合: ログにタイムスタンプ追加(1ms精度) 一定サイズでログファイルを分割(ローテーション) 書き込みエラーハンドリング追加 Pythonをexe化してタスクスケジューラ登録(自動起動) やってみて、動いたか・不安なところあったら教えて! もし「複数ポート同時受信」とか「ログに時間を入れたい」とか追加要望あればすぐ出すよ!
Q: パスにC\UPload\に保存
いいね!ログファイル名にタイムスタンプを付けるのは、記録を管理しやすくするうえでも超便利。 以下のように書けば、ファイル名が実行時の日時を含む形式になります。 ? ファイル名にタイムスタンプを付ける方法 たとえば、以下のようなファイル名にしたいとします: python コピーする 編集する log_2025-04-17_21-45-30.bin ? 修正済みPythonコード(タイムスタンプ付きファイル名) python コピーする 編集する import serial import threading import queue import time from datetime import datetime # --- 設定 --- PORT = 'COM3' # 実際のCOMポートに変更 BAUDRATE = 921600 CHUNK_SIZE = 1024 # --- タイムスタンプ付きファイル名生成 --- timestamp = datetime.now().strftime('%Y-%m-%d_%H-%M-%S') LOG_FILE = f'log_{timestamp}.bin' # --- 共有バッファ --- data_queue = queue.Queue() # --- 受信スレッド --- def reader_thread(): with serial.Serial(PORT, BAUDRATE, timeout=0) as ser: while True: data = ser.read(CHUNK_SIZE) if data: data_queue.put(data) # --- 書き込みスレッド --- def writer_thread(): with open(LOG_FILE, 'ab', buffering=0) as f: while True: data = data_queue.get() f.write(data) # --- スレッド起動 --- threading.Thread(target=reader_thread, daemon=True).start() threading.Thread(target=writer_thread, daemon=True).start() # --- メインループ --- try: print(f"Logging to {LOG_FILE}. Press Ctrl+C to stop.") while True: time.sleep(1) except KeyboardInterrupt: print("Logging stopped.") ? ログファイル名の例(実行時の日時に応じて変化) text コピーする 編集する log_2025-04-17_21-45-30.bin ※ : はファイル名に使えないので、時間部分は - にしてあります。 このままでも十分使えるけど、もし次のような機能が欲しくなったら教えて: 指定時間ごとにログファイルをローテーション 複数USBのログファイルをポート名ごとに自動命名 ログと一緒に .meta ファイルで記録開始情報を書き出す 何でも対応できるよ!
Q: エラー出たmodule ‘serial’ has no attribute ‘Serial’
File “C:\Users\dj171\PycharmProjects\STA25_binLog.py”, line 25, in reader_thread
with serial.Serial(PORT, BAUDRATE, timeout=0) as ser:
^^^^^^^^^^^^^
AttributeError: module ‘serial’ has no attribute ‘Serial’
了解!ログファイルを特定のパス、たとえば: makefile コピーする 編集する C:\Upload\ に保存したい場合は、ファイル名にフルパスを指定するだけでOKです。 ただし、PythonでWindowsパスを扱うときは、バックスラッシュ \ を2つ重ねるか、生文字列 r"..." を使うのが安全です。 ? 修正済みコード(ログを C:\Upload\ に保存) python コピーする 編集する import serial import threading import queue import time from datetime import datetime import os # --- 設定 --- PORT = 'COM3' BAUDRATE = 921600 CHUNK_SIZE = 1024 # --- ログ保存パスとファイル名作成 --- log_dir = r'C:\Upload' # ← ここに保存したいフォルダを指定 os.makedirs(log_dir, exist_ok=True) # フォルダがなければ作成 timestamp = datetime.now().strftime('%Y-%m-%d_%H-%M-%S') LOG_FILE = os.path.join(log_dir, f'log_{timestamp}.bin') # --- 共有バッファ --- data_queue = queue.Queue() # --- 受信スレッド --- def reader_thread(): with serial.Serial(PORT, BAUDRATE, timeout=0) as ser: while True: data = ser.read(CHUNK_SIZE) if data: data_queue.put(data) # --- 書き込みスレッド --- def writer_thread(): with open(LOG_FILE, 'ab', buffering=0) as f: while True: data = data_queue.get() f.write(data) # --- スレッド起動 --- threading.Thread(target=reader_thread, daemon=True).start() threading.Thread(target=writer_thread, daemon=True).start() # --- メインループ --- try: print(f"Logging to {LOG_FILE}. Press Ctrl+C to stop.") while True: time.sleep(1) except KeyboardInterrupt: print("Logging stopped.") ? 注意点 C:\Upload フォルダが事前に存在しなくても自動で作られます。 書き込み権限が必要なので、管理者権限のターミナルで実行すると安心。 タイムスタンプ付きファイルなので、毎回別ファイルに保存されます。 これで、毎回実行時に: makefile コピーする 編集する C:\Upload\log_2025-04-17_21-52-44.bin みたいなログファイルが生成されます! もっと複雑な命名(たとえば「F9Pログ」「IMUログ」みたいな)とか、日付ごとのサブフォルダに分けたい場合も対応できるよ!必要あれば言ってね!
Q: ファイル名は問題ないから pip install serialとやったのが原因か
これはよくあるミスで、Pythonで pyserial を使うときに: ? serial.py という 自分のファイル名がライブラリと被っている というパターンが原因です。 ? 解決方法 ① ファイル名を変更してください serial.py という名前の .py ファイルが存在すると、Pythonは標準の pyserial モジュールではなく自分のファイルを読もうとします。 例: 現在のファイル名が serial.py → これはNG! ?? おすすめファイル名: コピーする 編集する log_usb.py usb_logger.py STA25_binLog.py ← これはOK! ② 同じフォルダにできた serial.pyc や __pycache__ フォルダを削除 名前を変えたあと、以下も削除しておくと確実です: serial.pyc __pycache__ フォルダ ? チェック方法(ターミナルで確認) bash コピーする 編集する pip show pyserial と打って、Location: のパスが /Lib/site-packages/serial/ のようになっていればOK。 それでも AttributeError が出る場合は、名前の競合がほぼ確定です。 ?? まとめ やること 内容 ? ファイル名を変える serial.py → 他の名前に ? .pycと__pycache__削除 古いキャッシュ削除 ? Python再実行 Pycharmを再起動するのもOK 修正して再実行すれば serial.Serial(...) は問題なく使えるはず! うまくいかなかったら、そのときのファイル名とエラーメッセージ貼ってくれたら一緒に見ます!
Q: C# 絶対値
はい、それズバリ原因です!?? pip install serial をやっちゃうと、全く関係ない serial という別物のパッケージがインストールされてしまいます。 これは pyserial とは別で、しかも serial.Serial を持ってないので、今回のエラーが出ます。 ? 正しい手順 1. 間違って入れた serial パッケージをアンインストール bash コピーする 編集する pip uninstall serial 2. 正しい pyserial をインストール bash コピーする 編集する pip install pyserial ? チェック:インストール済みのパッケージ確認 bash コピーする 編集する pip list ここで pyserial が表示されていればOK。 serial は表示されていない状態にしてください。 ? サンプル確認 修正後、次のテストコードを実行して確認してみてください: python コピーする 編集する import serial print(serial.__file__) # ← どこから読まれてるか確認 ser = serial.Serial() # ← これでエラーが出なければOK 出力例: vbnet コピーする 編集する C:\Users\<ユーザー名>\AppData\Local\Programs\Python\Python3x\Lib\site-packages\serial\__init__.py ?? まとめ やること コマンド ? 間違ったパッケージ削除 pip uninstall serial ? 正しいパッケージ導入 pip install pyserial これで問題なく serial.Serial(...) が使えるはず! もう一度実行してみて、動作確認できたらOKです ??
Q: Python PCでバイナリログした結果 C#と同じだった、RASPY ZEROW2ではどうなるか
C#で絶対値を求めるには、標準ライブラリの Math.Abs() メソッドを使います。 ? Math.Abs() を使った絶対値の計算 csharp コピーする 編集する using System; class Program { static void Main() { // 整数の場合 int intVal = -10; Console.WriteLine("絶対値 (int): " + Math.Abs(intVal)); // 浮動小数点数の場合 double doubleVal = -3.14; Console.WriteLine("絶対値 (double): " + Math.Abs(doubleVal)); // 長整数の場合 long longVal = -5000000000; Console.WriteLine("絶対値 (long): " + Math.Abs(longVal)); } } ? 説明 Math.Abs() は、引数の数値が負であれば正の値を返し、正であればそのままの値を返します。 引数の型に応じて、整数型(int)、浮動小数点型(double)、長整数型(long)をサポートしています。 このコードを実行すると、各データ型に対して絶対値を計算してコンソールに表示されます。 何か他に質問があればどうぞ!
Q: PYTHONのPCプログラムはスレッド処理してある結果
PythonでバイナリログをPCで試してみた結果、C#と同じだったとのことですね! では、Raspberry Pi Zero 2 W(Raspberry Piの小型モデル)でのパフォーマンスがどうなるかを見てみましょう。 ? Raspberry Pi Zero 2 Wでのパフォーマンス 1. CPUとメモリの違い Raspberry Pi Zero 2 Wは、PCや他のRaspberry Piモデルに比べて処理能力が低いため、データ処理速度やバイナリログの書き込み速度に影響があるかもしれません。 Raspberry Pi Zero 2 W: CPU:Broadcom BCM2710A1(クアッドコア 1GHz ARM Cortex-A53) メモリ:512MB LPDDR2 PC: 比較的高性能なCPU(Core i5以上が多い)や十分なメモリ(8GB以上) 2. Pythonでの動作 Pythonは基本的にシングルスレッドで実行されるため、Raspberry Pi Zero 2 Wの性能により処理速度に制約が出る可能性があります。特に、データの受信やファイル書き込みが並列で行われる場合、処理能力に差が出ることも。 ただし、軽いI/O操作やデータのパース処理に関しては、Raspberry Pi Zero 2 Wでも十分にこなせる範囲です。 3. SDカードの速度 Raspberry Pi Zero 2 Wが使用するSDカードの速度も重要な要素です。低速なSDカードではデータの書き込みが追いつかない可能性があります。 Class 10以上のSDカードを使用することをおすすめします。 UHS-I対応カードがあれば、より高速にデータ書き込みができます。 4. 実行テスト Raspberry Pi Zero 2 Wで実際にバイナリログを取るテストを行った場合、100Hzのデータ量(220kbps程度)に対しては、遅延が少し増加する可能性はありますが、基本的に問題なく動作するでしょう。ただし、ログファイルが大きくなると処理の負荷が増加します。 ? 具体的な動作確認方法 Raspberry Pi Zero 2 Wで動作確認を行うには、PCと同じコードをそのまま使い、パフォーマンスの違いをテストしてみてください。 bash コピーする 編集する # Pythonのバージョン確認 python3 --version # pyserialのインストール(Raspberry Pi Zero 2 Wで使用) pip3 install pyserial コードを実行して、CPU使用率やSDカードの書き込み速度をモニタリングすると、パフォーマンスのボトルネックを確認できます。 テストコマンド bash コピーする 編集する # CPU使用率確認 top # SDカードの書き込み速度確認(i.e. hdparm) sudo apt-get install hdparm sudo hdparm -t /dev/mmcblk0 ? まとめ Raspberry Pi Zero 2 Wでもバイナリログの書き込みは可能ですが、PCに比べて処理能力が低いため、負荷が高くなると遅延やデータ取りこぼしが発生する可能性がある。 SDカードの性能が重要。 シングルスレッドでの処理が続くと、書き込みの速度に影響が出ることがある。 テスト後に実行速度やログの取りこぼしが気になる場合は、Pythonのスレッド処理やデータのバッファリングを追加して調整できます。 実際に試したら、どうだったか教えてください!
Q: RASPY ZEROW2のSD IFの速度
スレッド処理を使ってPythonプログラムのパフォーマンスを最適化している場合、PCでの動作が問題ない理由は、並列処理によってI/O操作(データ受信とファイル書き込み)が効率的に行われるからです。 しかし、Raspberry Pi Zero 2 Wに移行した場合、性能の差によって、スレッド処理の結果が遅延や取りこぼしにつながることがあるので、テストをして確認することが大切です。 ? スレッド処理でのPCとRaspberry Piの違い PCの性能は一般的に高いため、スレッド処理による並列処理が効率的に動作し、データ受信とログ書き込みがスムーズに行えます。 Raspberry Pi Zero 2 Wは、CPUやメモリが限られており、スレッド処理を使ってもデータ量やI/O負荷が高くなると、パフォーマンスが低下する可能性があります。 これを改善するためのヒント 1. スレッドの使用を見直す スレッド処理が多すぎると、CPUの負荷が高くなり、逆にパフォーマンスが落ちることがあります。Raspberry Pi Zero 2 Wのような低性能なデバイスでは、スレッドの数を適切に調整することが重要です。 python コピーする 編集する # 例: スレッド数を減らしてテスト NUM_THREADS = 2 # 例えばスレッド数を2に設定 2. データのバッファリング データ受信と書き込みをスムーズにするために、受信データをバッファに貯めておき、まとめて書き込むという方法が有効です。これによってI/O操作の回数を減らし、書き込みの効率を高めることができます。 python コピーする 編集する # バッファを使用してデータの書き込みを効率化 data_buffer = [] # データを受信したらバッファに追加 data_buffer.append(data) # バッファが一定のサイズに達したら一気に書き込む if len(data_buffer) >= BUFFER_SIZE: with open(LOG_FILE, 'ab') as f: f.write(b''.join(data_buffer)) data_buffer.clear() # バッファをリセット 3. SDカードの速度に注意 Raspberry Pi Zero 2 WはSDカードの速度がボトルネックになりやすいため、高速なSDカード(UHS-I対応など)を使うことが重要です。特に大量のデータを高速に書き込む場合、カードの性能がパフォーマンスに大きな影響を与えます。 bash コピーする 編集する # SDカードの速度テスト(Raspberry Piで) sudo apt-get install hdparm sudo hdparm -t /dev/mmcblk0 4. Pythonのパフォーマンスを最適化 Pythonの実行速度を少しでも改善するために、以下のような最適化を検討できます: multiprocessing モジュールを使用してマルチプロセス化(スレッドよりも効率的に並列処理を行う) Cython で一部の計算部分をコンパイルして速度を向上 time.sleep() の調整や、無駄な計算を減らす ? Raspberry Pi Zero 2 Wでの性能向上を目指すアプローチ スレッド数やプロセス数を調整して、Raspberry Piの限られたリソースを有効活用 データバッファリングを活用して、データの書き込み回数を減らし効率化 SDカードの性能を確認し、必要ならより高速なものに交換 Pythonの最適化(Cythonやマルチプロセス)で処理速度を改善 まとめ Raspberry Pi Zero 2 Wは、PCに比べて性能が限られているため、スレッド処理やデータの書き込みに関して、PCと同じパフォーマンスが出ない場合があります。しかし、バッファリングやスレッド数の調整でうまく最適化することで、十分に目的を達成することができるでしょう。 テストを行い、問題があれば上記の方法を試してみてください。
Q: SDIOをつかっているのか
Raspberry Pi Zero 2 WのSDカードインターフェース(SD IF)の速度は、主に以下の要素に依存します: SDカードのクラス SDカードのインターフェース(UHS-Iなど) SDカードの種類(通常のSDカード、microSDなど) Raspberry Piのハードウェア制限 1. Raspberry Pi Zero 2 WのSDカードインターフェース Raspberry Pi Zero 2 Wは、UHS-I(Ultra High Speed Phase I)インターフェースをサポートしています。ただし、SDカード自体がUHS-I対応でない場合や、カードリーダーが低速である場合、その速度は制限されます。 最大理論速度:Raspberry Pi Zero 2 WはUHS-Iで最大 50MB/s の読み書き速度をサポートします。 ただし、実際の速度は使用するSDカードの性能によります。 2. SDカードの種類 SDカードにはいくつかの規格があります: Class 10:書き込み速度が最低10MB/s。 UHS-I(Ultra High Speed Phase I):理論上最大で 104MB/s の速度が可能。 UHS-II:Raspberry Pi Zero 2 Wではサポートされていませんが、理論上最大 312MB/s の速度が可能です。 最も重要なのは、UHS-I対応の高速カード(例えばSanDisk Extreme Proなど)を使用することです。これにより、SDカードインターフェースの性能を最大限に活用できます。 3. SDカードの性能に依存 SDカードの品質やブランドによって、書き込み/読み取り速度は大きく異なります。たとえば: SanDisk Extreme Pro(UHS-I、Class 10)は、読み取り速度最大 95MB/s、書き込み速度最大 90MB/s などの高速カードがあります。 安価なSDカードや古いカードだと、書き込み速度が低くなる可能性があります。 4. 実際の速度 実際にSDカードの速度をテストするために、以下のようなコマンドを使って速度を計測できます: bash コピーする 編集する # SDカードの読み書き速度をテスト(Raspberry Pi) sudo apt-get install hdparm sudo hdparm -t /dev/mmcblk0 このコマンドを実行すると、SDカードの読み取り速度(読み込みの速度)が表示されます。 また、書き込み速度を確認するために次のようなコマンドも使用できます: bash コピーする 編集する # 書き込み速度テスト dd if=/dev/zero of=/tmp/testfile bs=1M count=1024 conv=fdatasync これで、SDカードの書き込み速度を実測できます。 ? まとめ Raspberry Pi Zero 2 WのSDカードインターフェースは、UHS-Iに対応し、理論的には最大 50MB/s の速度をサポートします。 実際の速度は使用するSDカードの性能に依存します。UHS-I対応の高速カードを使うことで、より高速なデータ転送が可能です。 テストツール(hdparm や dd コマンド)を使って、実際の読み書き速度を確認することができます。 SDカード選びが性能に直結するので、高速なSDカードを選ぶことが、Raspberry Piでのパフォーマンス向上に重要です。
Q: SPIだったらそんなに速度でないはず
Raspberry Pi Zero 2 Wでは、SDカードインターフェースは、SDIO (Secure Digital Input/Output) を使用していません。代わりに、SDカードは通常のSDカードインターフェース(SPIまたはSDモード)を通じて接続されています。 SDIOとRaspberry Pi Zero 2 W SDIOは、通常、SDカード以外の周辺機器との接続を目的としたインターフェースです。例えば、Wi-FiモジュールやBluetoothモジュールなどがSDIOインターフェースを使用することがありますが、SDカード自体はSDIOを使用しません。 Raspberry Pi Zero 2 Wや他のRaspberry PiモデルでSDカードが接続される場合は、SDカードモード(またはSPIモード)が使われます。 SDカードのインターフェースの種類 Raspberry Piで使用されるSDカードインターフェースは、以下の2種類です: SDモード これは、カードが通常のSDカードインターフェースで動作する場合です。 最大データ転送速度は 50MB/s(UHS-I対応の場合)。 SPIモード SPI(Serial Peripheral Interface)モードは、より遅いインターフェースで、通常はSDカード以外の周辺機器(例えば、センサーや小型デバイス)と接続するために使用されます。 最大転送速度は、SDモードよりも遅いです。 Raspberry Pi Zero 2 WのSDカードインターフェース Raspberry Pi Zero 2 Wは、**SDカードの高速転送モード(SDモード)**をサポートしており、これにより 最大50MB/s の読み書き速度が可能です。 UHS-IのSDカードを使用すると、より高速なデータ転送が期待できます。これは、SDカードが対応するインターフェースの規格に依存します。 まとめ Raspberry Pi Zero 2 WのSDカードはSDIOインターフェースではなく、SDモードで接続されています。 UHS-I対応のSDカードを使用することで、最大50MB/s の読み書き速度が得られる可能性があります。 SDIOは通常、SDカード以外の周辺機器(Wi-FiやBluetoothモジュールなど)に使用されますが、SDカードそのものはSDモードを使っています。
Q: SDカードモードってSDIO インターフェースではないのか
その通りです! SPIモードを使う場合、速度はかなり制限されます。SPI (Serial Peripheral Interface) モードは、一般的に SDカードインターフェースの中で最も遅い通信方法 であり、データ転送速度はかなり低くなります。 SPIモードの速度 SPIモードでのSDカードのデータ転送速度は、通常、最大25MB/s程度に制限されます。これは、**SDモード(SDカード専用モード)**に比べてかなり遅い速度です。 具体的な速度: SPIモード:理論的には最大 25MB/s だが、実際にはそれよりも遅くなることが多い(特にRaspberry Piのような低性能デバイスでは)。 SDモード:UHS-I対応カードを使用すると、理論上最大 50MB/s の速度が得られる。 したがって、SDカードを使ってSPIモードで接続している場合、速度はSDモードを使用した場合よりも遅くなり、Raspberry PiのSDカードインターフェースが本来持っている高速な読み書き能力をフルに活かすことができません。 Raspberry Pi Zero 2 Wでの実際の接続方法 Raspberry Pi Zero 2 Wでは、SDカードインターフェースはSDモード(通常のSDカードモード)を使って接続されています。これは、高速なデータ転送を実現するためです。 SDカードの転送速度が遅い場合の原因 もし、Raspberry Pi Zero 2 WでSDカードが遅い速度で動作している場合、いくつかの要因が考えられます: 低速なSDカード: 使用しているSDカードがUHS-Iに対応していない、またはClass 10以下である場合、転送速度が遅くなる可能性があります。 高速なSDカード(例えば、SanDisk ExtremeやSamsung EVO Plus)を使用することで、パフォーマンスが改善されることがあります。 不適切なSDカード: 古いカードや安価なカードは、特に書き込み速度が低くなることがよくあります。 SDカードインターフェースの設定: SDモードではなく、SPIモードで通信が行われている場合、速度が大きく制限されます。 正しい設定がされていないと、意図しないインターフェースで動作することがあるため、設定を再確認することが重要です。 まとめ Raspberry Pi Zero 2 Wは、SDカードに対してSDモード(SDカード専用モード)を使用しており、これにより理論的には最大50MB/sの速度が得られます。 SPIモードは、通常、SDカードの転送速度が制限され、最大25MB/s程度の速度にとどまります。 SDカードの速度が遅い場合は、高速なSDカードを使用し、SDモードが正しく設定されていることを確認することが重要です。 もし具体的な速度テストを行いたい場合、上記のコマンドを使用して、実際の転送速度を確認することができます。
Q: SDIOの制御は、LINUXがやっているのか
ご指摘の通り、SDカードモード(SDモード)では、SDIOインターフェースが使われています。すみません、前回の説明で誤解を招いた部分があったかもしれませんので、詳しく説明します。 SDカードモードとSDIOインターフェース SDカードモードは、SDIO(Secure Digital Input Output)インターフェースを使用します。このインターフェースは、SDカードが動作するための標準的なインターフェースです。 SDカード自体は、内部的に SDIOインターフェース を使用してデータ転送を行います。したがって、SDモードは SDIOインターフェースの一部です。 SDIOインターフェースの役割 SDIOインターフェースは、SDカードとの通信を行うための通信規格で、以下の特徴があります: SDカードモードでは、SDカードがSDIOインターフェースを通じてデータの読み書きを行います。 SDIOは、SDカードの他にも、Wi-FiモジュールやBluetoothモジュール、GPSモジュールなど、SDIO対応の周辺機器にも使用されることがあります。 SDIOとSPIの違い SPIモードは、SDカードのデータ転送のための別のインターフェースです。SPI(Serial Peripheral Interface)は、主に低速通信用のインターフェースであり、SDカードの読み書き速度は限られています(最大で約25MB/s程度)。 **SDモード(SDIOインターフェース)**は、SDカード専用の高速インターフェースで、UHS-I対応のカードを使用することで、理論上最大 50MB/s の速度を実現できます。 Raspberry Pi Zero 2 WのSDカードインターフェース Raspberry Pi Zero 2 Wは、SDカードをSDモード(SDIOインターフェース)で接続しています。これにより、SDカードの読み書き速度が最大50MB/s程度まで向上します。 まとめ **SDモード(SDIOインターフェース)**は、SDカードが通信に使用するインターフェースであり、読み書き速度が速いです(UHS-Iなどに対応)。 SPIモードは、低速なインターフェースであり、速度が制限されます(最大約25MB/s)。 Raspberry Pi Zero 2 Wでは、SDカードは**SDモード(SDIOインターフェース)**で接続されており、最大50MB/sの速度が期待できます。 おっしゃる通り、SDカードモードはSDIOインターフェースを使用しており、そのため転送速度が速く、SDカードに最適な通信方法です。
Q: ラズパイは、IOTでは、SOCの制御では遅くて使えないので使ってこなかった
はい、SDIOの制御は、Linuxカーネルが行っています。Raspberry Piを含む多くのLinuxベースのシステムでは、SDIOインターフェースを制御するためのドライバがカーネルに組み込まれており、これによってSDカードとの通信が可能になります。 SDIO制御の仕組み Linuxカーネルの役割: Linuxでは、SDカードやその他のSDIOデバイス(Wi-FiやBluetoothなど)との通信は、カーネルドライバによって管理されています。 SDIOインターフェースを使用するデバイスは、LinuxカーネルのSDHCI(SD Host Controller Interface)ドライバを使用して制御されます。SDHCIは、SDIOバスの通信を管理し、カードとのインタラクションを処理します。 SDHCIドライバ: SDHCIは、SDカードとホスト(Raspberry Piなど)との間でデータを転送するための標準的なインターフェースです。 Raspberry Pi Zero 2 Wや他のRaspberry Piモデルでは、SDカードの読み書きを行う際に、このSDHCIドライバを介してSDIOインターフェースを制御します。 SDIOデバイス(Wi-FiやBluetooth): SDIOはSDカードだけでなく、Wi-FiモジュールやBluetoothモジュール、GPSデバイスなど、さまざまな周辺機器でも使用されます。 これらの周辺機器も、Linuxのカーネルに組み込まれたSDIOドライバによって制御され、通信が行われます。 デバイスツリー(Device Tree): Raspberry PiのようなARMベースのシステムでは、デバイスツリーを使用して、SDカードやSDIOデバイスの設定を行います。デバイスツリーにより、カーネルがハードウェアリソースを認識し、適切なドライバをロードして制御します。 実際の動作 SDカードモード(SDIOインターフェース)を使用する場合、LinuxカーネルのSDHCIドライバがSDカードと通信し、データ転送を制御します。 これにより、SDカードの読み書きや高速転送が可能になります。 Linuxのカーネルは、SDIOインターフェースを介して、SDカードの状態管理やエラー処理なども行います。 まとめ SDIOの制御は、LinuxカーネルのSDHCIドライバによって行われます。 SDカードの読み書きや、その他のSDIOデバイス(Wi-FiやBluetoothなど)の制御は、カーネルが担当しています。 デバイスツリーにより、Raspberry PiなどのシステムでSDIOデバイスが正しく認識され、適切なドライバがロードされます。 Linuxカーネルは、SDIOインターフェースを通じてSDカードや周辺機器との通信を円滑に行えるように、必要なドライバと制御を提供しています。
Q: USB経由SDログという機能が、IOTマイコンが不得意でラズパイが得意という矛盾がある
保存されたメモリを更新しました なるほど、Raspberry Piは確かにIoT用途では、低消費電力や高速なリアルタイム制御が求められる場面では、処理速度やタイミングの精度で劣ることがあります。そのため、より高性能な専用のSoCやマイクロコントローラ(例えば、STM32やESP32など)を選ぶことが多いですよね。 もし、リアルタイム性やレスポンスの速さが重要な要件であれば、Raspberry Piのような汎用コンピュータではなく、リアルタイム処理が可能なプラットフォーム(例えば、RTOSを搭載したマイコンなど)を選ぶ方が無難かもしれません。 そのため、Raspberry Piは使わないという選択は、IoTプロジェクトの要求に応じた賢明な判断だと思います。
Q: 以下の記事をパワポにまとめる
USB経由SDログという機能が、IOTマイコンが不得意でラズパイが得意という矛盾がある
確かにその通りですね! USB経由でのSDカードログというタスクに関しては、一般的なIoTマイコン(例えば、ESP32やSTM32など)は、USBホスト機能や高速データ転送に対応していないため、ラズパイが得意とする領域となります。 ラズパイが得意な理由 Raspberry Piは、フル機能のLinuxを搭載しており、USBホスト機能やSDカードインターフェースを標準でサポートしています。これにより、USB経由でデバイス(例えば、センサーや別のコンピュータ)からデータを受け取り、そのデータをSDカードに高速に書き込むことが可能です。また、Linux環境で動作するため、ファイルシステムの管理やデータ処理も柔軟に行えます。 USBホスト機能:Raspberry PiはUSBホストとして動作でき、外部デバイス(例えば、USBドライブ、USBセンサーなど)を接続して、データ転送が可能です。 SDカードの管理:Raspberry Piは、SDカードへのデータ書き込みやファイルシステムの管理を得意としており、大容量のデータを高速で処理できます。 IoTマイコンが不得意な理由 一方で、IoTマイコンは多くの場合、以下のような制限があります: USBホスト機能の制限: 一部のマイコン(例えば、ESP32やSTM32)にはUSBホスト機能がないか、非常に限定的です。そのため、外部デバイスとのUSB通信を管理することが難しいです。 ストレージ容量やファイルシステムの管理: IoTマイコンは、大容量データの管理や高速なファイルシステムの処理に向いていません。SDカードにデータを保存する場合でも、専用の小規模なファイルシステムを扱うため、PCやRaspberry Piに比べて速度や管理に限界があります。 パフォーマンスとリソース制限: IoTマイコンは、CPU性能やメモリ容量が限られているため、リアルタイム処理や高速なデータ転送、ファイルシステム操作においてRaspberry Piほどのパフォーマンスは期待できません。 矛盾の解消 USB経由でのデータログというタスクは、高速なデータ転送や大容量のストレージ管理を伴うため、Raspberry Piの方が適しています。逆に、IoTマイコンは、データ収集やセンサーデータの処理には強いですが、外部ストレージとのインターフェースや複雑なファイル管理に関しては制限があります。 そのため、データロギングのようなシステムでは、Raspberry Piが適しているという点で、矛盾はないと思います。IoTマイコンは、リアルタイム処理や特定のタスクを効率的にこなすのに優れており、Raspberry Piは、データ管理やストレージといったより高度なタスクに優れているという、得意分野の違いがあるのです。 まとめ Raspberry Piは、USBホスト機能やSDカード管理、ファイルシステム操作が得意であり、USB経由でのデータログに適しています。 IoTマイコンは、リアルタイム処理やセンサー処理には強いですが、USBデバイスの取り扱いやファイルシステム管理には向いていません。 そのため、USB経由でのSDカードロギングという用途には、Raspberry Piが適しています。
Q: USBホスト機能をもてるCPU能力
確かにその通りですね! USB経由でのSDカードログというタスクに関しては、一般的なIoTマイコン(例えば、ESP32やSTM32など)は、USBホスト機能や高速データ転送に対応していないため、ラズパイが得意とする領域となります。 ラズパイが得意な理由 Raspberry Piは、フル機能のLinuxを搭載しており、USBホスト機能やSDカードインターフェースを標準でサポートしています。これにより、USB経由でデバイス(例えば、センサーや別のコンピュータ)からデータを受け取り、そのデータをSDカードに高速に書き込むことが可能です。また、Linux環境で動作するため、ファイルシステムの管理やデータ処理も柔軟に行えます。 USBホスト機能:Raspberry PiはUSBホストとして動作でき、外部デバイス(例えば、USBドライブ、USBセンサーなど)を接続して、データ転送が可能です。 SDカードの管理:Raspberry Piは、SDカードへのデータ書き込みやファイルシステムの管理を得意としており、大容量のデータを高速で処理できます。 IoTマイコンが不得意な理由 一方で、IoTマイコンは多くの場合、以下のような制限があります: USBホスト機能の制限: 一部のマイコン(例えば、ESP32やSTM32)にはUSBホスト機能がないか、非常に限定的です。そのため、外部デバイスとのUSB通信を管理することが難しいです。 ストレージ容量やファイルシステムの管理: IoTマイコンは、大容量データの管理や高速なファイルシステムの処理に向いていません。SDカードにデータを保存する場合でも、専用の小規模なファイルシステムを扱うため、PCやRaspberry Piに比べて速度や管理に限界があります。 パフォーマンスとリソース制限: IoTマイコンは、CPU性能やメモリ容量が限られているため、リアルタイム処理や高速なデータ転送、ファイルシステム操作においてRaspberry Piほどのパフォーマンスは期待できません。 矛盾の解消 USB経由でのデータログというタスクは、高速なデータ転送や大容量のストレージ管理を伴うため、Raspberry Piの方が適しています。逆に、IoTマイコンは、データ収集やセンサーデータの処理には強いですが、外部ストレージとのインターフェースや複雑なファイル管理に関しては制限があります。 そのため、データロギングのようなシステムでは、Raspberry Piが適しているという点で、矛盾はないと思います。IoTマイコンは、リアルタイム処理や特定のタスクを効率的にこなすのに優れており、Raspberry Piは、データ管理やストレージといったより高度なタスクに優れているという、得意分野の違いがあるのです。 まとめ Raspberry Piは、USBホスト機能やSDカード管理、ファイルシステム操作が得意であり、USB経由でのデータログに適しています。 IoTマイコンは、リアルタイム処理やセンサー処理には強いですが、USBデバイスの取り扱いやファイルシステム管理には向いていません。 そのため、USB経由でのSDカードロギングという用途には、Raspberry Piが適しています。
Q: USBホスト可能なマイコン一覧
画像が作成されました この画像を評価 Here is the PowerPoint slide summarizing the information. Let me know if you'd like any adjustments!
Q: Teensy4.1 CPU
USBホスト機能を持たせるには、以下のようなCPUやハードウェア能力が必要になります。これは、マイコンやSoCが「USBホストとして動作可能かどうか」の鍵になります。 ?? USBホストに必要なCPU/SoCの条件 1. USBホストコントローラ内蔵 必須です。多くの低価格マイコン(例:Arduino UNOなど)はUSBデバイス側のみで、ホスト機能を持っていません。 USBホストをサポートするマイコン例: STM32F4/F7/H7シリーズ ESP32-S2 / ESP32-S3(ただし制限あり) NXP i.MXシリーズ Raspberry Pi系(BCM系SoC) 2. 十分なメモリ(RAM) USBスタックは複雑なバッファリングを必要とするため、最低でも数十KBのRAMが望ましい。 バルク転送などの高速通信では、100KB以上のRAMがあると安定。 3. 高速クロック(CPU) USB通信は、1.5Mbps(Low)、12Mbps(Full)、480Mbps(High) など。これに対してリアルタイムに応答する必要あり。 実際には、72MHz以上の動作周波数がUSBホストで安定動作の目安。 4. OSまたはUSBスタックの実装 RTOSやLinux上ではUSBスタックを利用しやすく、マルチタスクで処理も安定。 裸のマイコン(Baremetal)でUSBホストを動かすには、USBスタックの実装が必要で難易度が高い。 5. ソフトウェアリソースとドライバ USBメモリ、マウス、シリアル変換など、**USBクラスドライバ(Mass Storage, CDC, HIDなど)**が用意されているかが重要。 ?? ラズパイ vs マイコン(比較) 項目 Raspberry Pi IoTマイコン(ESP32など) USBホスト機能 標準対応(複数ポート) 一部のみ対応(制限あり) RAM容量 数百MB~ 数百KB~数MB 処理能力(GHz級) 高速マルチコアCPU搭載 数十~数百MHz ファイルシステム管理 Linuxベースで強力 制限あり、簡易FSが多い USBクラス対応 ほぼすべて(OSレベル) 限定的 or 自前実装が必要 必要なら「USBホストが可能なマイコン一覧」などもまとめますが、そのあたりも見てみますか?
Q: ラズパイ CPU ベンチマーク とタブレット ATOM8550のベンチマーク
こちらが、USBホスト機能を持つ代表的なマイコンの一覧です。用途やパフォーマンス別に分類しています。 ? USBホスト対応マイコン一覧(代表的なもの) ?? 1. STM32シリーズ(STMicroelectronics) シリーズ名 USBホスト 特徴 STM32F4 ? Cortex-M4、USB OTG FS/HS対応。開発例も豊富。 STM32F7 ? Cortex-M7、高性能。HS対応あり。 STM32H7 ? Cortex-M7、産業用途向け。複数USBポート可。 STM32L4/L5 一部対応 低消費電力モデル。F4より低性能。 開発環境:STM32CubeIDE + HAL/LL + USB Host stack(MSC, HID, CDC など) ?? 2. ESP32ファミリー(Espressif) モデル USBホスト 備考 ESP32(初代) ? USBデバイスも非対応(USB UART経由) ESP32-S2 ?(制限あり) USBホスト/デバイス兼用。ドライバは限定的。 ESP32-S3 ?(制限あり) S2の改良版。より高速でAI向け命令セット搭載。 ESP32-C3 ? RISC-VベースだがUSBデバイスのみ。 注意:USBホストドライバは未完成な部分も多く、ESP-IDFでの開発が基本。 ?? 3. NXP LPC / i.MX RTシリーズ シリーズ名 USBホスト 特徴 LPC546xx ? Cortex-M4、USB FS/HS対応。 i.MX RT1050/1060 ? 「Crossover MCU」非常に高性能。USB HS対応。 i.MX RT1170 ? デュアルコア(M7+M4)、産業/AI向け。 高速でRAMも大きく、USBカメラやHDDも扱えるレベル。 ?? 4. Microchip PIC32 / SAMシリーズ モデル USBホスト 備考 PIC32MX / PIC32MZ ? USB Host/Device 両対応。豊富な開発資料あり。 SAMD51/SAME70 ? ARM Cortex-M系、Atmel時代の流れを継ぐ。 MPLAB X IDE、Harmony FrameworkでUSB開発可能。 ?? 5. Texas Instruments Tiva-C / Sitara モデル USBホスト 備考 Tiva-C TM4C ? Cortex-M4、USBホストスタックも提供。 Sitara AM335x ? BeagleBone系。Linux対応、ラズパイに近い。 ?? 6. その他・特殊系 モデル名 USBホスト 補足情報 Teensy 3.6 ? USBホストポート付き(5V電源が必要) Teensy 4.1 ?(非公式) ソフトで対応可能、USB Host Shield併用可 Arduino Due ?(要拡張) USB OTGポートはあるが、基本はデバイス側 ?? 注意ポイント USBホストは電源供給(VBUS)制御が必要 → 5V 供給できる回路設計が必要。 多くのマイコンでは、USBクラス(Mass Storage, HID, CDCなど)に合わせたスタックの実装が必要。 必要であれば、具体的な「USBメモリを接続してログを取る」例を使えるマイコンごとに提示することも可能です。 気になるマイコンがあればピンポイントで掘り下げますよ!
Q: ラズパイ4B と ZERO 2W
Teensy 4.1 に搭載されているCPUは、以下のような非常に高性能なマイコン用プロセッサです。 ?? Teensy 4.1 のCPU詳細 ? プロセッサ名: NXP i.MX RT1062(Crossover MCU) ? 主な仕様: 項目 内容 CPUコア ARM Cortex-M7 動作クロック 最大 600MHz(初期設定480MHz) フラッシュ 8MB(外部QSPI NOR Flash) RAM 1MB SRAM(オンチップ)+拡張用PSRAM対応 FPU 単精度 + 倍精度対応 DMA 複数チャネル搭載 USB機能 USB 2.0 OTG(High Speed / ホスト&デバイス両対応) SDカード SDIO対応(microSDソケットは別途) Ethernet 10/100 Mbps 対応(別途PHYが必要) シリアル/UART 7ポート SPI / I2C / CAN 豊富に搭載 ?? 特徴とメリット 超高速:600MHzのM7コアは、マイコンとしては異例のパフォーマンス。 USBホスト機能:USBメモリやシリアルデバイスなどに対応可。 RTOS対応:FreeRTOSなどのリアルタイムOSも動作可能。 ログ・データ処理用途に最適:シリアルデータをUSB経由で受信・SDカードへ記録する用途に非常に強い。 Arduino IDEやPlatformIOでの開発が可能(Teensyduino使用) ?? USBホスト利用の注意点(Teensy 4.1) Teensy 4.1 上では USBホスト用の専用ピン(D+, D-)があり、USB Hostケーブル+外部5V給電が必要。 使用にはUSB Host Shieldや自作回路も選択肢。 ?? 関連ノウハウ提供できます USBメモリへのログ書き込み例(FatFS使用) シリアル → SDカードの高速バイナリログ USB CDCデバイスと通信する例(IMUや他のMCU) Teensy 4.1 はラズパイと比べてRTOSや組み込み制御の強みを活かしながらUSBログもできる数少ない存在です。 気になる構成あれば図解やコードも用意できます!
Q: ベンチマークで 5 4 ZERO2W ATOMZ8550
Raspberry Pi 5とIntel Atom x5-Z8550(例:Lenovo Yoga Bookなどのタブレットに搭載)のCPU性能を比較すると、以下のようになります。 CPU comparison / processor comparison +5 Geekbench +5 Geekbench +5 ?? Geekbench 6 ベンチマーク比較 項目 Raspberry Pi 5 Intel Atom x5-Z8550 シングルコアスコア 約 764~1061点 約 169~208点 マルチコアスコア 約 1,588~1,617点 約 487~595点 ?? 性能差のポイント シングルコア性能:Raspberry Pi 5はAtom x5-Z8550の約4~6倍のスコアを記録しています。 マルチコア性能:Raspberry Pi 5はAtom x5-Z8550の約2.5~3倍のスコアです。 Geekbench +6 Geekbench +6 CPU comparison / processor comparison +6 この差は、Raspberry Pi 5が搭載するBroadcom BCM2712(Cortex-A76ベース、最大2.4GHz)と、Atom x5-Z8550(Cherry Trail世代、最大2.4GHz)のアーキテクチャの違いによるものです。 ?? 結論 Raspberry Pi 5は、Atom x5-Z8550搭載のタブレットと比較して、シングルコアおよびマルチコアの両方で大幅に高い性能を示しています。そのため、USB経由の高速データロギングやマルチスレッド処理を必要とする用途には、Raspberry Pi 5の方が適しています。 CPU comparison / processor comparison +5 Geekbench +5 Geekbench +5 一方、Atom x5-Z8550搭載のタブレットは、基本的な文書作成やウェブ閲覧などの軽量なタスクには十分な性能を持ちますが、高負荷の処理には向いていません。 より詳細な用途や要件に応じて、適切なデバイスの選定をお勧めします。 情報源
Q: pi5 とcorei5 M3230
Raspberry Pi 4B と Raspberry Pi Zero 2 W の性能比較を以下にまとめます。USBログやセンサーデータ処理の観点でも参考になる内容です。 ?? Raspberry Pi 4B vs Zero 2 W 性能比較 項目 Raspberry Pi 4B Raspberry Pi Zero 2 W CPU Broadcom BCM2711 (Cortex-A72 x4) Broadcom BCM2710A1 (Cortex-A53 x4) クロック 最大 1.5GHz 最大 1.0GHz コア数 4コア 4コア RAM 1GB / 2GB / 4GB / 8GB LPDDR4 512MB LPDDR2 USBポート USB 2.0 x2、USB 3.0 x2 microUSB(USB 2.0 OTG)x1 ストレージ microSD(高速)、USB 3.0経由のSSDも可 microSD(やや遅め) GPIOピン 40ピン 40ピン Wi-Fi 802.11ac(Wi-Fi 5) + Bluetooth 5.0 802.11n(Wi-Fi 4)+ Bluetooth 4.2 消費電力 やや高め(5V 3A 推奨) 低消費電力(5V 1A程度) ?? USBデータロギング用途の視点 観点 Raspberry Pi 4B Raspberry Pi Zero 2 W USBスループット USB 3.0が使えるため 高速 USB 2.0(microUSB経由)やや遅め SD書き込み速度 高速SDカード対応。安定して数MB/s以上 SDIO接続でも性能は控えめ 複数デバイス対応 複数USBポートで並列受信が容易 OTG 1ポートのみ。ハブ使用前提 ログ用途の安定性 長時間安定運用に適している 軽量用途、1本ずつのログに限定か ?? 結論とおすすめ Raspberry Pi 4B → 25Hz RTKログ+IMU 100Hz+アンプ系など220kbps以上の合計データレートにも十分対応可能。USB 3.0経由でSSDなども活用可。 Raspberry Pi Zero 2 W → 軽量&省電力。単一センサーや低データレートの簡易ログ用途向け。ただし220kbps級の連続書き込みには限界がある可能性あり。 もし使い分けで迷っているなら、Zero 2 Wを実験用、4Bを本番ロガーという構成もアリです。 もっと具体的な用途(構成やスレッド数)に合わせて相談にも乗れますよ!
Q: raspi5とPCどちら
以下は、Raspberry Pi 5、Raspberry Pi 4B、Raspberry Pi Zero 2 W、および Intel Atom x5-Z8550 の Geekbench ベンチマークスコアの比較です。 ?? Geekbench 6 ベンチマーク比較 デバイス シングルコアスコア マルチコアスコア Raspberry Pi 5 約 1,061 約 1,617 Raspberry Pi 4B 約 364 約 738 Raspberry Pi Zero 2 W 約 41 約 49 Intel Atom x5-Z8550 約 169 約 487 ?? 性能比較のポイント Raspberry Pi 5: 最新のCortex-A76アーキテクチャを採用し、シングルコアおよびマルチコアの両方で高い性能を示します。 Raspberry Pi 4B: 前世代のモデルで、Cortex-A72アーキテクチャを採用していますが、Pi 5と比較すると性能は劣ります。 Raspberry Pi Zero 2 W: 低消費電力のCortex-A53アーキテクチャを採用しており、性能は控えめです。 Intel Atom x5-Z8550: モバイル向けのプロセッサで、Raspberry Pi 4Bと比較してシングルコア性能は劣りますが、マルチコア性能ではやや上回ります。 ?? 結論 高性能を求める場合: Raspberry Pi 5が最適です。 コストパフォーマンスを重視する場合: Raspberry Pi 4Bが適しています。 低消費電力や小型デバイスが必要な場合: Raspberry Pi Zero 2 Wが適していますが、性能は控えめです。 既存のIntel Atom x5-Z8550搭載デバイスを活用する場合: 特定の用途には適していますが、最新のRaspberry Piと比較すると性能は劣ります。 具体的な用途や要件に応じて、最適なデバイスを選択することをお勧めします。 情報源
Q: python バイナリログプログラムを関数にまとめる
Raspberry Pi 5とIntel Core i5-3230Mの性能をGeekbench 6のスコアで比較すると、以下のようになります。 ?? Geekbench 6 ベンチマーク比較 デバイス シングルコアスコア マルチコアスコア Raspberry Pi 5 約 1,061 約 1,617 Intel Core i5-3230M 約 506 約 1,019 ※ Raspberry Pi 5のスコアは、Geekbench 6での平均値に基づいています 。 ?? 性能差のポイント シングルコア性能: Raspberry Pi 5は、Intel Core i5-3230Mの約2倍のスコアを記録しています。 マルチコア性能: Raspberry Pi 5は、Intel Core i5-3230Mの約1.6倍のスコアです。 この差は、Raspberry Pi 5が搭載するBroadcom BCM2712(Cortex-A76ベース、最大2.4GHz)と、Intel Core i5-3230M(Ivy Bridge世代、最大3.2GHz)のアーキテクチャの違いによるものです。 ?? 結論 Raspberry Pi 5は、Intel Core i5-3230Mと比較して、シングルコアおよびマルチコアの両方で高い性能を示しています。そのため、USB経由の高速データロギングやマルチスレッド処理を必要とする用途には、Raspberry Pi 5の方が適しています。 一方、Intel Core i5-3230Mは、一般的なオフィス作業やウェブ閲覧などの軽量なタスクには十分な性能を持ちますが、高負荷の処理には向いていません。 具体的な用途や要件に応じて、適切なデバイスの選定をお勧めします。 情報源
Q: import time はpip で
用途によりますが、Raspberry Pi 5 と 一般的なPC(例えばCore i5搭載ノートなど) を比べたときの「どちらが良いか」の判断ポイントを、以下にまとめます: ?? ざっくり比較表 項目 Raspberry Pi 5 一般的なPC(Core i5など) ?? OS Linux(Raspberry Pi OS) Windows / Linux ? 消費電力 非常に低い(10W以下) 中?高(30W?60W以上) ?? サイズ 手のひらサイズ ノートPC?タワー ?? ストレージ microSD or USB SSD HDD / SSD(速い) ?? 拡張性 GPIO・USB多数、SPI/I2Cあり 基本はUSBのみ ?? リアルタイム用途 やや強い 標準OSでは弱い(カスタム必要) ?? 価格 数千円? 数万円?数十万円 ?? 性能 ミドルクラス Core i5以上なら通常は上 ?? ソフト互換 一部制限あり(ARM) 圧倒的に高い(x86) ?? USBデータロギング ◎(Pi5は特に高速) ◎(ドライバ依存あり) ?? 結論:どちらを選ぶべき? ?? Raspberry Pi 5 が適している場合 小型・組み込み機器として動かしたい Linuxベースの制御やGPIOが必要 データロガーやIoT的な使い方 常時稼働させたい(消費電力重視) 自作ハードとの接続がある(SPI/I2C等) ?? PC(Core i5など)が適している場合 Windows前提のツールやGUIを使いたい 開発環境をフルで使いたい(VS, MATLAB等) 処理が非常に重い(画像処理・AIなど) 多くのUSBデバイスと同時接続したい x86バイナリやC#などの実行互換性が必要 ?? USB経由のSDログを考慮した場合 Raspberry Pi 5 はUSB 3.0と強化されたSoCで、USB→SDログには十分な帯域と安定性があります。 PCは当然さらに速いですが、組み込み性やコスト面では不利。 ? まとめ データログ専用機器:Pi 5で十分&省電力 汎用性・拡張性が必要:PCが強い どっちか迷ってるなら、 「まずPi 5で構築 → 足りなければPCへ移行」 というステップが無駄がなくておすすめです。 必要なら、どちらかでの構成例も出せますよ!どっちで設計進めようとしてますか?
Q: ログの停止をq キーにする
もちろん!以下に、PythonでバイナリデータをUSB経由で受信し、SDカード(または任意のパス)にログとして保存する処理を関数化したサンプルを示します。 ?? 関数化されたPythonログプログラム(Windows・Raspberry Pi両対応) python コピーする 編集する import serial import threading import time import os from datetime import datetime def get_timestamped_filename(directory: str, prefix: str = "log", ext: str = "bin") -> str: timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") filename = f"{prefix}_{timestamp}.{ext}" return os.path.join(directory, filename) def start_binary_logging(port: str, baudrate: int = 115200, log_dir: str = "C:/Upload", stop_event: threading.Event = None): os.makedirs(log_dir, exist_ok=True) filepath = get_timestamped_filename(log_dir) print(f"[INFO] Logging to: {filepath}") def reader_thread(): try: with serial.Serial(port, baudrate, timeout=0) as ser, open(filepath, "wb") as f: while not (stop_event and stop_event.is_set()): data = ser.read(1024) # read up to 1024 bytes if data: f.write(data) except serial.SerialException as e: print(f"[ERROR] Serial error: {e}") except Exception as e: print(f"[ERROR] {e}") thread = threading.Thread(target=reader_thread, daemon=True) thread.start() return thread, filepath ? 使い方例(mainから呼ぶ) python コピーする 編集する if __name__ == "__main__": import signal # シリアルポートとボーレート PORT = "COM3" # ラズパイなら "/dev/ttyUSB0" BAUDRATE = 230400 LOG_DIR = "C:/Upload" # Raspberry Piなら "/home/pi/logs"など stop_flag = threading.Event() def handle_sigint(signum, frame): print("[INFO] Ctrl+C detected, stopping logging...") stop_flag.set() signal.signal(signal.SIGINT, handle_sigint) thread, filename = start_binary_logging(PORT, BAUDRATE, LOG_DIR, stop_event=stop_flag) print("[INFO] Logging started. Press Ctrl+C to stop.") thread.join() print(f"[INFO] Logging stopped. Saved to {filename}") ? 特徴 get_timestamped_filename() で自動的に時刻付きファイル名を生成 start_binary_logging() はスレッドでバイナリログを取り続ける stop_event を使って安全に停止 ラズパイ/Windows どちらでも使用可能(ポート指定だけ注意) 必要に応じて、複数ポート対応版や、ログ中にファイルを分割する機能も追加可能です。 要望があれば、拡張していきましょうか?
Q: エラーで起動しない
import time は Python標準ライブラリの一部なので、pipでインストールする必要はありません! ? 解説 time モジュールは、Python に 最初から組み込まれている標準モジュールです。 したがって、以下のように使うだけでOKです: python コピーする 編集する import time now = time.time() print(f"現在のUNIX時刻: {now}") ? pipでインストールしない もし間違ってこんなふうにやってしまうと: bash コピーする 編集する pip install time ERROR: No matching distribution found for time のようなエラーになります(存在しないため)。 他にも os, threading, datetime などもすべて標準ライブラリです。 他に気になるモジュールがあれば、標準かどうかも含めて確認できますよ!
Q: PS C:\Users\dj171\PycharmProjects> c:; cd ‘c:\Users\dj171\PycharmProjects’; & ‘c:\Users\dj171\AppData\Local\Programs\Python\Python311\python.exe’ ‘c:\Users\dj171\.vscode\extensions\ms-python.debugpy-2025.6.0-win32-x64\bundled\libs\debugpy\launcher’ ‘65020’ ‘–‘ ‘c:\Users\dj171\PycharmProjects\STA25_binLog_rev01.py’
PS C:\Users\dj171\PycharmProjects> c:; cd ‘c:\Users\dj171\PycharmProjects’; & ‘c:\Users\dj171\AppData\Local\Programs\Python\Python311\python.exe’ ‘c:\Users\dj171\.vscode\extensions\ms-python.debugpy-2025.6.0-win32-x64\bundled\libs\debugpy\launcher’ ‘65033’ ‘–‘ ‘c:\Users\dj171\PycharmProjects\STA25_binLog_rev01.py’
\x5clibs\x5cdebugpy\x5clauncher’ ‘65033’ ‘–‘ ‘c:\x5cUsers\x5cdj171\x5cPycharmProjects\x5cSTA25_binLog_rev01.py’ ;99a4965d-be9e-41f1-af8a-124bdc160018PS C:\Users\dj171\PycharmProjects>
了解です! Ctrl+C ではなく 「qキーでログ停止」 にしたい場合、別スレッドでキーボード入力を監視する方法が使えます。 ?? qキーでログ停止できるように改良したコード(Windows・ラズパイ両対応) python コピーする 編集する import serial import threading import time import os from datetime import datetime def get_timestamped_filename(directory: str, prefix: str = "log", ext: str = "bin") -> str: timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") filename = f"{prefix}_{timestamp}.{ext}" return os.path.join(directory, filename) def start_binary_logging(port: str, baudrate: int = 115200, log_dir: str = "C:/Upload", stop_event: threading.Event = None): os.makedirs(log_dir, exist_ok=True) filepath = get_timestamped_filename(log_dir) print(f"[INFO] Logging to: {filepath}") def reader_thread(): try: with serial.Serial(port, baudrate, timeout=0) as ser, open(filepath, "wb") as f: while not stop_event.is_set(): data = ser.read(1024) if data: f.write(data) except serial.SerialException as e: print(f"[ERROR] Serial error: {e}") except Exception as e: print(f"[ERROR] {e}") thread = threading.Thread(target=reader_thread, daemon=True) thread.start() return thread, filepath def wait_for_q_key(stop_event: threading.Event): print("[INFO] Press 'q' then Enter to stop logging.") while not stop_event.is_set(): key = input() if key.lower() == 'q': stop_event.set() break ? main関数での呼び出し例 python コピーする 編集する if __name__ == "__main__": # 設定 PORT = "COM3" # ラズパイなら "/dev/ttyUSB0" BAUDRATE = 230400 LOG_DIR = "C:/Upload" # ラズパイなら "/home/pi/logs" stop_flag = threading.Event() # ログ開始 log_thread, filename = start_binary_logging(PORT, BAUDRATE, LOG_DIR, stop_event=stop_flag) # qキー待ち wait_for_q_key(stop_flag) # ログ終了 log_thread.join() print(f"[INFO] Logging stopped. File saved to: {filename}") ? 補足ポイント input() は標準入力をブロックするので、qを入力してエンターで止めます。 threading.Event() によって安全にスレッド停止可能。 Windows / Linux 両対応(Linuxでもターミナルからq + Enterで停止可能) 必要なら キーボード押下だけ(Enter不要) にもできます(getch や keyboard ライブラリ使用)。 希望があればそのバージョンも出しますよ!
Q: qキーのスレッドではない方法にしたい
了解!エラーの内容を確認して対処したいので、まず: ? 確認させてください: どの部分でエラーが出たか? エラーの全文(トレースバック)を貼ってもらえたら助かります。 Pythonのバージョンは? python --version で確認できます。 使用している環境は? Windows? Raspberry Pi?(Zero 2W など) ? よくある原因トップ3 1. serial.Serial がエラーになる場合 pyserial が正しくインストールされてないか、serial.py という自作ファイルと名前がかぶっている。 対処: bash コピーする 編集する pip uninstall serial pip install pyserial そして、フォルダ内に serial.py というファイルがあると壊れるので、削除 or 名前変更。 2. input() が動かない or EOFError input() はGUIアプリや一部の非標準端末では使えないことがあります。 その場合、別のキー入力検出方法に変更できます(たとえば keyboard モジュール使用)。 3. ログ保存先のフォルダがない C:/Upload フォルダが存在しない場合に書き込みエラーになる。 対処:os.makedirs(log_dir, exist_ok=True) が入ってるか確認。 ?? 応急処置:簡略版(エラーチェック付き) python コピーする 編集する import serial import threading import os from datetime import datetime def log_usb_binary(port="COM3", baudrate=230400, log_dir="C:/Upload"): try: os.makedirs(log_dir, exist_ok=True) filename = f"log_{datetime.now().strftime('%Y%m%d_%H%M%S')}.bin" path = os.path.join(log_dir, filename) stop_event = threading.Event() def read_thread(): with serial.Serial(port, baudrate, timeout=0) as ser, open(path, "wb") as f: print("[INFO] Logging started. Press 'q' + Enter to stop.") while not stop_event.is_set(): data = ser.read(1024) if data: f.write(data) t = threading.Thread(target=read_thread, daemon=True) t.start() while input().strip().lower() != "q": pass stop_event.set() t.join() print(f"[INFO] Logging complete: {path}") except Exception as e: print(f"[ERROR] {e}") if __name__ == "__main__": log_usb_binary() エラーの詳細を教えてもらえれば、ピンポイントで修正できます! 「起動しない」だけだと推測になるので、よければエラーメッセージ貼ってください ??
Q: 受信 ログはスレッドで、 qキーはループ内で
ありがとうございます! ログからすると Pythonがクラッシュしたり、正常に実行されなかった可能性がありますが、明確なエラーメッセージが表示されていません。 ? 対処ステップ 以下の確認と変更をお願いします: ① 実行エラーが表示されない対策 まず、スクリプトの一番下をこう変更してください?? python コピーする 編集する if __name__ == "__main__": try: log_usb_binary() except Exception as e: print(f"[ERROR] 実行時エラー: {e}") input("Enterキーで終了") これでエラーがあればちゃんと画面に表示されます。 ② VSCode/PyCharm での実行で動かない場合の対策 input() がうまく動かないケースがあるため、コマンドプロンプトやPowerShellから直接実行してみてください: bash コピーする 編集する python STA25_binLog_rev01.py ③ シリアルポートが正しいか確認 以下のように、実行前にデバイスマネージャーで COM ポート番号を確認してください: python コピーする 編集する PORT = "COM3" # ← ここを正しい番号に ④ シンプルな動作確認コード まず動作確認用に、簡単なコードを試してみましょう: python コピーする 編集する import serial PORT = "COM3" # ← 正しいポートに BAUDRATE = 230400 try: with serial.Serial(PORT, BAUDRATE, timeout=1) as ser: print("[INFO] 開始。受信待ち...") for _ in range(10): data = ser.read(32) print(data) except Exception as e: print(f"[ERROR] {e}") これが動けば、環境の問題は少ないです。 ?? あと少しで動きそうです! エラーメッセージの詳細や .py ファイルの中身(数行)を見せていただけたら、もっと正確に修正します! よかったら STA25_binLog_rev01.py の内容を少し貼ってください。 了解です! ログ中であることがわかるように、**「ロギング中です。'q' を押すと停止します」**というメッセージを表示し続けるようにしてみましょう。 以下は、Pythonスクリプトに「ログ中」の表示を追加したサンプルです(Windows用・msvcrt使用): ? USBバイナリログ + qで停止 + ログ中表示付き(Windows) python コピーする 編集する import serial import os import time import msvcrt from datetime import datetime PORT = "COM3" # 実際のシリアルポートに合わせて BAUDRATE = 230400 LOG_DIR = "C:/Upload" def binary_log(): os.makedirs(LOG_DIR, exist_ok=True) filename = f"log_{datetime.now().strftime('%Y%m%d_%H%M%S')}.bin" path = os.path.join(LOG_DIR, filename) try: with serial.Serial(PORT, BAUDRATE, timeout=0) as ser, open(path, "wb") as f: print("[INFO] ログ開始:'q' キーで停止します") counter = 0 while True: if msvcrt.kbhit(): key = msvcrt.getch().lower() if key == b'q': print("[INFO] ログを停止しました") break data = ser.read(1024) if data: f.write(data) # 1秒ごとにロギング中メッセージ表示 if counter % 10 == 0: print(f"[LOGGING] ロギング中... {datetime.now().strftime('%H:%M:%S')}") counter += 1 time.sleep(0.1) except Exception as e: print(f"[ERROR] {e}") if __name__ == "__main__": binary_log() ??ポイント msvcrt.kbhit() と msvcrt.getch() で「qキー」が押されたら終了。 1秒ごと(0.1秒×10)に [LOGGING] と時刻を表示。 ログファイルは "C:/Upload/log_yyyymmdd_hhmmss.bin" に保存。 ? Linux (Raspberry Pi) 用にしたいときはまた言ってください! このコードは Windows 専用ですが、Raspberry Pi 用にも tty + select を使って同じようなことが可能です。 気軽に声かけてください!
Q: main関数とログ関数わける
了解です! スレッドを使わずに、メインループ内でキー入力 (q) を検出して終了する方法で、できるだけシンプルな形に仕上げます。 ? スレッドなし版:qキーで停止(Windows用) python コピーする 編集する import serial import os import time import msvcrt from datetime import datetime PORT = "COM3" # 実際のポートに変更 BAUDRATE = 230400 LOG_DIR = "C:/Upload" def binary_log(): os.makedirs(LOG_DIR, exist_ok=True) filename = f"log_{datetime.now().strftime('%Y%m%d_%H%M%S')}.bin" path = os.path.join(LOG_DIR, filename) try: with serial.Serial(PORT, BAUDRATE, timeout=0) as ser, open(path, "wb") as f: print("[INFO] ログ開始:'q' キーで停止できます") last_print_time = time.time() while True: if msvcrt.kbhit(): key = msvcrt.getch().lower() if key == b'q': print("[INFO] 'q' が押されました。ログ停止。") break data = ser.read(1024) if data: f.write(data) now = time.time() if now - last_print_time >= 1.0: print(f"[LOGGING] {datetime.now().strftime('%H:%M:%S')} ログ中...") last_print_time = now time.sleep(0.01) except Exception as e: print(f"[ERROR] {e}") if __name__ == "__main__": binary_log() ? 特徴 スレッドなし msvcrt.kbhit() / getch() で q の入力をチェック 1秒ごとにログ中表示 serial.read(1024) で高速にバイナリログ C:/Upload にファイル名をタイムスタンプ付きで保存 必要であれば: Linux/Raspberry Pi 用に書き換え 複数ポート対応 ターミナル出力OFF などもできます!何でもどうぞ。
Q: ログ完了したら、ログ経過時間とログファイル名とサイズを表示
完璧な組み合わせですね! データ受信&ログはスレッドで動かし、qキーでメインループ内から停止制御する方式にしましょう。これなら安定して高速なログを取りつつ、シンプルに終了制御ができます。 ? 受信はスレッド / qキーはメインループで監視(Windows用) python コピーする 編集する import serial import os import time import msvcrt import threading from datetime import datetime PORT = "COM3" # 実際のポートに変更 BAUDRATE = 230400 LOG_DIR = "C:/Upload" stop_flag = False # グローバルフラグ def receiver_thread(log_path): global stop_flag try: with serial.Serial(PORT, BAUDRATE, timeout=0) as ser, open(log_path, "wb") as f: print("[RECEIVER] スレッド開始") while not stop_flag: data = ser.read(1024) if data: f.write(data) time.sleep(0.001) except Exception as e: print(f"[ERROR in receiver thread] {e}") def binary_log(): global stop_flag os.makedirs(LOG_DIR, exist_ok=True) filename = f"log_{datetime.now().strftime('%Y%m%d_%H%M%S')}.bin" log_path = os.path.join(LOG_DIR, filename) # ログ受信スレッド起動 thread = threading.Thread(target=receiver_thread, args=(log_path,)) thread.start() print("[MAIN] ログ中:'q' を押すと終了します") last_print = time.time() while not stop_flag: if msvcrt.kbhit(): key = msvcrt.getch().lower() if key == b'q': print("[MAIN] 'q' が押されました。停止します。") stop_flag = True break if time.time() - last_print >= 1.0: print(f"[MAIN] ログ中... {datetime.now().strftime('%H:%M:%S')}") last_print = time.time() time.sleep(0.05) thread.join() print("[MAIN] ログ完了") if __name__ == "__main__": binary_log() ? 構成ポイント 機能 実装 データ受信 & ログ スレッドでシリアル受信して wb 書き込み 停止方法 メインループで qキー検出、stop_flagを Trueに ログ状況表示 1秒ごとにログ中表示 ファイル保存 C:/Upload/log_YYYYMMDD_HHMMSS.bin に保存 これで「高速受信・安定・即時終了」の3拍子そろったログ環境になります! ?? 複数ポート対応 や Raspberry Pi移植用 にも対応できますので、必要なら言ってください!
Q: COM21 921600 UPload と変更
了解です! main() 関数と binary_log()(ログ処理)をしっかり分けた構成にしますね。こうすると他のプログラムからログ機能を呼び出すこともでき、保守性も良くなります。 ? main()とbinary_log()を分離した構成(スレッド+qキー終了) python コピーする 編集する import serial import os import time import msvcrt import threading from datetime import datetime # 設定 PORT = "COM3" # 必要に応じて変更 BAUDRATE = 230400 LOG_DIR = "C:/Upload" stop_flag = False # スレッドとmainで共有する終了フラグ def receiver_thread(log_path): """データ受信とログ書き込みを行うスレッド""" global stop_flag try: with serial.Serial(PORT, BAUDRATE, timeout=0) as ser, open(log_path, "wb") as f: print("[RECEIVER] スレッド開始") while not stop_flag: data = ser.read(1024) if data: f.write(data) time.sleep(0.001) except Exception as e: print(f"[ERROR in receiver thread] {e}") def binary_log(): """ログ処理の本体:スレッド起動と監視""" global stop_flag os.makedirs(LOG_DIR, exist_ok=True) filename = f"log_{datetime.now().strftime('%Y%m%d_%H%M%S')}.bin" log_path = os.path.join(LOG_DIR, filename) # スレッド起動 thread = threading.Thread(target=receiver_thread, args=(log_path,)) thread.start() print("[MAIN] ログ中:'q' を押すと停止します") last_print = time.time() while not stop_flag: if msvcrt.kbhit(): key = msvcrt.getch().lower() if key == b'q': print("[MAIN] 'q' が押されました。停止します。") stop_flag = True break if time.time() - last_print >= 1.0: print(f"[MAIN] ログ中... {datetime.now().strftime('%H:%M:%S')}") last_print = time.time() time.sleep(0.05) thread.join() print("[MAIN] ログ完了") def main(): """メインエントリーポイント""" binary_log() if __name__ == "__main__": main() ? ポイントまとめ main() は単に binary_log() を呼び出すだけ → 構造が明確で拡張しやすい。 binary_log() がログの中核処理。 receiver_thread() はログ専用スレッドとして完全に分離。 ??追加アレンジも可能: PORT や BAUDRATE を main() から引数で渡すようにもできます。 Raspberry Pi 対応(Linux)版の getch 方法への変更も対応できます。 要望あればなんでもどうぞ!
Q: Python threadの原理わからない
いいですね、それ入れましょう! ログ終了時に以下を表示します: 経過時間(秒) ファイル名 ファイルサイズ(KB) ? 修正後のコード python コピーする 編集する import serial import os import time import msvcrt import threading from datetime import datetime # 設定 PORT = "COM3" # 適宜変更 BAUDRATE = 230400 LOG_DIR = "C:/Upload" stop_flag = False # スレッドとmainで共有する終了フラグ def receiver_thread(log_path, start_time): """データ受信とログ書き込みを行うスレッド""" global stop_flag try: with serial.Serial(PORT, BAUDRATE, timeout=0) as ser, open(log_path, "wb") as f: print("[RECEIVER] スレッド開始") while not stop_flag: data = ser.read(1024) if data: f.write(data) time.sleep(0.001) except Exception as e: print(f"[ERROR in receiver thread] {e}") def binary_log(): """ログ処理の本体:スレッド起動と監視""" global stop_flag os.makedirs(LOG_DIR, exist_ok=True) filename = f"log_{datetime.now().strftime('%Y%m%d_%H%M%S')}.bin" log_path = os.path.join(LOG_DIR, filename) # 開始時間記録 start_time = time.time() # スレッド起動 thread = threading.Thread(target=receiver_thread, args=(log_path, start_time)) thread.start() print("[MAIN] ログ中:'q' を押すと停止します") last_print = time.time() while not stop_flag: if msvcrt.kbhit(): key = msvcrt.getch().lower() if key == b'q': print("[MAIN] 'q' が押されました。停止します。") stop_flag = True break if time.time() - last_print >= 1.0: print(f"[MAIN] ログ中... {datetime.now().strftime('%H:%M:%S')}") last_print = time.time() time.sleep(0.05) thread.join() # 結果の表示 elapsed = time.time() - start_time size_kb = os.path.getsize(log_path) / 1024 print(f"[完了] ファイル名: {filename}") print(f"[完了] 経過時間: {elapsed:.2f} 秒") print(f"[完了] ファイルサイズ: {size_kb:.1f} KB") def main(): """メインエントリーポイント""" binary_log() if __name__ == "__main__": main() ??もしMB単位で表示したい場合は、KB を MB に変えて / (1024 * 1024) にするだけです。 他にも「ログ中のスループット」や「リアルタイムサイズ表示」などの追加も可能です!やってみたいことあれば教えてください。
Q: t = threading.Thread(target=my_task) 意味
了解です!以下のように修正すればOKです: ? 修正ポイント: PORT = "COM21" BAUDRATE = 921600 LOG_DIR = "C:/UPload" ?? 修正済みコード: python コピーする 編集する import serial import os import time import msvcrt import threading from datetime import datetime # 設定(変更済) PORT = "COM21" BAUDRATE = 921600 LOG_DIR = "C:/UPload" stop_flag = False # スレッドとmainで共有する終了フラグ def receiver_thread(log_path, start_time): """データ受信とログ書き込みを行うスレッド""" global stop_flag try: with serial.Serial(PORT, BAUDRATE, timeout=0) as ser, open(log_path, "wb") as f: print("[RECEIVER] スレッド開始") while not stop_flag: data = ser.read(1024) if data: f.write(data) time.sleep(0.001) except Exception as e: print(f"[ERROR in receiver thread] {e}") def binary_log(): """ログ処理の本体:スレッド起動と監視""" global stop_flag os.makedirs(LOG_DIR, exist_ok=True) filename = f"log_{datetime.now().strftime('%Y%m%d_%H%M%S')}.bin" log_path = os.path.join(LOG_DIR, filename) # 開始時間記録 start_time = time.time() # スレッド起動 thread = threading.Thread(target=receiver_thread, args=(log_path, start_time)) thread.start() print("[MAIN] ログ中:'q' を押すと停止します") last_print = time.time() while not stop_flag: if msvcrt.kbhit(): key = msvcrt.getch().lower() if key == b'q': print("[MAIN] 'q' が押されました。停止します。") stop_flag = True break if time.time() - last_print >= 1.0: print(f"[MAIN] ログ中... {datetime.now().strftime('%H:%M:%S')}") last_print = time.time() time.sleep(0.05) thread.join() # 結果の表示 elapsed = time.time() - start_time size_kb = os.path.getsize(log_path) / 1024 print(f"[完了] ファイル名: {filename}") print(f"[完了] 経過時間: {elapsed:.2f} 秒") print(f"[完了] ファイルサイズ: {size_kb:.1f} KB") def main(): """メインエントリーポイント""" binary_log() if __name__ == "__main__": main() 必要なら、リアルタイム転送速度の表示やログファイルの分割保存にも対応できますよ!どうしましょうか?
Q: C#のスレッドよりシンプル
OK、ではPythonのthreadingの原理をわかりやすく説明しますね。マイコンの割り込みやタスクと比較すると理解しやすいかもです。 ?? Pythonのスレッド(threading.Thread)の原理 ?? 1. スレッドとは Pythonのスレッドは、「同時に別の処理を進める小さな作業の単位」です。 普通のPythonプログラムは1行ずつ順番に実行されます。 スレッドを使うと「複数の作業を同時進行してるように見せる」ことができます。 ??イメージ: 「メインはキーボードを見ていて、別の人が裏でデータを受信してメモ帳に書いてる」感じ。 ?? 2. Pythonでのスレッド作成方法 python コピーする 編集する import threading def my_task(): while True: print("作業中…") time.sleep(1) # スレッドを作って起動 t = threading.Thread(target=my_task) t.start() これで my_task が裏側で実行されます。 メインの処理は止まらず、別のことをできます。 ?? 3. threading.Thread の特徴(CPythonの場合) PythonスレッドはOSのスレッドを使っています(≒本物の並列処理)。 ただし、Pythonは**GIL(グローバルインタプリタロック)**という仕組みで「本当に同時」にはならず、ちょっとずつ切り替えて動いてる(コンテキストスイッチ)。 そのため、IO待ち(USBやネットワーク、ファイル書き込みなど)には非常に効果的。 ?? だから「USBデータ受信+キー入力チェック」みたいな処理に最適! ?? 4. スレッドの終了方法 スレッド側で stop_flag のようなフラグ変数を定期的にチェックして止めるのが一般的。 python コピーする 編集する running = True def worker(): while running: do_something() # スレッド終了させたいとき running = False ?? まとめ 項目 内容 同時実行の仕組み 1つのCPUを高速に切り替えて同時に動いてるように見せてる 適してる用途 USB受信・ファイル保存・通信などのIO系 本当に並列になるか GILのためCPUは実質1つずつ(IOなら問題なし) よくある使い方 threading.Thread(target=関数名) 必要なら図やアニメーション風に説明もできるよ! 「スレッド vs プロセスの違い」とかも知りたければそっちも解説します!
Q: C#の関数をPython変換
static string PVTcnv(byte[] d, ref pvt p)
{
string pvts = “”;
//PVT header[0-6]
//0:itow[6-9]
p.itow = (uint)Toint32(d[9], d[8], d[7], d[6]);
pvts = p.itow.ToString();
//Serial.printf(“PVTcnv:itow=%d\n\r”,pvt[0]);
//1:year[10-12]
p.year = (ushort)(d[10] + d[11] * 256);
pvts = pvts + “,” + p.year.ToString();
//2:month[12]
p.month = d[12];
pvts = pvts + “,” + p.month.ToString();
//3:day[13]
p.day = d[13];
pvts = pvts + “,” + p.day.ToString();
//4:hour[14]
p.hour = d[14];
pvts = pvts + “,” + p.hour.ToString();
//Serial.printf(“PVTcnv:hour=%d\n\r”,pvt[4]);
//5:min[15]
p.min = d[15];
pvts = pvts + “,” + p.min.ToString();
//Serial.printf(“PVTcnv:min=%d\n\r”,pvt[5]);
//6:sec[16]
p.sec = d[16];
pvts = pvts + “,” + p.sec.ToString();
//Serial.printf(“PVTcnv:sec=%d\n\r”,pvt[6]);
//7:valid[17]
p.valid = d[17];
pvts = pvts + “,” + p.valid.ToString();
//8:tAcc[18-21]
p.tacc = (uint)Toint32(d[21], d[20], d[19], d[18]);
pvts = pvts + “,” + p.tacc.ToString();
//9:nano[22-25]
p.nano = Toint32(d[25], d[24], d[23], d[22]);
pvts = pvts + “,” + p.nano.ToString();
//9:nano[22-25]
//10:fixType[26]
p.fixtype = d[26];
pvts = pvts + “,” + p.fixtype.ToString();
//11:flags[27] This is Fix status 131
p.flags = d[27];
pvts = pvts + “,” + p.flags.ToString();
//12:flags2[28]
p.flags2 = d[28];
pvts = pvts + “,” + p.flags2.ToString();
//13:numSV[29]
p.numsv = d[29];
pvts = pvts + “,” + p.numsv.ToString();
//14:lon[30-33]
p.lon = Toint32(d[33], d[32], d[31], d[30]);
pvts = pvts + “,” + p.lon.ToString();
//15:lat[34-37]
p.lat = Toint32(d[37], d[36], d[35], d[34]);
pvts = pvts + “,” + p.lat.ToString();
//16:height[38-41]
p.height = Toint32(d[41], d[40], d[39], d[38]);
pvts = pvts + “,” + p.height.ToString();
//17:hMSL[42-45]
p.hmsl = Toint32(d[45], d[44], d[43], d[42]);
pvts = pvts + “,” + p.hmsl.ToString();
//18:hAcc[46-49]
p.hacc = (uint)Toint32(d[49], d[48], d[47], d[46]);
if (p.hacc > 1000)
{
p.hacc = 0;
}
pvts = pvts + “,” + p.hacc.ToString();
//19:vAcc[50-53]
p.vacc = (uint)Toint32(d[53], d[52], d[51], d[50]);
pvts = pvts + “,” + p.vacc.ToString();
//20:velN[54-57]
p.veln = Toint32(d[57], d[56], d[55], d[54]);
pvts = pvts + “,” + p.veln.ToString();
//21:velE[58-61]
p.vele = Toint32(d[61], d[60], d[59], d[58]);
pvts = pvts + “,” + p.vele.ToString();
//22:velD[62-65]
p.veld = Toint32(d[65], d[64], d[63], d[62]);
pvts = pvts + “,” + p.veld.ToString();
//23:gSpeed[66-69]
p.gspeed = Toint32(d[69], d[68], d[67], d[66]);
pvts = pvts + “,” + p.gspeed.ToString();
//24:headMot[70-73]
p.headmot = Toint32(d[73], d[72], d[71], d[70]);
pvts = pvts + “,” + p.headmot.ToString();
//25:sAcc[74-77]
p.sacc = (uint)Toint32(d[77], d[76], d[75], d[74]);
pvts = pvts + “,” + p.sacc.ToString();
//26:headAcc[78-81]
p.headacc = (uint)Toint32(d[81], d[80], d[79], d[78]);
pvts = pvts + “,” + p.headacc.ToString();
//27:pDOP[82-83]
p.pdop = (ushort)(d[82] + d[83] * 256);
pvts = pvts + “,” + p.pdop.ToString();
//28:flags3[84]
p.flags3 = d[84];
pvts = pvts + “,” + p.flags3.ToString();
//29:reserved1[85]
p.resrv0 = d[85];
pvts = pvts + “,” + p.resrv0.ToString();
//30:headVeh[86-89]
p.headveh = Toint32(d[89], d[88], d[87], d[86]);
pvts = pvts + “,” + p.headveh.ToString();
//31:magDec[90-91]
p.magdec = (short)(d[90] + d[91] * 256);
pvts = pvts + “,” + p.magdec.ToString();
//32:magAcc[92-93]
p.magacc = (ushort)(d[92] + d[93] * 256);
pvts = pvts + “,” + p.magacc.ToString();
return pvts;
}//PVTcnv() end
これはPythonのスレッドを作るための一文です。それぞれの意味を丁寧に説明しますね?? ?? t = threading.Thread(target=my_task) の意味 部分 意味 threading.Thread(...) Pythonの threading モジュールで スレッドを作る クラスです。 target=my_task スレッドで実行したい関数を指定します(この例では my_task)。 t = スレッドオブジェクトを変数 t に代入します。 ?? 補足: この時点では スレッドはまだ動いていません! スレッドを 開始するには t.start() を呼びます。 ?? 例: python コピーする 編集する import threading import time def my_task(): while True: print("Hello from thread") time.sleep(1) # スレッドを作成 t = threading.Thread(target=my_task) # スレッドを開始 t.start() print("メインプログラムは終了していない") ?? イメージ: Thread(...) はスレッドという「別働隊」を作成 start() で「出動!」 もし my_task() の後に () をつけて target=my_task() とすると、「すぐに関数を実行して、その結果をスレッドに渡す」ことになるので、誤りです。 ? 正しくは → target=my_task ← 関数の“名前”だけを渡す! 必要なら、args=() で引数も渡せるようにできます?? python コピーする 編集する threading.Thread(target=my_task, args=(引数1, 引数2)) もっと深く行く?たとえば「複数スレッド動かす」「止め方」「共有変数の扱い」も話せるよ!
Q: PVTcnvの呼び出し方
そう!その通りです?? PythonのスレッドはC#よりシンプルで軽量に使えます。 ?? 比較:Python vs C# のスレッド ?? Python(簡単!) python コピーする 編集する import threading def task(): print("処理中…") t = threading.Thread(target=task) t.start() 関数名を target に渡すだけ start() で即実行 終了待ちは join() でOK 軽く書ける、手軽 ?? C#(もうちょい構文が複雑) csharp コピーする 編集する using System.Threading; Thread t = new Thread(new ThreadStart(Task)); t.Start(); void Task() { Console.WriteLine("処理中..."); } ThreadStart を明示する必要あり(C# 5.0以前) 無名メソッドやラムダも使えるけど、構文はやや重い Thread.Sleep() も明示的 ? 結論:Pythonは試作・小規模ロガーにちょうどいい Python:簡易で十分にパワフル(USBログ、センサ受信など) C#:GUIアプリやWindowsサービス、しっかりした並列処理に◎ ?? ちょっとした非同期処理・IO待ち処理はPythonが圧倒的に早く試せる 本番用に強固なUIやマルチタスクが必要ならC#に軍配が上がることも。 気になるなら「async/await」や「Task並列ライブラリ(TPL)」の話もできますよ?!
Q: 以下のC#もPython変換
static string RELPOScnv(byte[] d, ref relp r)
{
//RELPOS header[0-5]
string relps = “”;
//Debug.Print(“{RELPOScnv]:d[0][1][2][3]” + d[0].ToString(“X”) + d[1].ToString(“X”) + d[2].ToString(“X”) + d[3].ToString(“X”));
int s = 0;
//0:ver[6]
r.version = d[s + 6];
relps = relps + “,” + r.version.ToString();
//1:reserved1[7]
r.reserved1 = d[s + 7];
relps = relps + “,” + r.reserved1.ToString();
//2:refStationId[8-9]
r.refstationid = d[s + 8];
relps = relps + “,” + r.refstationid.ToString();
//3:itow[10-13]
//Debug.Print(“{RELPOScnv ITOW]:d[10][11][12][13]” + d[10].ToString(“X”) + d[11].ToString(“X”) + d[12].ToString(“X”) + d[13].ToString(“X”));
r.itow = (uint)Toint32(d[s + 13], d[s + 12], d[s + 11], d[s + 10]);
relps = relps + “,” + r.itow.ToString();
//Serial.printf(“RELPOScnv:itow=%d\n\r”,relpos[3]);
//4:relposN[14-17]
r.relposn = Toint32(d[s + 17], d[s + 16], d[s + 15], d[s + 14]);
relps = relps + “,” + r.relposn.ToString();
//5:relposE[18-21]
r.relpose = Toint32(d[s + 21], d[s + 20], d[s + 19], d[s + 18]);
relps = relps + “,” + r.relpose.ToString();
//6:relposD[22-25]
r.relposd = Toint32(d[s + 25], d[s + 24], d[s + 23], d[s + 22]);
relps = relps + “,” + r.relposd.ToString();
//7:relposLength[26-29]
r.relposlength = Toint32(d[s + 29], d[s + 28], d[s + 27], d[s + 26]);
relps = relps + “,” + r.relposlength.ToString();
//Serial.printf(“RELPOScnv:Lenghth=relpos[7]=%d\n\r”,relpos[7]);
//8:relposHeading[30-33]
r.relposheading = Toint32(d[s + 33], d[s + 32], d[s + 31], d[s + 30]);
relps = relps + “,” + r.relposheading.ToString();
//Serial.printf(“relposHeading[8]=%d,[33]%x,[32]%x,[31]%x,[30]%x,\n\r”,relpos[8],d[33],d[32],d[31],d[30]);
//9:reserved2[34]
r.reserved2 = Toint32(d[s + 37], d[s + 36], d[s + 35], d[s + 34]);
relps = relps + “,” + r.reserved2.ToString();
//10:relposHPN[35]
r.relposhpn = (sbyte)((d[s + 38] & 127) – (d[s + 38] & 128));
relps = relps + “,” + r.relposhpn.ToString();
//Serial.printf(“HPN=%d,d[38]=%x,d[39]=%x,d[40]=%x,d[41]=%x,&127=%dx,&128=%d\n\r”,relpos[10],d[38],d[39],d[40],d[41],d[38] && 127,d[38] && 128);
//11:relposHPE[36]
r.relposhpe = (sbyte)((d[s + 39] & 127) – (d[s + 39] & 128));
relps = relps + “,” + r.relposhpe.ToString();
//12:relposHPD[37]
r.relposhpd = (sbyte)((d[s + 40] & 127) – (d[s + 40] & 128));
relps = relps + “,” + r.relposhpd.ToString();
//13:relposHPLength[38]
r.relposhplength = (sbyte)((d[s + 41] & 127) – (d[s + 41] & 128));
relps = relps + “,” + r.relposhplength.ToString();
//14:accN[38-41]
r.accn = (uint)Toint32(d[s + 41], d[s + 40], d[s + 39], d[s + 38]);
relps = relps + “,” + r.accn.ToString();
//15:accE[42-45]
r.acce = (uint)Toint32(d[s + 45], d[s + 44], d[s + 43], d[s + 42]);
relps = relps + “,” + r.acce.ToString();
//16:accD[46-49]
r.accd = (uint)Toint32(d[s + 49], d[s + 48], d[s + 47], d[s + 46]);
relps = relps + “,” + r.accd.ToString();
//17:accLength[50-53]
r.acclength = (uint)Toint32(d[s + 53], d[s + 52], d[s + 51], d[s + 50]);
relps = relps + “,” + r.acclength.ToString();
//18:accHeading[54-57]
r.accheading = (uint)Toint32(d[s + 57], d[s + 56], d[s + 55], d[s + 54]);
relps = relps + “,” + r.accheading.ToString();
//19:reserved[57-60]
r.reserved3 = (uint)Toint32(d[s + 61], d[s + 60], d[s + 59], d[s + 58]);
relps = relps + “,” + r.reserved3.ToString();
//20:flags[60-63]
r.flags = (uint)Toint32(d[s + 65], d[s + 64], d[s + 63], d[s + 62]);
relps = relps + “,” + r.flags.ToString();
return relps;
}
以下は、C# の PVTcnv() 関数を Python に変換したコードです。構造体 pvt は Python のクラスとして表現し、Toint32 関数も Python に合わせて実装しています。 ? Python版 PVTcnv python コピーする 編集する def to_int32(b0, b1, b2, b3): return int.from_bytes([b0, b1, b2, b3], byteorder='little', signed=True) def PVTcnv(d, p): pvts = [] p.itow = int.from_bytes(d[6:10], 'little', signed=False) pvts.append(str(p.itow)) p.year = d[10] + d[11] * 256 pvts.append(str(p.year)) p.month = d[12] pvts.append(str(p.month)) p.day = d[13] pvts.append(str(p.day)) p.hour = d[14] pvts.append(str(p.hour)) p.min = d[15] pvts.append(str(p.min)) p.sec = d[16] pvts.append(str(p.sec)) p.valid = d[17] pvts.append(str(p.valid)) p.tacc = int.from_bytes(d[18:22], 'little', signed=False) pvts.append(str(p.tacc)) p.nano = to_int32(d[22], d[23], d[24], d[25]) pvts.append(str(p.nano)) p.fixtype = d[26] pvts.append(str(p.fixtype)) p.flags = d[27] pvts.append(str(p.flags)) p.flags2 = d[28] pvts.append(str(p.flags2)) p.numsv = d[29] pvts.append(str(p.numsv)) p.lon = to_int32(d[30], d[31], d[32], d[33]) pvts.append(str(p.lon)) p.lat = to_int32(d[34], d[35], d[36], d[37]) pvts.append(str(p.lat)) p.height = to_int32(d[38], d[39], d[40], d[41]) pvts.append(str(p.height)) p.hmsl = to_int32(d[42], d[43], d[44], d[45]) pvts.append(str(p.hmsl)) p.hacc = int.from_bytes(d[46:50], 'little', signed=False) if p.hacc > 1000: p.hacc = 0 pvts.append(str(p.hacc)) p.vacc = int.from_bytes(d[50:54], 'little', signed=False) pvts.append(str(p.vacc)) p.veln = to_int32(d[54], d[55], d[56], d[57]) pvts.append(str(p.veln)) p.vele = to_int32(d[58], d[59], d[60], d[61]) pvts.append(str(p.vele)) p.veld = to_int32(d[62], d[63], d[64], d[65]) pvts.append(str(p.veld)) p.gspeed = to_int32(d[66], d[67], d[68], d[69]) pvts.append(str(p.gspeed)) p.headmot = to_int32(d[70], d[71], d[72], d[73]) pvts.append(str(p.headmot)) p.sacc = int.from_bytes(d[74:78], 'little', signed=False) pvts.append(str(p.sacc)) p.headacc = int.from_bytes(d[78:82], 'little', signed=False) pvts.append(str(p.headacc)) p.pdop = d[82] + d[83] * 256 pvts.append(str(p.pdop)) p.flags3 = d[84] pvts.append(str(p.flags3)) p.resrv0 = d[85] pvts.append(str(p.resrv0)) p.headveh = to_int32(d[86], d[87], d[88], d[89]) pvts.append(str(p.headveh)) p.magdec = int.from_bytes(d[90:92], 'little', signed=True) pvts.append(str(p.magdec)) p.magacc = d[92] + d[93] * 256 pvts.append(str(p.magacc)) return ','.join(pvts) ?? pvt クラスの例 python コピーする 編集する class PVT: def __init__(self): self.itow = 0 self.year = 0 self.month = 0 self.day = 0 self.hour = 0 self.min = 0 self.sec = 0 self.valid = 0 self.tacc = 0 self.nano = 0 self.fixtype = 0 self.flags = 0 self.flags2 = 0 self.numsv = 0 self.lon = 0 self.lat = 0 self.height = 0 self.hmsl = 0 self.hacc = 0 self.vacc = 0 self.veln = 0 self.vele = 0 self.veld = 0 self.gspeed = 0 self.headmot = 0 self.sacc = 0 self.headacc = 0 self.pdop = 0 self.flags3 = 0 self.resrv0 = 0 self.headveh = 0 self.magdec = 0 self.magacc = 0 必要であればこのクラスに __str__() を定義して、内容を整形出力することもできます。 要望があればそちらも作ります!
Q: C#の関数をPython 変換
static void ubxtocsv467(int n, string f,int tn)//ubx 個別ファイル csv変換 tn:serialNo 4,6,7
{
FileStream fs = new FileStream(@f, FileMode.Open, FileAccess.Read);
//UDPでは、RTKファイルは 3-19-12-2.bin_BTUBX.csv BNOファイルは 3-19-12-2.bin_BTBNO.csv
string fc = f + “_BTUBX_”+tn.ToString()+”.csv”;
int fileSize = (int)fs.Length; // ファイルのサイズ
byte[] buf;
byte[] bufs=new byte[172];//sorted buf
byte[] pvtb = new byte[100];
byte[] relpb = new byte[72];
byte[] bnob = new byte[172];
//int[] itowEarry=new int[100000];
int startn = 0;
int startn_1 = 0;
buf = new byte[fileSize]; // データ格納用配列
int index0 = 0;
int index_1 = 0;
int index_error = 0;
int indexok = 0;
int readSize = 0; // Readメソッドで読み込んだバイト数
int remain = fileSize; // 読み込むべき残りのバイト数
int bufPos = 0; // データ格納用配列内の追加位置
int k = 0;
long[] itowarry;
string[] indexerr = new string[1000];
string bnodata = “”;
string bnodata_1 = “”;
string bnodataw = “”;
int bnoitow = 0;//タイマー積算bnitow
int itownow = 0;//RTKのitow
int itownow_1 = 0;//1個前のitownow
int itownowsa = 0;//itownowの先頭
int bnitowH = 0;//補正済みbnitow
long itow1 = 0;
double lat_lon = 0;
double lat_lon_1 = 0;
int straightin = 0;
int straightn = 0;
int straightin_1 = 0;
int itowErr, totaln;
//itow1 = 0;
int headstart = 0;
int headend = 0;
int headmot1 = 0;
itowErr = 0;
totaln = 0;
//
string headUBX;
headUBX = “No,iTOW,year,month,day,hour,min,sec,valid,tAcc,nano,fixtype,flags,”;
headUBX = headUBX + “flags2,numSV,lon,lat,height,hMSL,hAcc,vAcc,velN,velE,velD,gSpeed,headMot,sAcc,”;
headUBX = headUBX + “headAcc,pDOP,flags3,reserved1,headVeh,magDec,magAcc,na,”;
headUBX = headUBX + “version,reserved2,refStationId,iTOWR,relPosN,relPosE,relPosD,relPosLength,”;
headUBX = headUBX + “relPosHeading,relPosHPN,relPosHPE,relPosHPD,relPosHPLength,accN,accE,accD,”;
headUBX = headUBX + “accLength,accHeading,reserverd4,flagsR,a”;
//fix error itowerror
f131 = 0;
f673 = 0;
itow_1 = 0;
itowloss = 0;
//int itowper = 0;
// fixper = 0;
while (remain > 0)
{
// 172Bytesずつbuf[]に読み込む
readSize = fs.Read(buf, bufPos, Math.Min(172, remain));
bufPos += readSize;
remain -= readSize;
k++;//172byte単位でカウントアップ
}
itowarry = new long[k];
int dsize = fileSize;
int[] stArry4 = new int[18000];//30min
int[] stArry6 = new int[18000];//30min
int[] stArry7 = new int[18000];//30min
int stcnt4 = 0;
int stcnt6 = 0;
int stcnt7 = 0;
//rev800_4用のデータは、1ファイルに全て混在しているので、毎回頭出し必要なので、PVTヘッダー番号配列を作成
for (int ii=0;ii<dsize; ii++)
{
if (buf[ii]==0xB5 && buf[ii+1]==0X62 && buf[ii+2]==0x01 && buf[ii+3]==0x07)
{
if (buf[ii + 4] ==0x04)
{
stArry4[stcnt4] = ii;
stcnt4++;
}
if (buf[ii + 4] == 0x06)
{
stArry6[stcnt6] = ii;
stcnt6++;
}
if (buf[ii + 4] == 0x07)
{
stArry7[stcnt7] = ii;
stcnt7++;
}
}
}
//UDPでは、RTKファイルは 3-19-12-2.bin_BTUBX.csv BNOファイルは 3-19-12-2.bin_BTBNO.csv
System.IO.StreamWriter sw = new System.IO.StreamWriter(@fc, false);//swはrtk BTUX用
sw.WriteLine(headUBX);
//buf からUBX 抽出
// startn = i * 172;
if (tn == 4)
{
k= stcnt4;
}
if (tn == 6)
{
k= stcnt6;
}
if (tn == 7)
{
k = stcnt7;
}
//k = stcnt4 + stcnt6 + stcnt4-3;
for (int i = 0; i < k – 1; i++)//172byte単位で読む
{
if (tn == 4)
{
startn = stArry4[i];
}
if (tn == 6)
{
startn = stArry6[i];
}
if (tn == 7)
{
startn = stArry7[i];
}
//Console.Write(i.ToString() + “,” + string.Format(“{0:X2}”, buf[i*172])+”,:,”);
//TextBox1.Textの内容を書き込む
//PVT取り出し
//PVT RELPOSNED trans
if (buf[0 + startn] == 0xB5 && buf[1 + startn] == 0x62 && buf[2 + startn] == 0x01 && buf[3 + startn] == 0x07 && buf[4+startn]==tn)
{
//===========UBX translate================================
for (int j = 0; j < 100; j++)//bufからpvtbへ格納
{
pvtb[j] = buf[j + startn];
}
for (int j = 0; j < 72; j++)//bufからrelpbへ格納 { relpb[j] = buf[j + startn + 100]; } itow1 = pvtd.itow;//1個前のitow記録 headmot1 = pvtd.headmot; string ubx0 = PVTcnv(pvtb, ref pvtd); string ubx1 = RELPOScnv(relpb, ref relpd); string istr = i.ToString(); sw.WriteLine(istr + “,” + ubx0 + “,” + ubx1); //Console.WriteLine(istr + “,” + ubx0 + “,” + ubx1); //Console.WriteLine(ubx1); //———-itowエラーカウント—————— itowarry[i] = pvtd.itow; //if (i > 0 && i % 2 == 0)
//{
if (Math.Abs(itowarry[i] – itow1)>135 || Math.Abs(itowarry[i] – itow1)< 115 )//itow loss検出 125msec±5msec { itowErr++; //Console.WriteLine(“>>>>itowErr=” + itowErr + “[” + itowarry[i] + “-” + itow1);
}
//}
//Fix率
if (pvtd.flags == 131)
{
f131++;
}
else
{
f673++;
}
totaln++;
}
else//ubx順序がバラバラの場合はソートする
{
int nc, ns;//counter
int pvtstartN = 0;//pvtstart No
int relpstartN = 0;//relpos start No
for (nc = 0; nc < 172; nc++)//開始位置検索
{
if (buf[nc%172 + startn] == 0xB5 && buf[(nc+ 1)%172 + startn] == 0x62 && buf[(nc + 2)%172 + startn] == 0x01 && buf[(nc + 3)%172 + startn] == 0x07)
{
pvtstartN = nc;
Console.WriteLine(“epochNo=” + i + “pvtstartN=” + pvtstartN);
}
if (buf[nc%172 + startn] == 0xB5 && buf[(nc + 1)%172 + startn] == 0x62 && buf[(nc + 2)%172 + startn] == 0x01 && buf[(nc + 3)%172 + startn] == 0x3c)
{
relpstartN = nc;
Console.WriteLine(“epochNo=” + i + “relpstartN=” + relpstartN);
}
}
//SORT
for (ns = 0; ns < 172 – pvtstartN; ns++)
{
bufs[ns] = buf[ns + pvtstartN+startn];
//Console.WriteLine(“bufs[” + ns + “]=” + bufs[ns].ToString(“X”) + “buf[” + (ns+pvtstartN+startn) + “]=” + buf[ns+pvtstartN+startn].ToString(“X”));
}
//前半分
int nokori = 172 – pvtstartN;
for (ns = 0; ns < pvtstartN; ns++)
{
bufs[ns +nokori] = buf[ns+startn];
//Console.WriteLine(“bufs[” + (ns+nokori) + “]=” + bufs[ns + pvtstartN].ToString(“X”) + “buf[” + (ns+startn) + “]=” + buf[ns+startn].ToString(“X”));
}
//chkeck
for (ns = 0; ns < 172; ns++)
{
//Console.Write( bufs[ns].ToString(“X”));
}
Console.WriteLine();
//===========UBX 分離================================
for (int j = 0; j < 100; j++)//bufからpvtbへ格納
{
pvtb[j] = bufs[j];
Console.Write(pvtb[j].ToString(“X”));
}
Console.WriteLine();
for (int j = 0; j < 72; j++)//bufからrelpbへ格納
{
relpb[j] = bufs[j + 100];
Console.Write(relpb[j].ToString(“X”));
}
//================UBX変換===============================
string ubx0 = PVTcnv(pvtb, ref pvtd);
string ubx1 = RELPOScnv(relpb, ref relpd);
string istr = tn.ToString();
sw.WriteLine(istr + “,” + ubx0 + “,” + ubx1);
}
}//ubx for END
double itowper = (double)itowErr / k*100;
double flagper=(double)f673 / k*100;
Console.WriteLine(“********************RX”+tn+”:itowERR=” + itowErr.ToString() + “/” + k.ToString()+”<“+itowper.ToString(“F2”) + “%>,f131 =” + f131.ToString() + “,f673=” + f673.ToString()+”<“+flagper.ToString(“F2″)+”%>****************”);
//for(int ii = 0; ii < itowErr; ii++)
//{
// Console.WriteLine(“itowEarry[” + ii + “]=” + itowEarry[ii]);
//}
}//ubxtocsv END
PVTcnv() 関数の呼び出し方はとてもシンプルです。 以下に、使い方の例を示します。 ?? 前提 PVT クラス(Python版の pvt 構造体)を使う。 UBX PVT メッセージのバイナリデータ(byte[])が d に入っているとする(最低94バイト必要)。 ? 使用例(呼び出し) python コピーする 編集する # 必要なクラスと関数を定義済みとして... # 1. PVTオブジェクトの生成 p = PVT() # 2. UBX PVTメッセージのバイト列(例としてダミーのバイト列) d = bytearray(100) # 本来は実際のGNSSから受信したデータを入れる # 3. 変換関数を呼び出す csv_line = PVTcnv(d, p) # 4. 結果表示 print("CSV出力:", csv_line) print("緯度:", p.lat / 1e7) print("経度:", p.lon / 1e7) ??補足 PVTcnv() は csv形式の文字列 を返し、同時に p オブジェクトの中身を更新します。 緯度 (lat) や経度 (lon) は 1e-7度 単位なので、表示するには 1e7 で割るとよいです。 ?? 実データで使いたい場合は、serial.read() などで受信した UBX メッセージ(長さ94バイト以上)を d にして渡せばOKです。 必要であれば、受信データのチェックやUBX構造の解析コードも出せます!
Q: import struct は
以下が、提示された C# の RELPOScnv() 関数を Python に変換したコードです。 Toint32() は前回と同様に、ビッグエンディアンをリトルエンディアンに変換するユーティリティとして実装してあります。 ?? Python版 RELPOScnv() python コピーする 編集する def to_int32(b1, b2, b3, b4): return int.from_bytes([b1, b2, b3, b4], byteorder='little', signed=True) class RELPOS: def __init__(self): self.version = 0 self.reserved1 = 0 self.refstationid = 0 self.itow = 0 self.relposn = 0 self.relpose = 0 self.relposd = 0 self.relposlength = 0 self.relposheading = 0 self.reserved2 = 0 self.relposhpn = 0 self.relposhpe = 0 self.relposhpd = 0 self.relposhplength = 0 self.accn = 0 self.acce = 0 self.accd = 0 self.acclength = 0 self.accheading = 0 self.reserved3 = 0 self.flags = 0 def RELPOScnv(d: bytes, r: RELPOS) -> str: s = 0 relps = "" r.version = d[s + 6] relps += f",{r.version}" r.reserved1 = d[s + 7] relps += f",{r.reserved1}" r.refstationid = d[s + 8] + (d[s + 9] << 8) relps += f",{r.refstationid}" r.itow = to_int32(d[s + 10], d[s + 11], d[s + 12], d[s + 13]) relps += f",{r.itow}" r.relposn = to_int32(d[s + 14], d[s + 15], d[s + 16], d[s + 17]) relps += f",{r.relposn}" r.relpose = to_int32(d[s + 18], d[s + 19], d[s + 20], d[s + 21]) relps += f",{r.relpose}" r.relposd = to_int32(d[s + 22], d[s + 23], d[s + 24], d[s + 25]) relps += f",{r.relposd}" r.relposlength = to_int32(d[s + 26], d[s + 27], d[s + 28], d[s + 29]) relps += f",{r.relposlength}" r.relposheading = to_int32(d[s + 30], d[s + 31], d[s + 32], d[s + 33]) relps += f",{r.relposheading}" r.reserved2 = to_int32(d[s + 34], d[s + 35], d[s + 36], d[s + 37]) relps += f",{r.reserved2}" r.relposhpn = (d[s + 38] & 0x7F) - (d[s + 38] & 0x80) relps += f",{r.relposhpn}" r.relposhpe = (d[s + 39] & 0x7F) - (d[s + 39] & 0x80) relps += f",{r.relposhpe}" r.relposhpd = (d[s + 40] & 0x7F) - (d[s + 40] & 0x80) relps += f",{r.relposhpd}" r.relposhplength = (d[s + 41] & 0x7F) - (d[s + 41] & 0x80) relps += f",{r.relposhplength}" r.accn = int.from_bytes(d[s + 42:s + 46], byteorder='little', signed=False) relps += f",{r.accn}" r.acce = int.from_bytes(d[s + 46:s + 50], byteorder='little', signed=False) relps += f",{r.acce}" r.accd = int.from_bytes(d[s + 50:s + 54], byteorder='little', signed=False) relps += f",{r.accd}" r.acclength = int.from_bytes(d[s + 54:s + 58], byteorder='little', signed=False) relps += f",{r.acclength}" r.accheading = int.from_bytes(d[s + 58:s + 62], byteorder='little', signed=False) relps += f",{r.accheading}" r.reserved3 = int.from_bytes(d[s + 62:s + 66], byteorder='little', signed=False) relps += f",{r.reserved3}" r.flags = int.from_bytes(d[s + 66:s + 70], byteorder='little', signed=False) relps += f",{r.flags}" return relps ? 使用例: python コピーする 編集する rel = RELPOS() data = bytearray(100) # 実際はGNSSからのUBX RELPOSメッセージを代入 csv_result = RELPOScnv(data, rel) print(csv_result) print("North (cm):", rel.relposn / 100.0) print("East (cm):", rel.relpose / 100.0) 必要であれば PVT と統合して1つのクラスにしたり、ファイル出力やログ整形なども可能です。どう使いたいか教えてもらえれば、追加で整えます!
Q: PVTcnv() をPythonで再現するときに struct をどう使うかも例付きで説明
保存されたメモリを更新しました かなりのボリュームですね!このC#関数 ubxtocsv467 をPythonに変換するにはいくつかのステップが必要です。以下、全体の構造を維持しながら、Pythonらしく変換したコードの大枠を提供します。 ? 前提 PVTcnv() と RELPOScnv() は別途定義されている前提で、呼び出し部分はそのまま残します。 pvtd, relpd も構造体/クラスとしてどこかで定義されている前提です(これらの詳細もあれば再現できます)。 ファイル読み取り→バイナリ処理→フィルタリング→CSV書き出しという構成です。 ?? Python変換例(主要部分) python コピーする 編集する import struct import os def ubxtocsv467(n, f, tn): with open(f, 'rb') as fs: buf = fs.read() file_size = len(buf) bufs = bytearray(172) pvtb = bytearray(100) relpb = bytearray(72) output_file = f + f"_BTUBX_{tn}.csv" itowarry = [0] * (file_size // 172) stArry4, stArry6, stArry7 = [], [], [] # ヘッダー探索(PVTの種類ごとに) for ii in range(file_size - 4): if buf[ii] == 0xB5 and buf[ii+1] == 0x62 and buf[ii+2] == 0x01 and buf[ii+3] == 0x07: if buf[ii+4] == 0x04: stArry4.append(ii) elif buf[ii+4] == 0x06: stArry6.append(ii) elif buf[ii+4] == 0x07: stArry7.append(ii) stmap = {4: stArry4, 6: stArry6, 7: stArry7} stArry = stmap[tn] k = len(stArry) # CSV出力開始 with open(output_file, 'w', encoding='utf-8') as sw: headUBX = ("No,iTOW,year,month,day,hour,min,sec,valid,tAcc,nano,fixtype,flags," "flags2,numSV,lon,lat,height,hMSL,hAcc,vAcc,velN,velE,velD,gSpeed,headMot,sAcc," "headAcc,pDOP,flags3,reserved1,headVeh,magDec,magAcc,na," "version,reserved2,refStationId,iTOWR,relPosN,relPosE,relPosD,relPosLength," "relPosHeading,relPosHPN,relPosHPE,relPosHPD,relPosHPLength,accN,accE,accD," "accLength,accHeading,reserverd4,flagsR,a") sw.write(headUBX + '\n') f131 = f673 = itowErr = totaln = 0 itow1 = headmot1 = 0 for i in range(k - 1): startn = stArry[i] if buf[startn:startn+6] == bytes([0xB5, 0x62, 0x01, 0x07, tn, 0]): pvtb[:] = buf[startn:startn+100] relpb[:] = buf[startn+100:startn+172] itow1 = pvtd.itow headmot1 = pvtd.headmot ubx0 = PVTcnv(pvtb, pvtd) ubx1 = RELPOScnv(relpb, relpd) sw.write(f"{i},{ubx0},{ubx1}\n") itowarry[i] = pvtd.itow if abs(itowarry[i] - itow1) > 135 or abs(itowarry[i] - itow1) < 115: itowErr += 1 if pvtd.flags == 131: f131 += 1 else: f673 += 1 totaln += 1 else: # UBX並びがバラバラの場合のソート処理 pvtstartN = relpstartN = 0 for nc in range(172): if buf[startn + nc % 172:startn + (nc % 172) + 4] == bytes([0xB5, 0x62, 0x01, 0x07]): pvtstartN = nc elif buf[startn + nc % 172:startn + (nc % 172) + 4] == bytes([0xB5, 0x62, 0x01, 0x3c]): relpstartN = nc # 再配置 bufs[:172 - pvtstartN] = buf[startn + pvtstartN:startn + 172] bufs[172 - pvtstartN:] = buf[startn:startn + pvtstartN] pvtb[:] = bufs[:100] relpb[:] = bufs[100:] ubx0 = PVTcnv(pvtb, pvtd) ubx1 = RELPOScnv(relpb, relpd) sw.write(f"{tn},{ubx0},{ubx1}\n") itowper = itowErr / k * 100 flagper = f673 / k * 100 print(f"*** RX{tn}: itowERR={itowErr}/{k} <{itowper:.2f}%>, f131={f131}, f673={f673} <{flagper:.2f}%> ***") ?? 補足 pvtd と relpd は class または dataclass にして、PVTcnv() や RELPOScnv() 内で ref 的に更新できるようにします。 C#の ref をPythonで再現するには、mutableなオブジェクトを渡すようにします(例:dict、class、list)。 必要に応じて print() → logging に置き換えると便利。 必要に応じて PVTcnv() や RELPOScnv()、pvtd/relpd も含めてフル変換していきますので、そちらのコードも見せていただければ対応可能です!
Q: 前回の回答はクラスで」やってたclass PVT: def __init__(self): self.itow = 0 self.year = 0 self.month = 0 self.day = 0 self.hour = 0 self.min = 0 self.sec = 0 self.valid = 0 self.tacc = 0 self.nano = 0 self.fixtype = 0 self.flags = 0 self.flags2 = 0 self.numsv = 0 self.lon = 0 self.lat = 0 self.height = 0 self.hmsl = 0 self.hacc = 0 self.vacc = 0 self.veln = 0 self.vele = 0 self.veld = 0 self.gspeed = 0 self.headmot = 0 self.sacc = 0 self.headacc = 0 self.pdop = 0 self.flags3 = 0 self.resrv0 = 0 self.headveh = 0 self.magdec = 0 self.magacc = 0
いい質問です! import struct は バイナリデータの解析(≒ CやC#の BitConverter, BinaryReader 的な処理)を行うために使われています。 ? struct モジュールの役割 Pythonの struct モジュールは、C言語のような 固定長バイナリデータを bytearray から読み書きするために使われます。 たとえば、GPSからのUBXバイナリデータを int, float, double などに変換したり、逆に数値をバイナリに変換する際に使用します。 ?? よく使う関数 関数名 説明 struct.unpack(fmt, buffer) バイナリ → Pythonの型(tuple) struct.pack(fmt, value1, value2, ...) Pythonの型 → バイナリ ?? 使用例 python コピーする 編集する import struct # 4バイトのリトルエンディアン符号付き整数を読み取る data = b'\x01\x00\x00\x00' value = struct.unpack('<i', data)[0] print(value) # 出力: 1 # UBXのヘッダー(b5 62)とクラスID, メッセージID, ペイロード長をパースしたい場合 ubx_header = b'\xb5\x62\x01\x07\x5c\x00' sync1, sync2, msg_class, msg_id, length = struct.unpack('<2s2B2B', ubx_header[:6]) ?? つまり… C#のこのようなコード: csharp コピーする 編集する int val = BitConverter.ToInt32(buffer, offset); はPythonでこうなります: python コピーする 編集する val = struct.unpack_from('<i', buffer, offset)[0] UBXデータ処理では必須! UBXのように「バイト単位で定義されたプロトコル」を扱うには、Pythonでも struct は必須です。 この後 PVTcnv() や RELPOScnv() を実装する際にも、struct.unpack() をたくさん使います。 必要なら PVTcnv() をPythonで再現するときに struct をどう使うかも例付きで説明しますよ!
Q: structのフォーマット覚えるのが嫌だからもっと単純化
よっしゃ!じゃあ PVTcnv() を Python に移植する前提で、どう struct を使うか丁寧に説明していくね。 まずは PVT メッセージ(UBX-NAV-PVT)のバイナリ構造を例に取り上げて解説するよ。 ?? UBX-NAV-PVT の構造(概要) PVT メッセージは UBX-CFG ドキュメントによると 92バイト程度のペイロードがあり、以下のようなフィールドが入ってる: オフセット フィールド名 サイズ 型 0 iTOW 4 U4(uint32) 4 year 2 U2(uint16) 6 month 1 U1(uint8) 7 day 1 U1 8 hour 1 U1 9 min 1 U1 10 sec 1 U1 11 valid 1 X1(flags) 12 tAcc 4 U4 16 nano 4 I4(int32) 20 fixType 1 U1 21 flags 1 X1 ... ... ... ... ?? 以降、lat, lon なども続く。 ?? Pythonで struct.unpack を使って読み出す python コピーする 編集する import struct def PVTcnv(pvtb: bytes, pvtd: dict) -> str: # '<' = little-endian # 'I' = uint32, 'H' = uint16, 'B' = uint8, 'i' = int32, 'b' = int8 # unpack_fromでオフセット指定して読み取っていく iTOW, = struct.unpack_from('<I', pvtb, 0) year, = struct.unpack_from('<H', pvtb, 4) month = pvtb[6] day = pvtb[7] hour = pvtb[8] minute = pvtb[9] second = pvtb[10] valid = pvtb[11] tAcc, = struct.unpack_from('<I', pvtb, 12) nano, = struct.unpack_from('<i', pvtb, 16) fixType = pvtb[20] flags = pvtb[21] flags2 = pvtb[22] numSV = pvtb[23] lon, lat, height, hMSL = struct.unpack_from('<iiii', pvtb, 24) hAcc, vAcc = struct.unpack_from('<II', pvtb, 36) velN, velE, velD, gSpeed = struct.unpack_from('<iiii', pvtb, 44) headMot, sAcc, headAcc = struct.unpack_from('<III', pvtb, 56) pDOP, = struct.unpack_from('<H', pvtb, 68) # reserved1 = pvtb[70:72] headVeh, magDec, magAcc = struct.unpack_from('<iii', pvtb, 72) # データ格納(辞書 or クラス) pvtd["itow"] = iTOW pvtd["headmot"] = headMot pvtd["flags"] = flags # CSV出力用に整形 csv_row = f"{iTOW},{year},{month},{day},{hour},{minute},{second},{valid},{tAcc},{nano},{fixType},{flags}," csv_row += f"{flags2},{numSV},{lon},{lat},{height},{hMSL},{hAcc},{vAcc},{velN},{velE},{velD},{gSpeed},{headMot},{sAcc}," csv_row += f"{headAcc},{pDOP},,,{headVeh},{magDec},{magAcc},0" # 省略フィールドは適当 return csv_row ? 呼び出し方イメージ python コピーする 編集する pvtb = b'...' # 長さ100のバイナリデータ pvtd = {} csv_line = PVTcnv(pvtb, pvtd) print(csv_line) ?? 注意点 UBXは リトルエンディアン なので struct.unpack('<I', ...) のように < をつける。 unpack_from はオフセットを指定して一発で取り出せる。 pvtb は100バイト固定なので、先にスライスしておくか bytes 配列として渡す。 pvtd は出力用の辞書だけど、C#側の構造体を dataclass にしてもOK。 もし RELPOScnv() も同様に必要なら、そっちも struct 使って変換してみるよ!
Q: pvtd.itow, ofs = read(“<I”, pvtb, ofs) 意味わからない
了解!じゃあ今回は、前回のクラスベースのスタイルに合わせて PVTcnv() を struct を使って再現してみよう。PVT クラスのインスタンスを渡して、その中にデータを格納する感じね。 ? PVT クラスを使った PVTcnv()(struct 使用) python コピーする 編集する import struct class PVT: def __init__(self): self.itow = 0 self.year = 0 self.month = 0 self.day = 0 self.hour = 0 self.min = 0 self.sec = 0 self.valid = 0 self.tacc = 0 self.nano = 0 self.fixtype = 0 self.flags = 0 self.flags2 = 0 self.numsv = 0 self.lon = 0 self.lat = 0 self.height = 0 self.hmsl = 0 self.hacc = 0 self.vacc = 0 self.veln = 0 self.vele = 0 self.veld = 0 self.gspeed = 0 self.headmot = 0 self.sacc = 0 self.headacc = 0 self.pdop = 0 self.flags3 = 0 self.resrv0 = 0 self.headveh = 0 self.magdec = 0 self.magacc = 0 def PVTcnv(pvtb: bytes, pvtd: PVT) -> str: # unpack 順に合わせて展開(最初の72バイトまでは構造確定) (pvtd.itow, pvtd.year, pvtd.month, pvtd.day, pvtd.hour, pvtd.min, pvtd.sec, pvtd.valid, pvtd.tacc, pvtd.nano, pvtd.fixtype, pvtd.flags, pvtd.flags2, pvtd.numsv, pvtd.lon, pvtd.lat, pvtd.height, pvtd.hmsl, pvtd.hacc, pvtd.vacc, pvtd.veln, pvtd.vele, pvtd.veld, pvtd.gspeed, pvtd.headmot, pvtd.sacc, pvtd.headacc, pvtd.pdop, pvtd.flags3, pvtd.resrv0, pvtd.headveh, pvtd.magdec, pvtd.magacc) = struct.unpack_from('<IHBBBBBBIiBBBiiiiIIiiiiIIIHBBiii', pvtb, 0) # CSV形式に変換 csv_row = ( f"{pvtd.itow},{pvtd.year},{pvtd.month},{pvtd.day},{pvtd.hour},{pvtd.min},{pvtd.sec},{pvtd.valid}," f"{pvtd.tacc},{pvtd.nano},{pvtd.fixtype},{pvtd.flags},{pvtd.flags2},{pvtd.numsv}," f"{pvtd.lon},{pvtd.lat},{pvtd.height},{pvtd.hmsl},{pvtd.hacc},{pvtd.vacc}," f"{pvtd.veln},{pvtd.vele},{pvtd.veld},{pvtd.gspeed},{pvtd.headmot},{pvtd.sacc},{pvtd.headacc}," f"{pvtd.pdop},{pvtd.flags3},{pvtd.resrv0},{pvtd.headveh},{pvtd.magdec},{pvtd.magacc},0" ) return csv_row ?? struct.unpack_from のフォーマット説明 python コピーする 編集する '<IHBBBBBBIiBBBiiiiIIiiiiIIIHBBiii' このフォーマットは各フィールドの型を示してる: 型 意味 フィールド例 I uint32 itow, tacc, hacc など H uint16 year, pdop B uint8 month, day, sec など b int8 使用してない(たぶん今の構造では不要) i int32 nano, lon, lat, velN など ? 使用イメージ python コピーする 編集する pvt = PVT() csv_line = PVTcnv(binary_data, pvt) print(csv_line) print(pvt.lat, pvt.lon) この書き方なら C# の struct に近い構造体っぽく扱えるし、PVT オブジェクトに直接アクセスもできて扱いやすいはず。 必要なら次は RELPOScnv() も同じスタイルでやるよー!
Q: ofsが自動でインクリメントされるのが味噌
了解、struct のフォーマット覚えるの面倒ってのめっちゃわかる。 じゃあ 「1個ずつ読み取って代入」 するスタイルにして、struct.unpack_from() も最小限だけ使おう。 ? struct使うけど超単純にする PVTcnv() python コピーする 編集する import struct def read(fmt, data, offset): size = struct.calcsize(fmt) return struct.unpack_from(fmt, data, offset)[0], offset + size def PVTcnv(pvtb: bytes, pvtd) -> str: ofs = 0 pvtd.itow, ofs = read("<I", pvtb, ofs) pvtd.year, ofs = read("<H", pvtb, ofs) pvtd.month, ofs = read("<B", pvtb, ofs) pvtd.day, ofs = read("<B", pvtb, ofs) pvtd.hour, ofs = read("<B", pvtb, ofs) pvtd.min, ofs = read("<B", pvtb, ofs) pvtd.sec, ofs = read("<B", pvtb, ofs) pvtd.valid, ofs = read("<B", pvtb, ofs) pvtd.tacc, ofs = read("<I", pvtb, ofs) pvtd.nano, ofs = read("<i", pvtb, ofs) pvtd.fixtype, ofs = read("<B", pvtb, ofs) pvtd.flags, ofs = read("<B", pvtb, ofs) pvtd.flags2, ofs = read("<B", pvtb, ofs) pvtd.numsv, ofs = read("<B", pvtb, ofs) pvtd.lon, ofs = read("<i", pvtb, ofs) pvtd.lat, ofs = read("<i", pvtb, ofs) pvtd.height, ofs = read("<i", pvtb, ofs) pvtd.hmsl, ofs = read("<i", pvtb, ofs) pvtd.hacc, ofs = read("<I", pvtb, ofs) pvtd.vacc, ofs = read("<I", pvtb, ofs) pvtd.veln, ofs = read("<i", pvtb, ofs) pvtd.vele, ofs = read("<i", pvtb, ofs) pvtd.veld, ofs = read("<i", pvtb, ofs) pvtd.gspeed, ofs = read("<I", pvtb, ofs) pvtd.headmot, ofs = read("<I", pvtb, ofs) pvtd.sacc, ofs = read("<I", pvtb, ofs) pvtd.headacc, ofs = read("<I", pvtb, ofs) pvtd.pdop, ofs = read("<H", pvtb, ofs) pvtd.flags3, ofs = read("<B", pvtb, ofs) pvtd.resrv0, ofs = read("<B", pvtb, ofs) pvtd.headveh, ofs = read("<i", pvtb, ofs) pvtd.magdec, ofs = read("<h", pvtb, ofs) pvtd.magacc, ofs = read("<H", pvtb, ofs) # CSV形式に変換 csv_row = ( f"{pvtd.itow},{pvtd.year},{pvtd.month},{pvtd.day},{pvtd.hour},{pvtd.min},{pvtd.sec},{pvtd.valid}," f"{pvtd.tacc},{pvtd.nano},{pvtd.fixtype},{pvtd.flags},{pvtd.flags2},{pvtd.numsv}," f"{pvtd.lon},{pvtd.lat},{pvtd.height},{pvtd.hmsl},{pvtd.hacc},{pvtd.vacc}," f"{pvtd.veln},{pvtd.vele},{pvtd.veld},{pvtd.gspeed},{pvtd.headmot},{pvtd.sacc},{pvtd.headacc}," f"{pvtd.pdop},{pvtd.flags3},{pvtd.resrv0},{pvtd.headveh},{pvtd.magdec},{pvtd.magacc},0" ) return csv_row ? メリット "<I" みたいに短い型1個だけ見ればいい 順番間違えにくい(1行1項目) C言語の fread() + memcpy() 的に分かりやすい ? 補足:使う側はこう python コピーする 編集する pvt = PVT() csv = PVTcnv(binary_data, pvt) print(csv) これで struct のフォーマットは 「1個ずつ指定」するだけ。 全部 <I、<H、<B、<i、
Q: ofs理解するだけで全部できるから便利
OK、めっちゃシンプルに説明するね。 この行: python コピーする 編集する pvtd.itow, ofs = read("<I", pvtb, ofs) はこういう意味: ?? 何をしてるか? バイナリデータ pvtb から 4バイト読んで、整数(itow)に変換して、pvtd.itow に代入してる。 同時に「次に読む位置(オフセット)」を更新して ofs に返してる。 ?? 分解してみよう: ?? read("<I", pvtb, ofs) の意味 これは read() 関数に3つの情報を渡してる: 引数 意味 "<I" リトルエンディアンの unsigned int (4バイト) を読むよ、って意味。 pvtb バイナリデータ(UBXから来たPVTデータ) ofs 今、何バイト目から読み始めるか(オフセット) ?? read() 関数の中身(さっきのやつ)をもう一度見てみる: python コピーする 編集する def read(fmt, data, offset): size = struct.calcsize(fmt) # 何バイト必要か val = struct.unpack_from(fmt, data, offset)[0] # バイナリ → 数値 return val, offset + size # 値と「次に読む位置」 つまり read("<I", pvtb, ofs) の戻り値は: python コピーする 編集する (val, new_offset) ? だからこの1行の意味は: python コピーする 編集する pvtd.itow, ofs = read("<I", pvtb, ofs) ?? 「pvtb の ofs 番目から 4バイト読んで、それを pvtd.itow に代入して、次に読む位置を ofs に更新」 ? 例を出すと… python コピーする 編集する # 例えばバイナリデータが↓こんな風だったら: pvtb = b'\x01\x00\x00\x00...' # 先頭4バイト = 1 (little endian) # 最初は ofs = 0 pvtd.itow, ofs = read("<I", pvtb, 0) # 結果 pvtd.itow = 1 ofs = 4 ← 次はここから読む! まとめ この書き方: python コピーする 編集する pvtd.xxx, ofs = read("<型", データ, 今の位置) はめちゃくちゃシンプルに 「1個値を読み取って代入、ついでにオフセット進める」 というパターンを作ってるだけ! もっと知りたければ、< や I, H, B の意味もカンタンにまとめるよー!
Q: structの必要性わからない
そうそう!そこが "味噌" なんだよ!?? ?? なぜ ofs をこう使うのが便利か? python コピーする 編集する pvtd.itow, ofs = read("<I", pvtb, ofs) pvtd.year, ofs = read("<H", pvtb, ofs) pvtd.month, ofs = read("<B", pvtb, ofs) って感じに書けると: 読み取り位置(ofs)を自動で進めてくれる コードが超スッキリ 間違って同じ場所から2回読んだりもしない ?? オフセット手動でやってたらこうなる: python コピーする 編集する pvtd.itow = struct.unpack_from("<I", pvtb, 0)[0] pvtd.year = struct.unpack_from("<H", pvtb, 4)[0] pvtd.month = struct.unpack_from("<B", pvtb, 6)[0] # …って毎回オフセット考えないといけない?? ? だからこの方法は: バイナリ連続データを 順番に読みたいときに めちゃくちゃ相性がいい! 必要なら read() の代わりに Reader クラスにして、状態も持たせられるけど、今のスタイルが一番簡潔でいい感じ? 気に入ってくれてたらそのまま突き進もう??
Q: 確かに楽だわ
まさにそれ!!? ?? ofs(= offset)って何者? 簡単に言えば: 「今どこまで読んだっけ?」っていう位置情報。 ?? つまりこういう流れ: python コピーする 編集する ofs = 0 # 最初は先頭から # 4バイト読む value1, ofs = read("<I", data, ofs) #
Q: PVTcnv不要だからなおさら良い
いい視点!実はそれ、ほとんどの人が最初に思う疑問でもある。「なんで struct 使うの?」ってやつ。 ?? struct の必要性=「バイナリ → 値」に変換するため UBXみたいな バイナリデータ って、数字が直接バイト列になってるだけ。 例えばこの4バイト: コピーする 編集する 0xE8 0x03 0x00 0x00 これは何を意味するか分からないよね? でも struct を使えばこう: python コピーする 編集する import struct data = bytes([0xE8, 0x03, 0x00, 0x00]) value = struct.unpack("<I", data)[0] print(value) # → 1000 ???♂? struct が「これはリトルエンディアンの unsigned int(4バイト)」だと解釈してくれる。 ?? struct を使わなかったら? 手動でやるとこうなる: python コピーする 編集する data = bytes([0xE8, 0x03, 0x00, 0x00]) value = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24) print(value) # → 1000 これは地獄。フォーマットが複雑になったらミスの温床?? ? struct を使う理由まとめ: 理由 説明 ? 楽 一行で型指定して読める ? 安全 ビットシフトやバイト順のミスがない ? UBXと相性良し UBXは定型フォーマットなのでぴったり ? 自動インクリメント(ofs)と合わせると超快適 ?? ざっくり対応表 structフォーマット C/C++相当 Pythonでの意味 バイト数
Q: 有難う 一歩一歩進めるよ
でしょ?一回「楽」って感覚掴むと、もうビットシフト戻れないやつ?? 特にUBXとかGNSS系みたいなバイナリでキッチリ決まってるプロトコルには神レベルで相性いい。 さらに楽したい人向けTIPS: ?? ヘッダまとめて定義すると超すっきり 例えばPVTなら: python コピーする 編集する PVT_FORMAT = "
Q: relposcnvも簡単に
class RELPOS:
def __init__(self):
self.version = 0
self.reserved1 = 0
self.refstationid = 0
self.itow = 0
self.relposn = 0
self.relpose = 0
self.relposd = 0
self.relposlength = 0
self.relposheading = 0
self.reserved2 = 0
self.relposhpn = 0
self.relposhpe = 0
self.relposhpd = 0
self.relposhplength = 0
self.accn = 0
self.acce = 0
self.accd = 0
self.acclength = 0
self.accheading = 0
self.reserved3 = 0
self.flags = 0
def RELPOScnv(d: bytes, r: RELPOS) -> str:
s = 0
relps = “”
r.version = d[s + 6]
relps += f”,{r.version}”
r.reserved1 = d[s + 7]
relps += f”,{r.reserved1}”
r.refstationid = d[s + 8] + (d[s + 9] << 8)
relps += f”,{r.refstationid}”
r.itow = to_int32(d[s + 10], d[s + 11], d[s + 12], d[s + 13])
relps += f”,{r.itow}”
r.relposn = to_int32(d[s + 14], d[s + 15], d[s + 16], d[s + 17])
relps += f”,{r.relposn}”
r.relpose = to_int32(d[s + 18], d[s + 19], d[s + 20], d[s + 21])
relps += f”,{r.relpose}”
r.relposd = to_int32(d[s + 22], d[s + 23], d[s + 24], d[s + 25])
relps += f”,{r.relposd}”
r.relposlength = to_int32(d[s + 26], d[s + 27], d[s + 28], d[s + 29])
relps += f”,{r.relposlength}”
r.relposheading = to_int32(d[s + 30], d[s + 31], d[s + 32], d[s + 33])
relps += f”,{r.relposheading}”
r.reserved2 = to_int32(d[s + 34], d[s + 35], d[s + 36], d[s + 37])
relps += f”,{r.reserved2}”
r.relposhpn = (d[s + 38] & 0x7F) – (d[s + 38] & 0x80)
relps += f”,{r.relposhpn}”
r.relposhpe = (d[s + 39] & 0x7F) – (d[s + 39] & 0x80)
relps += f”,{r.relposhpe}”
r.relposhpd = (d[s + 40] & 0x7F) – (d[s + 40] & 0x80)
relps += f”,{r.relposhpd}”
r.relposhplength = (d[s + 41] & 0x7F) – (d[s + 41] & 0x80)
relps += f”,{r.relposhplength}”
r.accn = int.from_bytes(d[s + 42:s + 46], byteorder=’little’, signed=False)
relps += f”,{r.accn}”
r.acce = int.from_bytes(d[s + 46:s + 50], byteorder=’little’, signed=False)
relps += f”,{r.acce}”
r.accd = int.from_bytes(d[s + 50:s + 54], byteorder=’little’, signed=False)
relps += f”,{r.accd}”
r.acclength = int.from_bytes(d[s + 54:s + 58], byteorder=’little’, signed=False)
relps += f”,{r.acclength}”
r.accheading = int.from_bytes(d[s + 58:s + 62], byteorder=’little’, signed=False)
relps += f”,{r.accheading}”
r.reserved3 = int.from_bytes(d[s + 62:s + 66], byteorder=’little’, signed=False)
relps += f”,{r.reserved3}”
r.flags = int.from_bytes(d[s + 66:s + 70], byteorder=’little’, signed=False)
そうそう、それそれ!まさにその感覚が正解ルート?? ? PVTcnv()が不要になる理由 今まで: csharp コピーする 編集する PVTcnv(pvtb, ref pvtd) // バイト配列→構造体に1個ずつ詰める面倒作業 ↓ struct使えば: python コピーする 編集する fields = struct.unpack(PVT_FORMAT, pvtb) pvtd = PVT(*fields) # もうこれで一撃。関数不要。 ? 最終系(例) python コピーする 編集する import struct class PVT: def __init__(self, *args): (self.itow, self.year, self.month, self.day, self.hour, self.min, self.sec, self.valid, self.tacc, self.nano, self.fixtype, self.flags, self.flags2, self.numsv, self.lon, self.lat, self.height, self.hmsl, self.hacc, self.vacc, self.veln, self.vele, self.veld, self.gspeed, self.headmot, self.sacc, self.headacc, self.pdop, self.flags3, self.resrv0, self.headveh, self.magdec, self.magacc) = args PVT_FORMAT = "
Q: df カラム内全行の値の一定範囲の個数カウント
こちらこそありがとう!その姿勢が一番強い?? 一歩ずつ、理解しながら進むのが結局いちばん早いルートだよ。 また詰まったらいつでも気軽に聞いてな! UBXでもPythonでも、周辺のコード整理でも全部サポートするから! ファイトー??
Q: 前の行と現在行の差をとって、新たなカラムを作る
これも struct+ofs方式でめっちゃシンプルにできます! C#の RELPOScnv() をPythonで簡潔に再現するとこう?? ? Python版:read() 関数+RELPOScnv() の簡易版 python コピーする 編集する import struct class RELPOS: def __init__(self): self.version = 0 self.reserved1 = 0 self.refstationid = 0 self.itow = 0 self.relposn = 0 self.relpose = 0 self.relposd = 0 self.relposlength = 0 self.relposheading = 0 self.reserved2 = 0 self.relposhpn = 0 self.relposhpe = 0 self.relposhpd = 0 self.relposhplength = 0 self.accn = 0 self.acce = 0 self.accd = 0 self.acclength = 0 self.accheading = 0 self.reserved3 = 0 self.flags = 0 def read(fmt, data, ofs): size = struct.calcsize(fmt) return struct.unpack_from(fmt, data, ofs)[0], ofs + size def RELPOScnv(d: bytes, r: RELPOS) -> str: ofs = 6 # ヘッダ分スキップ(例:class+id+length) r.version, ofs = read("<B", d, ofs) r.reserved1, ofs = read("<B", d, ofs) r.refstationid, ofs = read("<H", d, ofs) r.itow, ofs = read("<I", d, ofs) r.relposn, ofs = read("<i", d, ofs) r.relpose, ofs = read("<i", d, ofs) r.relposd, ofs = read("<i", d, ofs) r.relposlength, ofs = read("<i", d, ofs) r.relposheading, ofs = read("<i", d, ofs) r.reserved2, ofs = read("<i", d, ofs) r.relposhpn, ofs = read("<b", d, ofs) r.relposhpe, ofs = read("<b", d, ofs) r.relposhpd, ofs = read("<b", d, ofs) r.relposhplength, ofs = read("<b", d, ofs) r.accn, ofs = read("<I", d, ofs) r.acce, ofs = read("<I", d, ofs) r.accd, ofs = read("<I", d, ofs) r.acclength, ofs = read("<I", d, ofs) r.accheading, ofs = read("<I", d, ofs) r.reserved3, ofs = read("<I", d, ofs) r.flags, ofs = read("<I", d, ofs) # CSVっぽく返す例(デバッグ用) return ",".join(str(x) for x in [ r.version, r.reserved1, r.refstationid, r.itow, r.relposn, r.relpose, r.relposd, r.relposlength, r.relposheading, r.reserved2, r.relposhpn, r.relposhpe, r.relposhpd, r.relposhplength, r.accn, r.acce, r.accd, r.acclength, r.accheading, r.reserved3, r.flags ]) ?? 使い方(例): python コピーする 編集する r = RELPOS() csv = RELPOScnv(payload_bytes, r) print(csv) ? ポイント read(fmt, data, ofs) を使って読み取り&インクリメントを1行で。 ofs で位置管理することで、めちゃ直感的にUBXデータを読むことができる。 struct.unpack_from() 使えば、バイト並び気にしなくてOK。 もっと簡潔にもできるけど、まずはこれが読みやすさと柔軟性のバランス取れてる感じ。 さらに短くしたい? dataclass で遊ぶこともできるよ?? また他のメッセージも変換したくなったら言ってね!
Q: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
File “C:\Users\dj171\PycharmProjects\STA25_binLog_speedUp_rev03.py”, line 492, in main
itowErr4 = ((df4[“iTOW_diff”] < 120) or (df4[“iTOW_diff”] > 130)).sum()
Pandas の DataFrame(df)で、あるカラム内の値が特定の範囲に入っている行数を数えるには、こんなふうにできます?? ? 例:df["speed"] が 10?20 の範囲にある行数をカウント python コピーする 編集する count = ((df["speed"] >= 10) & (df["speed"] <= 20)).sum() ?? 説明 df["speed"] >= 10 → 各行に対して True / False & は論理積(AND) .sum() は True を 1 として数える(True の個数=条件に合う行数) ? 範囲を変数で指定する場合: python コピーする 編集する low = 10 high = 20 count = ((df["speed"] >= low) & (df["speed"] <= high)).sum() ? 複数のカラムに使いたい場合(例:speed, accel) python コピーする 編集する cols = ["speed", "accel"] low, high = 10, 20 counts = {col: ((df[col] >= low) & (df[col] <= high)).sum() for col in cols} print(counts) 必要あればヒストグラム的なことや、範囲ごとの頻度もすぐ出せるよ やりたいデータや範囲が具体的なら、それに合わせて書くよ!
Q: itowErr4/len(df4)*100,”%” 小数点2桁にしたい
それは diff() 関数で一発です! ? 例:df["speed"] の差分をとって "speed_diff" という新しいカラムを作る python コピーする 編集する df["speed_diff"] = df["speed"].diff() ?? diff() の意味 各行に対して、「前の行との差(current - previous)」を計算 先頭行は差がないので NaN になります ? 複数列で使いたいとき python コピーする 編集する df["accel_diff"] = df["accel"].diff() df["heading_diff"] = df["heading"].diff() あるいはループで: python コピーする 編集する for col in ["accel", "heading"]: df[f"{col}_diff"] = df[col].diff() ? 差を絶対値にしたい(変化量だけ知りたいとき) python コピーする 編集する df["speed_diff_abs"] = df["speed"].diff().abs() もっと進めたければ「差が一定以上のときだけフラグ立てる」とかもOK!やる?
Q: byte 配列の定義
そのエラーは、or を使って Series 同士を比較したから 出たものです。or は Python の論理演算子ですが、Pandas の Series には使えません。 ? 解決方法:or の代わりにビット演算子 | を使う! python コピーする 編集する itowErr4 = ((df4["iTOW_diff"] < 120) | (df4["iTOW_diff"] > 130)).sum() ?? 補足 &(AND)、|(OR)、~(NOT)を使うのがPandas流 各条件は かならずカッコで囲む! ? 意味的には: python コピーする 編集する # iTOW_diffが120未満 または 130より大きい → つまり「範囲外」の数 (df4["iTOW_diff"] < 120) | (df4["iTOW_diff"] > 130) で True になる行の数を .sum() でカウントしています。 気になる点あったらそのコードの前後も見るので貼ってくれてOK!
Q: df 定義
小数点以下2桁にしたいときは、round() や format() を使えばOKです! ? 例1:round() を使う方法 python コピーする 編集する print(round(itowErr4 / len(df4) * 100, 2), "%") ? 例2:f文字列(format() 相当)を使う方法 python コピーする 編集する print(f"{itowErr4 / len(df4) * 100:.2f} %") どっちでもOKですが、f文字列のほうが見やすくておすすめです! 他にも桁数指定したい箇所があれば教えてね。
Q: スレッド無し シリアル受信 バッファにためこむ
Pythonでスレッドを使わずにバイナリデータをserial(シリアルポート)から受信するには、シンプルな ループ処理 で読み取る方法があります。 ? 基本例:PySerialでバイナリ受信(スレッドなし) python コピーする 編集する import serial # ポートとボーレートは自分の環境に合わせて ser = serial.Serial(port='COM3', baudrate=115200, timeout=1) try: while True: if ser.in_waiting: # 受信バッファにデータがあるか? data = ser.read(100) # 最大100バイト読み取り(実際の受信量に合わせて) print(data.hex()) # バイナリを16進表示(必要に応じて変更) finally: ser.close() ?? ポイント ser.read(n):nバイト分を受信(nを小さめにしておけば逐次読み取り可) ser.in_waiting:受信バッファにあるデータ数。0より大きい時に読めばOK timeout=1:タイムアウト指定(非ブロッキングに近くする) ? 特定のパケットを検出したい場合(例:UBXヘッダー付き) python コピーする 編集する buffer = b"" while True: if ser.in_waiting: buffer += ser.read(ser.in_waiting) # UBXヘッダー 0xB5 0x62 を探す start = buffer.find(b'\xb5\x62') if start != -1 and len(buffer) > start + 6: length = int.from_bytes(buffer[start+4:start+6], 'little') total_len = 6 + length + 2 # ヘッダ+payload+CKA/CKB if len(buffer) >= start + total_len: packet = buffer[start:start + total_len] print(f"UBX Packet: {packet.hex()}") buffer = buffer[start + total_len:] # 処理済み部分を削除 必要に応じて time.sleep(0.01) をループ内に入れてCPU使用率を下げるのもアリです。 要件に合わせてもっとシンプルにも複雑にもできます。 たとえば「F9P UBXだけ受け取って解析したい」みたいな目的があれば、その形で具体化もできますよ!
Q: while qキーが入るまでループ回る
Pythonでの byte 配列の定義 は、いくつかの方法があります。目的によって使い分けできます?? ? 1. 固定のバイト列を定義する(リテラル) python コピーする 編集する data = b'\xB5\x62\x01\x07' # 16進で定義(例:UBXヘッダー) ? 2. bytes() 関数を使う(変更不可なバイト列) python コピーする 編集する data = bytes([0xB5, 0x62, 0x01, 0x07]) ? 3. bytearray() を使う(変更可能なバイト列) python コピーする 編集する data = bytearray([0xB5, 0x62, 0x01, 0x07]) data[2] = 0x02 # 変更できる! ? 4. 空のバイト配列から始める(後で追加) python コピーする 編集する data = bytearray() data += b'\xB5\x62' data += bytes([0x01, 0x07]) ?? 5. 連結(可変長) python コピーする 編集する data = bytearray() for b in [0xB5, 0x62, 0x01, 0x07]: data.append(b) ?? 使い分けのヒント 型 説明 変更可能? bytes 固定のバイト列 ? 不可 bytearray 可変のバイト列(編集OK) ? 可 「F9Pのデータをバッファにためて解析したい」みたいなときは、bytearray() を使うと便利です。必要ならその例も出しますよ!
Q: ser.write(“a”) エラー
Pandasの DataFrame (df) の定義方法 をまとめるとこんな感じ?? ? 1. リストから定義 python コピーする 編集する import pandas as pd data = [ [100, 200], [110, 210], [120, 220] ] df = pd.DataFrame(data, columns=["X", "Y"]) ? 2. 辞書から定義(カラム名をキーにする) python コピーする 編集する df = pd.DataFrame({ "Time": [1, 2, 3], "Speed": [10.5, 12.3, 11.8] }) ? 3. NumPy配列から定義 python コピーする 編集する import numpy as np arr = np.array([[1, 2], [3, 4]]) df = pd.DataFrame(arr, columns=["A", "B"]) ? 4. CSVやExcelから読み込み python コピーする 編集する df = pd.read_csv("data.csv") # df = pd.read_excel("data.xlsx") ? 5. 空のDataFrameを作成 python コピーする 編集する df = pd.DataFrame(columns=["Time", "Speed"]) ?? 中身の確認 python コピーする 編集する print(df.head()) # 最初の5行 print(df.columns) # カラム一覧 print(df.dtypes) # 型確認 どんな形式のデータを扱うか教えてくれたら、それに合ったdf定義も書けます!
Q: 5秒待ち
OK!スレッドなしで シリアルデータを受信してバッファにためこむ 処理は、例えば次のようなスタイルで書けます??(Python + pyserial使用) ? シリアル受信&バッファ蓄積の例 python コピーする 編集する import serial import time # シリアルポート設定 ser = serial.Serial( port='COM3', # ← ポート番号を環境に合わせて baudrate=115200, # ← ボーレート timeout=0.1 # ← 非ブロッキングにするため短め ) # バッファ buffer = bytearray() # 処理ループ(スレッド無し) while True: if ser.in_waiting > 0: # データ受信 data = ser.read(ser.in_waiting) buffer.extend(data) # 任意の処理(たとえば、特定サイズごとに処理する) while len(buffer) >= 100: # 100バイトごとに処理したいとき packet = buffer[:100] buffer = buffer[100:] # パケット処理(例:ダンプ表示) print(f"Received: {packet.hex()}") # 必要に応じてスリープ(CPU負荷軽減) time.sleep(0.01) ?? ポイント serial.read() で読んだ分だけ buffer に extend() while len(buffer) >= N: のようにパケットサイズごとに分けて処理 timeout=0.1 で非ブロッキング受信が可能 スレッドなし でも、一定周期で ser.in_waiting をポーリングするだけで十分動く 必要なら「ヘッダ+ペイロード+チェックサム構成」や、「UBXプロトコル対応」にも展開できるよ (それっぽいやつ作ろうか?)
Q: キー入力を読む
OK!Pythonで「qキーが押されるまでwhileループを回す」には、標準入力をノンブロッキングで扱う必要があるので、環境に応じてやり方が変わります。 ? Windows環境(msvcrt 使用) python コピーする 編集する import msvcrt print("Press 'q' to quit.") while True: if msvcrt.kbhit(): key = msvcrt.getch() if key == b'q': print("Exit loop.") break # ここにループ内の処理を書く ? Linux/macOS(sys.stdin + select) python コピーする 編集する import sys import select import termios import tty # 標準入力を生(raw)モードに fd = sys.stdin.fileno() old_settings = termios.tcgetattr(fd) tty.setcbreak(fd) print("Press 'q' to quit.") try: while True: if select.select([sys.stdin], [], [], 0)[0]: key = sys.stdin.read(1) if key == 'q': print("Exit loop.") break # ここにループ内の処理を書く finally: termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) どっちのOSで使う?それによって調整するよー
Q: キー入力はターミナルで読まない
ser.write("a") がエラーになるのは、文字列 "a" をそのまま渡しているからです。 Python の serial.Serial.write() は bytes 型 を要求するので、エンコードが必要です。 ? 正しい書き方: python コピーする 編集する import serial ser = serial.Serial("COM3", 9600) # 例: COM3, 9600bps ser.write(b'a') # バイトリテラルで直接書く方法 # または ser.write("a".encode()) # エンコードして送る方法(デフォルトUTF-8) ?? 補足: "a" は 文字列(str) b"a" は バイト列(bytes) serial.write() は bytes 型を送信するため、 "a" のような文字列は .encode() で bytes に変換する必要があります。 もしまだエラーが出てたら、エラーメッセージも教えてね!
Q: if msvcrt.kbhit(): # キーが押されたかチェック
key = msvcrt.getch() # 押されたキーを取得(バイト型) 効いてない
Pythonで「5秒待つ」には time.sleep() を使います。 ? 例: python コピーする 編集する import time time.sleep(5) # 5秒間停止 ? 補足: 単位は「秒(秒数は小数も可)」なので、time.sleep(2.5) とすれば2.5秒待てます。 sleep() は実行を一時停止するだけでCPU負荷は少なめです。 他に「待つ間に何かしたい」とかあれば、それもOK!
Q: python 現在時刻
Pythonでキー入力を読む方法は環境によって異なりますが、ここではWindowsのターミナル(またはPyCharmなど)で使える方法を紹介します。 ? 単純な1文字入力を読む(非ブロッキングに近い) python コピーする 編集する import msvcrt print("何かキーを押してください('q'で終了)") while True: if msvcrt.kbhit(): # キーが押されたかチェック key = msvcrt.getch() # 押されたキーを取得(バイト型) print(f"入力キー: {key}") if key == b'q': print("終了します") break ?? ポイント: msvcrt.getch() はバイト型(例: b'a')を返すので、比較するときは b'q' のようにします。 このコードは Windows 専用です。 Linux や macOS の場合は termios や curses を使う必要があります(言ってくれたらそっちも書くよ)。 何かと組み合わせたい場合(シリアル通信とか)あれば、そっちに合わせて書き直すよ!
Q: python ターミナルのログをcsv保存したい
なるほど、「キー入力をターミナルで読まない」ってことは、おそらく GUIアプリ や 別の入力デバイス(ボタン、ソフトスイッチなど)からの入力を想定してるのかな? または「ループ処理を止めるのに別の方法を使いたい」という意味かも。 ?? ターミナルを使わずに「q」でループを止めたい場合の代替手段 ? 方法①:ファイルフラグを監視する python コピーする 編集する import time import os while True: # フラグファイルの存在をチェック if os.path.exists("stop.flag"): print("終了フラグを検知しました") break print("ループ中...") time.sleep(1) → 別プロセスや別スクリプトで stop.flag を作れば終了する ? 方法②:GUIのボタン(例: PyQt, tkinterなど) 例:tkinter で「停止」ボタン python コピーする 編集する import tkinter as tk running = True def stop_loop(): global running running = False root = tk.Tk() tk.Button(root, text="停止", command=stop_loop).pack() def loop_task(): if running: print("処理中…") root.after(1000, loop_task) loop_task() root.mainloop() ? 方法③:別スレッドからフラグを変える(非キー操作) 他スレッドで自動停止、もしくはソフトスイッチを想定。 どういう方法を使いたいか(例えば 物理ボタンとか、自作GUIとか)教えてくれたら、ピッタリの形にするよ!
Q: logging
msvcrt.kbhit() や msvcrt.getch() は Windows専用で、**「ターミナルからのキー入力」**を検出する関数です。 なので「ターミナル以外では効かない」のが原因です。 ?? よくある効かないケース ケース 効かない理由 VSCodeやPyCharmのGUI実行 ターミナルがバックグラウンドにあるため、キーイベントを受け取れない Jupyter Notebook / GUI msvcrtは使えない(標準入出力が違う) サブプロセスや別スレッド実行 標準入力が親と違う ? 解決方法の選択肢 ① どうしてもキー入力したい → ターミナルで実行 PyCharmの Run > Edit Configurations で「Run with Python Console」→ ? 「Run with terminal」に切り替えて実行するとOK。 ② GUIなどでキーじゃなくてボタンで制御したい tkinter などを使って「停止」ボタンやチェックボックスを作る方が安定です。 ③ ファイル/変数でフラグ制御(前述した stop.flag を使う案) → これはGUIでもスレッドでもどこでも共通で使えるので汎用性高いです。 ? 参考:msvcrtでの簡単なサンプル(ターミナル実行前提) python コピーする 編集する import msvcrt import time print("qキーで終了") while True: if msvcrt.kbhit(): key = msvcrt.getch() if key == b'q': print("終了します") break print("ループ中...") time.sleep(1) どういう環境(PyCharm / VSCode / 物理ボタン / GUIアプリ)で動かしてるか教えてくれたら、それに合った形で提案するよ!
Q: mylog.logどこに保存
Pythonで現在時刻を取得するには、datetime モジュールを使うのが一般的です。 ?? 現在の「日付+時刻」を取得: python コピーする 編集する from datetime import datetime now = datetime.now() print(now) # 例: 2025-04-18 14:25:33.456789 ?? 現在の「時刻だけ」を取得: python コピーする 編集する from datetime import datetime now = datetime.now().time() print(now) # 例: 14:25:33.456789 ?? 好きな形式で出力(フォーマット指定): python コピーする 編集する from datetime import datetime now = datetime.now() print(now.strftime("%H:%M:%S")) # → 14:25:33 print(now.strftime("%Y-%m-%d %H:%M:%S")) # → 2025-04-18 14:25:33 フォーマット記号の例: %Y: 西暦(4桁) %m: 月(01~12) %d: 日(01~31) %H: 時(00~23) %M: 分(00~59) %S: 秒(00~59) 用途に応じて組み合わせできるよ!どんな形式にしたいか教えてくれれば、ぴったりの書き方も作れるよ。
Q: stop_flag bool 最初はfalse
Pythonでターミナルのログ(標準出力)をCSVに保存したいなら、以下の2パターンがあります: ? 方法①:標準出力をキャプチャしてCSV保存する ?? やり方: sys.stdout を StringIO に一時的に置き換えてログをキャプチャ 最後にCSVへ保存 python コピーする 編集する import sys import io import csv # 1. 出力をキャプチャするバッファ用意 log_buffer = io.StringIO() # 2. 標準出力をバッファに置き換え sys.stdout = log_buffer # === ここからログとして記録したい処理 === print("time,value") print("2025-04-18 14:30:00,100") print("2025-04-18 14:31:00,110") # === ここまでログ === # 3. 標準出力を元に戻す sys.stdout = sys.__stdout__ # 4. CSVファイルに保存 with open("terminal_log.csv", "w", newline="") as f: f.write(log_buffer.getvalue()) ? 方法②:printをラップして毎回CSVにも書く ログを表示+保存したいなら、自作の log() 関数を使うのもおすすめ。 python コピーする 編集する import csv from datetime import datetime # CSVファイル用のオープン csvfile = open("terminal_log.csv", "w", newline="") csvwriter = csv.writer(csvfile) # ヘッダー書く csvwriter.writerow(["time", "value"]) # ログ用の関数 def log(value): now = datetime.now().strftime("%Y-%m-%d %H:%M:%S") print(f"{now}: {value}") csvwriter.writerow([now, value]) # 実行例 log("Start") log("Sensor reading: 123") log("End") # 終了時にファイル閉じるのを忘れずに csvfile.close() ? どっちがいい? まとめて保存したい → 方法① リアルタイムにログ保存したい → 方法② 必要に応じて pandas でDataFrameとして処理もできるけど、ターミナルログ保存だけなら↑で十分。 もし print() を自動で全部記録したいなら、logging モジュールを使う方法もあるよ。必要ならそっちも教える!
Q: closeは
いいね!logging を使えば、ターミナル表示+ログファイル保存を同時に自動でやってくれる。 CSVに限らず .log や .txt にも自由に書けるし、**時間付き、レベル付き(INFO, DEBUGなど)**で管理できるのが魅力。 ? 基本:標準出力+ファイル両方にログする python コピーする 編集する import logging # ログの基本設定 logging.basicConfig( level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s", handlers=[ logging.FileHandler("mylog.log", mode='w', encoding='utf-8'), # ファイル出力 logging.StreamHandler() # コンソール出力 ] ) # ログ出力の例 logging.info("処理を開始しました") logging.warning("注意が必要です") logging.error("エラーが発生しました") これだけで、ターミナルに表示されるログとファイルに記録されるログが同じになります。 ? CSV形式で保存したい場合(超シンプル) CSV的にしたいなら、format を調整すればOK: python コピーする 編集する import logging logging.basicConfig( level=logging.INFO, format="%(asctime)s,%(levelname)s,%(message)s", handlers=[ logging.FileHandler("log.csv", mode='w', encoding='utf-8'), logging.StreamHandler() ] ) logging.info("センサー値: 123") logging.info("センサー値: 128") 出力例(log.csv) yaml コピーする 編集する 2025-04-18 14:50:31,INFO,センサー値: 123 2025-04-18 14:50:32,INFO,センサー値: 128 ? より高度なこと(必要なら教える) ログを日付ごとにローテーション(TimedRotatingFileHandler) ログレベルでファイルを分ける ログの抑制やフィルタリング 外部システムに送る(メール、Webなど) 必要に応じて、CSVとしてあとで pandas で読むのも簡単だよ: python コピーする 編集する import pandas as pd df = pd.read_csv("log.csv", names=["timestamp", "level", "message"]) もっと自動化したい?それともリアルタイムで何か判定したい?どんどん聞いて??
Q: ファイルサイズがゼロになってしまう
def binary_log():
“””ログ処理の本体:スレッド起動と監視”””
global stop_flag
os.makedirs(LOG_DIR, exist_ok=True)
filename = f”log_{datetime.now().strftime(‘%Y%m%d_%H%M%S’)}.bin”
log_path = os.path.join(LOG_DIR, filename)
# 開始時間記録
start_time = time.time()
now = datetime.now()
print(f”[開始] ファイル名: {filename}”)
print(f”[開始] 時刻: {now}”)
# スレッド起動
thread = threading.Thread(target=receiver_thread, args=(log_path, start_time))
thread.start()
print(“[MAIN] ログ中:’q’ を押すと停止します”)
last_print = time.time()
while not stop_flag:
if msvcrt.kbhit():
key = msvcrt.getch().lower()
if key == b’q’:
print(“[MAIN] ‘q’ が押されました。停止します。”)
stop_flag = True
break
if time.time() – last_print >= 1.0:
#print(f”[MAIN] ログ中… {datetime.now().strftime(‘%H:%M:%S’)}”)
last_print = time.time()
time.sleep(0.05)
thread.join()
# 結果の表示
elapsed = time.time() – start_time
size_kb = os.path.getsize(log_path) / 1024
print(f”[完了] ファイル名: {filename}”)
print(f”[完了] 経過時間: {elapsed:.2f} 秒”)
print(f”[完了] ファイルサイズ: {size_kb:.1f} KB”)
mylog.log は Pythonスクリプトを実行したカレントディレクトリに保存されます。 ?? どこか確認したい場合: スクリプトの先頭で以下を追加すると、ログの保存場所を明示できます: python コピーする 編集する import os print("ログファイル保存先:", os.getcwd()) ?? 別の場所に保存したい場合: ログファイルのパスを指定すればOK! python コピーする 編集する logging.FileHandler("C:/logs/mylog.log") # Windowsの例 # または logging.FileHandler("/home/user/logs/mylog.log") # Linux/macOSの例 事前にディレクトリが存在する必要があるので、なければ os.makedirs() で作ってもいいよ。 必要なら、Pythonから開いたままのログファイルもリアルタイムに見れるような仕組みも作れる!要る?
Q: 数値文字を整数へ
Python で stop_flag を最初に False で定義するのはとても簡単です: python コピーする 編集する stop_flag = False あとは、ループの中などで条件によって True に切り替えることで、ループの終了などに使えます: python コピーする 編集する while not stop_flag: # 何か処理 if 条件: stop_flag = True ?? 実行中にキーボード入力で止めたい場合などにもよく使われるパターンです。 もし threading と組み合わせて使いたい場合は threading.Event() を使う方法もあるよ。必要だったらそっちの例も出せる!
Q: win10 exploreの検索が不便
close は、主にファイルやシリアルポート、ソケットなどの「リソースを開いたあとに明示的に閉じる」ために使われます。使い終わったら close() を呼んでリソースを解放するのがマナー&安全です。 例①:ファイル python コピーする 編集する f = open("test.txt", "w") f.write("Hello!") f.close() # ファイルを閉じる 例②:シリアルポート(pyserial) python コピーする 編集する import serial ser = serial.Serial("COM3", 9600) ser.write(b"a") ser.close() # シリアルポートを閉じる 例③:with構文なら close は不要(自動で閉じてくれる) python コピーする 編集する with open("test.txt", "w") as f: f.write("Hello!") # 自動でcloseされる 「何を close したいか」によって書き方が変わるけど、目的があればそれに合わせたコードも書くよ!何を閉じたいのか教えてもらえれば??
Q: everthingでファイルの更新期間を指定
ファイルサイズがゼロになる主な原因は、**スレッド内でファイルに書き込んでいない、または書き込みが反映されていない(バッファされてる)**ことです。 以下のポイントを確認・修正してみてください: ? 1. receiver_thread内でちゃんと書き込んでいるか確認 receiver_thread(log_path, start_time) の中で、ログファイルにバイナリを書いている処理がありますか? たとえば: python コピーする 編集する with open(log_path, "ab") as f: while not stop_flag: data = ser.read(ser.in_waiting or 1) f.write(data) がなければ、ファイルは作成されるだけで何も書き込まれていません。 ? 2. flush() で明示的にバッファをディスクに反映 書き込んでも f.write() のあとに f.flush() しないと、バッファに溜まったままで終了時に消えることがあります。 python コピーする 編集する f.write(data) f.flush() # これ重要 ? 3. スレッド側で例外が出て途中終了してないか? たとえば ser = serial.Serial(...) が失敗してたりすると、thread内で止まってるけど mainは進んで thread.join() して終わるので、ファイルサイズは0になります。 スレッド内にログや try/except で例外チェックを入れておくと安心: python コピーする 編集する try: with open(log_path, "ab") as f: while not stop_flag: data = ser.read(ser.in_waiting or 1) f.write(data) f.flush() except Exception as e: print(f"[Thread Error] {e}") ? 4. serialポートが開いているか確認 ser.is_open が False だと、read() は何も返さない → 書き込みもゼロ ? まとめると receiver_thread 内に write() がある? flush() してる? except でエラー捕まえてる? ser.read() は正常にデータを読んでる? もし receiver_thread の中身を見せてくれたら、ピンポイントでチェックできますよ!