把去年的二维码检测、图生文客户端、锥桶检测v8给加了进来,二维码检测新增深度相机检测

This commit is contained in:
2026-06-16 21:05:14 +08:00
parent 652c97646e
commit 5535dcab54
34 changed files with 1557 additions and 1 deletions

121
keyboard_control.py Executable file
View File

@@ -0,0 +1,121 @@
#!/usr/bin/env python3
"""
Keyboard control node for robot chassis.
W/S: forward/backward
A/D: turn left/right
I/K: increase/decrease linear speed
J/L: increase/decrease angular speed
X: stop
Q: quit
"""
import rclpy
from rclpy.node import Node
from geometry_msgs.msg import Twist
import sys
import select
import termios
import tty
HELP = """
========================================
Keyboard Control
========================================
W/S : forward / backward
A/D : turn left / turn right
I/K : linear speed +/- (step 0.05)
J/L : angular speed +/- (step 0.1)
X/Space: stop
Q : quit
========================================
Current: lin=%.2f ang=%.2f
"""
class KeyboardControl(Node):
def __init__(self):
super().__init__("keyboard_control")
self.pub = self.create_publisher(Twist, "/cmd_vel", 10)
self.lin_speed = 0.2
self.ang_speed = 0.5
self.lin_step = 0.05
self.ang_step = 0.1
self.print_help()
self.create_timer(0.05, self.read_key)
def print_help(self):
print(HELP % (self.lin_speed, self.ang_speed))
def get_key(self):
fd = sys.stdin.fileno()
old = termios.tcgetattr(fd)
try:
tty.setraw(fd)
r, _, _ = select.select([sys.stdin], [], [], 0.05)
if r:
return sys.stdin.read(1)
return None
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old)
def read_key(self):
key = self.get_key()
if key is None:
return
twist = Twist()
if key == 'w':
twist.linear.x = self.lin_speed
elif key == 's':
twist.linear.x = -self.lin_speed
elif key == 'a':
twist.angular.z = self.ang_speed
elif key == 'd':
twist.angular.z = -self.ang_speed
elif key == 'i':
self.lin_speed = round(self.lin_speed + self.lin_step, 2)
self.print_help()
return
elif key == 'k':
self.lin_speed = round(max(0.0, self.lin_speed - self.lin_step), 2)
self.print_help()
return
elif key == 'j':
self.ang_speed = round(self.ang_speed + self.ang_step, 2)
self.print_help()
return
elif key == 'l':
self.ang_speed = round(max(0.0, self.ang_speed - self.ang_step), 2)
self.print_help()
return
elif key == 'x' or key == ' ':
twist.linear.x = 0.0
twist.angular.z = 0.0
print("*** STOP ***")
elif key == 'q' or ord(key) == 3:
twist.linear.x = 0.0
twist.angular.z = 0.0
self.pub.publish(twist)
self.get_logger().info("Quitting...")
raise SystemExit
else:
return
self.pub.publish(twist)
def main():
rclpy.init()
try:
rclpy.spin(KeyboardControl())
except SystemExit:
pass
finally:
rclpy.shutdown()
if __name__ == "__main__":
main()

View File

@@ -147,7 +147,7 @@ controller_server_rclcpp_node:
local_costmap:
local_costmap:
ros__parameters:
update_frequency: 5.0
update_frequency: 1.0
publish_frequency: 2.0
transform_tolerance: 0.5
global_frame: odom

View File

@@ -0,0 +1,75 @@
cmake_minimum_required(VERSION 3.5)
project(qr_detection)
# Default to C99
if(NOT CMAKE_C_STANDARD)
set(CMAKE_C_STANDARD 99)
endif()
# Default to C++14
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 14)
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
# Find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)
find_package(dnn_node REQUIRED)
# find_package(hbm_img_msgs REQUIRED)
find_package(sensor_msgs REQUIRED)
find_package(ai_msgs REQUIRED)
find_package(OpenCV REQUIRED)
find_package(geometry_msgs REQUIRED)
find_package(rosidl_default_generators REQUIRED)
find_package(PkgConfig REQUIRED)
pkg_check_modules(ZBar REQUIRED zbar)
# rosidl_generate_interfaces(${PROJECT_NAME}
# "msg/SampleMessage.msg"
# )
# # Define executables
# add_executable(talker src/publisher_hbmem.cpp)
# ...
# add_executable(qr_dete_node src/qr_dete.cpp)
# ...
# install(DIRECTORY
# ${PROJECT_SOURCE_DIR}/launch/
# DESTINATION share/${PROJECT_NAME}/launch)
# ---- qr_dete_depth_node (sensor_msgs::Image, no hbmem) ----
add_executable(qr_dete_depth_node src/qr_dete_depth.cpp)
ament_target_dependencies(qr_dete_depth_node
rclcpp
std_msgs
sensor_msgs
geometry_msgs
)
target_include_directories(qr_dete_depth_node PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
${OpenCV_INCLUDE_DIRS} ${ZBar_INCLUDE_DIRS})
target_link_libraries(qr_dete_depth_node
${OpenCV_LIBS} ${ZBar_LIBRARIES}
)
install(TARGETS qr_dete_depth_node
DESTINATION lib/${PROJECT_NAME})
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
set(ament_cmake_copyright_FOUND TRUE)
set(ament_cmake_cpplint_FOUND TRUE)
ament_lint_auto_find_test_dependencies()
endif()
ament_package()

View File

@@ -0,0 +1,37 @@
import os
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.actions import IncludeLaunchDescription
from launch_ros.actions import Node
from launch.substitutions import TextSubstitution
from launch.substitutions import LaunchConfiguration
from launch.launch_description_sources import PythonLaunchDescriptionSource
from ament_index_python import get_package_share_directory
def generate_launch_description():
nv12_codec_node = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(
get_package_share_directory('hobot_codec'),
'launch/hobot_codec_decode.launch.py')),
launch_arguments={
# 'codec_channel': '2',
'codec_in_mode': 'ros',
'codec_out_mode': 'shared_mem',
'codec_sub_topic': '/image',
'codec_pub_topic': '/hbmem_img'
}.items()
)
qr_detection_node = Node(
package='qr_detection',
executable='qr_dete_node',
name='qr_dete_node',
output='screen'
)
return LaunchDescription([
nv12_codec_node,
qr_detection_node
])

