一文学会使用键盘控制moveit2机械臂模型

news2024/9/20 22:38:38

文章目录

  • 前言
  • 一、官方样例实现
    • 软件版本
    • bug修复
    • 运行测试
  • 二、gp110机械臂控制
    • 文件添加
    • 文件修改
    • 编译工程
    • 运行测试
  • 总结


前言

在之前文章的基础上相信大家已经学会了如何搭建一个机械臂模型,那么我们如何对其进行控制呢,上网检索了一下没找到能清晰指导实现整套流程的文章,所以自己摸索着写了一篇希望能帮到大家

这篇文章会分享记录如何实现用键盘控制之前我们建立的gp110机械臂的全套流程,想要学习搭建机械臂模型可参考–
一文学会MoveIt Setup Assistant搭建moveit2机械臂模型

请添加图片描述


一、官方样例实现

软件版本

官方样例的版本如下,这部分通过键盘做机械臂控制教程为–Realtime Arm Servoing

repository: moveit2_tutorials
branch: humble
commit hash: 1855ba9513584ea6f5a764ae618971fb0039cb8f

repository: moveit2
branch: humble
commit hash: 8d7a2140eab5d7ab344ab82f232e1e842fe21432

bug修复

官方教程有如下bug,已提交issus–realtime_servo can not control by keyboard input. fixed in local test #709

修复方法如下:

  1. 注释servo_cpp_interface_demo中不停发送控制指令部分
# moveit2_tutorials/doc/examples/realtime_servo/src/servo_cpp_interface_demo.cpp
# Line  188
 //rclcpp::TimerBase::SharedPtr timer = node_->create_wall_timer(50ms, publishCommands);
  1. 修改servo_keyboard_input中publisher的定义
# moveit2_tutorials/doc/examples/realtime_servo/src/servo_keyboard_input.cpp
# Line 70 71
const std::string TWIST_TOPIC = "/servo_demo_node/delta_twist_cmds";
const std::string JOINT_TOPIC = "/servo_demo_node/delta_joint_cmds";

运行测试

窗口1运行:

$ ros2 launch moveit2_tutorials servo_cpp_interface_demo.launch.py

窗口2运行:

$ ros2 run moveit2_tutorials servo_keyboard_input 
Reading from keyboard
---------------------------
Use arrow keys and the '.' and ';' keys to Cartesian jog
Use 'W' to Cartesian jog in the world frame, and 'E' for the End-Effector frame
Use 1|2|3|4|5|6|7 keys to joint jog. 'R' to reverse the direction of jogging.
'Q' to quit.

请添加图片描述

二、gp110机械臂控制

文件添加

拷贝源代码文件到gp110_moveit_config/src,具体文件如下
moveit2_tutorials/doc/examples/realtime_servo/src/servo_cpp_interface_demo.cpp
moveit2_tutorials/doc/examples/realtime_servo/src/servo_keyboard_input.cpp

拷贝launch文件到gp110_moveit_config/launch,具体文件如下
moveit2_tutorials/doc/examples/realtime_servo/launch/servo_cpp_interface_demo.launch.py

拷贝rviz参数及servo参数文件到gp110_moveit_config/config,具体文件如下
moveit2_tutorials/doc/examples/realtime_servo/config/demo_rviz_config.rviz改名为moveit_empty.rviz
moveit2/moveit_ros/moveit_servo/config/panda_simulated_config.yaml改名为gp110_simulated_config.yaml

修改后文件如下所示:

gp110_moveit_config$ tree .
.
├── CMakeLists.txt
├── config
│   ├── common_colors.xacro
│   ├── common_materials.xacro
│   ├── gp110_macro.xacro
│   ├── gp110_simulated_config.yaml
│   ├── gp110.urdf.xacro
│   ├── initial_positions.yaml
│   ├── joint_limits.yaml
│   ├── kinematics.yaml
│   ├── moveit_controllers.yaml
│   ├── moveit_empty.rviz
│   ├── moveit.rviz
│   ├── pilz_cartesian_limits.yaml
│   ├── robot.ros2_control.xacro
│   ├── robot.srdf
│   ├── robot.urdf.xacro
│   └── ros2_controllers.yaml
├── launch
│   ├── demo.launch.py
│   ├── move_group.launch.py
│   ├── moveit_rviz.launch.py
│   ├── rsp.launch.py
│   ├── servo_cpp_interface_demo.launch.py
│   ├── setup_assistant.launch.py
│   ├── spawn_controllers.launch.py
│   ├── static_virtual_joint_tfs.launch.py
│   └── warehouse_db.launch.py
├── package.xml
└── src
    ├── servo_cpp_interface_demo.cpp
    └── servo_keyboard_input.cpp

