これまでの色の認識と追跡をベースに、カラーパスを設定し、指定されたルートに沿って無人車両を自動走行させることができます 動画:PID制御による無人車両の自動運転
前章の知識を基礎として、比較的簡単で色認識の応用もあり、主に自動運転の基礎知識を習得し、無人運転で遭遇するさまざまな問題をさらに理解することができます。運転の質問
1. ライブラリをインポートして初期化する
from jetbotmini import Camera
from jetbotmini import bgr8_to_jpeg
from IPython.display import display
from jetbotmini import Robot
import numpy as np
import torch
import torchvision
import cv2
import traitlets
import ipywidgets.widgets as widgets
import numpy as np
#初始化摄像头
camera = Camera.instance(width=300, height=300)
#初始化机器人马达
robot = Robot()
#使用PID控制
import PID
turn_gain = 1.7
turn_gain_pid = PID.PositionalPID(0.15, 0, 0.05)
この部分は非常に単純です。カメラはまだ色認識用に初期化されています。ロボットはモーターとも呼ばれ、車輪の動きを駆動するために使用されます。無人車両をより安定させるために PID 制御を追加します。
2. 表示コンポーネント
# 红色数组
color_lower=np.array([156,43,46])
color_upper = np.array([180, 255, 255])
image_widget = widgets.Image(format='jpeg', width=300, height=300)
speed_widget = widgets.FloatSlider(value=0.4, min=0.0, max=1.0, description='speed')
display(widgets.VBox([
widgets.HBox([image_widget]),
speed_widget,
]))
width = int(image_widget.width)
height = int(image_widget.height)
def execute(change):
global turn_gain
target_value_speed = 0
#更新图片值
frame = camera.value
frame = cv2.resize(frame, (300, 300))
frame = cv2.GaussianBlur(frame,(5,5),0)
hsv =cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)
mask=cv2.inRange(hsv,color_lower,color_upper)
mask=cv2.erode(mask,None,iterations=2)
mask=cv2.dilate(mask,None,iterations=2)
mask=cv2.GaussianBlur(mask,(3,3),0)
cnts=cv2.findContours(mask.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[-2]
# 检测到目标
if len(cnts)>0:
cnt = max (cnts,key=cv2.contourArea)
(color_x,color_y),color_radius=cv2.minEnclosingCircle(cnt)
if color_radius > 10:
# 将检测到的颜色标记出来
cv2.circle(frame,(int(color_x),int(color_y)),int(color_radius),(255,0,255),2)
# 中心偏移量
center = (150 - color_x)/150
#转向增益PID调节
turn_gain_pid.SystemOutput = center
turn_gain_pid.SetStepSignal(0)
turn_gain_pid.SetInertiaTime(0.2, 0.1)
#将转向增益限制在有效范围内
target_value_turn_gain = 0.15 + abs(turn_gain_pid.SystemOutput)
if target_value_turn_gain < 0:
target_value_turn_gain = 0
elif target_value_turn_gain > 2:
target_value_turn_gain = 2
#将输出电机速度保持在有效行驶范围内
target_value_speedl = speed_widget.value - target_value_turn_gain * center
target_value_speedr = speed_widget.value + target_value_turn_gain * center
if target_value_speedl<0.3:
target_value_speedl=0
elif target_value_speedl>1:
target_value_speedl = 1
if target_value_speedr<0.3:
target_value_speedr=0
elif target_value_speedr>1:
target_value_speedr = 1
#设置马达速度
robot.set_motors(target_value_speedl, target_value_speedr)
# 没有检测到目标
else:
robot.stop()
# 更新图像显示至小部件
image_widget.value = bgr8_to_jpeg(frame)
ここが重要な部分で、ターゲット (ここでは赤色) を検出し、検出された位置を通じて左右のモーターの速度を制御し、無人車両の走行と旋回を駆動し、ターゲットの追跡状況を表示します。背景の画像コンポーネントを通じて無人車両を表示します。これは便利です。運転プロセス全体を通じて無人車両のさまざまな状態を確認できます。
3. 呼び出して実行する
execute({'new': camera.value})
camera.unobserve_all()
camera.observe(execute, names='value')
これは、前に紹介したもので、上で定義した実行のコールバックメソッドを使用して、オブザーバー メソッドを呼び出してカメラのデータを更新します。
4. 無人運転車を停止する
import time
camera.unobserve_all()
time.sleep(1.0)
robot.stop()
5.反転
前回の紹介は前進と方向転換についてであり、車を後進させる機能がまだ不足していました。まあ、非常に簡単で、後進機能を呼び出すだけです。
robot.backward(0.8)
time.sleep(0.5)
robot.stop()
6. カラー配列を調整する
ここでは赤いテープで床に貼り付けているので、赤い配列を使用しています。もちろん、ここにマスクを表示して、色の配列が適切に設定されているかどうかをテストすることもできます。コードは次のとおりです
from matplotlib import pyplot as plt
%matplotlib inline
from IPython import display
for i in range(10):
frame = camera.value
frame = cv2.resize(frame, (300, 300))
frame_=cv2.GaussianBlur(frame,(5,5),0)
hsv=cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)
mask=cv2.inRange(hsv,color_lower,color_upper) # 颜色数组的取值范围
mask=cv2.erode(mask,None,iterations=2)
mask=cv2.dilate(mask,None,iterations=2)
mask=cv2.GaussianBlur(mask,(3,3),0)
plt.imshow(mask)
plt.show()
#display.clear_output(wait=True)
ここでは、display.clear_output(wait=True)にアノテーションを付けます。10 枚の画像が連続的に生成され、そのすべてが Jupyter に表示されます。コメントを削除することもできるので、世代ごとに前の画像が消去され、より良く観察するのに便利です。10 枚の連続した写真は、誰でも理解できるようにアニメーション化されています。
マスク がない場合、またはマスクが少ない場合は、線に合わせてカラー配列を調整する必要があります。
7. アナログステアリングホイール
自動運転に制御してほしくない場合もあれば、人間による遠隔操作が必要な場面も多く、例えば鉱山などの危険な場所では、工事車両を遠隔操作して作業を行えることが最適です。
前進、後進、旋回についての上記の理解により、無人車両を制御するためのシミュレートされたステアリングホイールを作成できます。
7.1. ボタンのコンポーネント
# 创建按钮
button_layout = widgets.Layout(width='100px', height='80px', align_self='center')
stop_button = widgets.Button(description='停止', button_style='danger', layout=button_layout)
forward_button = widgets.Button(description='向前', layout=button_layout)
backward_button = widgets.Button(description='向后', layout=button_layout)
left_button = widgets.Button(description='向左', layout=button_layout)
right_button = widgets.Button(description='向右', layout=button_layout)
# 显示按钮
middle_box = widgets.HBox([left_button, stop_button, right_button], layout=widgets.Layout(align_self='center'))
controls_box = widgets.VBox([forward_button, middle_box, backward_button])
display(controls_box)
図に示すように:
ステアリング ホイールのレイアウトについては、 widgets.Layoutを通じてレイヤーを作成し、 widgets.Buttonを通じてその上にボタンを作成し、次にwidgets.HBoxとwidgets.VBoxを使用してボタンを水平方向と垂直方向にレイアウトします。水平:水平、水平。縦: 縦
7.2. 方向制御方法
def stop(change):
robot.stop()
def step_forward(change):
robot.forward(0.8)
time.sleep(0.5)
robot.stop()
def step_backward(change):
robot.backward(0.8)
time.sleep(0.5)
robot.stop()
def step_left(change):
robot.left(0.6)
time.sleep(0.5)
robot.stop()
def step_right(change):
robot.right(0.6)
time.sleep(0.5)
robot.stop()
ストップボタンを前後左右に追加する方法は非常に簡単で、左右のモーターの速度を制御するだけです。
7.3. ボタンのアクション
それぞれのメソッドを定義したら、メソッドをそれぞれのボタンにバインドするだけです。
stop_button.on_click(stop)
forward_button.on_click(step_forward)
backward_button.on_click(step_backward)
left_button.on_click(step_left)
right_button.on_click(step_right)
このようにして、ボタンをクリックして無人車両を遠隔制御できます。
8. ハートビートスイッチ
最後に、無人車両とブラウザ間の接続がまだ存在しているかどうかを検出する簡単な方法であるハートビート スイッチを紹介します。ハートビート周期 (秒単位) は、以下に示すスライダーで調整できます。2 つのハートビート以内にブラウザ間の往復通信がない場合、ハートビートのステータス (状態) 属性値は Dead に設定されます。接続すると、ステータス属性がアライブに設定されます。
from jetbotmini import Heartbeat
heartbeat = Heartbeat()
# 这个函数将在心跳状态改变时被调用
def handle_heartbeat_status(change):
if change['new'] == Heartbeat.Status.dead:
robot.stop()
heartbeat.observe(handle_heartbeat_status, names='status')
period_slider = widgets.FloatSlider(description='period', min=0.001, max=0.5, step=0.01, value=0.5)
traitlets.dlink((period_slider, 'value'), (heartbeat, 'period'))
display(period_slider, heartbeat.pulseout)
自動運転に関する知識を紹介していますので、間違いがあれば修正して、一緒に学んで上達していきましょう!