View File

@@ -0,0 +1,5 @@
int32 index
uint64 time_stamp
uint8[4194304] data
uint32 MAX_SIZE=4194304

View File

@@ -0,0 +1,22 @@
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>qr_detection</name>
<version>0.0.0</version>
<description>TODO: Package description</description>
<maintainer email="root@todo.todo">root</maintainer>
<license>TODO: License declaration</license>
<buildtool_depend>ament_cmake</buildtool_depend>
<build_depend>rosidl_default_generators</build_depend>
<exec_depend>rosidl_default_runtime</exec_depend>
<member_of_group>rosidl_interface_packages</member_of_group>
<depend>rclcpp</depend>
<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>
<export>
<build_type>ament_cmake</build_type>
</export>
</package>

View File

@@ -0,0 +1,70 @@
#include <chrono>
#include <functional>
#include <memory>
#include <string>
#include "rclcpp/rclcpp.hpp"
#include "qr_detection/msg/sample_message.hpp"
using namespace std::chrono_literals;
class MinimalHbmemPublisher : public rclcpp::Node {
public:
MinimalHbmemPublisher () : Node("minimal_hbmem_publisher"), count_(0) {
// 创建publisher_hbmemtopic为"topic"
publisher_ = this->create_publisher_hbmem<qr_detection::msg::SampleMessage>(
"topic", rclcpp::SensorDataQoS());
// 定时器每隔40毫秒调用一次timer_callback进行消息发送
timer_ = this->create_wall_timer(
40ms, std::bind(&MinimalHbmemPublisher::timer_callback, this));
}
private:
// 定时器回调函数
void timer_callback() {
// 获取要发送的消息
auto loanedMsg = publisher_->borrow_loaned_message();
// 判断消息是否可用,可能出现获取消息失败导致消息不可用的情况
if (loanedMsg.is_valid()) {
// 引用方式获取实际的消息
auto& msg = loanedMsg.get();
// 获取当前时间单位为us
auto time_now =
std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::steady_clock::now().time_since_epoch()).count();
// 对消息的index和time_stamp进行赋值
msg.index = count_;
msg.time_stamp = time_now;
// 打印发送消息
RCLCPP_INFO(this->get_logger(), "message: %d", msg.index);
publisher_->publish(std::move(loanedMsg));
// 注意发送后loanedMsg已不可用
// 计数器加一
count_++;
} else {
// 获取消息失败,丢弃该消息
RCLCPP_INFO(this->get_logger(), "Failed to get LoanMessage!");
}
}
// 定时器
rclcpp::TimerBase::SharedPtr timer_;
// hbmem publisher
rclcpp::PublisherHbmem<qr_detection::msg::SampleMessage>::SharedPtr publisher_;
// 计数器
size_t count_;
};
int main(int argc, char * argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<MinimalHbmemPublisher>());
rclcpp::shutdown();
return 0;
}

View File

