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

在ROS2中,通过MoveIt2控制Gazebo中的自定义机械手

目前的空余时间主要都在研究ROS2,最终目的是控制自己用舵机组装的机械手。
由于种种原因,先控制Gazebo的自定义机械手。
先看看目前的成果
在这里插入图片描述左侧是rviz2中的moveit组件的机械手,右侧是gazebo中的机械手。在moveit中进行路径规划并执行后,右侧gazebo中的机械手也就执行相应的动作。

1.软件的安装

1.1.Ubuntu 22.04

据说win10下也可以装ROS2,但是十分折腾,还是在Ubuntu下安装方便一些,Ubuntu22.04才有humble版本的ros2,Ubuntu20.04没有humble。

1.2.ROS2

按照鱼香ros的教程,在命令行中执行鱼香ROS的一键安装代码

wget http://fishros.com/install -O fishros && . fishros 

然后选择安装ros,选择humble版本。

1.3.Gazebo

参考教程
只要执行两行就行

sudo apt install gazebo11
sudo apt install ros-humble-gazebo-*

1.4.MoveIt2

参考教程
MoveIt2可以选择自己编译源码安装,或者直接从二进制安装。
个人建议直接二进制安装,可以省很多事。

sudo apt install ros-humble-moveit

1.5.moveit-setup-assistant

这是一个配套moveit的配置助手,有了它就可以方便地进行很多初始化的工作。

sudo apt install ros-humble-moveit-setup-assistant

2.机械手urdf文件的编写

我们用urdf文件来描述我们的机械手的外观以及物理性能。这里为了简便,就只用了基本的圆柱、立方体了。追求美观的朋友,还可以用dae文件来描述机械手的外形。
文件six_arm.urdf