3 directories, 29 files

文件修改

# gp110_simulated_config.yaml

...

## MoveIt properties
# move_group_name:  panda_arm  # Often 'manipulator' or 'arm'
# planning_frame: panda_link0  # The MoveIt planning frame. Often 'base_link' or 'world'
move_group_name:  gp110_arm  # Often 'manipulator' or 'arm'
planning_frame: base_link  # The MoveIt planning frame. Often 'base_link' or 'world'

## Other frames
# ee_frame_name: panda_link8  # The name of the end effector link, used to return the EE pose
# robot_link_command_frame:  panda_link0  # commands must be given in the frame of a robot link. Usually either the base or end effector
ee_frame_name: tool0  # The name of the end effector link, used to return the EE pose
robot_link_command_frame:  base_link  # commands must be given in the frame of a robot link. Usually either the base or end effector

...

# command_out_topic: /panda_arm_controller/joint_trajectory # Publish outgoing commands here
command_out_topic: /gp110_arm_controller/joint_trajectory # Publish outgoing commands here

# moveit_empty.rviz
Panels:
  - Class: rviz_common/Displays
    Help Height: 78
    Name: Displays
    Property Tree Widget:
      Expanded:
        - /Global Options1
        - /Status1
      Splitter Ratio: 0.5
    Tree Height: 628
  - Class: rviz_common/Selection
    Name: Selection
  - Class: rviz_common/Tool Properties
    Expanded:
      - /2D Goal Pose1
      - /Publish Point1
    Name: Tool Properties
    Splitter Ratio: 0.5886790156364441
  - Class: rviz_common/Views
    Expanded:
      - /Current View1
    Name: Views
    Splitter Ratio: 0.5
Visualization Manager:
  Class: ""
  Displays:
    - Alpha: 0.5
      Cell Size: 1
      Class: rviz_default_plugins/Grid
      Color: 160; 160; 164
      Enabled: true
      Line Style:
        Line Width: 0.029999999329447746
        Value: Lines
      Name: Grid
      Normal Cell Count: 0
      Offset:
        X: 0
        Y: 0
        Z: 0
      Plane: XY
      Plane Cell Count: 10
      Reference Frame: <Fixed Frame>
      Value: true
    - Class: moveit_rviz_plugin/PlanningScene
      Enabled: true
      Move Group Namespace: ""
      Name: PlanningScene
      Planning Scene Topic: /moveit_servo/publish_planning_scene
      Robot Description: robot_description
      Scene Geometry:
        Scene Alpha: 0.8999999761581421
        Scene Color: 50; 230; 50
        Scene Display Time: 0.20000000298023224
        Show Scene Geometry: true
        Voxel Coloring: Z-Axis
        Voxel Rendering: Occupied Voxels
      Value: true
  Enabled: true
  Global Options:
    Background Color: 48; 48; 48
    Fixed Frame: base_link
    Frame Rate: 30
  Name: root
  Tools:
    - Class: rviz_default_plugins/Interact
      Hide Inactive Objects: true
    - Class: rviz_default_plugins/MoveCamera
    - Class: rviz_default_plugins/Select
    - Class: rviz_default_plugins/FocusCamera
    - Class: rviz_default_plugins/Measure
      Line color: 128; 128; 0
    - Class: rviz_default_plugins/SetInitialPose
      Topic:
        Depth: 5
        Durability Policy: Volatile
        History Policy: Keep Last
        Reliability Policy: Reliable
        Value: /initialpose
    - Class: rviz_default_plugins/SetGoal
      Topic:
        Depth: 5
        Durability Policy: Volatile
        History Policy: Keep Last
        Reliability Policy: Reliable
        Value: /goal_pose
    - Class: rviz_default_plugins/PublishPoint
      Single click: true
      Topic:
        Depth: 5
        Durability Policy: Volatile
        History Policy: Keep Last
        Reliability Policy: Reliable
        Value: /clicked_point
  Transformation:
    Current:
      Class: rviz_default_plugins/TF
  Value: true
  Views:
    Current:
      Class: rviz_default_plugins/Orbit
      Distance: 2.155569553375244
      Enable Stereo Rendering:
        Stereo Eye Separation: 0.05999999865889549
        Stereo Focal Distance: 1
        Swap Stereo Eyes: false
        Value: false
      Focal Point:
        X: -0.08608254045248032
        Y: -0.20677587389945984
        Z: 0.3424459993839264
      Focal Shape Fixed Size: true
      Focal Shape Size: 0.05000000074505806
      Invert Z Axis: false
      Name: Current View
      Near Clip Distance: 0.009999999776482582
      Pitch: 0.4603978991508484
      Target Frame: <Fixed Frame>
      Value: Orbit (rviz)
      Yaw: 0.8753982782363892
    Saved: ~