@@ -0,0 +1,290 @@
#include <memory>
#include <iostream>
#include <opencv2/opencv.hpp>
#include <zbar.h>
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/int32.hpp"
#include "std_msgs/msg/string.hpp"
#include "hbm_img_msgs/msg/hbm_msg1080_p.hpp"
class MinimalHbmemSubscriber : public rclcpp::Node
{
public:
MinimalHbmemSubscriber()
: Node("qr_detection"), detect_qr_code_(true) // 默认不检测二维码
{
// 创建 subscription_hbmemtopic 为 "hbmem_img"
subscription_hbmem_ =
this->create_subscription_hbmem<hbm_img_msgs::msg::HbmMsg1080P>(
"hbmem_img",
10,
std::bind(&MinimalHbmemSubscriber::hbmem_callback, this, std::placeholders::_1));
// 创建订阅器,订阅 'sign4return' 话题
subscription_sign_ =
this->create_subscription<std_msgs::msg::Int32>(
"sign4return",
10,
std::bind(&MinimalHbmemSubscriber::sign_callback, this, std::placeholders::_1));
// 创建 publishertopic 为 "qr_results"
publisher_ =
this->create_publisher<std_msgs::msg::String>("qr_results", 10);
}
private:
// 消息回调函数,处理 hbmem_img 话题
void hbmem_callback(const hbm_img_msgs::msg::HbmMsg1080P::SharedPtr msg)
{
if (!detect_qr_code_)
{
RCLCPP_INFO(this->get_logger(), "QR detection is disabled");
return; // 如果标志位为 false则不进行二维码检测
}
// 创建 Clock 对象并获取当前时间
auto clock = std::make_shared<rclcpp::Clock>(RCL_SYSTEM_TIME);
auto now = clock->now();
// 转换消息时间戳为 ROS 时间
auto msg_time = rclcpp::Time(msg->time_stamp.sec, msg->time_stamp.nanosec);
// 计算延时(单位:微秒)
auto duration = now - msg_time;
auto delay_us = duration.nanoseconds() / 1000; // 转换为微秒
// 打印延迟
RCLCPP_INFO(this->get_logger(), "msg index: %d, time cost %dus", msg->index, delay_us);
// 获取图像数据并将其转换为 OpenCV 格式
cv::Mat image(msg->height, msg->width, CV_8UC1, const_cast<uint8_t*>(msg->data.data()));
// 初始化 ZBar 扫描器
zbar::ImageScanner scanner;
scanner.set_config(zbar::ZBAR_NONE, zbar::ZBAR_CFG_ENABLE, 1);
// 将 OpenCV 图像数据包装成 ZBar 图像
zbar::Image zbar_image(image.cols, image.rows, "Y800", image.data, image.cols * image.rows);
// 扫描图像中的条形码和二维码
std::string qr_results;
int n = scanner.scan(zbar_image);
if (n > 0) {
for (auto symbol = zbar_image.symbol_begin(); symbol != zbar_image.symbol_end(); ++symbol) {
qr_results += symbol->get_data();
RCLCPP_INFO(this->get_logger(), "Decoded %s symbol \"%s\"", symbol->get_type_name().c_str(), symbol->get_data().c_str());
}
} else {
qr_results = "QR Code not detected";
RCLCPP_INFO(this->get_logger(), "QR Code not detected");
}
// 发布 QR 结果
auto message = std_msgs::msg::String();
message.data = qr_results;
publisher_->publish(message);
}
// 消息回调函数,处理 sign4return 话题
void sign_callback(const std_msgs::msg::Int32::SharedPtr msg)
{
if (msg->data == 0)
{
detect_qr_code_ = true; // 启动二维码检测
RCLCPP_INFO(this->get_logger(), "QR detection started");
}
else if (msg->data == 5)
{
detect_qr_code_ = false; // 停止二维码检测
RCLCPP_INFO(this->get_logger(), "QR detection stopped");
}
}
// hbmem_img 订阅器
rclcpp::SubscriptionHbmem<hbm_img_msgs::msg::HbmMsg1080P>::SharedPtr subscription_hbmem_;
// sign4return 订阅器
rclcpp::Subscription<std_msgs::msg::Int32>::SharedPtr subscription_sign_;
// QR code results 发布器
rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
// 二维码检测标志位
bool detect_qr_code_;
};
int main(int argc, char * argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<MinimalHbmemSubscriber>());
rclcpp::shutdown();
return 0;
}
/*
实现接收和发布
*/
//#include <memory>
//#include <iostream>
//#include <opencv2/opencv.hpp>
//#include <zbar.h>
//#include "rclcpp/rclcpp.hpp"
//#include "std_msgs/msg/string.hpp"
//#include "hbm_img_msgs/msg/hbm_msg1080_p.hpp"
//
//class MinimalHbmemSubscriber : public rclcpp::Node
//{
//public:
// MinimalHbmemSubscriber()
// : Node("qr_detection")
// {
// // 创建 subscription_hbmemtopic 为 "hbmem_img"
// // 消息回调函数为 topic_callback
// subscription_ =
// this->create_subscription_hbmem<hbm_img_msgs::msg::HbmMsg1080P>(
// "hbmem_img",
// 10,
// std::bind(&MinimalHbmemSubscriber::topic_callback, this, std::placeholders::_1));
//
// // 创建 publishertopic 为 "qr_results"
// publisher_ =
// this->create_publisher<std_msgs::msg::String>("qr_results", 10);
// }
//
//private:
// // 消息回调函数
// void topic_callback(const hbm_img_msgs::msg::HbmMsg1080P::SharedPtr msg) const
// {
// // 创建 Clock 对象并获取当前时间
// auto clock = std::make_shared<rclcpp::Clock>(RCL_SYSTEM_TIME);
// auto now = clock->now();
//
// // 转换消息时间戳为 ROS 时间
// auto msg_time = rclcpp::Time(msg->time_stamp.sec, msg->time_stamp.nanosec);
//
// // 计算延时(单位:微秒)
// auto duration = now - msg_time;
// auto delay_us = duration.nanoseconds() / 1000; // 转换为微秒
//
// // 打印延迟
// RCLCPP_INFO(this->get_logger(), "msg index: %d, time cost %dus", msg->index, delay_us);
//
// // 获取图像数据并将其转换为 OpenCV 格式
// cv::Mat image(msg->height, msg->width, CV_8UC1, const_cast<uint8_t*>(msg->data.data()));
//
// // 初始化 ZBar 扫描器
// zbar::ImageScanner scanner;
// scanner.set_config(zbar::ZBAR_NONE, zbar::ZBAR_CFG_ENABLE, 1);
//
// // 将 OpenCV 图像数据包装成 ZBar 图像
// zbar::Image zbar_image(image.cols, image.rows, "Y800", image.data, image.cols * image.rows);
//
// // 扫描图像中的条形码和二维码
// std::string qr_results;
// int n = scanner.scan(zbar_image);
// if (n > 0) {
// for (auto symbol = zbar_image.symbol_begin(); symbol != zbar_image.symbol_end(); ++symbol) {
// qr_results += symbol->get_data() ;
// RCLCPP_INFO(this->get_logger(), "Decoded %s symbol \"%s\"", symbol->get_type_name().c_str(), symbol->get_data().c_str());
// }
// } else {
// qr_results = "QR Code not detected";
// RCLCPP_INFO(this->get_logger(), "QR Code not detected");
// }
//
// // 发布 QR 结果
// auto message = std_msgs::msg::String();
// message.data = qr_results;
// publisher_->publish(message);
// }
//
// // hbmem subscription
// rclcpp::SubscriptionHbmem<hbm_img_msgs::msg::HbmMsg1080P>::SharedPtr subscription_;
// // QR code results publisher
// rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
//};
//
//int main(int argc, char * argv[])
//{
// rclcpp::init(argc, argv);
// rclcpp::spin(std::make_shared<MinimalHbmemSubscriber>());
// rclcpp::shutdown();
// return 0;
//}
/*
只实现接收消息,不进行发布
*/
//#include <memory>
//#include <iostream>
//#include <opencv2/opencv.hpp>
//#include <zbar.h>
//#include "rclcpp/rclcpp.hpp"
//#include "hbm_img_msgs/msg/hbm_msg1080_p.hpp"
//
//class MinimalHbmemSubscriber : public rclcpp::Node
//{
//public:
// MinimalHbmemSubscriber()
// : Node("qr_detection")
// {
// // 创建 subscription_hbmemtopic 为 "hbmem_img"
// // 消息回调函数为 topic_callback
// subscription_ =
// this->create_subscription_hbmem<hbm_img_msgs::msg::HbmMsg1080P>(
// "hbmem_img",
// 10,
// std::bind(&MinimalHbmemSubscriber::topic_callback, this, std::placeholders::_1));
// }
//private:
// // 消息回调函数
// void topic_callback(
// const hbm_img_msgs::msg::HbmMsg1080P::SharedPtr msg) const
// {
// // 创建 Clock 对象并获取当前时间
// auto clock = std::make_shared<rclcpp::Clock>(RCL_SYSTEM_TIME);
// auto now = clock->now();
//
// // 转换消息时间戳为 ROS 时间
// auto msg_time = rclcpp::Time(msg->time_stamp.sec, msg->time_stamp.nanosec);
//
// // 计算延时(单位:微秒)
// auto duration = now - msg_time;
// auto delay_us = duration.nanoseconds() / 1000; // 转换为微秒
//
// // 打印延迟
// RCLCPP_INFO(this->get_logger(), "msg index: %d, time cost %dus", msg->index, delay_us);
//
// // 获取图像数据并将其转换为 OpenCV 格式
// cv::Mat image(msg->height, msg->width, CV_8UC1, const_cast<uint8_t*>(msg->data.data()));
//
// // 初始化 ZBar 扫描器
// zbar::ImageScanner scanner;
// scanner.set_config(zbar::ZBAR_NONE, zbar::ZBAR_CFG_ENABLE, 1);
//
// // 将 OpenCV 图像数据包装成 ZBar 图像
// zbar::Image zbar_image(image.cols, image.rows, "Y800", image.data, image.cols * image.rows);
//
// // 扫描图像中的条形码和二维码
// int n = scanner.scan(zbar_image);
// if (n > 0) {
// for (auto symbol = zbar_image.symbol_begin(); symbol != zbar_image.symbol_end(); ++symbol) {
// RCLCPP_INFO(this->get_logger(), "Decoded %s symbol \"%s\"", symbol->get_type_name().c_str(), symbol->get_data().c_str());
// }
// } else {
// RCLCPP_INFO(this->get_logger(), "QR Code not detected");
// }
// }
//
// // hbmem subscription
// rclcpp::SubscriptionHbmem<hbm_img_msgs::msg::HbmMsg1080P>::SharedPtr subscription_;
//};
//
//int main(int argc, char * argv[])
//{
// rclcpp::init(argc, argv);
// rclcpp::spin(std::make_shared<MinimalHbmemSubscriber>());
// rclcpp::shutdown();
// return 0;
//}