<?xml version="1.0"?>
<robot name="six_arm"><!-- Base link --><link name="base_link"><visual><geometry><box size="0.1 0.1 0.1"/></geometry><origin rpy="0 0 0" xyz="0 0 0.05"/><material name="blue"><color rgba="0 0 1.0 1"/></material></visual><collision><geometry><box size="0.1 0.1 0.1"/></geometry><origin rpy="0 0 0" xyz="0 0 0.05"/></collision><inertial><mass value="10"/><inertia ixx="0" ixy="0" ixz="0" iyy="0" iyz="0" izz="0"/></inertial></link><!-- Link 1 --><link name="link1"><visual><geometry><cylinder length="0.1" radius="0.03"/></geometry><origin rpy="0 0 0" xyz="0 0 0.05"/><material name="green"><color rgba="0 0.8 0 1"/></material></visual><collision><geometry><cylinder length="0.1" radius="0.03"/></geometry><origin rpy="0 0 0" xyz="0 0 0.05"/></collision><inertial><mass value="0.2"/><inertia ixx="0" ixy="0" ixz="0" iyy="0" iyz="0" izz="0"/></inertial></link><!-- Joint 1: rotation around X-axis --><joint name="joint1" type="continuous"><parent link="base_link"/><child link="link1"/><axis xyz="0 0 1"/><origin xyz="0 0 0.1" rpy="0 0 0"/></joint><!-- Link 2 --><link name="link2"><visual><geometry><cylinder length="0.1" radius="0.03"/></geometry><origin rpy="0 0 0" xyz="0 0 0.05"/><material name="red"><color rgba="0.8 0 0 1"/></material></visual><collision><geometry><cylinder length="0.1" radius="0.03"/></geometry><origin rpy="0 0 0" xyz="0 0 0.05"/></collision><inertial><mass value="0.2"/><inertia ixx="0" ixy="0" ixz="0" iyy="0" iyz="0" izz="0"/></inertial></link><!-- Joint 2: rotation around Y-axis --><joint name="joint2" type="continuous"><parent link="link1"/><child link="link2"/><axis xyz="1 0 0"/><origin xyz="0 0 0.1"/></joint><!-- Link 3 --><link name="link3"><visual><geometry><cylinder length="0.1" radius="0.03"/></geometry><origin rpy="0 0 0" xyz="0 0 0.05"/><material name="yellow"><color rgba="0.8 0.8 0 1"/></material></visual><collision><geometry><cylinder length="0.1" radius="0.03"/></geometry><origin rpy="0 0 0" xyz="0 0 0.05"/></collision><inertial><mass value="0.2"/><inertia ixx="0" ixy="0" ixz="0" iyy="0" iyz="0" izz="0"/></inertial></link><!-- Joint 3: rotation around x-axis --><joint name="joint3" type="continuous"><parent link="link2"/><child link="link3"/><axis xyz="1 0 0"/><origin xyz="0 0 0.1"/></joint><!-- Link 4 --><link name="link4"><visual><geometry><cylinder length="0.1" radius="0.03"/></geometry><origin rpy="0 0 0" xyz="0 0 0.05"/><material name="green"><color rgba="0 0.8 0 1"/></material></visual><collision><geometry><cylinder length="0.1" radius="0.03"/></geometry><origin rpy="0 0 0" xyz="0 0 0.05"/></collision><inertial><mass value="0.2"/><inertia ixx="0" ixy="0" ixz="0" iyy="0" iyz="0" izz="0"/></inertial></link><!-- Joint 4: rotation around X-axis --><joint name="joint4" type="continuous"><parent link="link3"/><child link="link4"/><axis xyz="0 1 0"/><origin xyz="0 0 0.1"/></joint><!-- Link 5 --><link name="link5"><visual><geometry><cylinder length="0.1" radius="0.03"/></geometry><origin rpy="0 0 0" xyz="0 0 0.05"/><material name="purple"><color rgba="0.8 0 0.8 1"/></material></visual><collision><geometry><cylinder length="0.1" radius="0.03"/></geometry><origin rpy="0 0 0" xyz="0 0 0.05"/></collision><inertial><mass value="0.2"/><inertia ixx="0" ixy="0" ixz="0" iyy="0" iyz="0" izz="0"/></inertial></link><!-- Joint 5: rotation around Y-axis --><joint name="joint5" type="continuous"><parent link="link4"/><child link="link5"/><axis xyz="1 0 0"/><origin xyz="0 0 0.1"/></joint><!-- Link 6 --><link name="link6"><visual><geometry><box size="0.1 0.1 0.2"/></geometry><origin rpy="0 0 0" xyz="0 0 0.1"/><material name="pink"><color rgba="0.8 0.4 0.8 1"/></material></visual><collision><geometry><box size="0.1 0.1 0.2"/></geometry><origin rpy="0 0 0" xyz="0 0 0.1"/></collision><inertial><mass value="0.2"/><inertia ixx="0" ixy="0" ixz="0" iyy="0" iyz="0" izz="0"/></inertial></link><!-- Joint 6: rotation around Z-axis --><joint name="joint6" type="continuous"><parent link="link5"/><child link="link6"/><axis xyz="0 0 1"/><origin xyz="0 0 0.1"/></joint><!-- Used for fixing robot to Gazebo 'base_link' 将机械手的基座固定在世界坐标上--><link name="world"/><joint name="fixed" type="fixed"><parent link="world"/><child link="base_link"/></joint><gazebo reference="base_link"><material>Gazebo/Black</material><gravity>true</gravity><selfCollide>false</selfCollide></gazebo><gazebo reference="link1"><material>Gazebo/Gray</material><selfCollide>false</selfCollide></gazebo><gazebo reference="link2"><material>Gazebo/Red</material><selfCollide>false</selfCollide></gazebo><gazebo reference="link3"><material>Gazebo/Blue</material></gazebo><gazebo reference="link4"><material>Gazebo/Green</material></gazebo><gazebo reference="link5"><material>Gazebo/Yellow</material></gazebo><gazebo reference="link6"><material>Gazebo/Orange</material></gazebo><!-- 在有需要时注释这个ros2_control节点--><ros2_control name="GazeboSystem" type="system"><hardware><plugin>gazebo_ros2_control/GazeboSystem</plugin></hardware><joint name="joint1"><command_interface name="position"><param name="min">-1</param><param name="max">1</param></command_interface><state_interface name="position"><param name="initial_value">0.0</param></state_interface><state_interface name="velocity"/></joint><joint name="joint2"><command_interface name="position"><param name="min">-1</param><param name="max">1</param></command_interface><state_interface name="position"><param name="initial_value">0.0</param></state_interface><state_interface name="velocity"/></joint><joint name="joint3"><command_interface name="position"><param name="min">-1</param><param name="max">1</param></command_interface><state_interface name="position"><param name="initial_value">0.0</param></state_interface><state_interface name="velocity"/></joint><joint name="joint4"><command_interface name="position"><param name="min">-1</param><param name="max">1</param></command_interface><state_interface name="position"><param name="initial_value">0.0</param></state_interface><state_interface name="velocity"/></joint><joint name="joint5"><command_interface name="position"><param name="min">-1</param><param name="max">1</param></command_interface><state_interface name="position"><param name="initial_value">0.0</param></state_interface><state_interface name="velocity"/></joint><joint name="joint6"><command_interface name="position"><param name="min">-1</param><param name="max">1</param></command_interface><state_interface name="position"><param name="initial_value">0.0</param></state_interface><state_interface name="velocity"/></joint></ros2_control><gazebo><plugin filename="libgazebo_ros2_control.so" name="gazebo_ros2_control"><parameters>/home/yong/Desktop/myRobot/src/mybot/config/ros2_controllers.yaml</parameters><robot_param_node>robot_state_publisher</robot_param_node></plugin></gazebo></robot>

2.1.机械手的外型

可以在vscode中打开这个文件然后用插件就可以看到这个机械手的外形,关于urdf语法的详细介绍,可以看这里。
在这里插入图片描述

2.2.机械手link的inertial的设置

我这里偷懒,随便设置的。真正设置的话,有公式,自己可以参考一下。
urdf里面的link必须要有旋转惯量矩阵‘intertial’的,否则在gazebo里面导入模型urdf时,会报下面的错。
[gazebo-1] [Err] [Model.cc:123] Error Code 23 Msg: FrameAttachedToGraph error, Non-LINK vertex with name [model] is disconnected; it should have 1 outgoing edge in MODEL attached_to graph.

2.3.ros2_control插件

该插件是在gazbo导入该模型文件时,创建与Ros2交互的接口。
在这里插入图片描述
上面的ros2_controllers.yaml文件是在下一步创建出来的,先不用管。
同时,ros2_control这个节点下的内容也是要和ros2_controllers.yaml对应的,也可以先不管。
这个节点在开始阶段先注释掉,否则会与通过moveit_setup_assistant创建的一个fake_systemde ros2_control冲突。
在这里插入图片描述