Window Geometry:
  Displays:
    collapsed: false
  Height: 857
  Hide Left Dock: false
  Hide Right Dock: true
  Selection:
    collapsed: false
  Tool Properties:
    collapsed: false
  Views:
    collapsed: true
  Width: 1586
  X: 1179
  Y: 393
# servo_cpp_interface_demo.launch.py
import os
from launch import LaunchDescription
from launch_ros.actions import Node
from ament_index_python.packages import get_package_share_directory
from launch.actions import ExecuteProcess
from moveit_configs_utils import MoveItConfigsBuilder
from launch_param_builder import ParameterBuilder


def generate_launch_description():
    moveit_config = (
        MoveItConfigsBuilder("moveit_resources_gp110")
        .robot_description(file_path="config/robot.urdf.xacro")
        .robot_description_semantic(file_path="config/robot.srdf")
        .trajectory_execution(file_path="config/moveit_controllers.yaml")
        .to_moveit_configs()
    )

    # Get parameters for the Servo node
    servo_params = (
        ParameterBuilder("moveit_resources_gp110_moveit_config")
        .yaml(
            parameter_namespace="moveit_servo",
            file_path="config/gp110_simulated_config.yaml",
        )
        .to_dict()
    )

    # A node to publish world -> base_link transform
    static_tf = Node(
        package="tf2_ros",
        executable="static_transform_publisher",
        name="static_transform_publisher",
        output="log",
        arguments=["0.0", "0.0", "0.0", "0.0", "0.0", "0.0", "world", "base_link"],
    )

    # The servo cpp interface demo
    # Creates the Servo node and publishes commands to it
    servo_node = Node(
        package="moveit_resources_gp110_moveit_config",
        executable="gp110_servo_cpp_interface_demo",
        output="screen",
        parameters=[
            servo_params,
            moveit_config.robot_description,
            moveit_config.robot_description_semantic,
        ],
    )

    # Publishes tf's for the robot
    robot_state_publisher = Node(
        package="robot_state_publisher",
        executable="robot_state_publisher",
        output="screen",
        parameters=[moveit_config.robot_description],
    )

    # RViz
    rviz_base = os.path.join(
        get_package_share_directory("moveit_resources_gp110_moveit_config"), "config"
    )
    rviz_full_config = os.path.join(rviz_base, "moveit_empty.rviz")

    rviz_node = Node(
        package="rviz2",
        executable="rviz2",
        name="rviz2",
        output="log",
        arguments=["-d", rviz_full_config],
        parameters=[
            moveit_config.robot_description,
            moveit_config.robot_description_semantic,
        ],
    )

    # ros2_control using FakeSystem as hardware
    ros2_controllers_path = os.path.join(
        get_package_share_directory("moveit_resources_gp110_moveit_config"),
        "config",
        "ros2_controllers.yaml",
    )
    ros2_control_node = Node(
        package="controller_manager",
        executable="ros2_control_node",
        parameters=[moveit_config.robot_description, ros2_controllers_path],
        output="both",
    )

    # Load controllers
    load_controllers = []
    for controller in ["gp110_arm_controller", "joint_state_broadcaster"]:
        load_controllers += [
            ExecuteProcess(
                cmd=["ros2 run controller_manager spawner {}".format(controller)],
                shell=True,
                output="screen",
            )
        ]

    return LaunchDescription(
        [rviz_node, static_tf, servo_node, ros2_control_node, robot_state_publisher]
        + load_controllers
    )
// servo_cpp_interface_demo.cpp

...

  // Next we will create a collision object in the way of the arm. As the arm is servoed towards it, it will slow down
  // and stop before colliding
  moveit_msgs::msg::CollisionObject collision_object;
  collision_object.header.frame_id = "base_link";
  collision_object.id = "box";

...

  // 屏蔽下一行
  // rclcpp::TimerBase::SharedPtr timer = node_->create_wall_timer(50ms, publishCommands);
// servo_keyboard_input.cpp

...