View File

@@ -0,0 +1,131 @@
#include <memory>
#include <iostream>
#include <opencv2/opencv.hpp>
#include <zbar.h>
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/int32.hpp"
#include "std_msgs/msg/string.hpp"
#include "sensor_msgs/msg/image.hpp"
class MinimalHbmemSubscriber : public rclcpp::Node
{
public:
MinimalHbmemSubscriber()
: Node("qr_detection"), detect_qr_code_(true) // 默认检测二维码
{
// 订阅 /aurora/rgb/image_rawsensor_msgs::msg::Image 格式)
subscription_image_ =
this->create_subscription<sensor_msgs::msg::Image>(
"/aurora/rgb/image_raw",
10,
std::bind(&MinimalHbmemSubscriber::image_callback, this, std::placeholders::_1));
// 创建订阅器,订阅 'sign4return' 话题
subscription_sign_ =
this->create_subscription<std_msgs::msg::Int32>(
"sign4return",
10,
std::bind(&MinimalHbmemSubscriber::sign_callback, this, std::placeholders::_1));
// 创建 publishertopic 为 "qr_results"
publisher_ =
this->create_publisher<std_msgs::msg::String>("qr_results", 10);
}
private:
// 图像回调函数,处理 /aurora/rgb/image_raw 话题
void image_callback(const sensor_msgs::msg::Image::SharedPtr msg)
{
if (!detect_qr_code_)
{
RCLCPP_INFO(this->get_logger(), "QR detection is disabled");
return;
}
// 创建 Clock 对象并获取当前时间
auto clock = std::make_shared<rclcpp::Clock>(RCL_SYSTEM_TIME);
auto now = clock->now();
// 转换消息时间戳为 ROS 时间
auto msg_time = rclcpp::Time(msg->header.stamp.sec, msg->header.stamp.nanosec);
// 计算延时(单位:微秒)
auto duration = now - msg_time;
auto delay_us = duration.nanoseconds() / 1000; // 转换为微秒
// 打印延迟
RCLCPP_INFO(this->get_logger(), "frame_id: %s, time cost %ldus",
msg->header.frame_id.c_str(), delay_us);
// 将 sensor_msgs::Image 转换为 OpenCV 格式Aurora RGB 为 bgr8 编码,需转为灰度给 ZBar
if (msg->encoding != "bgr8") {
RCLCPP_ERROR(this->get_logger(), "Expected bgr8 encoding, got %s", msg->encoding.c_str());
return;
}
cv::Mat rgb_image(msg->height, msg->width, CV_8UC3,
const_cast<uint8_t*>(msg->data.data()));
cv::Mat gray_image;
cv::cvtColor(rgb_image, gray_image, cv::COLOR_BGR2GRAY);
// 初始化 ZBar 扫描器
zbar::ImageScanner scanner;
scanner.set_config(zbar::ZBAR_NONE, zbar::ZBAR_CFG_ENABLE, 1);
// 将 OpenCV 图像数据包装成 ZBar 图像
zbar::Image zbar_image(gray_image.cols, gray_image.rows, "Y800",
gray_image.data, gray_image.cols * gray_image.rows);
// 扫描图像中的条形码和二维码
std::string qr_results;
int n = scanner.scan(zbar_image);
if (n > 0) {
for (auto symbol = zbar_image.symbol_begin();
symbol != zbar_image.symbol_end(); ++symbol) {
qr_results += symbol->get_data();
RCLCPP_INFO(this->get_logger(), "Decoded %s symbol \"%s\"",
symbol->get_type_name().c_str(), symbol->get_data().c_str());
}
} else {
qr_results = "QR Code not detected";
RCLCPP_INFO(this->get_logger(), "QR Code not detected");
}
// 发布 QR 结果
auto message = std_msgs::msg::String();
message.data = qr_results;
publisher_->publish(message);
}
// 消息回调函数,处理 sign4return 话题
void sign_callback(const std_msgs::msg::Int32::SharedPtr msg)
{
if (msg->data == 0)
{
detect_qr_code_ = true; // 启动二维码检测
RCLCPP_INFO(this->get_logger(), "QR detection started");
}
else if (msg->data == 5)
{
detect_qr_code_ = false; // 停止二维码检测
RCLCPP_INFO(this->get_logger(), "QR detection stopped");
}
}
// /aurora/rgb/image_raw 订阅器
rclcpp::Subscription<sensor_msgs::msg::Image>::SharedPtr subscription_image_;
// sign4return 订阅器
rclcpp::Subscription<std_msgs::msg::Int32>::SharedPtr subscription_sign_;
// QR code results 发布器
rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
// 二维码检测标志位
bool detect_qr_code_;
};
int main(int argc, char * argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<MinimalHbmemSubscriber>());
rclcpp::shutdown();
return 0;
}

View File