3.机械手与MoveIt的关联

通过前面的操作,我们拥有了一个描述机械手的文件 six_arm.urdf,接下来我们利用该文件创建一个可以利用MoveIt进行路径规划的“工程”。

3.1.建立一个文件夹myRobot,然后再在此文件夹中建立一个src文件夹

在这里插入图片描述

3.2.然后进入src文件夹路径,创建包

ros2 pkg create mybot_description --build-type ament_python

在这里插入图片描述

3.3.在 src/mybot_description文件夹下,创建urdf文件夹,然后把six_arm.urdf放进去,如下图所示。

在这里插入图片描述

3.4.返回myRobot目录,然后编译一下

colcon build

在这里插入图片描述

3.5.source一下

source的目的是为了把我们创建的 mybot_description项目暴露给控制台,然后让后续的moveit_setup_assistant可以找到对应的urdf文件

source install/setup.bash 

3.6.利用moveit_setup_assistant创建项目

参考教程,启动moveit_setup_assistant

 ros2 run moveit_setup_assistant moveit_setup_assistant

记得选择src里面的urdf,然后后面的就按照教程来干了。
注意:group name设置my_group
一些关键的设置看下列图
在这里插入图片描述在这里插入图片描述

在这里插入图片描述在这里插入图片描述在最后一步保存时,在我们前面创建的src文件夹里面,创建一个mybot文件夹
在这里插入图片描述然后在助手里选择该路径,点击generat package
在这里插入图片描述

3.7.编译试运行

此时,退出助手,并执行编译;
编译完成后,重新source一下。

colcon build
source install/setup.bash 

在这里插入图片描述
记得把前面的urdf文件里面的这个路径改成你自己的。
在这里插入图片描述这段注释一下,否则会有冲突。到后面就可以取消注释,但是目前要注释掉。
在这里插入图片描述

每次修改完文件后,记得都要 colcon build一下。

试着执行

ros2 launch mybot demo.launch.py

会报错
在这里插入图片描述
这是因为在编译时没有把urdf文件拷贝到install目录中,因此我们需要修改一下 src/mybot_description/setup.py
修改三处地方,将其修改成类似下面这样
修改完之后就可以自动在编译时复制到install目录了,具体原理可以自己按照代码推测一下

from setuptools import setupfrom glob import glob #这里
import os #这里package_name = 'mybot_description'setup(name=package_name,version='0.0.0',packages=[package_name],data_files=[('share/ament_index/resource_index/packages',['resource/' + package_name]),('share/' + package_name, ['package.xml']),(os.path.join('share', package_name, 'urdf'), glob('urdf/**')), #这里],install_requires=['setuptools'],zip_safe=True,maintainer='yong',maintainer_email='yong@todo.todo',description='TODO: Package description',license='TODO: License declaration',tests_require=['pytest'],entry_points={'console_scripts': [],},
)

colcon build一下。
然后启动

ros2 launch mybot demo.launch.py

然后就可以愉快地玩耍了。
在这里插入图片描述
假如报其他错误请查看此处。

4.机械手与Gazebo的关联

4.1.在 src/mybot/launch 路径下,新建一个文件: gazebo.launch.py

在这里插入图片描述其内容如下

import os
from launch import LaunchDescription
from launch.actions import ExecuteProcess, RegisterEventHandler
from launch_ros.actions import Node
from launch_ros.substitutions import FindPackageSharefrom launch.event_handlers import OnProcessExitdef generate_launch_description():robot_name_in_model = 'six_arm'package_name = 'mybot_description'urdf_name = "six_arm.urdf"pkg_share = FindPackageShare(package=package_name).find(package_name) urdf_model_path = os.path.join(pkg_share, f'urdf/{urdf_name}')# Start Gazebo serverstart_gazebo_cmd =  ExecuteProcess(cmd=['gazebo', '--verbose','-s', 'libgazebo_ros_init.so', '-s', 'libgazebo_ros_factory.so'],output='screen')# Launch the robotspawn_entity_cmd = Node(package='gazebo_ros', executable='spawn_entity.py',arguments=['-entity', robot_name_in_model,  '-file', urdf_model_path ], output='screen')node_robot_state_publisher = Node(package='robot_state_publisher',executable='robot_state_publisher',arguments=[urdf_model_path],parameters=[{'use_sim_time': True}],output='screen')# 关节状态发布器load_joint_state_controller = ExecuteProcess(cmd=['ros2', 'control', 'load_controller', '--set-state', 'active','joint_state_broadcaster'],output='screen')# 路径执行控制器load_joint_trajectory_controller = ExecuteProcess(cmd=['ros2', 'control', 'load_controller', '--set-state', 'active','my_group_controller'],output='screen')close_evt1 =  RegisterEventHandler( event_handler=OnProcessExit(target_action=spawn_entity_cmd,on_exit=[load_joint_state_controller],))close_evt2 = RegisterEventHandler(event_handler=OnProcessExit(target_action=load_joint_state_controller,on_exit=[load_joint_trajectory_controller],))ld = LaunchDescription()ld.add_entity(close_evt1)ld.add_entity(close_evt2)ld.add_action(start_gazebo_cmd)ld.add_action(node_robot_state_publisher)ld.add_action(spawn_entity_cmd)return ld

