kanon
主にPC関係の備忘録です。 あと、娘の成長日記も入れたいと思います。
2025年8月17日日曜日
新PC購入【GMKtec Nucbox M5 Plus】
2025年8月4日月曜日
ロボットカー CSIカメラ制御
CSIカメラモジュールが同梱されているが、これが何者なのか分からない。
Raspberry Pi OS(64bit版)には、カメラ認識用の機能がインストールされているようです。
$ rpicam-hello --list-cameras
>>
Available cameras
-----------------
0 : ov5647 [2592x1944 10-bit GBRG] (/base/soc/i2c0mux/i2c@1/ov5647@36)
Modes: 'SGBRG10_CSI2P' : 640x480 [58.92 fps - (16, 0)/2560x1920 crop]
1296x972 [46.34 fps - (0, 0)/2592x1944 crop]
1920x1080 [32.81 fps - (348, 434)/1928x1080 crop]
2592x1944 [15.63 fps - (0, 0)/2592x1944 crop]
ov5647というカメラモジュールが認識されました。
カメラ制御には現在、picamera2というライブラリがよさそうです。
とりあえず撮影
$ libcamera-still -n --width 1280 --height 1024 -o photo.jpg -t 1
※-n : プレビュー非表示、-o : 保存ファイル名、-t : 撮影までの待ち時間(秒)
---camera_test.py---
from picamera2 import Picamera2
from libcamera import Transform
import time
picam2 = Picamera2(0)
config1 = picam2.create_still_configuration(transform=Transform(hflip=False, vflip=False))
#config2 = picam2.create_video_configuration(main={"size": (640, 480)})
picam2.configure(config1)
picam2.start()
time.sleep(2)
picam2.capture_file("camera_image.jpg")
picam2.stop()
------
2592x1944サイズのjpgファイルができました。きちんと撮れてます。
2025年7月31日木曜日
ロボットカー サーボモーター操作
【配線図】
サーボモーターからの配線をPCA9685の15番に接続します。
サーボモーター(SG-90)のデータシートより
PWMperiod:20ms(50Hz) ←freqencyは50がよさそう
Duty cycle:0.5~2.4ms
Operating speed: 0.12 s/60 degree
ライブラリ
adafruit_servokit
kit = adafruit_servokit.ServoKit(channels=16):PCA9685は16ch
kit.servo[15].set_pulse_width_range(500, 2400)
※PCA9685の15番ピンに接続したサーボモーター(SG90)のDuty cycleは0.5ms~2.4msなので上記の設定となる。
kit.servo[15].angle = 0
※PCA9685の15番ピンに接続したサーボモーター(SG90)の角度を0°にする。
servo.py | 備考 |
---|---|
import time import board import busio from adafruit_pca9685 import PCA9685 import RPi.GPIO as GPIO i2c = busio.I2C(board.SCL, board.SDA) pwm = PCA9685(i2c) pwm.frequency = 50 GPIO.setmode(GPIO.BCM) from adafruit_servokit import ServoKit kit = ServoKit(channels=16) kit.servo[15].set_pulse_width_range(500, 2400) kit.servo[15].angle = 0 time.sleep(2) for i in range(180): kit.servo[15].angle = i time.sleep(0.01) for i in range(180): x = 180 - i kit.servo[15].angle = x time.sleep(0.01) GPIO.cleanup() | I2Cオブジェクトの作成 周波数は50Hz adafruit_servokitを使用 Duty cycle:0.5~2.4ms 0°にして 2秒待つ 0~180°を 1°ずつ増やす 0.01秒ごとに 180~0°へ 1°ずつ減らす 0.01秒ごとに ピン解放 |
adafruit_pca9685でPCA9685.set_pwm()が使えない。
pwm.set_pwm(チャンネル, 0, パルス幅) のように使うらしいが、、
2025年7月25日金曜日
ロボットカー DCモーター操作
【配線図】
(画像:https://osoyoo.com/2023/03/09/raspberry-pi-robot-car-v4-0-lesson-1-basic-installation-and-movement/)
osoyoo model X モータードライバー(L298N)
IN1 = 23 #Left motor direction pin Board16
IN2 = 24 #Left motor direction pin Board18
IN3 = 27 #Right motor direction pin Board13
IN4 = 22 #Right motor direction pin Board15
ENA = 0 #Left motor speed PCA9685 port 0
ENB = 1 #Right motor speed PCA9685 port 1
ENA、ENBとはenablePINでPWM制御のためにある。既にosoyooPWMHAT(PCA9685)に接続しているため、併せてPWM制御も行う。
RPi.GPIO
ラズパイのGPIOピンを制御するためのpythonライブラリ。
使い方(例)
①インポート
$ import RPi.GPIO as GPIO # as GPIO とするのが一般的なよう。
②GPIOモードの設定
ピン番号の解釈の指定 BCM と BOARD がある。
$ GPIO.setmode(GPIO.BCM) BCMが多い?
③ピンの設定
各ピンを入力か出力かを設定する。
$ GPIO.setup(17, GPIO.OUT) #ピン17を出力に設定
$ GPIO.setup(22, GPIO.IN) #ピン22を入力に設定
④出力
出力ピン(③でGPIO.OUTに設定したピン)にHIGH(3.3V)かLOW(0V)を設定。
⑤入力
入力ピンの状態を読み取る
$ input_value = GPIO.input(22) #ピン22の状態を読み取り
if input_value == GPIO.HIGH:
print("Button is pressed")
⑥ピンのクリーンアップ
スクリプトの最後に、GPIOピンの状態をリセットする。
$ GPIO.cleanup()
PWM制御
ラズパイにはGPIOピンが少ないため、I2CでPWM制御が可能なPWMドライバを使用することが多いようです。
今回はOSOYOO PWM HAT v1.0(PCA9685)を使用します。
osoyoo PWM HAT(PCA9685)を使用する場合は、
①ライブラリのインポート:adafruit_pca9685
②PCA9685の初期化
③PWM周波数の設定
④DCモーター制御
Python Code
RPi.GPIO
mtr.py | 備考 |
---|---|
import time import board import busio from adafruit_pca9685 import PCA9685 import RPi.GPIO as GPIO i2c = busio.I2C(board.SCL, board.SDA) pwm = PCA9685(i2c) pwm.frequency = 50 IN1 = 23 IN2 = 24 IN3 = 27 IN4 = 22 ENA = 0 ENB = 1 GPIO.setmode(GPIO.BCM) GPIO.setup(IN1, GPIO.OUT) GPIO.setup(IN2, GPIO.OUT) GPIO.setup(IN3, GPIO.OUT) GPIO.setup(IN4, GPIO.OUT) def motor_speed(speed): duty_cycle = int(speed * 65535) pwm.channels[ENA].duty_cycle = duty_cycle pwm.channels[ENB].duty_cycle = duty_cycle def car_stop(): GPIO.output(IN1, GPIO.LOW) GPIO.output(IN2, GPIO.LOW) GPIO.output(IN3, GPIO.LOW) GPIO.output(IN4, GPIO.LOW) motor_speed(0) def car_forward(): GPIO.output(IN1, GPIO.HIGH) GPIO.output(IN2, GPIO.LOW) GPIO.output(IN3, GPIO.LOW) GPIO.output(IN4, GPIO.HIGH) motor_speed(0.5) def car_backward(): def car_right_turn(): def car_left_turn(): def main(): try: car_forward() time.sleep(2) except KeyboardInterrupt: pass finally: car_stop() main() GPIO.cleanup() time.sleep(2) | I2Cオブジェクトの作成 #Left motor direction pin #Left motor direction pin #Right motor direction pin #Right motor direction pin #Left motor PCA9685 port0 #Right motor PCA9685 port1 GPIO設定 speed 0(停止)~1(全速) ctrl + "c" main関数の実行 GPIOピンの解放 |
2025年7月24日木曜日
python ロボットカー
amazonでosoyoo ラズパイ用のロボットカーを購入した。
https://osoyoo.com/2023/03/30/osoyoo-v4-0-robotic-car-for-raspberry-pi-introduction-model2020005500/
環境
Raspberry Pi 3 Model B Plus Rev 1.3
OS:Debian GNU/Linux 12 (bookworm)
言語:python3.11.2
GPIO制御:基本はRPi.GPIO
PWM HAT V1.0
model X motor driver module
CSI camera
Tracking sensor module
Ultrasonic sensor
他にもマイクロSDカードや2000mAh 18650充電池など、ラズパイさえあれば使用可能なキットになっている。
組み立て
小学4年の子供と一緒に組み立て。公式の作成動画を見ながら割と簡単に組み立ては完了。
目標
アンドロイド端末から、カメラを見ながらラジコン操作。 pythonで。
目次
2.モーター制御(後進、旋回)
2020年9月28日月曜日
pythonで子ども用の計算アプリを作成
小学3年の娘の集中力が持続せず、ひき算やわり算の計算がはかどらない。
私がパソコンをいじっている姿をよく見ているためか、パソコンには興味を持ってくれているようなので、ラズベリーパイを使って、計算用のプログラムを作ってみた。
使用言語:python3
---わり算.py---
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
####設定用################################
問題数 = 2 #出題数
ファイル名 = 'わり算.py' #このファイル名
記録ファイル = 'data.csv' #記録ファイルのパス
#######################################
import random
import time
import csv
def 問題(num):
global 得点
a=random.randint(100,999)
b=random.randint(10,99)
c=a//b
d=a%b
正解 = "{}...{}".format(c,d)
print("第{}問:{} ÷ {} =".format(num+1,a,b))
解答 = input()
if 正解 == 解答:
得点 = 得点 + 1
print("正解◯")
else:
print("間違い×。正解は" + str(正解))
#記録ファイル参照
print("名前を入力しなさい。(●/●)")
名前 = str(input())
lst = []
記録=1000
with open(記録ファイル ,'r') as file:
reader = csv.reader(file)
lst = [r for r in reader]
for row in lst:
if row[0] == ファイル名:
if row[1] == 名前:
記録 = int(row[2])
#名前が違う場合に再入力を強制する。
while [str(ファイル名),str(名前),str(記録)] not in lst:
print("名前が違うよ。もう一度名前を入力しなさい")
名前=input()
for row in lst:
if row[0] == ファイル名:
if row[1] == 名前:
記録 = int(row[2])
else:
print("記録は {} 秒です".format(記録))
#開始
得点 = 0
print("〇あまり〇 → 〇...〇 の形で答えなさい")
print("Enterキーで開始 全{}問".format(問題数))
input()
start=time.time()
#ループ開始
for num in range(問題数):
問題(num)
print("-------------------")
#ループ後の処理
finish=time.time()
経過時間=int(finish-start)
print("得点:{}/{} 点。記録は {} 秒です".format(得点,問題数,経過時間))
if 得点 == 問題数:
if 記録 > 経過時間 :
sec = 記録 - 経過時間
print("新記録達成!! {} 秒更新".format(sec))
for row in lst:
if row[0] == ファイル名:
if row[1] == 名前:
row[2]=str(経過時間)
with open(記録ファイル ,'w',encoding='utf-8') as file:
writer = csv.writer(file)
writer.writerows(lst)
else:
sec = 経過時間 - 記録
print("残念!" + str(sec) + "秒とどかず")
else:
print("{}点目指してがんばれ!!".format(問題数))
print("Enterキーで終了")
input()
# 使用方法
# ターミナルで保存したディレクトリへ移動し、”sudo chmod 755 か
わり算.py”を実行しファイルに実行権限を与える。
# 記録ファイルに「わり算.py,名前,999」を追記(なければ新規作成)する。
# ダブルクリックし、端末で実行を選択する。
#説明
#def 問題(num): ここだけ変えれば、いろいろな問題に対応可能。
#記録ファイル参照:csvファイルを参照し、ユーザーごとの記録を表示する。
#名前が違う場合に再入力を強制する。:
data.csvに[名前,ファイル名,*]がなければ、名前が違うとして再入力を促す。
#開始:
#ループ開始:
for A in range Bを使用し、B(問題数)回ループさせる。
#ループ後の処理:
time.time()を使用し、開始時と終了時の時間差を取得する。
満点でかつ、記録を更新すれば、新たにcsvファイルに記録を上書きする。
ファイル名 = __file__とするとなぜかうまく行かない。
LXTerminalのフォントサイズが小さく、見えにくい場合には、ターミナルを起動して、「編集→設定(s)→スタイル→フォント」でデフォルトのサイズを変更可能。
5インチディスプレイだと下が表示されない問題があるので、
$ sudo nano /boot/config.txt
末尾に”display_rotate=1”を追記し保存。
$ sudo reboot
90度回転されて表示されるので、下まで確認できる。設定後は追記した一文を削除して再起動。
Failed to execute child process "xterm"(そのようなファイルやディレクトリはありません):と表示される場合は、/usr/bin/xtermがないので、シンボリックリンクを作成します。
$ cd /usr/bin
$ sudo ln -s lxterminal xterm
2020年7月7日火曜日
ラズベリーパイ 録画サーバー
※録画した動画をアップロードするのは犯罪ですのでしてはいけません。
※私的複製であれば、放送波を正規の方法(B-casカード) で復調しているだけで、ダビング10などの暗号化を解除している訳ではないので、現行法上はグレーゾーンの話題です。今後の法改正次第では違法となる可能性があるので、ご注意ください。(法解釈が間違っていたらごめんなさい🙇)
用意するもの
・Raspberry Pi 3B+
・KTV-FSUSB2
・recfsusb2n_http_patch2.zip(ダウンロード先:適当な何かの別館にあるダウンロードページ)パスワードは適当な何かの別館内に記載あり
・Mirakurun(使用verは3.1.0)
・Chinachu
・ffmpeg (最新verは4.1.4)

◆導入
ターミナル | ||
---|---|---|
1 | $ sudo apt update | おまじない |
2 | $ sudo apt upgrade | |
3 | $ sudo apt install libboost-all-dev | libboost1.50-allでは上手くいかなかった。 |
4 | $ sudo apt install git | 最新バージョン (1:2.20.1-2+deb10u3) |
5 | $ git clone https://github.com/sh0/recfsusb2n | Cloning into 'recfsusb2n'... remote: Enumerating objects: 62, done. remote: Total 62 (delta 0), reused 0 (delta 0), pack-reused 62 Unpacking objects: 100% (62/62), done. |
6 | $ cd recfsusb2n | |
7 | $ mkdir patch | |
8 | $ cd patch | |
9 | $ mv /home/pi/Downloads/recfsusb2n_http_patch2.zip ./ | recfsusb2n_http_patch2.zipをDownloadsに保存した場合。 素直にsambaとかでカット&ペーストした方が早い |
10 | $ unzip recfsusb2n_http_patch2.zip | zipファイルを解凍 Archive: recfsusb2n_http_patch2.zip inflating: decoder.h inflating: tssplitter_lite.cpp inflating: tssplitter_lite.h inflating: readme_patch.txt inflating: Makefile inflating: fsusb2n.cpp |
11 | $ mv Makefile ../src $ mv fsusb2n.cpp ../src $ mv tssplitter_lite.h ../src $ mv decoder.h ../src $ mv tssplitter_lite.cpp ../src | 5つのファイルをsrcディレクトリに移動 素直にsambaを使おう。 |
12 | $ cd ../src $ nano Makefile | srcディレクトリに移動して、Makefileを編集 4か所 |
13 | $ make | /usr/bin/ld:-lboost_thread-mtが見つかりませんと出た時は、Makefil15行目の-mtを削除する。 |
14 | $ sudo cp recfsusb2n /usr/local/bin/recfsusb2n | パスの通ったディレクトリにコピー |
/home/pi/fsusb2n/src/Makefile | |
---|---|
1 | # options |
2 | B25 = -DB25 |
3 | |
4 | ifdef B25 |
5 | B25_PATH = ./arib25 |
6 | B25_OBJS = B25Decoder.o |
7 | B25_OBJS_EXT = $(B25_PATH)/arib_std_b25.o $(B25_PATH)/b_cas_card.o $(B25_PATH)/multi2.o $(B25_PATH)/ts_section_parser.o |
8 | endif |
9 | |
10 | CXX = g++ |
11 | CXXFLAGS = -O2 -march=native -g -Wall -pthread -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 $(B25) ※”-march=native”を削除 |
12 | CC = gcc |
13 | CFLAGS = -O2 -march=native -g -Wall -pthread -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 $(B25) ※”-march=native”を削除 |
14 | OBJS = fsusb2n.o usbops.o em2874-core.o ktv.o IoThread.o tssplitter_lite.o $(B25_OBJS) |
15 | #LIBS = -lpthread -lboost_system -lboost_thread-mt -lboost_filesystem ※"#"と"-mt"を削除 |
16 | #LIBS = -lpthread -lboost_thread-mt -lboost_filesystem ※#を追加してコメントアウト |
17 | TARGET = recfsusb2n |
18 | |
19 | all: $(TARGET) |
20 | |
21 | clean: |
22 | rm -f $(OBJS) $(B25_OBJS_EXT) $(TARGET) |
23 | $(TARGET): $(OBJS) $(B25_OBJS_EXT) |
24 | $(CXX) -o $(TARGET) $(OBJS) $(B25_OBJS_EXT) $(LIBS) |
25 | |
26 | depend: |
27 | $(CXX) -MM $(OBJS:.o=.cpp) > Makefile.dep |
28 | |
29 | -include Makefile.dep |
◆録画テスト
実際に録画できるか試してみる。ターミナル | ||
---|---|---|
1 | $ sudo nano /lib/udev/rules.d/89-tuner.rules | 89-tuner.rulesファイルを新規作成して下の2行を書き込み保存。 |
2 | $poweroff | シャットダウン |
/lib/udev/rules.d/89-tuner.rules | |
---|---|
1 | # FSUSB2N |
2 | SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="0511", ATTRS{idProduct}=="0029", MODE="0664", GROUP="video" |
KTV-FSUSB2を接続し、Raspberry Pi 3B+を起動。
$ lsusb
>>ID 0511:0029 N'Able (DataBook) Technologies, Inc.
$ recfsusb2n --b25 --sid hd --wait 100 13 10 test.ts
>>チャンネル 録画時間(秒) ファイル名
/home/pi/test.ts(約18MiB)ができていれば成功。
recfsusb2n ver. 0.9.2
ISDB-T DTV Tuner FSUSB2N
device: "/dev/bus/usb/001/004"
pid = 4677
B25Decoder initialized.
チャンネル一覧
東北放送 | NHKEテレ | NHK総合 | 宮城テレビ | 東日本放送 | 仙台放送 |
---|---|---|---|---|---|
19 | 13 | 17 | 24 | 28 | 21 |
ハードウェアエンコード
ffmpegのセットアップ$ sudo apt install ffmpeg インストール済みだった
$ ffmpeg -codecs | grep h264
>> DEV.LS h264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (decoders: h264 h264_v4l2m2m h264_mmal ) (encoders: libx264 libx264rgb h264_omx h264_v4l2m2m h264_vaapi )
$ ffmpeg -i test.ts -codec:v h264_omx -b:v 3000k test.mp4
>>codecにh264_omxを指定することでハードウェアエンコーダを利用してh.264に変換する。-b:v 3000k は映像ビットレートを3000kB/sに指定。>>1.02倍速で変換。
実際に運用するには番組表から予約できないと使えない。
①Mirakurun + chinachu
②Mirakurun + EPGStation
あたりが有名らしい。ただ、チューナーにはPX-S1UDやPT3とかが一般的で、KTV-FSUSB2とかの情報は結構少ない。
今回は①のchinachuを導入してみる。比較的情報量が多いため。EPGStationだと録画後のエンコードまで可能らしい。
Mirakurunの導入
$ sudo apt install build-essential curl git-core vainfo$ curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
$ sudo apt install nodejs
PM2のインストール
$ sudo apt install npm
※npm(Node Package Manager)Node.jsのパッケージを管理する。
$ sudo npm install pm2 -g
Mirakurun のインストール
$ sudo npm install mirakurun -g --unsafe-perm --production
$ sudo EDITOR="nano" mirakurun config server
※EDITOR=nano といれるとnanoで編集できる。入れないとVim。
server
logLevel: 2
path: /var/run/mirakurun.sock
port: 40772
※コピー&ペーストするとインデントエラーでMirakurunが上手く起動しない。
$ sudo EDITOR="nano" mirakurun config tuners
tuners
- name: FSUSB2N
types:
- GR
command: recfsusb2n -b <channel> - -
isDisabled: false
$ sudo EDITOR="nano" mirakurun config channels
channels
- name: NHKEテレ
type: GR
channel: '13'
- name: NHK総合
type: GR
channel: '17'
- name: TBCテレビ
type: GR
channel: '19'
- name: 仙台放送
type: GR
channel: '21'
- name: ミヤギテレビ
type: GR
channel: '24'
- name: 東日本放送CH
type: GR
channel: '28'
Chinachuのインストール
実行ユーザーのvideoグループへの登録$ sudo gpasswd -a pi video
Gitリポジトリからクローン・インストール
$ git clone git://github.com/kanreisa/Chinachu.git ~/chinachu
$ cd ~/chinachu/
$ ./chinachu installer
1) Auto (full) 3)Node.js Environment 5)ffmpeg
2)submodule 4)Node.js Modules
what do you install? > 1
※結構時間がかかります。気長に待ちましょう。数時間?
$ cp config.sample.json config.json
$ sudo nano config.json
"uid": "pi", ※デフォルトのnullからpi(実行ユーザー名)へ変更。
"recordedDir" : "./recorded/",録画用ディレクトリ
"wuiOpenHost": "0.0.0.0" , ※wuiHostからwuiOpenHostへ名前変更。
空の設定ファイルを作成
$ echo [] > rules.json
サービスが実行可能か確認。
$ ./chinachu service wui execute
$ ./chinachu service operator execute
※pm2へchinachu-wuiとchinachu-operatorを登録する。
$ sudo pm2 start processes.json
$ sudo pm2 save
[PM2][ERROR] Error: Interpreter .nave/node is NOT AVAILABLE in PATH. (type 'which .nave/node' to double check.) |
---|
$ sudo pm2 start processes.jsonとすると、 [PM2][ERROR] Error: Interpreter .nave/node is NOT AVAILABLE in PATH. (type 'which .nave/node' to double check.)とエラーが出て、先に進めなかった。どうやら、chinachu-wuiとchinachu-operatorが起動していないよう。 シンボリックリンクがなかったため(又は無効なリンク)のようで、 $ sudo ln -s /usr/bin/node /home/pi/chinachu/.nave/node $ sudo ln -s /usr/bin/npm /home/pi/chinachu/.nave/npm とすることで、無事正常に起動した。 |
ブラウザで http://IPAddress:20772 と入力すると、chinachuで番組表からの予約が可能。