@@ -0,0 +1,50 @@
#include <memory>
#include "rclcpp/rclcpp.hpp"
#include "hbm_img_msgs/msg/hbm_msg1080_p.hpp"
class MinimalHbmemSubscriber : public rclcpp::Node
{
public:
MinimalHbmemSubscriber()
: Node("qr_detection")
{
// 创建 subscription_hbmemtopic 为 "hbmem_img"
// 消息回调函数为 topic_callback
subscription_ =
this->create_subscription_hbmem<hbm_img_msgs::msg::HbmMsg1080P>(
"hbmem_img",
10,
std::bind(&MinimalHbmemSubscriber::topic_callback, this, std::placeholders::_1));
}
private:
// 消息回调函数
void topic_callback(
const hbm_img_msgs::msg::HbmMsg1080P::SharedPtr msg) const
{
// 创建 Clock 对象并获取当前时间
auto clock = std::make_shared<rclcpp::Clock>(RCL_SYSTEM_TIME);
auto now = clock->now();
// 转换消息时间戳为 ROS 时间
auto msg_time = rclcpp::Time(msg->time_stamp.sec, msg->time_stamp.nanosec);
// 计算延时(单位:微秒)
auto duration = now - msg_time;
auto delay_us = duration.nanoseconds() / 1000; // 转换为微秒
// 打印延迟
RCLCPP_INFO(this->get_logger(), "msg index: %d, time cost %dus", msg->index, delay_us);
}
// hbmem subscription
rclcpp::SubscriptionHbmem<hbm_img_msgs::msg::HbmMsg1080P>::SharedPtr subscription_;
};
int main(int argc, char * argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<MinimalHbmemSubscriber>());
rclcpp::shutdown();
return 0;
}

View File

@@ -0,0 +1,36 @@
#include <iostream>
#include <zbar.h>
#include <opencv2/opencv.hpp>
int main(int argc, char* argv[]) {
if (argc != 2) {
std::cerr << "Usage: " << argv[0] << " <image_path>" << std::endl;
return -1;
}
std::string image_path = argv[1];
cv::Mat image = cv::imread(image_path, cv::IMREAD_GRAYSCALE);
if (image.empty()) {
std::cerr << "Could not open or find the image: " << image_path << std::endl;
return -1;
}
// Initialize ZBar scanner
zbar::ImageScanner scanner;
scanner.set_config(zbar::ZBAR_NONE, zbar::ZBAR_CFG_ENABLE, 1);
// Wrap OpenCV image data in a ZBar image
zbar::Image zbar_image(image.cols, image.rows, "Y800", image.data, image.cols * image.rows);
// Scan the image for barcodes and QR codes
int n = scanner.scan(zbar_image);
if (n > 0) {
for (auto symbol = zbar_image.symbol_begin(); symbol != zbar_image.symbol_end(); ++symbol) {
std::cout << "Decoded " << symbol->get_type_name() << " symbol \"" << symbol->get_data() << '"' << std::endl;
}
} else {
std::cout << "QR Code not detected" << std::endl;
}
return 0;
}

View File

@@ -0,0 +1,45 @@
#include <memory>
#include "rclcpp/rclcpp.hpp"
#include "qr_detection/msg/sample_message.hpp"
class MinimalHbmemSubscriber : public rclcpp::Node {
public:
MinimalHbmemSubscriber () : Node("minimal_hbmem_subscriber") {
// 创建subscription_hbmemtopic为"sample"
// 消息回调函数为topic_callback
subscription_ =
this->create_subscription_hbmem<qr_detection::msg::SampleMessage>(
"topic", rclcpp::SensorDataQoS(),
std::bind(&MinimalHbmemSubscriber ::topic_callback, this,
std::placeholders::_1));
}
private:
// 消息回调函数
void topic_callback(
const qr_detection::msg::SampleMessage::SharedPtr msg) const {
// 注意msg只能在回调函数中使用回调函数返回后该消息就会被释放
// 获取当前时间
auto time_now =
std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::steady_clock::now().time_since_epoch())
.count();
// 计算延时并打印出来
RCLCPP_INFO(this->get_logger(), "msg %d, time cost %dus", msg->index,
time_now - msg->time_stamp);
}
// hbmem subscription
rclcpp::SubscriptionHbmem<qr_detection::msg::SampleMessage>::SharedPtr
subscription_;
};
int main(int argc, char * argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<MinimalHbmemSubscriber>());
rclcpp::shutdown();
return 0;
}

View File

@@ -0,0 +1,18 @@
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>vlm_detect</name>
<version>0.0.0</version>
<description>TODO: Package description</description>
<maintainer email="root@todo.todo">root</maintainer>
<license>TODO: License declaration</license>
<test_depend>ament_copyright</test_depend>
<test_depend>ament_flake8</test_depend>
<test_depend>ament_pep257</test_depend>
<test_depend>python3-pytest</test_depend>
<export>
<build_type>ament_python</build_type>
</export>
</package>

View File

4
src/vlm_detect/setup.cfg Normal file
View File

@@ -0,0 +1,4 @@
[develop]
script_dir=$base/lib/vlm_detect
[install]
install_scripts=$base/lib/vlm_detect

26
src/vlm_detect/setup.py Normal file
View File

@@ -0,0 +1,26 @@
from setuptools import find_packages, setup
package_name = 'vlm_detect'
setup(
name=package_name,
version='0.0.0',
packages=find_packages(exclude=['test']),
data_files=[
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
],
install_requires=['setuptools'],
zip_safe=True,
maintainer='root',
maintainer_email='root@todo.todo',
description='TODO: Package description',
license='TODO: License declaration',
tests_require=['pytest'],
entry_points={
'console_scripts': [
'vlm_node = vlm_detect.vlm_node:main',
],
},
)

View File

@@ -0,0 +1,25 @@
# Copyright 2015 Open Source Robotics Foundation, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from ament_copyright.main import main
import pytest
# Remove the `skip` decorator once the source file(s) have a copyright header
@pytest.mark.skip(reason='No copyright header has been placed in the generated source file.')
@pytest.mark.copyright
@pytest.mark.linter
def test_copyright():
rc = main(argv=['.', 'test'])
assert rc == 0, 'Found errors'

View File

