当前位置: 首页 > news >正文

【ROS2】Beginner: Client libraries - 发布者、订阅者例子 C++ Python

编写简单的C++发布者和订阅者

目标:使用C++创建并运行发布者和订阅者节点。

教程级别:初学者
预计时间:20分钟

目录

  • 背景
  • 前提条件
  • 任务
    1. 创建功能包
    2. 编写发布者节点
    3. 编写订阅者节点
    4. 构建并运行
  • 总结
  • 下一步

背景

节点是通过ROS图进行通信的可执行进程。在本教程中,节点将通过话题以字符串消息的形式相互传递信息。这里使用的示例是一个简单的"说话者"(talker)和"听者"(listener)系统:一个节点发布数据,另一个节点订阅该话题以接收数据。

本示例中使用的代码可以在这里找到。

前提条件

在之前的教程中,你已经学会了如何创建工作空间和功能包。

任务

1. 创建功能包

打开一个新终端并配置ROS 2环境,以便ros2命令可以正常工作。

进入之前教程中创建的ros2_ws目录。

记得功能包应该在src目录中创建,而不是在工作空间的根目录。因此,进入ros2_ws/src,然后运行功能包创建命令:

ros2 pkg create --build-type ament_cmake --license Apache-2.0 cpp_pubsub

终端会返回一条消息,确认你的cpp_pubsub功能包及其所有必要文件和文件夹已创建。

进入ros2_ws/src/cpp_pubsub/src目录。请记住,这是任何CMake功能包中包含可执行文件的源文件存放位置。

2. 编写发布者节点

通过以下命令下载示例的talker代码:

Linux/macOS

wget -O publisher_lambda_function.cpp https://raw.githubusercontent.com/ros2/examples/kilted/rclcpp/topics/minimal_publisher/lambda.cpp

Windows命令提示符

curl -sk https://raw.githubusercontent.com/ros2/examples/kilted/rclcpp/topics/minimal_publisher/lambda.cpp -o publisher_lambda_function.cpp

Windows PowerShell

curl https://raw.githubusercontent.com/ros2/examples/kilted/rclcpp/topics/minimal_publisher/lambda.cpp -o publisher_lambda_function.cpp

现在会有一个名为publisher_lambda_function.cpp的新文件。用你喜欢的文本编辑器打开它:

#include <chrono>
#include <memory>
#include <string>#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"using namespace std::chrono_literals;/* 这个示例创建了一个Node的子类,并使用了C++11的lambda函数* 来简化回调语法,代价是代码乍看之下可能有些难以理解。 */class MinimalPublisher : public rclcpp::Node
{
public:MinimalPublisher(): Node("minimal_publisher"), count_(0){publisher_ = this->create_publisher<std_msgs::msg::String>("topic", 10);auto timer_callback =[this]() -> void {auto message = std_msgs::msg::String();message.data = "Hello, world! " + std::to_string(this->count_++);RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str());this->publisher_->publish(message);};timer_ = this->create_wall_timer(500ms, timer_callback);}private:rclcpp::TimerBase::SharedPtr timer_;rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;size_t count_;
};int main(int argc, char * argv[])
{rclcpp::init(argc, argv);rclcpp::spin(std::make_shared<MinimalPublisher>());rclcpp::shutdown();return 0;
}
2.1 代码解析

代码顶部包含了你将使用的标准C++头文件。标准C++头文件之后是rclcpp/rclcpp.hpp,它允许你使用ROS 2系统中最常用的部分。最后是std_msgs/msg/string.hpp,它包含了你将用来发布数据的内置消息类型。

#include <chrono>
#include <memory>
#include <string>#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"using namespace std::chrono_literals;

这些行代表了节点的依赖关系。记得需要将这些依赖添加到package.xmlCMakeLists.txt中,这将在下一节完成。

下一行通过继承rclcpp::Node创建了节点类MinimalPublisher。代码中的每个this都指代这个节点。

class MinimalPublisher : public rclcpp::Node

公共构造函数将节点命名为minimal_publisher并将count_初始化为0。在构造函数内部,发布者被初始化为使用String消息类型、话题名称topic和队列大小10(用于在消息积压时限制数量)。接下来,声明了一个名为timer_callback的lambda函数,它以引用方式捕获当前对象this,不接受输入参数并返回void。timer_callback函数创建一个新的String类型消息,设置其数据为所需字符串并发布它。RCLCPP_INFO宏确保每条发布的消息都打印到控制台。最后,初始化timer_,它会使timer_callback函数每秒执行两次。

