サーバルです
骨折41日目
あいかわらず骨折部の一部が腫れているが、考えてみると一部癒着が剥れて炎症が強まったような気がしている。
現状では指を曲げる場合は自力でかなり力を入れて握れるが、伸ばすほうは自力でほとんど曲げられない。一方で、他力だと曲げる方向には最大まで曲がらず、伸ばすほうならかなり曲げることができる。
基本的には曲げるほうに集中してリハビリをしてたけど、伸ばすほうを意識しはじめたら腫れてきたように思う。というか指先を持って伸ばすほうに動かしたらビリビリと剥れるような感覚はあったんだよな……
骨折40日目
通院でレントゲン。診察で動きも問題ないのでもう通院しなくて良いとのこと。
指が完全に伸びない (骨折部もそうだけど、骨折部の先の関節が伸びきらない) のは多少骨折部で腱が癒着してるからだろうとのこと。動かしてると改善していくという話だった。
指を伸ばしたときに、特定の部分にでっぱりが発生するが、これはまだ腫れてるせいとのこと。
だいたい日常生活では問題ないぐらいには使えるようになったけど、可動域はあいかわらず狭い。手のひらをついたりすると痛いので部分的に動作に制限がある。
Mac でウェブカメラの定期撮影を Swift で書く
macOS 用にウェブカメラからjpgを取得するコマンドラインツールにimagesnapというのがある。単発で使うには問題ないんだけど、インターバル撮影を数時間続けたところメモリを食いつくして死んだため代替を書く気概になった。
毎回プロセスを立ちあげればメモリリークが起きないが、カメラデバイスを初期化する処理が数秒あって遅いので、できればちゃんとデバイスを開きっぱなしで動かしたい。
やりたいこと
やりたいことはウェブカメラ経由のタイムラプスの撮影で、撮影したファイルはffmpegで読みこませる。そのためファイル名にも要件がある
- foobar-00001.jpg みたいなファイル名にする
- メモリリークしない
swift で書きなおす
xcrun swift で動かせるとスクリプト的に使えて便利なので、そのようにした。特に難しいことはしてないんだけど、やりかたをググっても API がのきなみ古いとかでやる気がなくなる。現時点では最新の方法だが、iOS だと既に deprecated になっているAPIが macOS だと生きていたりするのでややこしい。
#!/usr/bin/xcrun swift
import Darwin
import Cocoa
import AVFoundation
struct ProgramOption {
var deviceName: String? = nil
var list: Bool = false
var help: Bool = false
var interval: Double = 10
var format: String = "snapshot-%05d.jpg"
var sequence: Int = 1
}
var option = ProgramOption()
var args = CommandLine.arguments
while (!args.isEmpty) {
let arg = args.removeFirst()
switch arg {
case "-h", "--help":
option.help = true
case "-l", "--list":
option.list = true
case "-d", "--device":
let val = args.removeFirst()
option.deviceName = val
case "-i", "--interval":
let val = args.removeFirst()
option.interval = Double(val)!
case "-f", "--format":
let val = args.removeFirst()
option.format = val
case "--start":
let val = args.removeFirst()
option.sequence = Int(val)!
default:
break
}
}
if option.help {
print("Usage: $0 [options]")
print(" -h --help show help")
print(" -l --list list devices")
print(" -d [name] --device [name] specify camera device name (default: system default device)")
print(" -i [num] --interval [num] specify snapshot interval (default: 10)")
print(" -f [format] --format [format] specify filename format (default: snapshot-%05d.jpg)")
print(" --start [num] specify start number of sequence")
exit(0)
}
if option.list {
let devices = AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo)! as! [AVCaptureDevice]
for var device in devices {
print(String(format: "'%@' (%@ %@)", device.localizedName, device.manufacturer, device.modelID))
}
exit(0)
}
print("opening capture device")
let device: AVCaptureDevice
if option.deviceName != nil {
let devices = AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo)! as! [AVCaptureDevice]
device = devices.first(where: { (i) in i.localizedName == option.deviceName })!
print(device)
} else {
print("using default capture device")
device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)!
}
let input = try! AVCaptureDeviceInput.init(device: device)
let output = AVCaptureStillImageOutput()
let session = AVCaptureSession()
session.sessionPreset = AVCaptureSessionPresetPhoto
session.addInput(input)
session.addOutput(output)
session.startRunning()
let connection = output.connection(withMediaType: AVMediaTypeVideo)!
let semaphore = DispatchSemaphore(value : 0)
var seq = option.sequence
while (true) {
output.captureStillImageAsynchronously(
from: connection,
completionHandler: { (imageDataBuffer, error) in
print("captured")
semaphore.signal()
if let e = error {
print(e.localizedDescription)
return
}
if let buffer = imageDataBuffer {
if let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(buffer) {
do {
let filename = String(format: option.format, seq)
try imageData.write(to: URL.init(fileURLWithPath: filename), options: [])
seq += 1
print("wrote to file \(filename)")
} catch {
print("failed to write file...")
exit(1)
}
}
} else {
print("buffer is empty")
}
}
)
// output.isCapturingStillImage
semaphore.wait()
print("sleep \(option.interval) sec")
Thread.sleep(forTimeInterval: option.interval)
}
デスク整理用のなにか
デスクを部屋の中に向けて配置しているけど、必然的に部屋の中側にケーブルが煩雑に這うようになるので、これの見た目を多少でも良くしようと覆いをかぶせている。(わかりにくいと思うけど)
これまで微妙な固定方法をとっていたが、3D プリンタでうまい具合の部品を出せた。覆い自体はプラスチックダンボールに木目シートを貼ったもので、軽いので、単にクリップで止められるようにした。2つプリントしてつけてる。
ケーブルをある程度束ねておけるようなスペースもつけた。
M15 なら Fusion360 で直接ネジをモデリングしてプリントしても締めることができた。
Prusa i3 MK2S のベッドにウェブカメラC270をつける
表題のようなものは thingverse とかで検索するといろいろあるんだけど、だいたいベッドを固定しているビスと共締めするものになっている。あんまり共締めしたくなかったのでベッドのフレームを挟みこんで固定するようなものをモデリングした。
3つのパーツで、ベッドに近いところは PETG でプリントしている。
C270 用のピント調節機能つきカバー
https://www.thingiverse.com/thing:714475 をベースにして、ピント調節リングだけhttps://www.thingiverse.com/thing:1406879 に変えたものをプリントした。
製品もともとのピント調節だとどうしてもレンズに指がかぶってしまってあわせるのが難しかったのでめっちゃ便利。
Prusa i3 MK2S のエクストルーダー付近
ダストフィルター・オイラー
https://www.thingiverse.com/thing:2086804
一回エクストルーダーが詰まって定量でなくなったことがあったのでつけてみた。埃をふきとると同時に油をつけている。これをつけてからは一回も詰まってないので効果があるっぽい。
30mm ファンカバー
https://www.thingiverse.com/thing:2523236
これ。0.1mm で出力しないとハニカム部分が薄くなりすぎるので罠
ファンカバーはいらないと思っていたけど、糸状になったプラスチックが噛みこむことがあって、そうするとかなり悪い状況になるので多少でも緩和できるかと思ってつけることにした。
40mm ファンカバー
https://www.thingiverse.com/thing:2076234
これのうち FrontFanCover_RoundV2.STL だけ出力した
レイヤーファンノズル
https://www.thingiverse.com/thing:2276997
デフォルトだと横からノズルに風があたるようになっていて、あまり出力レイヤーには風があたらない。PLA だとできるだけ出力したものを急冷させるのが反りを軽減するのに大事らしいので、効果を期待してかえてみた。PETG で出力。