@@ -0,0 +1,25 @@
# Copyright 2017 Open Source Robotics Foundation, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from ament_flake8.main import main_with_errors
import pytest
@pytest.mark.flake8
@pytest.mark.linter
def test_flake8():
rc, errors = main_with_errors(argv=[])
assert rc == 0, \
'Found %d code style errors / warnings:\n' % len(errors) + \
'\n'.join(errors)

View File

@@ -0,0 +1,23 @@
# Copyright 2015 Open Source Robotics Foundation, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from ament_pep257.main import main
import pytest
@pytest.mark.linter
@pytest.mark.pep257
def test_pep257():
rc = main(argv=['.', 'test'])
assert rc == 0, 'Found code style errors / warnings'

View File

View File

@@ -0,0 +1,144 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import rclpy
from rclpy.node import Node
from std_msgs.msg import Int32, String
from sensor_msgs.msg import CompressedImage
from cv_bridge import CvBridge
import cv2
import base64
import threading
from openai import OpenAI
import os
import time
import numpy as np
class VLMProcessor(Node):
def __init__(self):
super().__init__('vlm_dtetct')
# 初始化 OpenAI 客户端
self.client = OpenAI(
base_url="http://192.168.1.103:8000/v1",
api_key="EMPTY"
)
# ROS2 组件
self.bridge = CvBridge()
self.latest_image = None
self.image_lock = threading.Lock()
# 订阅图像话题
self.image_sub = self.create_subscription(
CompressedImage,
'/image',
self.image_callback,
10
)
# 订阅触发信号
self.sign_sub = self.create_subscription(
Int32,
'/sign4return',
self.sign_callback,
10
)
# 发布结果
self.result_pub = self.create_publisher(
String,
'/vlm_result',
10
)
self.get_logger().info("VLM Processor...")
def image_callback(self, msg):
"""保存最新的图像"""
with self.image_lock:
try:
np_arr = np.frombuffer(msg.data, np.uint8)
# 使用 OpenCV 解码图像
cv_image = cv2.imdecode(np_arr, cv2.IMREAD_COLOR)
self.latest_image = cv_image
self.get_logger().debug("recive picture")
except Exception as e:
self.get_logger().error("err picture")
def sign_callback(self, msg):
"""处理触发信号"""
if msg.data == 9:
self.get_logger().info("收到触发信号 (6),开始处理图像...")
# 检查是否有可用图像
with self.image_lock:
if self.latest_image is None:
self.get_logger().warning("没有可用图像")
return
# 保存临时图像文件
temp_path = "/tmp/vlm_temp_image.jpg"
cv2.imwrite(temp_path, self.latest_image)
self.get_logger().info("已保存临时图像}")
# 处理图像
try:
description = self.process_image(temp_path)
self.get_logger().info(f"图像描述结果:")
# 发布结果
result_msg = String()
result_msg.data = description
self.result_pub.publish(result_msg)
# 清理临时文件
os.remove(temp_path)
except Exception as e:
self.get_logger().error(f"处理图像时出错:{e}")
def process_image(self, image_path):
"""使用 VLM 模型处理图像"""
# 读取并编码图像
with open(image_path, "rb") as image_file:
base64_image = base64.b64encode(image_file.read()).decode('utf-8')
# 发送请求到 VLM 模型
start_time = time.time()
response = self.client.chat.completions.create(
model="/home/yyh/vllm_test/model/InternVL3-1B",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "描述图片中的动漫病人"},
{
"type": "image_url",
"image_url": {
"url": f"data:image/jpeg;base64,{base64_image}"
}
}
]
}
],
max_tokens=100
)
processing_time = time.time() - start_time
self.get_logger().info("VLM 处理耗时秒")
return response.choices[0].message.content
def main(args=None):
rclpy.init(args=args)
node = VLMProcessor()
try:
rclpy.spin(node)
except KeyboardInterrupt:
pass
finally:
node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()

View File

@@ -0,0 +1 @@
cone

View File

