ROS--机器人小车仿真rviz

news2025/1/13 15:59:45

URDF练习

需求描述:

创建一个四轮圆柱状机器人模型,机器人参数如下,底盘为圆柱状,半径 10cm,高 8cm,四轮由两个驱动轮和两个万向支撑轮组成,两个驱动轮半径为 3.25cm,轮胎宽度1.5cm,两个万向轮为球状,半径 0.75cm,底盘离地间距为 1.5cm(与万向轮直径一致)

实现流程:

创建机器人模型可以分步骤实现

新建 urdf 文件,并与 launch 文件集成

搭建底盘

在底盘上添加两个驱动轮

在底盘上添加两个万向轮

添加项目辅助包

urdf xacro

查看工作文档目录

在这里插入图片描述

创建一个机器人模型:semo02_date.urdf.xacro

<!--
    使用 xacro 优化 URDF 版的小车底盘实现:

    实现思路:
    1.将一些常量、变量封装为 xacro:property
      比如:PI 值、小车底盘半径、离地间距、车轮半径、宽度 ....
    2.使用 宏 封装驱动轮以及支撑轮实现,调用相关宏生成驱动轮与支撑轮

-->
<!-- 根标签,必须声明 xmlns:xacro -->
<robot name="my_base" xmlns:xacro="http://www.ros.org/wiki/xacro">
    <!-- 封装变量、常量 -->
    <xacro:property name="PI" value="3.141"/>
    <!--:黑色设置 -->
    <material name="black">
        <color rgba="0.0 0.0 0.0 1.0" />
    </material>
    <!-- 底盘属性 -->
    <xacro:property name="base_footprint_radius" value="0.001" /> <!-- base_footprint 半径  -->
    <xacro:property name="base_link_radius" value="0.1" /> <!-- base_link 半径 -->
    <xacro:property name="base_link_length" value="0.08" /> <!-- base_link 长 -->
    <xacro:property name="earth_space" value="0.015" /> <!-- 离地间距 -->

    <!-- 底盘 -->
    <link name="base_footprint">
      <visual>
        <geometry>
          <sphere radius="${base_footprint_radius}" />
        </geometry>
      </visual>
    </link>

    <link name="base_link">
      <visual>
        <geometry>
          <cylinder radius="${base_link_radius}" length="${base_link_length}" />
        </geometry>
        <origin xyz="0 0 0" rpy="0 0 0" />
        <material name="yellow">
          <color rgba="0.5 0.3 0.0 0.5" />
        </material>
      </visual>
    </link>

    <joint name="base_link2base_footprint" type="fixed">
      <parent link="base_footprint" />
      <child link="base_link" />
      <origin xyz="0 0 ${earth_space + base_link_length / 2 }" />
    </joint>

    <!-- 驱动轮 -->
    <!-- 驱动轮属性 -->
    <xacro:property name="wheel_radius" value="0.0325" /><!-- 半径 -->
    <xacro:property name="wheel_length" value="0.015" /><!-- 宽度 -->
    <!-- 驱动轮宏实现 -->
    <xacro:macro name="add_wheels" params="name flag">
      <link name="${name}_wheel">
        <visual>
          <geometry>
            <cylinder radius="${wheel_radius}" length="${wheel_length}" />
          </geometry>
          <origin xyz="0.0 0.0 0.0" rpy="${PI / 2} 0.0 0.0" />
          <material name="black" />
        </visual>
      </link>

      <joint name="${name}_wheel2base_link" type="continuous">
        <parent link="base_link" />
        <child link="${name}_wheel" />
        <origin xyz="0 ${flag * base_link_radius} ${-(earth_space + base_link_length / 2 - wheel_radius) }" />
        <axis xyz="0 1 0" />
      </joint>
    </xacro:macro>
    <xacro:add_wheels name="left" flag="1" />
    <xacro:add_wheels name="right" flag="-1" />
    <!-- 支撑轮 -->
    <!-- 支撑轮属性 -->
    <xacro:property name="support_wheel_radius" value="0.0075" /> <!-- 支撑轮半径 -->

    <!-- 支撑轮宏 -->
    <xacro:macro name="add_support_wheel" params="name flag" >
      <link name="${name}_wheel">
        <visual>
            <geometry>
                <sphere radius="${support_wheel_radius}" />
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0" />
            <material name="black" />
        </visual>
      </link>

      <joint name="${name}_wheel2base_link" type="continuous">
          <parent link="base_link" />
          <child link="${name}_wheel" />
          <origin xyz="${flag * (base_link_radius - support_wheel_radius)} 0 ${-(base_link_length / 2 + earth_space / 2)}" />
          <axis xyz="1 1 1" />
      </joint>
    </xacro:macro>

    <xacro:add_support_wheel name="front" flag="1" />
    <xacro:add_support_wheel name="back" flag="-1" />

