ラズパイでラジコン製作(Rev#2-2)

2024-04-10 linux raspi sinatra /posts/2024/2024-04-10-control-of-raspi-car.png

前回モータの制御クラスは作れたので、今回はこれ(motors.Motor)を使って、ファイルに記載された速度をリアルタイム(0.1秒ごと)に読み取り反映させるプログラムを作りました。起動時には一旦速度を0にリセットします。読み取り部分に例外処理があるのは、後述の速度書き込みプログラムの動作タイミングによっては空値を読み取ってしまうためです。

import motors
import time

if __name__ == "__main__":
    # Reset the speed to 0.
    with open('motor-left.txt', 'w') as f:
        f.write('0')
    with open('motor-right.txt', 'w') as f:
        f.write('0')

    m = motors.Motors()
    l, r = 0, 0
    # keep reading the speed from file.
    while True:
        try:
            with open('motor-left.txt', 'r') as f:
                l = float(f.read())
            with open('motor-right.txt', 'r') as f:
                r = float(f.read())
            m.left_wheel(l)
            m.right_wheel(r)
        except Exception as e:
            print(f"An error occurred: {str(e)}")
        time.sleep(0.1)

書き込みのAPIはsinatraを利用してhttpサーバを立ち上げて作成します(やっぱ便利)。

#! /usr/bin/env ruby
require 'sinatra'

# Shows the control panel
get '/' do
  erb :index
end

# Write the speed of a motor into file.
get '/set-speed' do
  motor = params[:motor]
  speed = params[:speed].to_f
  File.open("motor-#{motor}.txt", 'w') { |file| file.write(speed) }
end

JavaScriptで呼び出す例(実際のコードからの抜粋)です。スライダーの値が変化する都度、APIをコールします。

// show range value in text
function setSpeed(id,newValue) {
    document.getElementById("value-"+id).innerHTML = newValue;
    // send speed to server using fetch API
    fetch("/set-speed?motor="+id+"&speed="+newValue);
}

document.getElementById("range-left").oninput = function() {
    setSpeed(this.id.replace("range-",""),this.value);
};

document.getElementById("range-right").oninput = function() {
    setSpeed(this.id.replace("range-",""),this.value);
};

動作している動画は Facebook に(また時間ができたらYouTubeにも載せます)。