public:MinimalPublisher(): Node("minimal_publisher"), count_(0){publisher_ = this->create_publisher<std_msgs::msg::String>("topic", 10);auto timer_callback =[this]() -> void {auto message = std_msgs::msg::String();message.data = "Hello, world! " + std::to_string(this->count_++);RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str());this->publisher_->publish(message);};timer_ = this->create_wall_timer(500ms, timer_callback);}

类的底部是定时器、发布者和计数器字段的声明。

private:rclcpp::TimerBase::SharedPtr timer_;rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;size_t count_;

MinimalPublisher类之后是main函数,节点实际在这里执行。rclcpp::init初始化ROS 2,rclcpp::spin开始处理节点的数据,包括来自定时器的回调。

int main(int argc, char * argv[])
{rclcpp::init(argc, argv);rclcpp::spin(std::make_shared<MinimalPublisher>());rclcpp::shutdown();return 0;
}
2.2 添加依赖

回到ros2_ws/src/cpp_pubsub目录,这里已经为你创建了CMakeLists.txtpackage.xml文件。

用文本编辑器打开package.xml

如前所述,确保填写<description><maintainer><license>标签:

<description>Examples of minimal publisher/subscriber using rclcpp</description>
<maintainer email="you@email.com">Your Name</maintainer>
<license>Apache-2.0</license>

ament_cmake构建工具依赖之后添加新行,并粘贴与你节点的include语句对应的以下依赖:

<depend>rclcpp</depend>
<depend>std_msgs</depend>

这声明了该功能包在构建和执行代码时需要rclcppstd_msgs

记得保存文件。

2.3 CMakeLists.txt

现在打开CMakeLists.txt文件。在现有的依赖find_package(ament_cmake REQUIRED)下方,添加以下行:

find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)

之后,添加可执行文件并命名为talker,这样你就可以使用ros2 run运行节点:

add_executable(talker src/publisher_lambda_function.cpp)
target_link_libraries(talker PUBLIC rclcpp::rclcpp ${std_msgs_TARGETS})

最后,添加install(TARGETS...)部分,这样ros2 run才能找到你的可执行文件:

install(TARGETStalkerDESTINATION lib/${PROJECT_NAME})

你可以清理一下CMakeLists.txt,删除一些不必要的部分和注释,使其看起来像这样:

cmake_minimum_required(VERSION 3.5)
project(cpp_pubsub)# 默认使用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_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)add_executable(talker src/publisher_lambda_function.cpp)
target_link_libraries(talker PUBLIC rclcpp::rclcpp ${std_msgs_TARGETS})install(TARGETStalkerDESTINATION lib/${PROJECT_NAME})ament_package()

你现在可以构建功能包、配置本地设置文件并运行它,但让我们先创建订阅者节点,这样你就能看到完整系统的工作效果。

3. 编写订阅者节点

回到ros2_ws/src/cpp_pubsub/src目录创建下一个节点。在终端中输入以下命令:

Linux/macOS

wget -O subscriber_lambda_function.cpp https://raw.githubusercontent.com/ros2/examples/kilted/rclcpp/topics/minimal_subscriber/lambda.cpp

Windows命令提示符

curl -sk https://raw.githubusercontent.com/ros2/examples/kilted/rclcpp/topics/minimal_subscriber/lambda.cpp -o subscriber_lambda_function.cpp

Windows PowerShell

curl https://raw.githubusercontent.com/ros2/examples/kilted/rclcpp/topics/minimal_subscriber/lambda.cpp -o subscriber_lambda_function.cpp

检查确保这些文件存在:

publisher_lambda_function.cpp  subscriber_lambda_function.cpp

用文本编辑器打开subscriber_lambda_function.cpp