</robot>

创建摄像头xacro 文件:semo03_date.urdf.xacro

<!-- 摄像头相关的 xacro 文件 -->
<robot name="my_camera" xmlns:xacro="http://wiki.ros.org/xacro">
    <!-- 摄像头属性 -->
    <xacro:property name="camera_length" value="0.01" /> <!-- 摄像头长度(x) -->
    <xacro:property name="camera_width" value="0.025" /> <!-- 摄像头宽度(y) -->
    <xacro:property name="camera_height" value="0.025" /> <!-- 摄像头高度(z) -->
    <xacro:property name="camera_x" value="0.08" /> <!-- 摄像头安装的x坐标 -->
    <xacro:property name="camera_y" value="0.0" /> <!-- 摄像头安装的y坐标 -->
    <xacro:property name="camera_z" value="${base_link_length / 2 + camera_height / 2}" /> <!-- 摄像头安装的z坐标:底盘高度 / 2 + 摄像头高度 / 2  -->

    <!-- 摄像头关节以及link -->
    <link name="camera">
        <visual>
            <geometry>
                <box size="${camera_length} ${camera_width} ${camera_height}" />
            </geometry>
            <origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0" />
            <material name="black" />
        </visual>
    </link>

    <joint name="camera2base_link" type="fixed">
        <parent link="base_link" />
        <child link="camera" />
        <origin xyz="${camera_x} ${camera_y} ${camera_z}" />
    </joint>
</robot>

创建雷达xacro 文件:semo_04_date.urdf.xacro

<!--
    小车底盘添加雷达
-->
<robot name="my_laser" xmlns:xacro="http://wiki.ros.org/xacro">

    <!-- 雷达支架 -->
    <xacro:property name="support_length" value="0.15" /> <!-- 支架长度 -->
    <xacro:property name="support_radius" value="0.01" /> <!-- 支架半径 -->
    <xacro:property name="support_x" value="0.0" /> <!-- 支架安装的x坐标 -->
    <xacro:property name="support_y" value="0.0" /> <!-- 支架安装的y坐标 -->
    <xacro:property name="support_z" value="${base_link_length / 2 + support_length / 2}" /> <!-- 支架安装的z坐标:底盘高度 / 2 + 支架高度 / 2  -->

    <link name="support">
        <visual>
            <geometry>
                <cylinder radius="${support_radius}" length="${support_length}" />
            </geometry>
            <origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0" />
            <material name="red">
                <color rgba="0.8 0.2 0.0 0.8" />
            </material>
        </visual>
    </link>

    <joint name="support2base_link" type="fixed">
        <parent link="base_link" />
        <child link="support" />
        <origin xyz="${support_x} ${support_y} ${support_z}" />
    </joint>


    <!-- 雷达属性 -->
    <xacro:property name="laser_length" value="0.05" /> <!-- 雷达长度 -->
    <xacro:property name="laser_radius" value="0.03" /> <!-- 雷达半径 -->
    <xacro:property name="laser_x" value="0.0" /> <!-- 雷达安装的x坐标 -->
    <xacro:property name="laser_y" value="0.0" /> <!-- 雷达安装的y坐标 -->
    <xacro:property name="laser_z" value="${support_length / 2 + laser_length / 2}" /> <!-- 雷达安装的z坐标:支架高度 / 2 + 雷达高度 / 2  -->

    <!-- 雷达关节以及link -->
    <link name="laser">
        <visual>
            <geometry>
                <cylinder radius="${laser_radius}" length="${laser_length}" />
            </geometry>
            <origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0" />
            <material name="black" />
        </visual>
    </link>

    <joint name="laser2support" type="fixed">
        <parent link="support" />
        <child link="laser" />
        <origin xyz="${laser_x} ${laser_y} ${laser_z}" />
    </joint>