4.2.将 src/mybot_description/urdf/six_arm.urdf 的内容修改一下

将这一段取消注释。
在这里插入图片描述

4.3.编译、运行

每次修改完文件后,记得都要 colcon build一下。
colcon build一下。
然后启动

ros2 launch mybot gazebo.launch.py 

然后就可以愉快地玩耍了。
在这里插入图片描述

4.4. action send_goal 测试

目前运行的这这个gazebo例子已经开放了一个action接口,通过这个接口,我们就可以直接发送一个路径让其执行。
在这里插入图片描述
我们可以手写一个轨迹,然后让其执行
新建一个my_send_goal.sh文件,然后通过 chmod +x 使其具有执行权限
在这里插入图片描述
在这里插入图片描述
文件内容如下:

ros2 action send_goal /my_group_controller/follow_joint_trajectory control_msgs/action/FollowJointTrajectory "{trajectory: {joint_names: [joint1, joint2, joint3, joint4, joint5, joint6],points: [{ positions: [0.1, 0.1, 0.1, 0.1, 0.1, 0.1], time_from_start: { sec: 0, nanosec: 500 } },{ positions: [0.2, 0.5, 0.2 ,0.2, 0.2, 0.2], time_from_start: { sec: 5, nanosec: 500 } },{ positions: [0.3, 0.3, 0.7, -0.5, 0.3, 0.3], time_from_start: { sec: 7, nanosec: 500 } },{ positions: [0.4, 0.4, 0.9, 0.4, 0.4, 0.4], time_from_start: { sec: 8, nanosec: 500 } }]}
}"

然后在控台里面执行

./my_send_goal.sh 

接下来可以看到gazebo中的机械手按照我们设定的轨迹进行运动了。
在这里插入图片描述可以尝试改变一下my_send_goal.sh 的内容,然后推测一下各个参数的意义。

5.MoveIt与Gazebo的关联

moveit提供了路径规划接口,gazebo提供了执行接口,因此只需要将他们连起来就实现了路径规划仿真了。

5.1.原理分析

在前面通过moveit_setup_assistant创建的包中,之所以可以进行路径规划并执行,是因为他既启动了moveit的组件,也启动了一个FakeSystem节点,该节点代替了实际的机械手反馈moveit的路径规划(提供action给moveit连接)。
在这里插入图片描述
从下图可以看出,当我们执行demo时,有好几个节点启动了。
在这里插入图片描述
但是假如我们需要将FakeSystem节点替换成gazebo的节点,就可以通过只启动需要的几个节点,然后不启动FakeSystem就行。

5.2.launch文件编写

按照5.1的分析,我们可以在src/mybot/launch下新建一个文件my_moveit_rviz.launch.py,
在这里插入图片描述文件内容为

from moveit_configs_utils import MoveItConfigsBuilder
from moveit_configs_utils.launches import generate_moveit_rviz_launchfrom launch import LaunchDescription
from launch.actions import (DeclareLaunchArgument,IncludeLaunchDescription,
)
from moveit_configs_utils.launch_utils import (add_debuggable_node,DeclareBooleanLaunchArg,
)
from launch.substitutions import LaunchConfiguration
from launch_ros.parameter_descriptions import ParameterValuedef generate_launch_description():moveit_config = MoveItConfigsBuilder("six_arm", package_name="mybot_description").to_moveit_configs()ld = LaunchDescription()# 启动move_groupmy_generate_move_group_launch(ld, moveit_config)# 启动rvizmy_generate_moveit_rviz_launch(ld, moveit_config)return lddef my_generate_move_group_launch(ld, moveit_config):ld.add_action(DeclareBooleanLaunchArg("debug", default_value=False))ld.add_action(DeclareBooleanLaunchArg("allow_trajectory_execution", default_value=True))ld.add_action(DeclareBooleanLaunchArg("publish_monitored_planning_scene", default_value=True))# load non-default MoveGroup capabilities (space separated)ld.add_action(DeclareLaunchArgument("capabilities", default_value=""))# inhibit these default MoveGroup capabilities (space separated)ld.add_action(DeclareLaunchArgument("disable_capabilities", default_value=""))# do not copy dynamics information from /joint_states to internal robot monitoring# default to false, because almost nothing in move_group relies on this informationld.add_action(DeclareBooleanLaunchArg("monitor_dynamics", default_value=False))should_publish = LaunchConfiguration("publish_monitored_planning_scene")move_group_configuration = {"publish_robot_description_semantic": True,"allow_trajectory_execution": LaunchConfiguration("allow_trajectory_execution"),# Note: Wrapping the following values is necessary so that the parameter value can be the empty string"capabilities": ParameterValue(LaunchConfiguration("capabilities"), value_type=str),"disable_capabilities": ParameterValue(LaunchConfiguration("disable_capabilities"), value_type=str),# Publish the planning scene of the physical robot so that rviz plugin can know actual robot"publish_planning_scene": should_publish,"publish_geometry_updates": should_publish,"publish_state_updates": should_publish,"publish_transforms_updates": should_publish,"monitor_dynamics": False,}move_group_params = [moveit_config.to_dict(),move_group_configuration,]move_group_params.append({"use_sim_time": True})add_debuggable_node(ld,package="moveit_ros_move_group",executable="move_group",commands_file=str(moveit_config.package_path / "launch" / "gdb_settings.gdb"),output="screen",parameters=move_group_params,extra_debug_args=["--debug"],# Set the display variable, in case OpenGL code is used internallyadditional_env={"DISPLAY": ":0"},)return lddef my_generate_moveit_rviz_launch(ld, moveit_config):"""Launch file for rviz"""ld.add_action(DeclareBooleanLaunchArg("debug", default_value=False))ld.add_action(DeclareLaunchArgument("rviz_config",default_value=str(moveit_config.package_path / "config/moveit.rviz"),))rviz_parameters = [moveit_config.planning_pipelines,moveit_config.robot_description_kinematics,]rviz_parameters.append({"use_sim_time": True})add_debuggable_node(ld,package="rviz2",executable="rviz2",output="log",respawn=False,arguments=["-d", LaunchConfiguration("rviz_config")],parameters=rviz_parameters,)return ld

