4号機製作も大詰めに。IchigoJam版と同等の機能はあっさり作れたので、次は、PicoWのWifi機能を活かした設計にします。
RaspberryPiをWifiのアクセスポイントとしてセットアップし、そこにTCPのソケットをオープンしておきます。PicoW側から接続して、センサーの値を送信します。その応答としてモーターの回転(今回はとりあえずON/OFFのみ)を返すという要領です。
サーバのプログラムは以下のような感じ:
#!/usr/bin/env ruby
require 'socket'
# 計算ロジックファイルを読み込む
logic_file = ARGV[0] || 'logic_default.rb'
require_relative logic_file.sub(/\.rb$/, '')
unless defined?(calculate_outputs)
puts "Error: calculate_outputs function not found in #{logic_file}"
exit 1
end
server = TCPServer.new 2000 # Server bind to port 2000
loop do
client = server.accept # Wait for a client to connect
client.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) # クライアント接続も低遅延化
puts "Client connected: #{client.peeraddr[3]}"
begin
# クライアントが接続している間、高速ループを継続
loop do
# センサー値2つを受信 (例: "100,200\n" の形式を想定)
data = client.gets
break if data.nil? # 接続が切れたらループを抜ける
inputs = data.strip.split(',').map(&:to_i)
# センサー値に基づいてモーター速度を計算
outputs = calculate_outputs(inputs)
# モーター速度2つを返信 (例: "150,180\n" の形式)
client.puts outputs.join(',')
end
rescue => e
puts "Error: #{e.message}"
ensure
client.close
puts "Client disconnected"
end
end
logic_defaults.rb の実装例:
# デフォルトのセンサー値からモーター速度を計算する関数
def calculate_outputs(inputs)
sensor1, sensor2 = inputs
motor1 = sensor1 < 50000 ? 1 : 0
motor2 = sensor2 < 50000 ? 1 : 0
[motor1, motor2]
end
以下のようにサーバを実行します。引数としてロジックファイルを指定することが可能です。
ruby tcp-server.rb logic_default.rb
PicoWのコード以下のようになります。センサーの値をサーバに送り、応答を受け取ってモーターの回転方向を決定します。
import socket
import time
import network
from machine import Pin, ADC
# WiFi設定
WIFI_SSID = "360-raspi"
WIFI_PASSWORD = "" # Wifiのパスワード
HOST = 'raspi26.local'
PORT = 2000
led = Pin("LED", Pin.OUT) # Pico W組み込みLED
print("Connecting to WiFi...")
# WiFiに接続
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(WIFI_SSID, WIFI_PASSWORD)
while wlan.isconnected() == False:
print("connecting to %s.." % (WIFI_SSID))
# LED点滅
for _ in range(2):
led.value(1)
time.sleep(0.25)
led.value(0)
time.sleep(0.25)
wlan_status = wlan.ifconfig()
print("connected! as %s" % (wlan_status[0]))
# センサーとモーター用ピンの初期化
adc1 = ADC(0)
adc2 = ADC(1)
ma1 = Pin(14, Pin.OUT)
ma2 = Pin(15, Pin.OUT)
mb1 = Pin(16, Pin.OUT)
mb2 = Pin(17, Pin.OUT)
# 初期状態
ma1.value(0)
ma2.value(0)
mb1.value(0)
mb2.value(0)
print("Connecting to %s:%d..." % (HOST, PORT))
try:
# サーバに接続
sock = socket.socket()
sock.connect(socket.getaddrinfo(HOST, PORT)[0][-1])
# 接続成功: LEDを点灯
led.value(1)
print("Connected!")
# メインループ
while True:
# アナログ入力を読み取り (0-65535の16bit値)
sensor1 = adc1.read_u16()
sensor2 = adc2.read_u16()
# サーバに送信
message = f"{sensor1},{sensor2}\n"
sock.send(message.encode())
# 応答を受信
response = sock.recv(128).decode().strip()
if response:
motor1_val, motor2_val = map(int, response.split(','))
# 0:停止, 正: 前進, 負: 後退
if motor1_val > 0:
ma1.value(1)
ma2.value(0)
elif motor1_val < 0:
ma1.value(0)
ma2.value(1)
else:
ma1.value(0)
ma2.value(0)
if motor2_val > 0:
mb1.value(1)
mb2.value(0)
elif motor2_val < 0:
mb1.value(0)
mb2.value(1)
else:
mb1.value(0)
mb2.value(0)
# デバッグ出力
print(f"Sensors: {sensor1}, {sensor2} -> Motors: {motor1_val}, {motor2_val}")
else:
# 接続が切れた
print("Connection lost")
break
# 短い待機(必要に応じて調整)
time.sleep(0.01)
except Exception as e:
# エラー時: LEDを点滅
print(f"Error: {e}")
for _ in range(10):
led.value(1)
time.sleep(0.2)
led.value(0)
time.sleep(0.2)
finally:
sock.close()
led.value(0)
ma1.value(0)
ma2.value(0)
mb1.value(0)
mb2.value(0)
print("Disconnected")
これらのコードでひとまずは動くのですが、Wifiの接続が安定しない問題が発生しています。しばらく繋がらない場合と、途中で切断されてしまう場合とがあります。引き続き調査していきます。