</robot>

组合底盘摄像头与雷达的 xacro 文件:car.urdf.xacro

<!-- 组合小车底盘与摄像头与雷达 -->
<robot name="my_car_camera" xmlns:xacro="http://wiki.ros.org/xacro">
    <xacro:include filename="semo02_date.urdf.xacro" />
    <xacro:include filename="semo03_date.urdf.xacro" />
    <xacro:include filename="semo_04_date.urdf.xacro" />
</robot>

创建launch 文件:car_ee.launch

<launch>
    <param name="robot_description" command="$(find xacro)/xacro $(find urdlee)/urdf/xacro/car.urdf.xacro" />

    <node pkg="rviz" type="rviz" name="rviz" args="-d $(find urdlee)/config/showmycar.rviz" />
    <node pkg="joint_state_publisher" type="joint_state_publisher" name="joint_state_publisher" output="screen" />
    <node pkg="robot_state_publisher" type="robot_state_publisher" name="robot_state_publisher" output="screen" />
    <node pkg="joint_state_publisher_gui" type="joint_state_publisher_gui" name="joint_state_publisher_gui" output="screen" />

    <node name="arbotix" pkg="arbotix_python" type="arbotix_driver" output="screen">
        <rosparam file="$(find urdlee)/config/control.yaml" command="load" />
        <param name="sim" value="true" />
    </node>


</launch>

上面使用的 /config/control.yaml

添加 arbotix 所需的配置文件:control.yaml

# 该文件是控制器配置,一个机器人模型可能有多个控制器,比如: 底盘、机械臂、夹持器(机械手)....
# 因此,根 name 是 controller
controllers: {
   # 单控制器设置
   base_controller: {
          #类型: 差速控制器
       type: diff_controller,
       #参考坐标
       base_frame_id: base_footprint, 
       #两个轮子之间的间距
       base_width: 0.2,
       #控制频率
       ticks_meter: 2000, 
       #PID控制参数,使机器人车轮快速达到预期速度
       Kp: 12, 
       Kd: 12, 
       Ki: 0, 
       Ko: 50, 
       #加速限制
       accel_limit: 1.0 
    }
}

上面使用的:showmycar.rviz"

<node pkg="rviz" type="rviz" name="rviz" args="-d $(find urdlee)/config/showmycar.rviz" />

中的showmycar.rviz代码

Panels:
  - Class: rviz/Displays
    Help Height: 78
    Name: Displays
    Property Tree Widget:
      Expanded:
        - /Global Options1
        - /Status1
        - /RobotModel1
        - /RobotModel1/Status1
      Splitter Ratio: 0.5
    Tree Height: 719
  - Class: rviz/Selection
    Name: Selection
  - Class: rviz/Tool Properties
    Expanded:
      - /2D Pose Estimate1
      - /2D Nav Goal1
      - /Publish Point1
    Name: Tool Properties
    Splitter Ratio: 0.5886790156364441
  - Class: rviz/Views<node pkg="rviz" type="rviz" name="rviz" args="-d $(find urdlee)/config/showmycar.rviz" />

    Expanded:
      - /Current View1
    Name: Views
    Splitter Ratio: 0.5
  - Class: rviz/Time
    Name: Time
    SyncMode: 0
    SyncSource: ""