在文件中,我们主要启动了两个节点:move_group、rviz。
这里面这还涉及到一个use_sim_time的问题,因此才这样重写。参考这里
然后colcon build一下。

5.2.执行测试

分别打开两个控制台,然后分别执行以下命令

ros2 launch mybot gazebo.launch.py
ros2 launch mybot my_moveit_rviz.launch.py 

在这里插入图片描述
注意是要先运行gazebo(ros2 launch mybot gazebo.launch.py),然后再运行moveit(ros2 launch mybot my_moveit_rviz.launch.py )
在moveit里面规划路径、然后执行。
在gazebo就可以看到模型动了起来。
在这里插入图片描述

6.总结

目前只是通过大致的操作完成了moveit控制gazebo里面的机械手,是偏操作方面的,原理可以粗略地理解成action的通讯。至于更加详细以及深入的教程,就等各位大佬来完成了。

相关文章:

在ROS2中,通过MoveIt2控制Gazebo中的自定义机械手

目前的空余时间主要都在研究ROS2&#xff0c;最终目的是控制自己用舵机组装的机械手。 由于种种原因&#xff0c;先控制Gazebo的自定义机械手。 先看看目前的成果 左侧是rviz2中的moveit组件的机械手&#xff0c;右侧是gazebo中的机械手。在moveit中进行路径规划并执行后&#…...

Java-线程池 原子性 类

Java-线程池 原子性 类线程池构造方法调用Executors静态方法创建调用方法直接创建线程池对象原子性volatile-问题出现原因:volatile解决原子性AtomicInteger的常用方法悲观锁和乐观锁synchronized(悲)和CAS(乐)的区别并发工具类Hashtable集合ConcurrentHashMap原理:CountDownLa…...

力扣sql简单篇练习(二十五)

力扣sql简单篇练习(二十五) 1 无效的推文 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 # Write your MySQL query statement below SELECT tweet_id FROM Tweets WHERE CHAR_LENGTH(content)>151.3 运行截图 2 求关注者的数量 2.1 基本题目内…...

计算机网络:OSPF协议和链路状态算法

OSPF协议 开放最短路经优先OSPF协议是基于最短路径算法SPF,其主要特征就是使用分布式的链路状态协议OSPF协议的特点&#xff1a; 1.使用泛洪法向自治系统中的所有路由器发送信息&#xff0c;即路由器通过输出端口向所有相邻的路由器发送信息&#xff0c;而每一个相邻的路由器又…...

利用表驱动法+策略模式优化switch-case

1.前言 我有一个需求&#xff1a;有四个系统需要处理字段&#xff0c;一开始利用switch-case进行区分编码&#xff0c;后期字段处理越来越多&#xff0c;导致switch-case代码冗余&#xff0c;不太好&#xff0c;然后想通过java单继承多实现的性质进行优化。 2.实现 2.1定义S…...

SpringBoot创建和使用

目录 什么是SpringBoot SpringBoot的优点 SpringBoot项目的创建 1、使用idea创建 2、项目目录介绍和运行 Spring Boot配置文件 1、配置文件 2、配置文件的格式 3、properties 3.1、properties基本语法 3.2、读取配置文件 3.3、缺点 4、yml 4.1、优点 4.2、yml基本…...

which、whereis、locate文件查找命令

Linux下查找文件的命令有which、whereis、locate和find&#xff0c;find命令因要遍历文件系统&#xff0c;导致速度较慢&#xff0c;而且还会影响系统性能&#xff0c;而且命令选项较多&#xff0c;就单独放一篇介绍&#xff0c;可参见find命令——根据路径和条件搜索指定文件_…...

Uipath Excel 自动化系列14-SaveExcelFile(保存Excel)

活动描述 SaveExcelFile 保存Excel:保存工作簿&#xff0c;在修改 Excel 文件的用户界面自动化活动之后使用此活动&#xff0c;以保存对文件的更改 SaveExcelFile As 另存Excel : 将workbook 另存为文件 SaveExcelFile As PDF &#xff1a;将Excel 另存为PDF文件。该三个活…...

MyBatis学习

MyBatis优点 轻量级&#xff0c;性能出色 SQL 和 Java 编码分开&#xff0c;功能边界清晰。Java代码专注业务、SQL语句专注数据 开发效率稍逊于HIbernate&#xff0c;但是完全能够接受 补充&#xff1a;POJO 一&#xff1a;什么是POJO POJO的名称有多种&#xff0c;pure old…...

高速PCB设计指南系列(二)

