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

news2024/11/15 11:00:49

目前的空余时间主要都在研究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的的设置

我这里偷懒,随便设置的。真正设置的话,有公式,自己可以参考一下。
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 setup

from 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 FindPackageShare

from launch.event_handlers import OnProcessExit

def 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 server
    start_gazebo_cmd =  ExecuteProcess(
        cmd=['gazebo', '--verbose','-s', 'libgazebo_ros_init.so', '-s', 'libgazebo_ros_factory.so'],
        output='screen')

    # Launch the robot
    spawn_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接口,通过这个接口,我们就可以直接发送一个路径让其执行。
我们手写一个路径,然后让其执行
新建一个send_goal.sh文件,然后通过 chmod +x 使其具有执行权限
文件内容如下:(明天写)
+++++++++
++++++
然后。。。。

接下来可以看到gazebo中的机械手按照我们设定的轨迹进行运动了。

5.MoveIt与Gazebo的关联

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

5.1.原理分析

在前面通过moveit_setup_assistant创建的包中,之所以可以进行路径规划并执行,是因为他启动了一个fake_system节点,该节点代替了实际的机械手反馈moveit的路径规划(提供action个moveit连接)。从下图可以看出
当我们执行demo时,有好几个节点启动了。

因此假如我们需要将fake_system节点替换成gazebo的节点,就可以通过只启动需要的几个节点,然后不启动fake_system就行。

未完待续。。。

5.2.launch文件编写

按照5.1的分析,我们可以编写一个文件如下。
这还涉及到一个use_sim_time的问题,因此才这样重写。参考----

未完待续。。。

5.2.执行测试

先运行gazebo
然后运行moveit
在moveit里面规划路径、然后执行。
在gazebo就可以看到模型动了起来。
未完待续。。。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/400123.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RolePred: Open-Vocabulary Argument Role Prediction for Event Extraction 论文解读

Open-Vocabulary Argument Role Prediction for Event Extraction 论文&#xff1a;2211.01577.pdf (53yu.com) 代码&#xff1a;yzjiao/RolePred: Source code for EMNLP findings paper “Open-Vocabulary Argument Role Prediction for Event Extraction” (github.com) 期…

优思学院|我们的企业面对哪些危机?六西格玛如何处理这些危机?

如果你在某公司买到的产品经常出现问题&#xff0c;你还会再去买他们的产品吗&#xff1f;如果某公司为你提供的服务经常不如你所预期&#xff0c;你还会再次使用他们的服务吗&#xff1f; 六西格玛管理是以客户为中心&#xff0c;透过六西格玛的工具和方法&#xff0c;针对问…

【黑马】Java基础从入门到起飞目录合集

视频链接&#xff1a; Java入门到起飞&#xff08;上部&#xff09;&#xff1a;BV17F411T7AoJava入门到起飞&#xff08;下部&#xff09;&#xff1a;BV1yW4y1Y7Ms 学习时间&#xff1a; 2023/02/01 —— 2023/03/09断断续续的学习&#xff0c;历时大概37天&#xff0c;完结撒…

php+bootstrap+jquery+mysql实现购物车项目案例

获取源码 一键三连后&#xff0c;评论区留下邮箱安排发送&#xff1a;&#xff09; 介绍 使用php,bootstrap,jquery,mysql实现的简易购物车案例。 通过本案例&#xff0c;你将学习到以下知识点&#xff1a; php 操作 mysql 实现增删改查掌握 php 常用数组函数掌握 php $…

HBase 2.x核心技术

HBase 2.x主要包含以下核心功能&#xff1a; 1、基于Procedure v2重新设计了HBase的Assignment Manager和核心管理流程。通过Procedure v2&#xff0c;HBase能保证各核心步骤的原子性&#xff0c;从设计上解决了分布式场景下多状态不一致的问题。 2、实现了In Memory Compactio…

Chapter2.2:线性表的顺序表示

该系列属于计算机基础系列中的《数据结构基础》子系列&#xff0c;参考书《数据结构考研复习指导》(王道论坛 组编)&#xff0c;完整内容请阅读原书。 2.线性表的顺序表示 2.1 顺序表的定义 线性表的顺序存储亦称为顺序表&#xff0c;是用一组地址连续的存储单元依次存储线性表…

脑机接口科普0017——飞米

本文禁止转载&#xff01;&#xff01;&#xff01;&#xff01; 在我们的九年制义务教育体系中&#xff0c;我们知道纳米是个很小的单位&#xff0c;一般进行单位制的转换的时候&#xff0c;最小就只能到达纳米级别了。 1nm 10^-9 m 这会给学生造成一种误解。认为纳米就是…

搭建兰空图床(Lsky Pro)-docker