Preferences:
  PromptSaveOnExit: true
Toolbars:
  toolButtonStyle: 2
Visualization Manager:
  Class: ""
  Displays:
    - Alpha: 0.5
      Cell Size: 1
      Class: rviz/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
    - Alpha: 1
      Class: rviz/RobotModel
      Collision Enabled: false
      Enabled: true
      Links:
        All Links Enabled: true
        Expand Joint Details: false
        Expand Link Details: false
        Expand Tree: false
        Link Tree Style: Links in Alphabetic Order
        base_link:
          Alpha: 1
          Show Axes: false
          Show Trail: false
          Value: true
      Name: RobotModel
      Robot Description: robot_description
      TF Prefix: ""
      Update Interval: 0
      Value: true
      Visual Enabled: true
  Enabled: true
  Global Options:
    Background Color: 48; 48; 48
    Default Light: true
    Fixed Frame: base_link
    Frame Rate: 30
  Name: root
  Tools:
    - Class: rviz/Interact
      Hide Inactive Objects: true
    - Class: rviz/MoveCamera
    - Class: rviz/Select
    - Class: rviz/FocusCamera
    - Class: rviz/Measure
    - Class: rviz/SetInitialPose
      Theta std deviation: 0.2617993950843811
      Topic: /initialpose
      X std deviation: 0.5
      Y std deviation: 0.5
    - Class: rviz/SetGoal
      Topic: /move_base_simple/goal
    - Class: rviz/PublishPoint
      Single click: true
      Topic: /clicked_point
  Value: true
  Views:
    Current:
      Class: rviz/Orbit
      Distance: 10
      Enable Stereo Rendering:
        Stereo Eye Separation: 0.05999999865889549
        Stereo Focal Distance: 1
        Swap Stereo Eyes: false
        Value: false
      Field of View: 0.7853981852531433
      Focal Point:
        X: 0
        Y: 0
        Z: 0
      Focal Shape Fixed Size: true
      Focal Shape Size: 0.05000000074505806
      Invert Z Axis: false
      Name: Current View
      Near Clip Distance: 0.009999999776482582
      Pitch: 0.5103980302810669
      Target Frame: <Fixed Frame>
      Yaw: 5.4685821533203125
    Saved: ~
Window Geometry:
  Displays:
    collapsed: false
  Height: 1016
  Hide Left Dock: false
  Hide Right Dock: false
  QMainWindow State: 000000ff00000000fd0000000400000000000001560000035afc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003d0000035a000000c900fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f0000035afc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003d0000035a000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000007380000003efc0100000002fb0000000800540069006d0065010000000000000738000003bc00fffffffb0000000800540069006d00650100000000000004500000000000000000000004c70000035a00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000
  Selection:
    collapsed: false
  Time:
    collapsed: false
  Tool Properties:
    collapsed: false
  Views:
    collapsed: false
  Width: 1848
  X: 72
  Y: 27

使用命令运行

source ./devel/setup.bash
roslaunch urdlee car_ee.launch

在这里插入图片描述

查看节点命令:rostopic list

/clicked_point
/cmd_vel
/diagnostics
/initialpose
/joint_states
/move_base_simple/goal
/odom
/rosout
/rosout_agg
/tf
/tf_static

使用:odom运行小车
在这里插入图片描述

运行命令

代码自动运行

rostopic pub -r 10 /cmd_vel geometry_msgs/Twist '{linear: {x: 0.2, y: 0, z: 0}, angular: {x: 0, y: 0, z: 0.5}}'

键盘手动运行

rosrun teleop_twist_keyboard teleop_twist_keyboard.py

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

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

相关文章

企业业财数字化建设-财务管理领域的产品设计