// 修改如下
// Some constants used in the Servo Teleop demo
// const std::string TWIST_TOPIC = "/servo_node/delta_twist_cmds";
// const std::string JOINT_TOPIC = "/servo_node/delta_joint_cmds";
const std::string TWIST_TOPIC = "/servo_demo_node/delta_twist_cmds";
const std::string JOINT_TOPIC = "/servo_demo_node/delta_joint_cmds";
const size_t ROS_QUEUE_SIZE = 10;
const std::string EEF_FRAME_ID = "tool0";
const std::string BASE_FRAME_ID = "base_link";

...

      case KEYCODE_1:
        RCLCPP_DEBUG(nh_->get_logger(), "1");
        // joint_msg->joint_names.push_back("panda_joint1");
        joint_msg->joint_names.push_back("joint_1_s");
        joint_msg->velocities.push_back(joint_vel_cmd_);
        publish_joint = true;
        break;
      case KEYCODE_2:
        RCLCPP_DEBUG(nh_->get_logger(), "2");
        // joint_msg->joint_names.push_back("panda_joint2");
        joint_msg->joint_names.push_back("joint_2_l");
        joint_msg->velocities.push_back(joint_vel_cmd_);
        publish_joint = true;
        break;
      case KEYCODE_3:
        RCLCPP_DEBUG(nh_->get_logger(), "3");
        // joint_msg->joint_names.push_back("panda_joint3");
        joint_msg->joint_names.push_back("joint_3_u");
        joint_msg->velocities.push_back(joint_vel_cmd_);
        publish_joint = true;
        break;
      case KEYCODE_4:
        RCLCPP_DEBUG(nh_->get_logger(), "4");
        // joint_msg->joint_names.push_back("panda_joint4");
        joint_msg->joint_names.push_back("joint_4_r");
        joint_msg->velocities.push_back(joint_vel_cmd_);
        publish_joint = true;
        break;
      case KEYCODE_5:
        RCLCPP_DEBUG(nh_->get_logger(), "5");
        // joint_msg->joint_names.push_back("panda_joint5");
        joint_msg->joint_names.push_back("joint_5_b");
        joint_msg->velocities.push_back(joint_vel_cmd_);
        publish_joint = true;
        break;
      case KEYCODE_6:
        RCLCPP_DEBUG(nh_->get_logger(), "6");
        // joint_msg->joint_names.push_back("panda_joint6");
        joint_msg->joint_names.push_back("joint_6_t");
        joint_msg->velocities.push_back(joint_vel_cmd_);
        publish_joint = true;
        break;
      // case KEYCODE_7:
      //   RCLCPP_DEBUG(nh_->get_logger(), "7");
      //   joint_msg->joint_names.push_back("panda_joint7");
      //   joint_msg->velocities.push_back(joint_vel_cmd_);
      //   publish_joint = true;
      //   break;
# CMakeLists.txt
cmake_minimum_required(VERSION 3.22)
project(moveit_resources_gp110_moveit_config)

find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)
find_package(control_msgs REQUIRED)
find_package(moveit_msgs REQUIRED)
find_package(moveit_servo REQUIRED)

add_executable(gp110_servo_keyboard_input src/servo_keyboard_input.cpp)
target_include_directories(gp110_servo_keyboard_input PUBLIC include)
ament_target_dependencies(gp110_servo_keyboard_input std_msgs control_msgs rclcpp)

add_executable(gp110_servo_cpp_interface_demo src/servo_cpp_interface_demo.cpp)
target_include_directories(gp110_servo_cpp_interface_demo PUBLIC include)
ament_target_dependencies(gp110_servo_cpp_interface_demo moveit_servo rclcpp)

install(
  TARGETS
    gp110_servo_keyboard_input
    gp110_servo_cpp_interface_demo
  DESTINATION
    lib/${PROJECT_NAME}
)

install(DIRECTORY launch DESTINATION share/${PROJECT_NAME}
  PATTERN "setup_assistant.launch" EXCLUDE)
install(DIRECTORY config DESTINATION share/${PROJECT_NAME})
install(FILES .setup_assistant DESTINATION share/${PROJECT_NAME})

ament_package()
<!-- package.xml 增加如下--> 

  <exec_depend>rclcpp</exec_depend>
  <exec_depend>control_msgs</exec_depend>
  <exec_depend>moveit_msgs</exec_depend>
  <exec_depend>moveit_servo</exec_depend>

编译工程

$ colcon build --packages-up-to --cmake-args -DCMAKE_BUILD_TYPE=Release
$ . install/setup.bash