第三篇 高速PCB设计 &#xff08;一&#xff09;、电子系统设计所面临的挑战   随着系统设计复杂性和集成度的大规模提高&#xff0c;电子系统设计师们正在从事100MHZ以上的电路设计&#xff0c;总线的工作频率也已经达到或者超过50MHZ&#xff0c;有的甚至超过100MHZ。目前…...

uniapp项目打包上线流程

平台&#xff1a;h5小程序app &#xff08;安卓&#xff09;小程序打包上线流程第一步&#xff1a;登录小程序公众平台第二步&#xff1a;hbuilderx打包小程序1.在mainfest.json文件中进行相关配置2.需要将项目中的网络请求改为https协议做为生产环境&#xff08;配置项目的环境…...

垃圾回收:垃圾数据如何自动回收

有些数据被使用之后&#xff0c;可能就不再需要了&#xff0c;我们把这种数据称为垃圾数据。如果这些垃圾数据一直保存在内存中&#xff0c;那么内存会越用越多&#xff0c;所以我们需要对这些垃圾数据进行回收&#xff0c;以释放有限的内存空间 不同语言的垃圾回收策略 通常…...

苹果笔不用原装可以吗?Apple Pencil平替笔推荐

近些年来&#xff0c;不管是学习还是画画&#xff0c;都有不少人喜欢用ipad。而ipad的用户&#xff0c;也是比较重视它的实用价值&#xff0c;尤其是不少人都想要好好利用来进行学习记笔记。事实上&#xff0c;有很多替代品都能替代Apple Pencil&#xff0c;仅仅用于记笔记就没…...

uniCloud基础使用-杂文