兰空图床(Lsky Pro) 官方网站&#xff1a;https://www.lsky.pro/ GitHub&#xff1a;https://github.com/lsky-org/lsky-pro 一, 安装docker-compose 下载-授权 #下载 国内地址 curl -L https://get.daocloud.io/docker/compose/releases/download/1.25.5/docker-compose-una…

dl----算法常识100例

1.depthwise卷积&&Pointwise卷积 depthwise与pointwise卷积又被称为Depthwise Separable Convolution&#xff0c;与常规卷积不同的是此卷积极大地减少了参数数量&#xff0c;同时保持了模型地精度&#xff0c;depthwise操作是先进行二维平面上地操作&#xff0c;然后利…

nginx的学习

1. 我们今天的目标是学习 了解认识nginx的基本结构和语法学习经典案例 2. Nginx是什么 Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器&#xff0c;Nginx是由俄罗斯的人开发的&#xff0c;因它的稳定性、丰富的功能集…

爬虫(二)解析数据

文章目录1. Xpath2. jsonpath3. BeautifulSoup4. 正则表达式4.1 特殊符号4.2 特殊字符4.3 限定符4.3 常用函数4.4 匹配策略4.5 常用正则爬虫将数据爬取到后&#xff0c;并不是全部的数据都能用&#xff0c;我们只需要截取里面的一些数据来用&#xff0c;这也就是解析爬取到的信…

通过测试驱动开发(TDD)的方式开发Web项目

最近在看一本书《Test-Driven Development with Python》&#xff0c;里面非常详细的介绍了如何一步一步通过测试驱动开发(TDD)的方式开发Web项目。刚好这本书中使用了我之前所了解的一些技术&#xff0c;Django、selenium、unittest等。所以&#xff0c;读下来受益匪浅。 我相…

NFT的前景,元宇宙的发展

互联网的普及和数字技术的广泛应用&#xff0c;成为消费升级的新动力&#xff0c;在不断创造出更好的数字化生活的同时&#xff0c;也改变了人们的消费习惯、消费内容、消费模式&#xff0c;甚至是消费理念&#xff0c;数字经济时代的文化消费呈现出新的特征。 2020年有关机构工…

性能优化的核心思路

性能优化的本质是良好的用户体验和有限的资源之间的矛盾。核心思路【1】堆硬件 优化软件&#xff08;算法、步骤&#xff09;【2】开源&#xff08;堆机器&#xff09; 节流&#xff08;提高资源利用率&#xff0c;少占资源&#xff09;【3】输入、计算、输出【4】权衡核心思想…

谷粒学院开发(二):教师管理模块

前后端分离开发 前端 html, css, js, jq 主要作用&#xff1a;数据显示 ajax后端 controller service mapper 主要作用&#xff1a;返回数据或操作数据 接口 讲师管理模块&#xff08;后端&#xff09; 准备工作 创建数据库&#xff0c;创建讲师数据库表 CREATE TABLE edu…

git 当有人邀请你加入项目(gitee)

第一步&#xff0c;找到仓库地址 https://gitee.com/xxxxxxxxxxxxxxxx/abcd.git https://gitee.com/xxxxxxxxxxxxxxxx/abcd.git 2&#xff0c;打开git bush git clone https://gitee.com/xxxxxxxxxxxxxxxx/abcd.git 这条命令新建一个名为abcd&#xff08;也就是项目目录结尾…

python操作频谱仪(是德科技N9030B)

由于工作需要&#xff0c;需要针对产品进行一些自动化的测试&#xff0c;其中就包含了验证开机启动或者长时间运行时候对射频、晶振频率等等一些列进行获取频率或者功率的偏差。这里就需要用到了频谱仪&#xff0c;可以使用脚本连接到频谱仪进行循环对数据的采集等等。直接开始…

Python中的property介绍

Python中的property介绍 Python中进行OOP&#xff08;面向对象程序设计&#xff09;时&#xff0c;获取、设置和删除对象属性&#xff08; attribute&#xff09;的时候&#xff0c;常常需要限制对象属性的设置和获取&#xff0c;比如设置为只读、设置取值范围限制等&#xff…

28个案例问题分析---06---没有复用思想的接口和sql--mybatis,spring

复用思维故事背景没有复用的接口没有复用思想的接口优化方案问题一优化获取所有的课程获取某个人创建的课程问题二优化升华故事背景 项目里有两处没有复用的思想的体现。在这里进行总结并且进行优化。以这种思维方式和习惯来指导我们进行开发工作。 没有复用的接口 通过查看代…

PowerShell远程代码执行漏洞(CVE-2022-41076)分析与复现

漏洞概述PowerShell&#xff08;包括Windows PowerShell和PowerShell Core&#xff09;是微软公司开发的任务自动化和配置管理程序&#xff0c;最初只是一个 Windows 组件&#xff0c;由命令行 shell 和相关的脚本语言组成。后于2016年8月18日开源并提供跨平台支持。PowerShell…