四驱四转移动机器人 web移动端显示
在进行四驱四转机器人控制过程中,由于使用手柄进行进行控制,为了更加清晰的观测到摄像头采集的数据,经过查阅资料 ,以及古月居泡泡论坛的提问,本人将使用手机作为移动端,使用手机Web端查看USB摄像头图像,搭配手柄支架,将手机固定的方式。
硬件如下
Xbox手柄一个,手机一个,移动机器人(ros2 foxy版本)
步骤如下:
1、摄像头画面获取
在ROS 2中使用Python开发摄像头获取包可以让我们轻松地获取摄像头数据,并将其用于后续处理或传输到其他节点。下面是创建一个ROS 2摄像头获取包的步骤:
步骤 1:创建ROS 2功能包
首先,我们需要创建一个ROS 2功能包来容纳我们的摄像头获取代码。打开终端并执行以下命令:
bashCopy code
ros2 pkg create camera_capture_py
这将在当前目录下创建一个名为camera_capture_py
的ROS 2功能包。
步骤 2:创建摄像头获取节点
在刚创建的功能包中,我们需要创建一个ROS 2节点来获取摄像头数据。创建一个名为camera_capture_node.py
的Python文件,并在其中编写以下代码:
pythonCopy codeimport rclpy
from rclpy.node import Node
from sensor_msgs.msg import Image
from cv_bridge import CvBridge
import cv2
class CameraCaptureNode(Node):
def __init__(self):
super().__init__('camera_capture_node')
self.publisher_ = self.create_publisher(Image, 'camera_topic', 10)
self.timer_ = self.create_timer(0.1, self.capture_image)
self.bridge_ = CvBridge()
def capture_image(self):
# 获取摄像头图像
# 这里使用OpenCV来获取摄像头数据
cap = cv2.VideoCapture(0)
ret, frame = cap.read()
cap.release()
if ret:
# 将图像转换为ROS 2图像消息
msg = self.bridge_.cv2_to_imgmsg(frame)
self.publisher_.publish(msg)
def main(args=None):
rclpy.init(args=args)
node = CameraCaptureNode()
rclpy.spin(node)
node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
以上代码创建了一个名为CameraCaptureNode
的ROS 2节点,它会定时获取摄像头图像,并将其发布到名为camera_image
的话题上。请根据需要调整摄像头的索引和图像发布频率。
步骤 3:构建和运行摄像头获取包
完成节点的编写后,我们需要将功能包构建并运行节点。执行以下步骤:
- 打开终端并进入功能包的根目录。
bashCopy code
cd camera_capture_py
- 在终端中构建功能包。
bashCopy code
colcon build
- 在同一终端中,使用以下命令运行摄像头获取节点。
bashCopy code
ros2 run camera_capture_py camera_capture_node.py
现在,ROS 2摄像头获取包已经成功创建,并且节点正在运行以获取摄像头图像并发布到ROS 2话题上。
2、使用WebSocket将图像流传输到Web端
使用Python和ROS2创建的功能包,用于从ROS2图像话题接收图像数据,并通过WebSocket将图像流传输到Web端。下面逐行解释代码,并介绍如何创建ROS2功能包、编译和运行。
代码解释
- 导入所需的Python库和ROS2相关库。
import asyncio
import cv2
import websockets
from cv_bridge import CvBridge
from sensor_msgs.msg import Image
import rclpy
from rclpy.node import Node
- 创建一个名为CameraSubscriber的ROS2节点类,继承自Node类。该节点类用于接收图像消息,并处理WebSocket连接。
pythonCopy codeclass CameraSubscriber(Node):
def __init__(self):
super().__init__('camera_subscriber')
self.bridge = CvBridge()
self.websocket = None
- 在CameraSubscriber类中定义了handle_websocket方法,用于处理WebSocket连接。
pythonCopy code async def handle_websocket(self, websocket, path):
self.websocket = websocket
print("WebSocket connection established.")
while True:
# 接收来自WebSocket客户端的消息
message = await websocket.recv()
print(f"Received message from client: {message}")
- 定义了send_image方法,用于将图像帧数据发送给WebSocket客户端。
pythonCopy code async def send_image(self, image):
if self.websocket:
try:
# 将帧转换为JPEG格式
_, encoded_frame = cv2.imencode('.jpg', image)
# 发送帧数据给WebSocket客户端
await self.websocket.send(encoded_frame.tobytes())
except Exception as e:
print(f"Error sending image: {str(e)}")
- 定义了image_callback方法,用于接收ROS2图像消息,并将其转发给send_image方法发送给WebSocket客户端。
pythonCopy code def image_callback(self, msg):
if self.websocket:
try:
# 将ROS图像消息转换为OpenCV图像格式
frame = self.bridge.imgmsg_to_cv2(msg, desired_encoding='bgr8')
# 在后台发送图像数据
asyncio.create_task(self.send_image(frame))
except Exception as e:
print(f"Error sending image: {str(e)}")
- 在main函数中初始化ROS2节点和订阅图像话题,并创建一个WebSocket服务器来处理WebSocket连接。
pythonCopy codedef main(args=None):
rclpy.init(args=args)
camera_subscriber = CameraSubscriber()
image_subscriber = camera_subscriber.create_subscription(
Image,
'camera_topic',
camera_subscriber.image_callback,
10
)
async def run():
# 启动WebSocket服务器
start_server = websockets.serve(camera_subscriber.handle_websocket, 'localhost', 8001)
try:
async with start_server:
print("WebSocket server started.")
await asyncio.Future() # 保持主循环运行,直到键盘中断
except KeyboardInterrupt:
pass
camera_subscriber.destroy_node()
rclpy.shutdown()
asyncio.run(run())
if __name__ == '__main__':
main()
创建ROS2功能包、编译和运行
下面是创建ROS2功能包、编译和运行的步骤:
- 创建ROS2功能包:使用以下命令创建一个ROS2功能包,用于包含上述代码。
bashCopy code
ros2 pkg create my_package
- 将上述代码复制到
my_package
目录中的camera_subscriber.py
文件中。 - 在
my_package
目录中创建一个名为launch
的文件夹,并在其中创建一个名为camera_subscriber.launch.py
的文件。 - 将以下内容添加到
camera_subscriber.launch.py
文件中,用于启动ROS2节点。
pythonCopy codeimport launch
from launch_ros.actions import Node
def generate_launch_description():
return launch.LaunchDescription([
Node(
package='my_package',
executable='camera_subscriber',
name='camera_subscriber',
output='screen'
)
])
- 在终端中,进入ROS2工作空间根目录,并编译功能包。
bashCopy codecd ~/ros2_ws
colcon build --packages-select my_package
- 运行ROS2节点。
bashCopy code
ros2 launch my_package camera_subscriber.launch.py
现在,您的ROS2节点将接收图像消息,并通过WebSocket服务器将图像流传输到Web端。
web端接收视频流
在Web开发中,使用WebSocket可以实现实时的双向通信。结合HTML5的video元素,我们可以在Web端接收并显示视频流。下面是在Web端接收视频流的步骤:
步骤 1:建立WebSocket连接
首先,我们需要在Web端建立WebSocket连接以接收视频流。在JavaScript中,可以使用WebSocket API来创建WebSocket对象,并指定要连接的服务器地址。以下是建立WebSocket连接的示例代码:
javascriptCopy code
const websocket = new WebSocket('ws://localhost:8001');
将上述代码放置在Web页面的JavaScript脚本中,并将服务器地址替换为实际的WebSocket服务器地址。
步骤 2:接收和显示视频流
接下来,我们需要编写JavaScript代码来接收和显示视频流。通过WebSocket连接,我们可以接收来自服务器的视频帧数据,并使用HTML5的video元素显示这些帧。以下是接收和显示视频流的示例代码:
javascriptCopy codeconst videoElement = document.getElementById('video');
websocket.onmessage = function(event) {
// 接收到视频帧数据
const frameData = event.data;
// 将帧数据转换为Blob对象
const blob = new Blob([frameData], { type: 'image/jpeg' });
// 创建URL对象
const url = URL.createObjectURL(blob);
// 设置<video>元素的源为接收到的视频帧
videoElement.src = url;
};
websocket.onclose = function() {
// WebSocket连接关闭
console.log('WebSocket connection closed.');
};
在上述代码中,我们通过WebSocket的onmessage
事件处理程序接收到视频帧数据。然后,我们将帧数据转换为Blob对象,并使用URL.createObjectURL()方法创建URL对象。最后,我们将URL对象设置为video元素的源,从而显示接收到的视频帧。
确保在HTML文件中定义了一个video元素,并为其分配一个唯一的ID,例如:
htmlCopy code
<video id="video" autoplay></video>
这将在Web页面中显示一个video元素,并使其自动播放视频。
问题补充
当使用Python的WebSocket进行视频流传输到Web端时,有时可能会遇到一些问题。
问题1: Failed to open a WebSocket connection: invalid Connection header: keep-alive.
当浏览器尝试直接连接WebSocket服务器时,会出现”Failed to open a WebSocket connection: invalid Connection header: keep-alive.”错误。这是因为您需要一个WebSocket客户端来连接WebSocket服务器,而不能直接在浏览器中访问WebSocket服务器。
解决方法: 确保您在Web端使用WebSocket客户端连接WebSocket服务器。
javascriptCopy code
const websocket = new WebSocket('ws://localhost:8001');
问题2: 没有接收到视频帧
如果WebSocket连接成功,但未接收到视频帧,可能存在以下问题。
-
验证视频帧是否发送成功
-
检查WebSocket服务器的代码,确保它正确发送视频帧。可以添加调试语句或记录来验证视频帧是否按预期发送。
-
确认视频帧是否正确编码和发送
-
确保在将视频帧发送到WebSocket连接之前,正确对其进行编码(如JPEG或PNG)。在服务器和客户端双方的编码和解码步骤上仔细检查,确保正确性。
-
检查WebSocket客户端代码
-
检查运行在浏览器WebSocket客户端中的JavaScript代码。确保它正确处理接收到的视频帧,并使用HTML的
<video>
元素更新接收到的帧。请仔细检查代码是否存在错误或缺失功能。 -
验证HTML
<video>
元素的兼容性 -
确保在Web页面中的HTML
<video>
元素正确设置以显示接收到的视频帧。检查元素是否具有所需的属性,如src
和autoplay
,并正确设置样式。 -
检查浏览器控制台
评论(0)
您还未登录,请登录后发表或查看评论