数字经济时代&#xff0c;企业数字化建设成为发展的必经之路&#xff0c;更多的企业搭建全渠道的营销&#xff0c;交易&#xff0c;履约和售后体系触达和服务用户&#xff0c;特别是面向小B和C端用户&#xff0c;交易变得更灵活多变。使得资源管控&#xff0c;稳定保守为底层基…

C语言的缺陷/错误处理问题探讨

最近遇到一个问题&#xff0c;先看看如下代码&#xff1a; uint8_t Bcd2Dec01(uint8_t bcd) {uint8_t one (bcd & 0x0F);uint8_t ten (bcd & 0xF0) >> 4;if ((one > 9) || (ten > 9)){printf("请输入合法的BCD码&#xff01;");return 0;}retu…

《C++内存管理》

本文主要介绍C内存管理的知识&#xff0c;主要包括new和delete&#xff0c;其实很简单&#xff0c;类比我们的C语言的内存管理malloc/free&#xff0c;就是在堆上申请内存的 小知识点&#xff1a; C构造对象的顺序&#xff1a;先构造全局&#xff0c;再构造局部静态对象&#x…

一些解决方案

文件异步下载方案 1 set QueryBussessType manually different type --> different resolving code、wherecondition 2. frontend request with the type 3. get excelHeader --> groovyUtil load from db 4. getData from db with pagination 5. saveData in an excel 6…

【测试面试】你要的宝典,软件接口测试面试题大全(总结)--附答案

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、接口测试主要目…

将war包发布到容器中的tomcat

文章目录 将war包直接发布到容器中使用数据卷将war包持久化到docker的宿主机(CentOS7) 将war包直接发布到容器中 1、将windows中的文件通过xftp程序传到centOS7中 2、创建容器&#xff0c;通过docker中的命令将web.jar复制到tomcat容器中 # 查看docker中的镜像 ~]$ docker imag…

0.8秒捕捉,速度超乎想象,小米和WPS用户太激动,office用户已用

只需0.8秒就能捕捉 距离4月18日小米13ultra发布会时间还剩一天。这几天雷军的微博已经把小米13ultra的亮点已经做了很多铺垫宣传。 除了系统和硬件之外&#xff0c;就是这次小米13ultra最大的“杀手锏”的就是“徕卡相机”。连宣传文案都改成了&#xff1a;一个伟大的瞬间&…

【UE】玩家位置存档

在上一篇博客中&#xff08;【UE】将存档的值显示在控件蓝图上&#xff09;我们介绍了如何将存档的值显示在控件蓝图上&#xff0c;本篇博客要介绍的是如何将玩家位置进行存档。 效果 可以看到重新进入游戏时&#xff0c;角色在存档点出现&#xff0c;而不是玩家出生点 步骤 …

XMU 算法分析与设计第三次上机题解

文章目录 一、BFS试炼之微博转发二、DFS试炼之不同路径数三、并查集试炼之合并集合并查集的介绍 四、堆排序堆排序的介绍 五、厦大GPA&#xff08;分组背包&#xff09;分组背包介绍 六、消防安全指挥问题&#xff08;最短路Floyd&#xff09;七、铺设光纤问题(最小生成树Prim)…

干货满满~如何解决跨域!!

1. 为什么会存在跨域 首先要知道&#xff0c;在浏览器/app中使用异步请求(ajax)发送到服务器时&#xff0c;会出现跨域问题。若是服务与服务之间通信是没有跨域这一说的 2. 浏览器为什么要设置跨域的存在&#xff1f; 为了防止恶意网页可以获取其他网站的本地数据&#xff0…

4.23、TCP状态转换(为什么四次挥手)

4.23、TCP状态转换 1.TCP状态转换图2.为什么需要四次挥手&#xff0c;状态转换 1.TCP状态转换图 2.为什么需要四次挥手&#xff0c;状态转换 2MSL&#xff08;Maximum Segment Lifetime&#xff09; 主动断开连接的一方, 最后进入一个 TIME_WAIT状态, 这个状态会持续: 2msl ms…