#include <memory>#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"class MinimalSubscriber : public rclcpp::Node
{
public:MinimalSubscriber(): Node("minimal_subscriber"){auto topic_callback =[this](std_msgs::msg::String::UniquePtr msg) -> void {RCLCPP_INFO(this->get_logger(), "I heard: '%s'", msg->data.c_str());};subscription_ =this->create_subscription<std_msgs::msg::String>("topic", 10, topic_callback);}private:rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription_;
};int main(int argc, char * argv[])
{rclcpp::init(argc, argv);rclcpp::spin(std::make_shared<MinimalSubscriber>());rclcpp::shutdown();return 0;
}
3.1 代码解析

订阅者节点的代码与发布者的几乎相同。现在节点名为minimal_subscriber,构造函数使用节点的create_subscription函数来执行回调。

这里没有定时器,因为订阅者只是在有数据发布到topic话题时才做出响应。

topic_callback函数接收通过话题发布的字符串消息数据,并使用RCLCPP_INFO宏将其写入控制台。

从话题教程中记得,发布者和订阅者使用的话题名称和消息类型必须匹配才能通信。

public:MinimalSubscriber(): Node("minimal_subscriber"){auto topic_callback =[this](std_msgs::msg::String::UniquePtr msg) -> void {RCLCPP_INFO(this->get_logger(), "I heard: '%s'", msg->data.c_str());};subscription_ =this->create_subscription<std_msgs::msg::String>("topic", 10, topic_callback);}

这个类中唯一的字段声明是订阅者。

private:rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription_;

main函数完全相同,只是现在它spin的是MinimalSubscriber节点。对于发布者节点,spin意味着启动定时器,但对于订阅者,它只是准备好在消息到达时接收消息。

由于这个节点与发布者节点有相同的依赖,所以不需要向package.xml添加新内容。

3.2 CMakeLists.txt

重新打开CMakeLists.txt,在发布者的条目下方添加订阅者节点的可执行文件和目标:

add_executable(listener src/subscriber_lambda_function.cpp)
target_link_libraries(listener PUBLIC rclcpp::rclcpp ${std_msgs_TARGETS})install(TARGETStalkerlistenerDESTINATION lib/${PROJECT_NAME})

保存文件,你的发布/订阅系统就准备好了。

4. 构建并运行

你可能已经将rclcppstd_msgs作为ROS 2系统的一部分安装了。在构建前,在工作空间根目录(ros2_ws)运行rosdep检查缺失依赖是个好习惯:

Linux

rosdep install -i --from-path src --rosdistro kilted -y

rosdep只在Linux上运行,所以macOS和Windows用户可以直接跳到下一步。

仍在工作空间根目录ros2_ws中,构建你的新功能包:

Linux/macOS

colcon build --packages-select cpp_pubsub

Windows

colcon build --merge-install --packages-select cpp_pubsub

打开一个新终端,进入ros2_ws,并配置设置文件:

Linux/macOS

. install/setup.bash

Windows

call install/setup.bat

现在运行talker节点。终端应该会开始每0.5秒发布一条信息,如下所示:

ros2 run cpp_pubsub talker
[INFO] [minimal_publisher]: Publishing: "Hello World: 0"
[INFO] [minimal_publisher]: Publishing: "Hello World: 1"
[INFO] [minimal_publisher]: Publishing: "Hello World: 2"
[INFO] [minimal_publisher]: Publishing: "Hello World: 3"
[INFO] [minimal_publisher]: Publishing: "Hello World: 4"

打开另一个终端,再次在ros2_ws中配置设置文件,然后启动listener节点。listener会开始在控制台打印消息,从发布者当时的消息计数开始:

ros2 run cpp_pubsub listener
[INFO] [minimal_subscriber]: I heard: "Hello World: 10"
[INFO] [minimal_subscriber]: I heard: "Hello World: 11"
[INFO] [minimal_subscriber]: I heard: "Hello World: 12"
[INFO] [minimal_subscriber]: I heard: "Hello World: 13"
[INFO] [minimal_subscriber]: I heard: "Hello World: 14"

在每个终端中按Ctrl+C停止节点运行。

总结

你创建了两个节点来通过话题发布和订阅数据。在编译和运行它们之前,你将它们的依赖和可执行文件添加到了功能包的配置文件中。

下一步

接下来,你将使用服务/客户端模型创建另一个简单的ROS 2功能包。同样,你可以选择用C++或Python编写。

二、编写简单的Python发布者和订阅者

目标:使用Python创建并运行发布者和订阅者节点。

教程级别:初学者
预计时间:20分钟