@@ -0,0 +1,239 @@
# Copyright (c) 2024D-Robotics.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.actions import IncludeLaunchDescription
from launch_ros.actions import Node
from launch.substitutions import TextSubstitution
from launch.substitutions import LaunchConfiguration
from launch.launch_description_sources import PythonLaunchDescriptionSource
from ament_index_python import get_package_share_directory
from ament_index_python.packages import get_package_prefix
def generate_launch_description():
# args that can be set from the command line or a default will be used
config_file_launch_arg = DeclareLaunchArgument(
"dnn_example_config_file", default_value=TextSubstitution(text="/root/yolov8workconfig.json")
)
dump_render_launch_arg = DeclareLaunchArgument(
"dnn_example_dump_render_img", default_value=TextSubstitution(text="0")
)
image_width_launch_arg = DeclareLaunchArgument(
"dnn_example_image_width", default_value=TextSubstitution(text="640")
)
image_height_launch_arg = DeclareLaunchArgument(
"dnn_example_image_height", default_value=TextSubstitution(text="480")
)
msg_pub_topic_name_launch_arg = DeclareLaunchArgument(
"dnn_example_msg_pub_topic_name", default_value=TextSubstitution(text="hobot_dnn_detection")
)
camera_type = os.getenv('CAM_TYPE')
camera_type = 'usb'
print("camera_type is ", camera_type)
cam_node = None
camera_type_mipi = None
camera_device_arg = None
if camera_type == "usb":
# usb cam图片发布pkg
usb_cam_device_arg = DeclareLaunchArgument(
'device',
default_value='/dev/video8',
description='usb camera device')
usb_node = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(
get_package_share_directory('hobot_usb_cam'),
'launch/hobot_usb_cam.launch.py')),
launch_arguments={
'usb_image_width': LaunchConfiguration('dnn_example_image_width'),
'usb_image_height': LaunchConfiguration('dnn_example_image_height'),
'usb_video_device': LaunchConfiguration('device')
}.items()
)
print("using usb cam")
cam_node = usb_node
camera_type_mipi = False
camera_device_arg = usb_cam_device_arg
elif camera_type == "fb":
# 本地图片发布
feedback_picture_arg = DeclareLaunchArgument(
'publish_image_source',
default_value='./config/target.jpg',
description='feedback picture')
publish_image_fps = DeclareLaunchArgument(
'publish_image_fps',
default_value='5',
description='publish_image_fps picture')
fb_node = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(
get_package_share_directory('hobot_image_publisher'),
'launch/hobot_image_publisher.launch.py')),
launch_arguments={
'publish_image_source': LaunchConfiguration('publish_image_source'),
'publish_image_format': LaunchConfiguration('publish_image_format'),
'publish_message_topic_name': '/hbmem_img',
'publish_fps': LaunchConfiguration('publish_image_fps')
}.items()
)
print("using feedback")
cam_node = fb_node
camera_type_mipi = True
camera_device_arg = feedback_picture_arg
else:
if camera_type == "mipi":
print("using mipi cam")
else:
print("invalid camera_type ", camera_type,
", which is set with export CAM_TYPE=usb/mipi/fb, using default mipi cam")
# mipi cam图片发布pkg
mipi_cam_device_arg = DeclareLaunchArgument(
'device',
default_value='F37',
description='mipi camera device')
mipi_node = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(
get_package_share_directory('mipi_cam'),
'launch/mipi_cam.launch.py')),
launch_arguments={
'mipi_image_width': LaunchConfiguration('dnn_example_image_width'),
'mipi_image_height': LaunchConfiguration('dnn_example_image_height'),
'mipi_io_method': 'shared_mem',
'mipi_frame_ts_type': 'realtime',
'mipi_video_device': LaunchConfiguration('device')
}.items()
)
cam_node = mipi_node
camera_type_mipi = True
camera_device_arg = mipi_cam_device_arg
# jpeg图片编码&发布pkg
jpeg_codec_node = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(
get_package_share_directory('hobot_codec'),
'launch/hobot_codec_encode.launch.py')),
launch_arguments={
'codec_in_mode': 'shared_mem',
'codec_out_mode': 'ros',
'codec_sub_topic': '/hbmem_img',
'codec_pub_topic': '/image'
}.items()
)
# nv12图片解码&发布pkg
nv12_codec_node = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(
get_package_share_directory('hobot_codec'),
'launch/hobot_codec_decode.launch.py')),
launch_arguments={
'codec_in_mode': 'ros',
'codec_out_mode': 'shared_mem',
'codec_sub_topic': '/image',
'codec_pub_topic': '/hbmem_img'
}.items()
)
# web展示pkg
web_node = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(
get_package_share_directory('websocket'),
'launch/websocket.launch.py')),
launch_arguments={
'websocket_image_topic': '/image',
'websocket_image_type': 'mjpeg',
'websocket_smart_topic': LaunchConfiguration("dnn_example_msg_pub_topic_name")
}.items()
)
# 算法pkg
dnn_node_example_node = Node(
package='dnn_node_example',
executable='example',
output='screen',
parameters=[
{"config_file": LaunchConfiguration('dnn_example_config_file')},
{"dump_render_img": LaunchConfiguration(
'dnn_example_dump_render_img')},
{"feed_type": 1},
{"is_shared_mem_sub": 1},
{"msg_pub_topic_name": LaunchConfiguration(
"dnn_example_msg_pub_topic_name")}
],
arguments=['--ros-args', '--log-level', 'warn']
)
shared_mem_node = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(
get_package_share_directory('hobot_shm'),
'launch/hobot_shm.launch.py'))
)
if camera_type_mipi:
return LaunchDescription([
camera_device_arg,
config_file_launch_arg,
dump_render_launch_arg,
image_width_launch_arg,
image_height_launch_arg,
msg_pub_topic_name_launch_arg,
# 启动零拷贝环境配置node
# shared_mem_node,
# 图片发布pkg
cam_node,
# 图片编解码&发布pkg
nv12_codec_node,
# 启动example pkg
dnn_node_example_node,
# 启动web展示pkg
web_node
])
else:
return LaunchDescription([
camera_device_arg,
config_file_launch_arg,
dump_render_launch_arg,
image_width_launch_arg,
image_height_launch_arg,
msg_pub_topic_name_launch_arg,
# 启动零拷贝环境配置node
# shared_mem_node,
# 图片发布pkg
cam_node,
# 图片编解码&发布pkg
nv12_codec_node,
# 启动example pkg
dnn_node_example_node,
# 启动web展示pkg
web_node
])

View File

@@ -0,0 +1,18 @@
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>yolov8_launch</name>
<version>0.0.0</version>
<description>TODO: Package description</description>
<maintainer email="root@todo.todo">root</maintainer>
<license>TODO: License declaration</license>
<test_depend>ament_copyright</test_depend>
<test_depend>ament_flake8</test_depend>
<test_depend>ament_pep257</test_depend>
<test_depend>python3-pytest</test_depend>
<export>
<build_type>ament_python</build_type>
</export>
</package>

View File

View File

@@ -0,0 +1,4 @@
[develop]
script_dir=$base/lib/yolov8_launch
[install]
install_scripts=$base/lib/yolov8_launch

View File

@@ -0,0 +1,27 @@
from setuptools import find_packages, setup
import os
from glob import glob
package_name = 'yolov8_launch'
setup(
name=package_name,
version='0.0.0',
packages=find_packages(exclude=['test']),
data_files=[
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
('share/' + package_name + '/launch', glob('launch/*.launch.py')),
],
install_requires=['setuptools'],
zip_safe=True,
maintainer='root',
maintainer_email='root@todo.todo',
description='TODO: Package description',
license='TODO: License declaration',
tests_require=['pytest'],
entry_points={
'console_scripts': [
],
},
)

View File

@@ -0,0 +1,25 @@
# Copyright 2015 Open Source Robotics Foundation, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from ament_copyright.main import main
import pytest
# Remove the `skip` decorator once the source file(s) have a copyright header
@pytest.mark.skip(reason='No copyright header has been placed in the generated source file.')
@pytest.mark.copyright
@pytest.mark.linter
def test_copyright():
rc = main(argv=['.', 'test'])
assert rc == 0, 'Found errors'

View File

@@ -0,0 +1,25 @@
# Copyright 2017 Open Source Robotics Foundation, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from ament_flake8.main import main_with_errors
import pytest
@pytest.mark.flake8
@pytest.mark.linter
def test_flake8():
rc, errors = main_with_errors(argv=[])
assert rc == 0, \
'Found %d code style errors / warnings:\n' % len(errors) + \
'\n'.join(errors)

View File