实例化构造方法static统统都学会

文章目录 前言一、实例化是什么&#xff1f;二、构造方法1.概念2.特性3.. 如果用户没有显式定义&#xff0c;编译器会生成一份默认的构造方法&#xff0c;生成的默认构造方法一定是无参的 四.static1.static修饰成员变量2.static修饰成员方法3.static成员变量初始化 总结 前言 …

AR实战-基于Krpano的多场景融合及热点自定义

背景 在之前的博客中&#xff0c;曾经介绍了关于Krpano的相关知识&#xff0c;原文&#xff1a;全景自动切片技术-krpano初识。简单讲解了基于krpano1.19-pr13下单张全景照片的处理与展示。随着实景中国在各地的落地生根&#xff0c;三维园区、三维景区、三维乡村等等需求的集中…

ERP系统给企业管理带来哪些改变?

企业资源计划&#xff08;ERP&#xff09;系统是一种综合性的管理工具&#xff0c;它可以集成和管理企业内部所有的业务流程和信息。自上世纪90年代以来&#xff0c;ERP系统已成为许多企业的重要工具&#xff0c;为企业管理带来了巨大的变革。 第一&#xff0c;ERP系统可以将企…

ArrayList与顺序表

目录 ​编辑 一、线性表 二、顺序表 1、接口的实现 &#xff08;1&#xff09;打印顺序表 &#xff08;2&#xff09;新增元素 &#xff08;3&#xff09;判定是否包含某个元素 &#xff08;4&#xff09;查找某个元素对应的位置下标 &#xff08;5&#xff09;获取 …

基于QTableView中的MVD代理添加总结

目录 1、Qt中MVD说明 1.1 View 1.2 Delegate 1.3 Model/View的基本原理 2、代码是现实示例 2.1 设置样式文件 2.2 set base attribute 2.3 设置model 2.4 设置表头 2.5 设置数据 2.6 添加代理控件 2.6.1 添加 QSpinBox 代理 2.6.2 添加 QComboBox 代理 2.6.…

【JS】vis.js使用之vis-timeline使用攻略,vis-timeline在vue3中实现时间轴、甘特图

vis.js使用之vis-timeline使用攻略&#xff0c;vis-timeline实现时间轴、甘特图 1、vis-timeline简介2、安装插件及依赖3、简单示例4、疑难问题集合1. 中文zh-cn本地化2. 关于自定义class样式无法被渲染3. 关于双向数据绑定 vis.js是一个基于浏览器的可视化库&#xff0c;它提供…

深度探索vector

vector是什么 &#xff1f; vector就是一个可以自动扩充的array。 源码解析 vector主要是通过三个指针来维护的&#xff0c;分别是起点&#xff0c;当前终点&#xff0c;以及当前最大空间 sizeof(vector对象) 3 * 指针大小 vector每当遇到空间不同的情况&#xff0c;都会…

Windows逆向安全(一)之基础知识(十三)

Switch语句 先前讲了分支结构的if else形式&#xff0c;除此之外还有一种分支结构&#xff1a;switch 此次就来以反汇编的角度研究switch语句&#xff0c;并与if else进行比较 Switch语句的使用 有关Switch语句在vc6.0中生成的反汇编可分为4种情况&#xff0c;这4种情况的区…

不用科学上网,免费的GPT-4 IDE工具Cursor保姆级使用教程

1、Cursor 编辑器 可以直接官方网站下载&#xff1a;https://www.cursor.so/ &#xff08;这里以Mac为例&#xff09; 这是一款与OpenAI合作并且基于GPT4的新一代辅助编程神器&#xff0c;它支持多种文件类型&#xff0c;支持格式化文本、多种主题、多语言语法高亮、快捷键设…