目录

  • 背景
  • 前提条件
  • 任务
    1. 创建功能包
    2. 编写发布者节点
    3. 编写订阅者节点
    4. 构建并运行
  • 总结
  • 下一步

背景

在本教程中,你将创建通过话题以字符串消息形式相互传递信息的节点。这里使用的示例是一个简单的"说话者"(talker)和"听者"(listener)系统:一个节点发布数据,另一个节点订阅该话题以接收数据。

示例代码可在这里找到。

前提条件

  • 已完成前面的工作空间和功能包创建教程
  • 建议对Python有基本了解(非必需)

任务

1. 创建功能包

打开新终端并配置ROS 2环境,使ros2命令可用。

进入之前创建的ros2_ws目录。

记得功能包应在src目录中创建,而非工作空间根目录。进入ros2_ws/src,运行功能包创建命令:

ros2 pkg create --build-type ament_python --license Apache-2.0 py_pubsub

终端会返回确认信息,显示py_pubsub功能包及其所有必要文件和文件夹已创建。

2. 编写发布者节点

进入ros2_ws/src/py_pubsub/py_pubsub目录(这是与ROS 2功能包同名的Python包目录)。

通过以下命令下载示例talker代码:

Linux/macOS

wget https://raw.githubusercontent.com/ros2/examples/kilted/rclpy/topics/minimal_publisher/examples_rclpy_minimal_publisher/publisher_member_function.py

Windows命令提示符

curl -sk https://raw.githubusercontent.com/ros2/examples/kilted/rclpy/topics/minimal_publisher/examples_rclpy_minimal_publisher/publisher_member_function.py -o publisher_member_function.py

Windows PowerShell

curl https://raw.githubusercontent.com/ros2/examples/kilted/rclpy/topics/minimal_publisher/examples_rclpy_minimal_publisher/publisher_member_function.py -o publisher_member_function.py

现在__init__.py旁边会有一个新文件publisher_member_function.py

用文本编辑器打开该文件:

import rclpy
from rclpy.executors import ExternalShutdownException
from rclpy.node import Nodefrom std_msgs.msg import Stringclass MinimalPublisher(Node):def __init__(self):super().__init__('minimal_publisher')self.publisher_ = self.create_publisher(String, 'topic', 10)timer_period = 0.5  # secondsself.timer = self.create_timer(timer_period, self.timer_callback)self.i = 0def timer_callback(self):msg = String()msg.data = 'Hello World: %d' % self.iself.publisher_.publish(msg)self.get_logger().info('Publishing: "%s"' % msg.data)self.i += 1def main(args=None):try:with rclpy.init(args=args):minimal_publisher = MinimalPublisher()rclpy.spin(minimal_publisher)except (KeyboardInterrupt, ExternalShutdownException):passif __name__ == '__main__':main()
2.1 代码解析

代码开头导入了rclpy及其Node类,以便创建节点。

import rclpy
from rclpy.executors import ExternalShutdownException
from rclpy.node import Node

下一行导入了节点用于在话题上传递数据的内置字符串消息类型。

from std_msgs.msg import String

这些行代表了节点的依赖关系,需要添加到package.xml中(将在下一节完成)。

接下来创建了MinimalPublisher类,继承自Node类。

class MinimalPublisher(Node):

类的构造函数中,super().__init__调用了Node类的构造函数并给节点命名为minimal_publisher

create_publisher声明该节点通过名为topic的话题发布String类型的消息,队列大小为10。队列大小是QoS(服务质量)的必要设置,用于限制当订阅者接收速度不够快时的消息积压数量。

然后创建了一个定时器,每0.5秒执行一次回调函数。self.i是回调函数中使用的计数器。

def __init__(self):super().__init__('minimal_publisher')self.publisher_ = self.create_publisher(String, 'topic', 10)timer_period = 0.5  # secondsself.timer = self.create_timer(timer_period, self.timer_callback)self.i = 0

timer_callback创建带有计数器值的消息,并通过get_logger().info将其发布到控制台。

def timer_callback(self):msg = String()msg.data = 'Hello World: %d' % self.iself.publisher_.publish(msg)self.get_logger().info('Publishing: "%s"' % msg.data)self.i += 1

最后定义了main函数:

def main(args=None):try:with rclpy.init(args=args):minimal_publisher = MinimalPublisher()rclpy.spin(minimal_publisher)except (KeyboardInterrupt, ExternalShutdownException):pass

该函数初始化rclpy库,创建节点,然后"spin"节点以调用其回调函数。

2.2 添加依赖

回到ros2_ws/src/py_pubsub目录,这里已为你创建了setup.pysetup.cfgpackage.xml文件。

用文本编辑器打开package.xml,填写<description><maintainer><license>标签:

<description>Examples of minimal publisher/subscriber using rclpy</description>
<maintainer email="you@email.com">Your Name</maintainer>
<license>Apache-2.0</license>

在这些行之后,添加与节点导入语句对应的依赖:

<exec_depend>rclpy</exec_depend>
<exec_depend>std_msgs</exec_depend>

这声明了代码执行时需要rclpystd_msgs。保存文件。

2.3 添加入口点

打开setup.py文件,确保maintainermaintainer_emaildescriptionlicense字段与package.xml匹配:

maintainer='YourName',
maintainer_email='you@email.com',
description='Examples of minimal publisher/subscriber using rclpy',
license='Apache-2.0',

entry_points字段的console_scripts括号内添加以下行:

entry_points={'console_scripts': ['talker = py_pubsub.publisher_member_function:main',],
},

保存文件。

2.4 检查setup.cfg

setup.cfg文件内容应已自动正确填充:

[develop]
script_dir=$base/lib/py_pubsub[install]
install_scripts=$base/lib/py_pubsub

这告诉setuptools将你的可执行文件放在lib目录中,因为ros2 run会在那里寻找它们。

你现在可以构建功能包并运行,但让我们先创建订阅者节点,以便看到完整系统的工作效果。

3. 编写订阅者节点

回到ros2_ws/src/py_pubsub/py_pubsub目录,通过以下命令下载订阅者代码:

Linux/macOS

wget https://raw.githubusercontent.com/ros2/examples/kilted/rclpy/topics/minimal_subscriber/examples_rclpy_minimal_subscriber/subscriber_member_function.py

Windows命令提示符

curl -sk https://raw.githubusercontent.com/ros2/examples/kilted/rclpy/topics/minimal_subscriber/examples_rclpy_minimal_subscriber/subscriber_member_function.py -o subscriber_member_function.py

Windows PowerShell

curl https://raw.githubusercontent.com/ros2/examples/kilted/rclpy/topics/minimal_subscriber/examples_rclpy_minimal_subscriber/subscriber_member_function.py -o subscriber_member_function.py

现在目录中应该有这些文件:

__init__.py  publisher_member_function.py  subscriber_member_function.py
3.1 代码解析

用文本编辑器打开subscriber_member_function.py

import rclpy
from rclpy.executors import ExternalShutdownException
from rclpy.node import Nodefrom std_msgs.msg import Stringclass MinimalSubscriber(Node):def __init__(self):super().__init__('minimal_subscriber')self.subscription = self.create_subscription(String,'topic',self.listener_callback,10)self.subscription  # 防止未使用变量的警告def listener_callback(self, msg):self.get_logger().info('I heard: "%s"' % msg.data)def main(args=None):try:with rclpy.init(args=args):minimal_subscriber = MinimalSubscriber()rclpy.spin(minimal_subscriber)except (KeyboardInterrupt, ExternalShutdownException):passif __name__ == '__main__':main()

订阅者节点代码与发布者几乎相同。构造函数创建了一个订阅者,使用与发布者相同的参数。从话题教程中记得,发布者和订阅者使用的话题名称和消息类型必须匹配才能通信。

self.subscription = self.create_subscription(String,'topic',self.listener_callback,10)

订阅者的构造函数和回调函数没有定时器定义,因为它不需要—只要收到消息,回调函数就会被调用。

回调函数定义简单地将信息消息和接收到的数据打印到控制台。

def listener_callback(self, msg):self.get_logger().info('I heard: "%s"' % msg.data)

main函数几乎相同,只是创建和spin的是订阅者节点而非发布者。

minimal_subscriber = MinimalSubscriber()
rclpy.spin(minimal_subscriber)

由于该节点与发布者有相同的依赖,无需向package.xml添加新内容,setup.cfg文件也无需修改。

3.2 添加入口点