@@ -0,0 +1,23 @@
# Copyright 2015 Open Source Robotics Foundation, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from ament_pep257.main import main
import pytest
@pytest.mark.linter
@pytest.mark.pep257
def test_pep257():
rc = main(argv=['.', 'test'])
assert rc == 0, 'Found code style errors / warnings'

47
wget-log Normal file
View File

@@ -0,0 +1,47 @@
--2026-06-15 22:41:04-- https://github.com/xiongqi123123/dtop/releases/download/v1.1.0/dtop-arm64-ubuntu22.04.tar.gz
Resolving github.com (github.com)... 20.205.243.166
Connecting to github.com (github.com)|20.205.243.166|:443... connected.
HTTP request sent, awaiting response... No data received.
Retrying.
--2026-06-15 22:42:35-- (try: 2) https://github.com/xiongqi123123/dtop/releases/download/v1.1.0/dtop-arm64-ubuntu22.04.tar.gz
Connecting to github.com (github.com)|20.205.243.166|:443... connected.
HTTP request sent, awaiting response... No data received.
Retrying.
--2026-06-15 22:44:23-- (try: 3) https://github.com/xiongqi123123/dtop/releases/download/v1.1.0/dtop-arm64-ubuntu22.04.tar.gz
Connecting to github.com (github.com)|20.205.243.166|:443... connected.
HTTP request sent, awaiting response... No data received.
Retrying.
--2026-06-15 22:45:57-- (try: 4) https://github.com/xiongqi123123/dtop/releases/download/v1.1.0/dtop-arm64-ubuntu22.04.tar.gz
Connecting to github.com (github.com)|20.205.243.166|:443... failed: Connection timed out.
Resolving github.com (github.com)... 20.205.243.166
Connecting to github.com (github.com)|20.205.243.166|:443... failed: Connection timed out.
Retrying.
--2026-06-15 22:50:24-- (try: 5) https://github.com/xiongqi123123/dtop/releases/download/v1.1.0/dtop-arm64-ubuntu22.04.tar.gz
Connecting to github.com (github.com)|20.205.243.166|:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: https://release-assets.githubusercontent.com/github-production-release-asset/1029081525/f827fe4e-a10d-4add-b5e0-0826bb0ab476?sp=r&sv=2018-11-09&sr=b&spr=https&se=2026-06-15T15%3A45%3A59Z&rscd=attachment%3B+filename%3Ddtop-arm64-ubuntu22.04.tar.gz&rsct=application%2Foctet-stream&skoid=96c2d410-5711-43a1-aedd-ab1947aa7ab0&sktid=398a6654-997b-47e9-b12b-9515b896b4de&skt=2026-06-15T14%3A45%3A25Z&ske=2026-06-15T15%3A45%3A59Z&sks=b&skv=2018-11-09&sig=kk4nXxUt6miqrbhECM%2FuKWbFpwRp9VUofTHRECaQVq0%3D&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmVsZWFzZS1hc3NldHMuZ2l0aHVidXNlcmNvbnRlbnQuY29tIiwia2V5Ijoia2V5MSIsImV4cCI6MTc4MTUzNTMyNSwibmJmIjoxNzgxNTM1MDI1LCJwYXRoIjoicmVsZWFzZWFzc2V0cHJvZHVjdGlvbi5ibG9iLmNvcmUud2luZG93cy5uZXQifQ.utpBoEPybhRRSyqA_PRGkEHpxOA5k0qAXygmA87AjhQ&response-content-disposition=attachment%3B%20filename%3Ddtop-arm64-ubuntu22.04.tar.gz&response-content-type=application%2Foctet-stream [following]
--2026-06-15 22:50:25-- https://release-assets.githubusercontent.com/github-production-release-asset/1029081525/f827fe4e-a10d-4add-b5e0-0826bb0ab476?sp=r&sv=2018-11-09&sr=b&spr=https&se=2026-06-15T15%3A45%3A59Z&rscd=attachment%3B+filename%3Ddtop-arm64-ubuntu22.04.tar.gz&rsct=application%2Foctet-stream&skoid=96c2d410-5711-43a1-aedd-ab1947aa7ab0&sktid=398a6654-997b-47e9-b12b-9515b896b4de&skt=2026-06-15T14%3A45%3A25Z&ske=2026-06-15T15%3A45%3A59Z&sks=b&skv=2018-11-09&sig=kk4nXxUt6miqrbhECM%2FuKWbFpwRp9VUofTHRECaQVq0%3D&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmVsZWFzZS1hc3NldHMuZ2l0aHVidXNlcmNvbnRlbnQuY29tIiwia2V5Ijoia2V5MSIsImV4cCI6MTc4MTUzNTMyNSwibmJmIjoxNzgxNTM1MDI1LCJwYXRoIjoicmVsZWFzZWFzc2V0cHJvZHVjdGlvbi5ibG9iLmNvcmUud2luZG93cy5uZXQifQ.utpBoEPybhRRSyqA_PRGkEHpxOA5k0qAXygmA87AjhQ&response-content-disposition=attachment%3B%20filename%3Ddtop-arm64-ubuntu22.04.tar.gz&response-content-type=application%2Foctet-stream
Resolving release-assets.githubusercontent.com (release-assets.githubusercontent.com)... 185.199.109.133, 185.199.110.133, 185.199.108.133, ...
Connecting to release-assets.githubusercontent.com (release-assets.githubusercontent.com)|185.199.109.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 529991 (518K) [application/octet-stream]
Saving to: dtop-arm64-ubuntu22.04.tar.gz
0K .......... .......... .......... .......... .......... 9% 206K 2s
50K .......... .......... .......... .......... .......... 19% 258K 2s
100K .......... .......... .......... .......... .......... 28% 915K 1s
150K .......... .......... .......... .......... .......... 38% 1.11M 1s
200K .......... .......... .......... .......... .......... 48% 460K 1s
250K .......... .......... .......... .......... .......... 57% 1.48M 0s
300K .......... .......... .......... .......... .......... 67% 1.36M 0s
350K .......... .......... .......... .......... .......... 77% 1.30M 0s
400K .......... .......... .......... .......... .......... 86% 2.84M 0s
450K .......... .......... .......... .......... .......... 96% 2.01M 0s
500K .......... ....... 100% 390K=0.8s
2026-06-15 22:50:27 (619 KB/s) - dtop-arm64-ubuntu22.04.tar.gz saved [529991/529991]