运行测试

窗口1运行:

$ ros2 launch moveit_resources_gp110_moveit_config servo_cpp_interface_demo.launch.py

窗口2运行:

$ ros2 run moveit_resources_gp110_moveit_config gp110_servo_keyboard_input 
Reading from keyboard
---------------------------
Use arrow keys and the '.' and ';' keys to Cartesian jog
Use 'W' to Cartesian jog in the world frame, and 'E' for the End-Effector frame
Use 1|2|3|4|5|6|7 keys to joint jog. 'R' to reverse the direction of jogging.
'Q' to quit.

请添加图片描述


总结

以上就是今天要讲的内容,本文从头配置和修改实现了键盘控制机械臂,如果是joycon或其他输入控制与本文所分享思想相同,控制响应和publisher即可。

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

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

相关文章

3.2 Java标识符

3.2 Java标识符 关键字&#xff0c;Java中一些预先设定好的单词被称为关键字常用关键字如下图所示 图中的关键字都是Java预先设定好的&#xff0c;在平时应用中不能用这些关键词作为名字来使用。因为Java已经赋予这些关键字一些意义不能直接使用&#xff0c;这些关键词是Java中…

真实遇到Redis双写一致性问题

今天工作中接到一个bug&#xff0c;产品那边描述&#xff0c; 在后台添加一个供应商后前台无法展示。 是个例还是全部&#xff1f;他说应该是个例。 开始分析。。。。。。。 首先数据库查询可以查出新添加的这个供应商的&#xff0c;说明添加成功的&#xff0c;唯一的问题肯定…

Baltamatica 北太天元 —— 基于模拟退火算法的旅行商问题

文章目录 北太天元&#xff08;Baltamatica&#xff09;简介Baltamatica 复现基于Matlab的旅行商问题问题描述模拟退火算法Metropolis准则算法流程图&#xff1a; Demo1&#xff1a;只考虑累计距离&#xff0c;通过模拟退火算法求解最短路径matlab代码&#xff1a;Baltam代码&a…

Go 语言基础语法:Hello World 实例(涉及定义变量;fmt 包、Print、Println、Printf)

Hello world实例 package mainimport "fmt"func main() {fmt.Println("Hello, World!") } 编译 运行 go run hello.go Hello, World! go run 做了编译和执行两动作&#xff0c;编译会生成 hello 文件&#xff0c;执行完成后此文件会被删除。 web展示 …

STM32外设系列—L298N

文章目录 一、L298N简介二、L298N电路图三、L298N使用方法四、L298N驱动电机实例4.1 麦克纳姆轮简介4.2 定时器PWM配置4.3 智能车行驶控制 五、拓展应用 一、L298N简介 L298N是SGS公司生产的一款通用的电机驱动模块。其内部包含4路逻辑驱动电路&#xff0c;有两个H桥的高电压大…

java并发编程 3:synchronized与锁(重点)

目录 共享问题synchronized锁及使用synchronized代码块synchronized 修饰成员方法synchronized 修饰静态方法 变量的线程安全分析成员变量和静态变量是否线程安全局部变量是否线程安全常见线程安全类 synchronized底层原理Java对象头Monitor管程字节码看原理 锁状态及转换四种锁…

vscode 快速修复(quick fix) 快捷键(Ctrl + .)被占用问题解决方法

vscode 快速修复(quick fix) 快捷键(Ctrl .)被占用 微软拼音的中/英文标点切换的快捷键为Ctrl .&#xff0c;与 vscode 快速修复(quick fix)快捷键冲突。修复方法如下&#xff1a; 切换到微软拼音&#xff0c;在输入法中或英字上&#xff0c;点击右键。 再点设置 - 按键。 …

MTK平台WLAN的Roaming机制和案例log解析

一 、WLAN漫游简介 [百度百科]:当网络环境存在多个相同SSID的AP,且它们的微单元互相有一定范围的重合时,无线用户可以在整个WLAN覆盖区内移动,无线网卡能够自动发现附近信号强度最大的AP,并通过这个AP收发数据,保持不间断的网络连接,这就称为无线漫游。 简单来说:WLA…

Flink中时间和窗口

文章目录 一、时间定义二、水位线(Watermark)1、概念2、水位线特征3、生成水位线3.1 水位线生成策略&#xff08;Watermark Strategies&#xff09;3.2 Flink 内置水位线生成器3.3 自定义水位线策略 4、水位线的传递 三、窗口(Window)1、概念2、窗口分类2.1 驱动类型分类2.2 窗…