重新打开setup.py,在发布者入口点下方添加订阅者节点的入口点。entry_points字段现在应如下所示:

entry_points={'console_scripts': ['talker = py_pubsub.publisher_member_function:main','listener = py_pubsub.subscriber_member_function:main',],
},

保存文件,你的发布/订阅系统现在已准备就绪。

4. 构建并运行

你可能已经将rclpystd_msgs作为ROS 2系统的一部分安装了。在构建前,在工作空间根目录(ros2_ws)运行rosdep检查缺失依赖是个好习惯:

Linux

rosdep install -i --from-path src --rosdistro kilted -y

rosdep只在Linux上运行,macOS和Windows用户可以直接跳到下一步。

在工作空间根目录ros2_ws中构建新功能包:

Linux/macOS

colcon build --packages-select py_pubsub

Windows

colcon build --merge-install --packages-select py_pubsub

打开新终端,进入ros2_ws,配置设置文件:

Linux

source install/setup.bash

macOS

. install/setup.bash

Windows

call install/setup.bat

现在运行talker节点。终端应该会开始每0.5秒发布一条信息:

ros2 run py_pubsub talker
[info] [minimal_publisher]: publishing: "hello world: 0"
[info] [minimal_publisher]: publishing: "hello world: 1"
[info] [minimal_publisher]: publishing: "hello world: 2"
[info] [minimal_publisher]: publishing: "hello world: 3"
[info] [minimal_publisher]: publishing: "hello world: 4"
...

打开另一个终端,再次在ros2_ws中配置设置文件,然后启动listener节点。listener会从发布者当前的消息计数开始打印消息:

ros2 run py_pubsub listener
[INFO] [minimal_subscriber]: I heard: "Hello World: 10"
[INFO] [minimal_subscriber]: I heard: "Hello World: 11"
[INFO] [minimal_subscriber]: I heard: "Hello World: 12"
[INFO] [minimal_subscriber]: I heard: "Hello World: 13"
[INFO] [minimal_subscriber]: I heard: "Hello World: 14"

在每个终端中按Ctrl+C停止节点运行。

总结

你创建了两个节点通过话题发布和订阅数据。在运行它们之前,你将依赖关系和入口点添加到了功能包的配置文件中。

下一步

接下来,你将使用服务/客户端模型创建另一个简单的ROS 2功能包,同样可以选择用C++或Python编写。

http://www.dtcms.com/a/395774.html

相关文章:

  • AI设计功能性病毒:从DNA语言模型到精准杀菌实战
  • Qt 共享指针QSharedPointer与std::shared_ptr
  • Java课程 第02周 预习、实验与作业:Java基础语法2:面向对象入门
  • 词性标注技术漫谈:为词语赋予语法灵魂的旅程
  • K230基础-MicroPython
  • 网站访问问题:无法访问此网站、404
  • Redis 与Memcached 的对比
  • PyTorch 神经网络工具箱:核心原理与实践指南
  • 广义矩估计错误指定时的一个推导【续5】
  • 【STM32】ADC数模转换器
  • Tensorboard学习记录
  • Redis中常见数据结构底层实现结构是什么
  • 高频交易技术演进:从毫秒到纳秒的极限延迟优化之路
  • 从零开始搭建并部署一个基于Django和YOLO的智能模型项目
  • MySQL零基础学习Day2——数据库基础操作
  • 数学笔试选择题:题组1
  • Linux常用命令51——tail查看文件尾部内容
  • Django多数据库配置:mysql、mongo、redis、达梦
  • 图像拼接(反向拼接巨难,求指教!)
  • [免费]基于Python的深度学习音乐推荐系统(后端Django)【论文+源码+SQL脚本】
  • 南华 NHL-1 型加载减速工况法轻型柴油车烟度检测系统:技术解析与实战指南
  • 学习Java遇到的一些问题
  • 基于SpringBoot招聘信息管理系统
  • 多线程—线程通信之notifyAll()/wait()方法Demo
  • kotlin 常用函数
  • 2025年CSP-J1入门级初赛题解
  • vue3的基本指令以及对js的导入和导出
  • Linux 基础:关机与重启
  • React Native:分享Windows平台搭建react native并构建apk的操作流程和配置信息
  • EC24026露营灯警示灯芯片方案 报警声语音IC 单片机方案开发