获取openID云函数use strict; exports.main async (event, context) > {//event为客户端上传的参数console.log(event : , event)// jscode2session 微信小程序登录接口&#xff0c;获取openidconst {code} event;// 云函数中如需要请求其他http服务&#xff0c;则使用uni…...

vector的模拟实现

文章目录vector的模拟实现vector 结构定义1. vector的迭代器的实现2. vector四个默认成员函数2.1 构造函数2.1.1 无参2.1.2 n个val初始化2.1.3 迭代器初始化2.2 析构函数2.3 拷贝构造函数2.3.1 传统写法2.3.2 现代写法2.4 赋值重载运算符3. 管理数组相关接口3.1 reserve3.2 res…...

【无标题】compose系列教程-4.相对布局ConstraintLayout的使用

相对布局在Compose中被称为ConstraintLayout&#xff0c;它可以让您以相对于其他元素的方式放置元素。 以下是使用ConstraintLayout实现相对布局的示例代码&#xff1a; Composable fun ConstraintLayoutExample() { ConstraintLayout(modifier Modifier.fillMaxSize()…...

JavaEE简单示例——Bean管理

简单介绍&#xff1a; 在这一章节我们会比较详细的介绍我们在之前的测试类中以及Bean管理XML配置文件中所使用到的类和方法&#xff0c;以及XML中配置的属性所代表的详细含义。以及之前我们反复提到但是一直没有详细的讲解的一个东西&#xff1a;容器。我们可以大致的有一个概…...

react+antdpro+ts实现企业级项目四:注册页面实现及useEmotionCss的介绍

创建文件路径并注册register路由 在pages/User下创建Register文件夹并创建index.tsx文件 然后在config/routes创建register注册路由。注册完后&#xff0c;当在登陆页面点击注册按钮时就可以跳转到此注册页面而不会报404了。 export default [{path: /user,layout: false,rou…...

Shifu基础功能:数据采集

数据采集 我们可以通过HTTP/gRPC与deviceShifu进行通信&#xff0c;deviceShifu会将我们发送的请求转换成设备所支持协议的形式&#xff0c;并发送给设备。 当设备接收到指令之后&#xff0c;数据会传输到deviceShifu中&#xff0c;之后deviceShifu将数据作为我们请求的返回值…...

代码随想录算法训练营day54 | 动态规划之子序列 392.判断子序列 115.不同的子序列

day54392.判断子序列1.确定dp数组&#xff08;dp table&#xff09;以及下标的含义2.确定递推公式3.dp数组如何初始化4.确定遍历顺序5.举例推导dp数组115.不同的子序列1.确定dp数组&#xff08;dp table&#xff09;以及下标的含义2.确定递推公式3.dp数组如何初始化4.确定遍历顺…...

MCAL知识点(三):Port与Dio配置

目录 1、概述 2、 Port的EB-tresos配置 2.1、创建模块 2.2 General配置 2.3、PortCnfigSet 2.4、Port的属性...

初识C++需要了解的一些东西(1)

目录&#x1f947;命名空间&#x1f3c5;存在原因&#x1f3f5;命名空间定义&#x1f3a7;命名空间的3种使用方式&#x1f3c6;C输入和输出&#x1f31d;缺省参数&#x1f31c;缺省参数概念⭐️缺省参数分类☀️函数重载&#x1f525;引用&#x1f31a;引用概念&#x1f313;引…...

友元函数的使用大全

概述 我们知道&#xff0c;C的类具有封装和信息隐藏的特性。一般情况下&#xff0c;我们会封装public的成员函数供用户调用&#xff0c;而将成员变量设置为private或protected。但在一些比较复杂的业务情况下&#xff0c;可能需要去访问对象中大量的private或protected成员变量…...

QT学习笔记-QT多项目系统中如何指定各项目的编译顺序

QT学习笔记-QT多项目系统中如何指定各项目的编译顺序背景环境解决思路具体操作背景 为了更好的复用程序功能以及更优雅的管理程序&#xff0c;有经验的程序员通常要对程序进行分层和模块化设计。在QT/C这个工具中同样可以通过创建子项目的方式对程序进行模块化&#xff0c;在这…...

JWT令牌解析及刷新令牌(十一)

写在前面&#xff1a;各位看到此博客的小伙伴&#xff0c;如有不对的地方请及时通过私信我或者评论此博客的方式指出&#xff0c;以免误人子弟。多谢&#xff01;如果我的博客对你有帮助&#xff0c;欢迎进行评论✏️✏️、点赞&#x1f44d;&#x1f44d;、收藏⭐️⭐️&#…...

Hibernate学习(一)

Hibernate学习&#xff08;一&#xff09; Hibernate框架的概述&#xff1a; 一&#xff1a;什么是框架&#xff1a;指软件的半成品&#xff0c;已经完成了部分功能。 二&#xff1a;EE的三层架构&#xff1a; 1.EE的三层经典架构&#xff1a; 我在这里主要学的是ssh框架。 三…...

Go的 context 包的使用

文章目录背景简介主要方法获得顶级上下文当前协程上下文的操作创建下级协程的Context场景示例背景 在父子协程协作过程中, 父协程需要给子协程传递信息, 子协程依据父协程传递的信息来决定自己的操作. 这种需求下可以使用 context 包 简介 Context通常被称为上下文&#xff…...

微服务为什么要用到 API 网关?

本文介绍了 API 网关日志的价值&#xff0c;并以知名网关 Apache APISIX 为例&#xff0c;展示如何集成 API 网关日志。 作者程小兰&#xff0c;API7.ai 技术工程师&#xff0c;Apache APISIX Contributor。 原文链接 什么是微服务 微服务架构&#xff08;通常简称为微服务&a…...

SWUST OJ 1042: 中缀表达式转换为后缀表达式【表达式转逆波兰表达式】

题目描述 中缀表达式是一个通用的算术或逻辑公式表示方法&#xff0c;操作符是以中缀形式处于操作数的中间&#xff08;例&#xff1a;3 4&#xff09;&#xff0c;中缀表达式是人们常用的算术表示方法。后缀表达式不包含括号&#xff0c;运算符放在两个运算对象的后面&#…...

Matlab基础知识

MATLAB批量读入文件和导出文件一、 批量读入文件1.若文件名称有序&#xff0c;则按照文件名称规律循环读取文件(1)读入不同的excelfor i1:1:10strstrcat(F:\数据\v,int2str(i),.xlsx); %连接字符串形成文件名Axlsread(str); end注&#xff1a;变量i为整数时&#xff0c;可以用i…...

动手学深度学习【2】——softmax回归

动手学深度学习网址&#xff1a;动手学深度学习 注&#xff1a;本部分只对基础知识进行简单的介绍并附上完整的代码实现&#xff0c;更多内容可参考上述网址。 前言 前面一节我们谈到了线性回归&#xff0c;它解决的是预测某个值的问题。但是在日常生活这&#xff0c;除了预测…...

深入理解Activity的生命周期

之前学习安卓的时候只是知道生命周期是什么&#xff0c;有哪几个&#xff0c;但具体的详细的东西却不知道&#xff0c;后来看过《Android开发艺术探索》和大量博客之后&#xff0c;才觉得自己真正有点理解生命周期&#xff0c;本文是我对生命周期的认识的总结。废话少说先上图。…...

Go语言刷题常用数据结构和算法

数据结构 字符串 string 访问字符串中的值 通过下标访问 s1 : "hello world"first : s[0]通过切片访问 s2 : []byte(s1) first : s2[0]通过for-range循环访问 for i, v : range s1 {fmt.Println(i, v) }查询字符是否属于特定字符集 // 判断字符串中是否包含a、b、…...

深入vue2.x源码系列:手写代码来模拟Vue2.x的响应式数据实现

前言 Vue响应式原理由以下三个部分组成&#xff1a; 数据劫持&#xff1a;Vue通过Object.defineProperty()方法对data中的每个属性进行拦截&#xff0c;当属性值发生变化时&#xff0c;会触发setter方法&#xff0c;通知依赖更新。发布-订阅模式&#xff1a;Vue使用发布-订阅…...

Linux线程控制

本篇我将学习如何使用多线程。要使用多线程&#xff0c;因为Linux没有给一般用户直接提供操作线程的接口&#xff0c;我们使用的接口&#xff0c;都是系统工程师封装打包成原生线程库中的。那么就需要用到原生线程库。因此&#xff0c;需要引入-lpthread&#xff0c;即连接原生…...

【LeetCode】剑指 Offer(20)

目录 题目&#xff1a;剑指 Offer 38. 字符串的排列 - 力扣&#xff08;Leetcode&#xff09; 题目的接口&#xff1a; 解题思路&#xff1a; 代码&#xff1a; 过啦&#xff01;&#xff01;&#xff01; 写在最后&#xff1a; 题目&#xff1a;剑指 Offer 38. 字符串的…...

FutureTask中的outcome字段是如何保证可见性的?

最近在阅读FutureTask的源码是发现了一个问题那就是源码中封装结果的字段并没有使用volatile修饰&#xff0c;源码如下&#xff1a;public class FutureTask<V> implements RunnableFuture<V> {/*** 状态变化路径* Possible state transitions:* NEW -> COMPLET…...

直播回顾 | 聚焦科技自立自强,Bonree ONE 助力国产办公自动化平稳替代

3月5日&#xff0c;两会发布《政府工作报告》&#xff0c;强调科技政策要聚焦自立自强。 统计显示&#xff0c;2022年金融信创项目数同比增长300%&#xff0c;金融领域信创建设当前已进入发展爆发期&#xff0c;由国有大型银行逐渐向中小型银行、非银金融机构不断扩展。信创云…...

深入理解Linux进程

进程参数和环境变量的意义一般情况下&#xff0c;子进程的创建是为了解决某个问题。那么解决问题什么问题呢&#xff1f;这个就需要进程参数和环境变量来进行决定的。子进程解决问题需要父进程的“数据输入”(进程参数 & 环境变量)设计原则&#xff1a;3.1 子进程启动的时候…...

Vue3之组件间的双向绑定

何为组件间双向绑定 我们都知道当父组件改变了某个值后&#xff0c;如果这个值传给了子组件&#xff0c;那么子组件也会自动跟着改变&#xff0c;但是这是单向的&#xff0c;使用v-bind的方式&#xff0c;即子组件可以使用父组件的值&#xff0c;但是不能改变这个值。组件间的…...

Java语法基础(一)

目录 代码注释方法 编码规范 基本数据类型及取值范围 变量和常量的声明与赋值 变量 常量 标识符 基本数据类型的使用 整数类型的使用 浮点类型的使用 布尔类型的使用 字符类型的使用 代码注释方法 单行注释&#xff1a;使用“//”进行单行注释多行注释&#xff1a;使…...

优思学院|零质量控制是什么概念?

零质量控制&#xff08;Zero Quality Control&#xff09;是指一个理想的系统&#xff0c;可以生产没有任何缺陷的产品&#xff0c;因此不需要频繁的检查&#xff0c;从而节省时间和金钱。那些追求过程优化并致力于持续过程改进的组织将零质量控制&#xff08;Zero Quality Con…...

2023-03-09 CMU15445-Query Execution

摘要: CMU15445, Project #3 - Query Execution 参考: Project #3 - Query Execution | CMU 15-445/645 :: Intro to Database Systems (Fall 2022) https://github.com/cmu-db/bustub 要求: OVERVIEW At this point in the semester, you have implemented the internal co…...

vuedraggable的使用

Draggable为基于Sortable.js的vue组件&#xff0c;用以实现拖拽功能。 特性 支持触摸设备 支持拖拽和选择文本 支持智能滚动 支持不同列表之间的拖拽 不以jQuery为基础 和视图模型同步刷新 和vue2的国度动画兼容 支持撤销操作 当需要完全控制时&#xff0c;可以抛出所有变化 可…...

双馈风力发电机-900V直流混合储能并网系统MATLAB仿真

MATLAB2016b主体模型&#xff1a;双馈感应风机模块、采用真实风速数据。混合储能模块、逆变器模块、转子过电流保护模块、整流器控制模块、逆变器控制模块。直流母线电压&#xff1a;有功、无功输出&#xff08;此处忘记乘负一信号输出&#xff09;&#xff0c;所以是负的。蓄电…...

leader选举过程

启动electionTimer&#xff0c;进行leader选举。 一段时间没有leader和follower通信&#xff0c;就会超时&#xff0c;开始选举leader过程。有个超时时间&#xff0c;如果到了这个时间&#xff0c;就会触发一个回调函数。具体如下: private void handleElectionTimeout() {boo…...

建造者模式

介绍 Java中的建造者模式是一种创建型设计模式,它的主要目的是为了通过一系列简单的步骤构建复杂的对象,允许创建复杂对象的不同表示形式,同时隐藏构造细节.它能够逐步构建对象,即先创建基本对象,然后逐步添加更多属性或部件,直到最终构建出完整的对象. 该模式的主要思想是将…...

IO与NIO区别

一、概念 NIO即New IO,这个库是在JDK1.4中才引入的。NIO和IO有相同的作用和目的,但实现方式不同,NIO主要用到的是块,所以NIO的效率要比IO高很多。在Java API中提供了两套NIO,一套是针对标准输入输出NIO,另一套就是网络编程NIO。 二、NIO和IO的主要区别 下表总结了Java I…...

无监督循环一致生成式对抗网络:PAN-Sharpening

Unsupervised Cycle-Consistent Generative Adversarial Networks for Pan Sharpening &#xff08;基于无监督循环一致生成式对抗网络的全色锐化&#xff09; 基于深度学习的全色锐化近年来受到了广泛的关注。现有方法大多属于监督学习框架&#xff0c;即对多光谱&#xff0…...

ArrayList源码分析(JDK17)

ArrayList类简介类层次结构构造无参构造有参构造添加元素add&#xff1a;添加/插入一个元素addAll:添加集合中的元素扩容mount与迭代器其他常见方法不常见方法不常见方法的源码和小介绍常见方法的源码和小介绍积累面试题ArrayList是什么&#xff1f;可以用来干嘛&#xff1f;Ar…...