chatgpt赋能python:Python输入之后的运行过程

Python输入之后的运行过程 在Python中&#xff0c;输入是必不可少的一部分&#xff0c;它使我们能够更加交互和动态地使用这门语言。在本篇文章中&#xff0c;我们将介绍Python输入的运行过程&#xff0c;包括如何读取和处理输入以及输入与程序运行的交互方式。 什么是Python…

ZLMediaKit 的安装及使用介绍

ZLMediaKit 介绍 ZLMediaKit是一个基于C开发的开源流媒体服务器。它提供了高性能的音视频处理能力&#xff0c;支持常见的流媒体协议&#xff0c;如RTSP、RTMP、HLS和HTTP-FLV&#xff0c;并且具有低延迟和高并发处理能力。 开源地址&#xff1a;https://github.com/xia-chu/…

抖音seo账号矩阵系统源码代开发组件

一.开发矩阵系统的项目背景&#xff1a; 目录 一.开发矩阵系统的项目背景&#xff1a; 二.短视频矩阵系统SaaS模板组件通常包含以下几个方面的内容&#xff1a; 三.抖音SEO账号矩阵系统源码的技术搭建过程可以分为几个步骤&#xff1a; 1.确定系统的需求和目标&#xff0c…

DFS深度优先搜索

目录 一、DFS的概念DFS的定义DFS的搜索方式DFS采用的数据结构DFS的特点 二、DFS的实战应用1.排列数字2.n-皇后问题 一、DFS的概念 DFS的定义 DFS&#xff08;Depth-First Search&#xff09;深度优先搜索&#xff0c;是一种常用的图遍历算法&#xff0c;用于在图或树数据结构…

金蝶云星空财务软件被locked勒索病毒攻击后如何更快解密数据库数据?

金蝶云星空财务软件是一款广泛应用于企业财务管理领域的软件&#xff0c;然而&#xff0c;近期很多企业的金蝶云星空财务软件遭受到了locked勒索病毒的攻击&#xff0c;导致数据库数据被加密。而这次的locked勒索病毒采用了新的加密形式&#xff0c;它不仅能够扫描出各种软件系…

数据结构--顺序表VS链表

数据结构–顺序表VS链表 逻辑结构 存储结构 顺序表&#xff1a; 优点:支持随机存取、存储密度高 缺点:大片连续空间分配不方便&#xff0c;改变容量不方便 链表&#xff1a; 优点:离散的小空间分配方便&#xff0c;改变容量方便 缺点:不可随机存取&#xff0c;存储密度低 基本…

从零开始 Spring Boot 49:Hibernate Entity Lifecycle

从零开始 Spring Boot 49&#xff1a;Hibernate Entity Lifecycle 图源&#xff1a;简书 (jianshu.com) 本文将介绍 Hibernate 的 Session 接口&#xff0c;以及如何用 Session 的相关 API 转换实体&#xff08;Entity&#xff09;的生命周期状态。 如果缺少的 JPA 和 Hiberna…

ubuntu18.04 ros报错Command ‘roscore‘ not found

问题描述 git clone https://github.com/ros/catkin.gitcd catkingit branch melodic-develgit checkout melodic-develmkdir buildcd buildcmake …make -j8 && sudo make installcd .. sudo python2 setup.py installsudo python3 setup.py install出现问题 hua…

ADB命令(app自动化测试底层技术)

一、adb相关知识体系 1&#xff0c;adb的使用场景 操作手机设备 app自动化测试2&#xff0c;adb测试体系 app自动化测试-appium 遍历测试-appcrawier app性能测试 app专项测试 STF设备管理平台 云测平台 兼容性测试 二、adb 基础 1&#xff0c;什么是adb Adb是用来操作Andro…

spark、pyspark 常用的模版 demo 网址

1、我自己有时候用百度或者其他的搜索出来的spark 常用案例&#xff0c;质量有的好有的差有时候就很烦。特地分享一个我常用的质量高的网站地址 https://sparkbyexamples.com/pyspark/pyspark-collect/

进阶2:JVM 启动参数

目录 jvm启动参数 参数分类 系统属性 功能解析 运行模式 jvm有两种运行模式 堆内存 设置堆内存 GC相关 GC 日志相关的参数 分析诊断 指定垃圾收集器相关参数 JavaAgent 什么是Java agent 常见问题 视频 前言 这堂课程不用过多的记忆&#xff0c;自身有印象即可…