Forráskód Böngészése

Merge branch 'master' of https://github.com/fishros/d2l-ros2

alyssa1024 3 éve
szülő
commit
a406bc2929

+ 99 - 7
docs/chapt10/10.4Cartographer介绍与安装.md

@@ -22,6 +22,8 @@ Cartographer是Google开源的一个可跨多个平台和传感器配置以2D和
 
 
 
+
+
 ## 2.Carttographer安装
 
 ### 2.1 apt安装
@@ -74,13 +76,13 @@ colcon build --packages-up-to cartographer_ros
 
 如果是源码编译请先source下工作空间后再使用下面指令查看是否安装成功;
 
-```
+```shell
 ros2 pkg list | grep cartographer
 ```
 
 能看到下面的结果即可
 
-```
+```shell
 cartographer_ros
 cartographer_ros_msgs
 ```
@@ -95,15 +97,17 @@ cartographer_ros_msgs
 
 Cartographer参数是使用lua文件来描述的,不会lua也没关系,我们只是改改参数而已。
 
-3.1 轨迹构建参数
+> 小鱼提示:lua中的注释采用 -- 开头
 
-**文件:trajectory_builder_2d**
+### 3.1 前端参数
+
+**文件:trajectory_builder_2d** 
 
 `src/cartographer_core/cartographer/configuration_files/trajectory_builder_2d.lua`
 
 请你打开这个文件自行浏览,小鱼对其中我们可能会在初次建图配置的参数进行介绍。
 
-```
+```lua
   -- 是否使用IMU数据
   use_imu_data = true, 
   -- 深度数据最小范围
@@ -112,17 +116,105 @@ Cartographer参数是使用lua文件来描述的,不会lua也没关系,我
   max_range = 30.,
   -- 传感器数据超出有效范围最大值时,按此值来处理
   missing_data_ray_length = 5.,
-  
+  -- 是否使用实时回环检测来进行前端的扫描匹配
+  use_online_correlative_scan_matching = true
+  -- 运动过滤,检测运动变化,避免机器人静止时插入数据
+  motion_filter.max_angle_radians
+```
+
+### 3.2 后端参数
+
+**文件:pose_graph.lua**-后端参数配置项
+
+路径`src/cartographer_core/cartographer/configuration_files/pose_graph.lua`
+
+该文件主要和地图构建
+
+```lua
+--Fast csm的最低分数,高于此分数才进行优化。
+constraint_builder.min_score = 0.65
+--全局定位最小分数,低于此分数则认为目前全局定位不准确
+constraint_builder.global_localization_min_score = 0.7
+```
+
+### 3.3 Carotgrapher_ROS参数配置
+
+该部分参数主要是用于和ROS2进行通信和数据收发的配置,比如配置从哪个话题读取里程记数据,从哪个话题来获取深度信息(雷达)。
+
+**文件:backpack_2d.lua**
+
+路径:`src/cartographer_core/cartographer_ros/cartographer_ros/configuration_files/backpack_2d.lua`
+
+```lua
+include "map_builder.lua"
+include "trajectory_builder.lua"
+
+options = {
+  map_builder = MAP_BUILDER,
+  trajectory_builder = TRAJECTORY_BUILDER,
+  -- 用来发布子地图的ROS坐标系ID,位姿的父坐标系,通常是map。
+  map_frame = "map",
+  -- SLAM算法跟随的坐标系ID
+  tracking_frame = "base_link",
+  -- 将发布map到published_frame之间的tf
+  published_frame = "base_link",
+  -- 位于“published_frame ”和“map_frame”之间,用来发布本地SLAM结果(非闭环),通常是“odom”
+  odom_frame = "odom",
+  -- 是否提供里程计
+  provide_odom_frame = true,
+  -- 只发布二维位姿态(不包含俯仰角)
+  publish_frame_projected_to_2d = false,
+  -- 是否使用里程计数据
+  use_odometry = false,
+  -- 是否使用GPS定位
+  use_nav_sat = false,
+  -- 是否使用路标
+  use_landmarks = false,
+  -- 订阅的laser scan topics的个数
+  num_laser_scans = 0,
+  -- 订阅多回波技术laser scan topics的个数
+  num_multi_echo_laser_scans = 1,
+  -- 分割雷达数据的个数
+  num_subdivisions_per_laser_scan = 10,
+  -- 订阅的点云topics的个数
+  num_point_clouds = 0,
+  -- 使用tf2查找变换的超时秒数
+  lookup_transform_timeout_sec = 0.2,
+  -- 发布submap的周期间隔
+  submap_publish_period_sec = 0.3,
+  -- 发布姿态的周期间隔
+  pose_publish_period_sec = 5e-3,
+  -- 轨迹发布周期间隔
+  trajectory_publish_period_sec = 30e-3,
+  -- 测距仪的采样率
+  rangefinder_sampling_ratio = 1.,
+  --里程记数据采样率
+  odometry_sampling_ratio = 1.,
+  -- 固定的frame位姿采样率
+  fixed_frame_pose_sampling_ratio = 1.,
+  -- IMU数据采样率
+  imu_sampling_ratio = 1.,
+  -- 路标采样率
+  landmarks_sampling_ratio = 1.,
+}
 ```
 
 
 
 ## 4.总结
 
-本节我们简单的介绍了Cartographer以及二进制和源码安装的方法,下一节我们就开始为fishbot配置cartographer,接着就可以使用fishbot进行建图了。
+本节我们简单的介绍了Cartographer以及二进制和源码安装的方法,并对参数进行介绍
 
+下一节我们就开始为fishbot配置cartographer,接着就可以使用fishbot进行建图了。
 
 
+
+参考文章:
+
+- https://google-cartographer.readthedocs.io/en/latest/configuration.html
+
+  
+
 --------------
 
 技术交流&&问题求助:

+ 301 - 2
docs/chapt10/10.5配置Fishbot进行建图.md

@@ -1,29 +1,328 @@
-10.5 配置Fishbot进行建图
+# 10.5 配置Fishbot进行建图
 
-上一节我们安装好了cartographer,这节课我们就开始动手写代码实现cartographer建图。
+上一节我们安装好了cartographer,这节课我们就开始配置cartographer进行建图。
 
+我们需要创建一个功能包,将参数文件和`Cartographer`启动文件放到一起然后启动。
 
+![cartographer](10.5%E9%85%8D%E7%BD%AEFishbot%E8%BF%9B%E8%A1%8C%E5%BB%BA%E5%9B%BE/imgs/cartographer.gif)
 
+## 1.创建fishbot_cartographer
 
+在src目录下,使用创建功能包指令,创建功能包
 
+```shell
+cd src
+ros2 pkg create fishbot_cartographer
+```
 
+接着创建配置文件夹、launch文件夹和rviz配置文件夹。
 
+```shell
+cd fishbot_cartographer
+mkdir config
+mkdir launch
+mkdir rviz
+```
 
+创建完成的功能包结构
 
+```
+.
+├── CMakeLists.txt
+├── config
+├── launch
+├── src
+├── package.xml
+└── rviz
+```
 
+## 2.添加cartographer配置文件
 
+在`fishbot/config`目录下创建`fishbot_lds_2d.lua`文件。
 
+接着我们来写一下配置文件,相较于默认的配置文件,主要修改以下内容(见注释)
 
+```lua
+include "map_builder.lua"
+include "trajectory_builder.lua"
 
+options = {
+  map_builder = MAP_BUILDER,
+  trajectory_builder = TRAJECTORY_BUILDER,
+  map_frame = "map",
+  tracking_frame = "base_link",
+  -- base_link改为odom,发布map到odom之间的位姿态
+  published_frame = "odom",
+  odom_frame = "odom",
+  -- true改为false,不用提供里程计数据
+  provide_odom_frame = false,
+  -- false改为true,仅发布2D位资
+  publish_frame_projected_to_2d = true,
+  -- false改为true,使用里程计数据
+  use_odometry = true,
+  use_nav_sat = false,
+  use_landmarks = false,
+  -- 0改为1,使用一个雷达
+  num_laser_scans = 1,
+  -- 1改为0,不使用多波雷达
+  num_multi_echo_laser_scans = 0,
+  -- 10改为1,1/1=1等于不分割
+  num_subdivisions_per_laser_scan = 1,
+  num_point_clouds = 0,
+  lookup_transform_timeout_sec = 0.2,
+  submap_publish_period_sec = 0.3,
+  pose_publish_period_sec = 5e-3,
+  trajectory_publish_period_sec = 30e-3,
+  rangefinder_sampling_ratio = 1.,
+  odometry_sampling_ratio = 1.,
+  fixed_frame_pose_sampling_ratio = 1.,
+  imu_sampling_ratio = 1.,
+  landmarks_sampling_ratio = 1.,
+}
 
 
+-- false改为true,启动2D SLAM
+MAP_BUILDER.use_trajectory_builder_2d = true
 
+-- 0改成0.10,比机器人半径小的都忽略
+TRAJECTORY_BUILDER_2D.min_range = 0.10
+-- 30改成3.5,限制在雷达最大扫描范围内,越小一般越精确些
+TRAJECTORY_BUILDER_2D.max_range = 3.5
+-- 5改成3,传感器数据超出有效范围最大值
+TRAJECTORY_BUILDER_2D.missing_data_ray_length = 3.
+-- true改成false,不使用IMU数据,大家可以开启,然后对比下效果
+TRAJECTORY_BUILDER_2D.use_imu_data = false
+-- false改成true,使用实时回环检测来进行前端的扫描匹配
+TRAJECTORY_BUILDER_2D.use_online_correlative_scan_matching = true 
+-- 1.0改成0.1,提高对运动的敏感度
+TRAJECTORY_BUILDER_2D.motion_filter.max_angle_radians = math.rad(0.1)
 
+-- 0.55改成0.65,Fast csm的最低分数,高于此分数才进行优化。
+POSE_GRAPH.constraint_builder.min_score = 0.65
+--0.6改成0.7,全局定位最小分数,低于此分数则认为目前全局定位不准确
+POSE_GRAPH.constraint_builder.global_localization_min_score = 0.7
 
+-- 设置0可关闭全局SLAM
+-- POSE_GRAPH.optimize_every_n_nodes = 0
 
+return options
+```
 
 
 
+## 3.添加launch文件
+
+### 3.1 launch需要包含的节点
+
+要完成使用Cartographer进行建图,需要两个节点的参与,整个过程的计算流图如下:
+
+![image-20220503212253994](10.5%E9%85%8D%E7%BD%AEFishbot%E8%BF%9B%E8%A1%8C%E5%BB%BA%E5%9B%BE/imgs/image-20220503212253994.png)
+
+**/cartographer_node节点:**
+
+该节点从/scan和/odom话题接收数据进行计算,输出/submap_list数据.
+
+该节点需要接收一个参数配置文件(第二部分写的那个)参数。
+
+**/occupancy_grid_node节点:**
+
+该节点接收/submap_list子图列表,然后将其拼接成map并发布
+
+该节点需要配置地图分辨率和更新周期两个参数。
+
+### 3.2 编写launch文件
+
+在路径`src/fishbot_cartographer/launch/`下新建`cartographer.launch.py`文件,接着我们将上面两个节点加入到这个launch文件中。
+
+我们在第二部分写的配置文件就是给cartographer_node节点的,可以通过这个节点启动参数`configuration_directory`和`configuration_basename`进行传递。
+
+
+
+```
+import os
+from launch import LaunchDescription
+from launch.substitutions import LaunchConfiguration
+from launch_ros.actions import Node
+from launch_ros.substitutions import FindPackageShare
+
+
+def generate_launch_description():
+    # 定位到功能包的地址
+    pkg_share = FindPackageShare(package='fishbot_cartographer').find('fishbot_cartographer')
+    
+    #=====================运行节点需要的配置=======================================================================
+    # 是否使用仿真时间,我们用gazebo,这里设置成true
+    use_sim_time = LaunchConfiguration('use_sim_time', default='true')
+    # 地图的分辨率
+    resolution = LaunchConfiguration('resolution', default='0.05')
+    # 地图的发布周期
+    publish_period_sec = LaunchConfiguration('publish_period_sec', default='1.0')
+    # 配置文件夹路径
+    configuration_directory = LaunchConfiguration('configuration_directory',default= os.path.join(pkg_share, 'config') )
+    # 配置文件
+    configuration_basename = LaunchConfiguration('configuration_basename', default='fishbot_2d.lua')
+
+    
+    #=====================声明三个节点,cartographer/occupancy_grid_node/rviz_node=================================
+    cartographer_node = Node(
+        package='cartographer_ros',
+        executable='cartographer_node',
+        name='cartographer_node',
+        output='screen',
+        parameters=[{'use_sim_time': use_sim_time}],
+        arguments=['-configuration_directory', configuration_directory,
+                   '-configuration_basename', configuration_basename])
+
+    occupancy_grid_node = Node(
+        package='cartographer_ros',
+        executable='occupancy_grid_node',
+        name='occupancy_grid_node',
+        output='screen',
+        parameters=[{'use_sim_time': use_sim_time}],
+        arguments=['-resolution', resolution, '-publish_period_sec', publish_period_sec])
+
+    rviz_node = Node(
+        package='rviz2',
+        executable='rviz2',
+        name='rviz2',
+        # arguments=['-d', rviz_config_dir],
+        parameters=[{'use_sim_time': use_sim_time}],
+        output='screen')
+
+    #===============================================定义启动文件========================================================
+    ld = LaunchDescription()
+    ld.add_action(cartographer_node)
+    ld.add_action(occupancy_grid_node)
+    ld.add_action(rviz_node)
+
+    return ld
+```
+
+## 4.添加安装指令
+
+做完上面的操作,我们还需要添加安装指令。
+
+打开CmakeLists.txt,添加下面一条指令,将三个目录安装到install目录。
+
+```
+install(
+  DIRECTORY config launch rviz
+  DESTINATION share/${PROJECT_NAME}
+)
+```
+
+
+
+## 5.开始建图
+
+### 5.1编译启动
+
+```shell
+colcon build --packages-select fishbot_cartographer 
+```
+
+启动建图前,需要先启动gazebo仿真环境,因为我们的建图程序依赖于Gazebo提供雷达和里程计等数据。
+
+```shell
+source install/setup.bash
+ros2 launch fishbot_description gazebo.launch.py
+```
+
+source,启动建图
+
+```shell
+source install/setup.bash
+ros2 launch fishbot_cartographer cartographer.launch.py 
+```
+
+### 5.2修改配置
+
+如果一切正常,你应该看到的是一个空空如也的RVIZ界面
+
+![image-20220503221911478](10.5%E9%85%8D%E7%BD%AEFishbot%E8%BF%9B%E8%A1%8C%E5%BB%BA%E5%9B%BE/imgs/image-20220503221911478.png)
+
+不用担心,此时地图其实已经有了,我们需要添加一下地图相关的插件即可。
+
+通过`Add`->`By Topic`添加组件。
+
+![image-20220503222230429](10.5%E9%85%8D%E7%BD%AEFishbot%E8%BF%9B%E8%A1%8C%E5%BB%BA%E5%9B%BE/imgs/image-20220503222230429.png)
+
+最后通过左边的插件你应该可以看到图和机器人了。
+
+![image-20220503222158266](10.5%E9%85%8D%E7%BD%AEFishbot%E8%BF%9B%E8%A1%8C%E5%BB%BA%E5%9B%BE/imgs/image-20220503222158266.png)
+
+
+
+### 5.3开始建图
+
+打开我们机器人遥控节点,降低速度,控制机器人走一圈,看看地图的变化。
+
+```
+ros2 run teleop_twist_keyboard teleop_twist_keyboard 
+```
+
+![cartographer](10.5%E9%85%8D%E7%BD%AEFishbot%E8%BF%9B%E8%A1%8C%E5%BB%BA%E5%9B%BE/imgs/cartographer.gif)
+
+### 6.保存地图
+
+走完一圈,没有黑影部分,我们就可以保存地图为一个本地文件了。我们需要使用一个叫做`nav2_map_server`的工具。
+
+### 6.1 安装nav2_map_server
+
+```
+sudo apt install ros-foxy-nav2-map-server
+```
+
+### 6.2 保存地图
+
+```
+ros2 run nav2_map_server map_saver_cli --help
+```
+
+可以看到有下面的用法
+
+```shell
+Usage:
+  map_saver_cli [arguments] [--ros-args ROS remapping args]
+
+Arguments:
+  -h/--help
+  -t <map_topic>
+  -f <mapname>
+  --occ <threshold_occupied>
+  --free <threshold_free>
+  --fmt <image_format>
+  --mode trinary(default)/scale/raw
+
+NOTE: --ros-args should be passed at the end of command line
+```
+
+我们的地图话题为map,文件名字我们用fishbot_map,所以有下面这个这样写的命令行。
+
+```shell
+# 先将地图保存到src/fishbot_cartographer/map目录下
+cd src/fishbot_cartographer/ && mkdir map && cd map
+ros2 run nav2_map_server map_saver_cli -t map -f fishbot_map
+```
+
+接着我们就可以得到下面的两个文件
+
+```shell
+.
+├── fishbot_map.pgm
+└── fishbot_map.yaml
+
+0 directories, 2 files
+```
+
+这两个文件就是对当前地图保存下来的文件,下面的导航我们将要使用到这两个文件。
+
+
+
+## 7.总结
+
+本节小鱼带你一起完成了Fishbot的Cartographer配置和建图,下一节小鱼会对地图是什么以及如何使用进行介绍,接着我们就可以配置Nav2进行Fishbot的导航了。
+
 
 
 --------------

BIN
docs/chapt10/10.5配置Fishbot进行建图/imgs/cartographer.gif


BIN
docs/chapt10/10.5配置Fishbot进行建图/imgs/image-20220503212253994.png


BIN
docs/chapt10/10.5配置Fishbot进行建图/imgs/image-20220503221911478.png


BIN
docs/chapt10/10.5配置Fishbot进行建图/imgs/image-20220503222158266.png


BIN
docs/chapt10/10.5配置Fishbot进行建图/imgs/image-20220503222230429.png


+ 63 - 1
docs/chapt10/10.6导航地图概述.md

@@ -1,4 +1,66 @@
-内容还在更新中,请关注公众号鱼香ROS,第一时间获取更新
+# 10.6导航地图概述
+
+地图是对环境建模的结果,拥有地图,我们就可以在不进行任何测量的情况下来了解环境,从而完成一些比如路径规划的操作。
+
+本节小鱼带你一起了解ROS2中地图的原理、常见格式及转换,加载方式、修改方式等基本操作。
+
+1.地图与占据栅格地图
+
+在日常生活中,我们会用到各种各样的地图,比如交通轨道图、城市地图、世界地图。
+
+1.1 地图分类
+
+我们根据地图所表达信息的不同可以将地图分为三类:
+
+1. 尺度地图(Metric Map)
+
+尺度地图用于表示尺寸距离,可以理解为把真实世界按比例缩小,尺度地图中每个点都可以使用一个经纬值进行表示。
+
+> 因为尺度地图是按照真实世界按比例缩小,所以要有比例尺来表示缩小比例。
+
+2. 拓扑地图(Topological Map)
+拓扑地图用于表示点与点之间的连接信息,比如地铁轨道交通图。
+
+3. 语义地图(Semantic Map)
+语义地图可以理解为在上面两个地图上增加了语义,比如尺度地图中某处是红绿灯、斑马线。拓扑地图中某个点是深圳北站。
+
+
+在机器人领域,尺度地图常用于定位于地图构建(Mapping)、定位(Localization)和同时定位与地图构建(Simultaneous Localization And Mapping,SLAM),拓扑地图常用于路径规划(Path Planning),而语义地图常用于人机交互(Human Robot Interaction)。
+
+1.2 占据栅格地图
+
+我们先了解下什么是栅格地图(Grid Map)。
+
+![栅格数据集图](10.6导航地图概述/imgs/20140206174127486.gif)
+
+如上图将地图数据分割为一块块的栅格来表达地图信息,就是栅格地图。
+
+那什么是占据(Occupancy)呢?
+
+机器人通过激光雷达等传感器来感知深度信息,但我们知道,传感器都是有噪声的(在前面的机器人仿真建模过程中,我们为了更加真实给激光雷达还添加了高斯噪声),所以机器人前方的某个位置到底有没有物体(障碍物)是不确定的。
+
+我们可以采用概率来解决这一问题,认为确实有物体的栅格的占据率为100%,确定没有物体的栅格占据率为0%,不确定的栅格就用(确认占据概率/确认非占据概率)值表示占据率。
+
+
+由此我们知道占据栅格地图就是一张写满占据率的格子组成的地图。
+
+![image-20220506134542099](10.6导航地图概述/imgs/image-20220506134542099.png)
+
+![image-20220506141320374](10.6导航地图概述/imgs/image-20220506141320374.png)
+
+2.地图加载
+
+OccupancyGrid由一个.yaml格式的元数据文件,和图片格式的地图数据文件组成。
+
+
+
+3.地图编辑
+
+
+
+参考文章:
+
+- https://zhuanlan.zhihu.com/p/21738718
 
 --------------
 

BIN
docs/chapt10/10.6导航地图概述/imgs/20140206174127486.gif


BIN
docs/chapt10/10.6导航地图概述/imgs/image-20220504131231862.png


BIN
docs/chapt10/10.6导航地图概述/imgs/image-20220506134542099.png


BIN
docs/chapt10/10.6导航地图概述/imgs/image-20220506141320374.png


+ 17 - 17
docs/chapt7/7.2.3姿态的多种表示.md

@@ -23,9 +23,9 @@
 
 ## 1.旋转矩阵
 
-关于旋转矩阵我们在前几节教程中已经介绍了,旋转矩阵采用的是`旋转后的坐标系`三个轴分别与`原坐标系`三个轴的夹角余弦值共九个数字组成3*3矩阵。
+关于旋转矩阵我们在前几节教程中已经介绍了,旋转矩阵采用的是`旋转后的坐标系`三个轴分别与`原坐标系`三个轴的夹角余弦值共九个数字组成3*3矩阵。
 
-旋转矩阵一般记作记作$R$ 
+旋转矩阵一般记作$R$ 
 
 > 若两个坐标系姿态相同,其旋转矩阵为单位矩阵。
 
@@ -34,14 +34,14 @@
 ![坐标系和坐标系P关系](https://img-blog.csdnimg.cn/4f205bc34fce4a7497c487394b4a3a3f.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6bG86aaZUk9T,size_20,color_FFFFFF,t_70,g_se,x_16)
 
 
-如图,描述`坐标系{P}`和`参考坐标系{A}`之间的姿态关系来表示${^A_P}R$点的姿态
+如图,描述`坐标系{P}`和`参考坐标系{A}`之间的姿态关系的旋转矩阵用符号${^A_P}R$来表示
 
 
 $$
 {^A_P}R=[{^A}x_{P} \ {^A}y_{P} \ {^A}z_{P}] = \begin{bmatrix}{r_{11}}&{r_{12}}&{r_{13}}\\{r_{21}}&{r_{22}}&{r_{23}}\\{r_{31}}&{r_{32}}&{r_{33}}\\\end{bmatrix} \tag{旋转矩阵}
 $$
 
-两个向量的点乘=两个向量的长度(1)与它们夹角余弦的积,所以$r11$可以表示为向量$P_{x}$与$A_{x}$的点积,旋转矩阵就可以写为下面的形式
+两个向量的点乘=两个向量的长度(1)与它们夹角余弦的积所以$r11$可以表示为向量$P_{x}$与$A_{x}$的点积,旋转矩阵就可以写为下面的形式
 
 $$
 {^A_P}R = \begin{bmatrix} 
@@ -52,7 +52,7 @@ $$
 $$
 
 
-### 1.2 绕某一轴旋转$\theta$旋转矩阵
+### 1.2 绕某一轴旋转$\theta$角的旋转矩阵
 
 `新的坐标系`绕`原坐标系`某一坐标轴旋转任意角度得到的旋转矩阵有如下等式。
 
@@ -88,9 +88,9 @@ $$
 ## 2.欧拉角-绕坐标轴的旋转
 
 ### 2.1 12种旋转顺序
-旋转矩阵是一个冗余的(九个值之间存在约束关系),可以只需要三个参数来表示旋转矩阵。聪明的鱼粉肯定会想到,假如知道坐标系绕分别绕X、Y、Z轴的旋转角度,不就同样可以表示旋转了吗?
+旋转矩阵是一个冗余的(九个值之间存在约束关系),可以只需要三个参数来表示矩阵。聪明的鱼粉肯定会想到,假如知道坐标系绕分别绕X、Y、Z轴的旋转角度,不就同样可以表示旋转了吗?
 
-这个猜想是对的,结合1.2中绕三个轴旋转的三个$\theta$,按照特定的顺序将对应的旋转矩阵乘起来就可以确定一个旋转矩阵。
+这个猜想是对的,结合1.2中绕三个轴旋转的三个$\theta$,按照特定的顺序将对应的旋转矩阵乘起来就可以确定一个旋转矩阵。
 
 但需要注意的是,矩阵的乘法不具备交换性,所以旋转顺序不同会造成不同的结果。
 
@@ -156,19 +156,19 @@ $$
 - 接着坐标系{B}绕着A的y轴`Ay`旋转$\beta$
 - 接着绕`Az`旋转$\gamma$
 
-上述三次旋转中,旋转时都是绕着A坐标系的xyz轴为参考坐标系,该旋转方式成为固定旋转轴的旋转,称之为固定角欧拉角或固定轴旋转。
+上述三次旋转,都是以A坐标系的xyz轴为参考坐标系进行旋转,该旋转方式为固定旋转轴的旋转,通常称之为固定角欧拉角或固定轴旋转。
 
 #### 2.2.2 参考自身坐标系
 ![参考自身坐标系](https://img-blog.csdnimg.cn/fa42e7371bf84f848eaf55c4406699b5.gif)
 
 我们也可以不沿着坐标系A的各轴旋转,而是绕旋转之后B的某一轴再次旋转,我们称之为非固定旋转轴的欧拉角。
 
-> 小鱼说:无论是参考自身坐标系还是参考固定的坐标系,都有12种旋转方式,所以欧拉角有12*2=24种旋转方式,后面的计算中我们也直观的感受到24种旋转方式的不同。
+> 小鱼说无论是参考自身坐标系还是参考固定的坐标系,都有12种旋转方式,所以欧拉角有12*2=24种旋转方式,后面的计算中我们也直观的感受到24种旋转方式的不同。
 
 ### 2.3 固定转轴欧拉角 转 旋转矩阵
 首先我们来考虑绕固定的坐标系旋转如何转换成旋转矩阵
 
-我们以顺序XYZ来举例说明,其他旋转顺序类似
+我们以XYZ的旋转顺序来举例说明,其他旋转顺序类似
 
 现在假设A、B两个坐标系重合,B坐标系绕A坐标系的X轴旋转45度,绕A的Z轴旋转90度.
 
@@ -187,7 +187,7 @@ $$
 
 这里引用林沛群老师的解释:
 
-我们可以假设一个向量v固定在B坐标系上,那我们让B坐标系绕着A坐标系的三个轴做旋转,就可以认为是让向量v绕着坐标系A的三个轴做旋转,那先转的肯定先乘,所以我们先让向量v乘上Rx(45),再让其乘上Rz(90),即:
+我们可以假设一个向量v固定在B坐标系上,那我们让B坐标系绕着A坐标系的三个轴做旋转,就可以认为是让向量v绕着坐标系A的三个轴做旋转,那先转的肯定先乘,所以我们先让向量v乘上Rx(45)再让其乘上Rz(90),即:
 $$
 v' = R_{Z(90)}(R_{X(45)}v)
 $$
@@ -203,7 +203,7 @@ $$
 最终结果:
 ![固定轴欧拉角转旋转矩阵](https://img-blog.csdnimg.cn/b36d9d33b5ae47bfb3759556f10fd70f.png)
 
-根据旋转顺序不同,固定角有12种旋转方式,这里我们给出了绕固定轴以XYZ顺序旋转欧拉角转旋转矩阵的等式,其他旋转顺序对应的旋转矩阵可以尝试自行推导.
+根据旋转顺序不同,固定角有12种旋转方式,这里我们给出了绕固定轴以XYZ顺序旋转欧拉角转旋转矩阵的等式,其他旋转顺序对应的旋转矩阵可以尝试自行推导
 
 ### 2.2 非固定旋转轴的欧拉角
 
@@ -241,11 +241,11 @@ $$
 说到这里相信你已经理解了轴角的意义,接着我们给出轴角和旋转矩阵之间的转换关系
 
 ### 轴角转旋转矩阵
-假设坐标系B和参考坐标系A宠儿,将B绕着A坐标系下的矢量$^AK$按右手定则旋转$\theta$角度,旋转之后B坐标系在A坐标系下的姿态可以用
+假设坐标系B和参考坐标系A重合,将B绕着A坐标系下的矢量$^AK$按右手定则旋转$\theta$角度,旋转之后B坐标系在A坐标系下的姿态可以用
 $$
 ^A_BR(K,\theta)
 $$
-表示,注意矢量K为单位矢量(模为1),K为一个3*1的矢量
+表示,注意矢量K为单位矢量(模为1),K为一个3*1的矢量
 $$
 ^AK=[k_x,k_y,k_z]^T
 $$
@@ -272,7 +272,7 @@ $\theta$的符号由右手定则确定,右手大拇指指向矢量K的方向.
 
 ## 4.四元数
 
-除了轴角可以使用一个表示角度和三个表示旋转轴,一共四个数字表示旋转外。还有另外一种方式可以表示旋转——四元数。
+除了轴角可以使用一个数字表示角度,三个数字表示旋转轴,一共四个数字表示旋转外。还有另外一种四个数字表示表示旋转的方式——四元数。
 
 四元数的四个数字由一个实部和三个虚部组成,是一个超复数形式
 
@@ -283,7 +283,7 @@ $$
 
 关于四元数的由来有个小故事,小鱼分享一下:
 
-> 1843年10月16日的傍晚,英国数学家哈密顿和他的妻子一起步行去都柏林,途中经过布鲁哈姆桥时,他的脚步突然放慢了。妻子以为他要尽情欣赏周围的景色,于是也放慢了脚步。其实哈密顿此时正在思考他久久不能解决的问题。早在1828年,他就想发明一种新的代数,用来描述绕空间一定轴转动并同时进行伸缩的向量的运动。他设想这种新代数应包含四个分量:两个来固定转动轴,一个来规定转动角度,第四个来规定向量的伸缩。但是在构造新代数的过程中,由于他受传统观念的影响,不肯放弃乘法交换律,故屡受挫折。哈密顿盲目地相信,普通代数最重要的规律必定继续存在于他寻找的代数中。然而此刻,他的脑际突然产生了一个闪念:在所寻找的代数中,能否让交换律不成立呢?比方说,A×B不等于B×A而是等于负的B×A。这个想法太大胆了,他感到非常激动。哈密顿马上掏出笔记本,把他的思想火花记录下来。这一火花就是I,J,K之间的基本方程,即四元数乘法基本公式。哈密顿因此把1843年10月16日称为四元数的生日。此后,哈密顿一生的最后22年几乎完全致力于四元数的研究,成果发表在他去世后出版的《四元数基础》一书中。四元数的出现,推倒了传统代数的关卡,故有数学史上程碑的美誉。后人为了纪念这一发明,特意在当年哈密顿刻划过的石头上镶嵌了一块水泥板,上面清楚地记载着1843年曾经发生的故事。
+> 1843年10月16日的傍晚,英国数学家哈密顿和他的妻子一起步行去都柏林,途中经过布鲁哈姆桥时,他的脚步突然放慢了。妻子以为他要尽情欣赏周围的景色,于是也放慢了脚步。其实哈密顿此时正在思考他久久不能解决的问题。早在1828年,他就想发明一种新的代数,用来描述绕空间一定轴转动并同时进行伸缩的向量的运动。他设想这种新代数应包含四个分量:两个来固定转动轴,一个来规定转动角度,第四个来规定向量的伸缩。但是在构造新代数的过程中,由于他受传统观念的影响,不肯放弃乘法交换律,故屡受挫折。哈密顿盲目地相信,普通代数最重要的规律必定继续存在于他寻找的代数中。然而此刻,他的脑际突然产生了一个闪念:在所寻找的代数中,能否让交换律不成立呢?比方说,A×B不等于B×A而是等于负的B×A。这个想法太大胆了,他感到非常激动。哈密顿马上掏出笔记本,把他的思想火花记录下来。这一火花就是I,J,K之间的基本方程,即四元数乘法基本公式。哈密顿因此把1843年10月16日称为四元数的生日。此后,哈密顿一生的最后22年几乎完全致力于四元数的研究,成果发表在他去世后出版的《四元数基础》一书中。四元数的出现,推倒了传统代数的关卡,故有数学史上程碑的美誉。后人为了纪念这一发明,特意在当年哈密顿刻划过的石头上镶嵌了一块水泥板,上面清楚地记载着1843年曾经发生的故事。
 
 
 
@@ -311,7 +311,7 @@ $$
 
 ![image-20211229184338075](7.2.3姿态的多种表示/imgs/image-20211229184338075.png)
 
-四元数转轴角
+轴角转四元数
 
 轴:$^AK=[k_x,k_y,k_z]^T$ 角:$\theta$
 $$

+ 8 - 8
docs/chapt7/7.3.1齐次坐标变换.md

@@ -1,7 +1,7 @@
 
 # 7.3.1 齐次坐标变换
 
-前面几节中,小鱼带你一起学习了使用TF进行坐标的变换,也带你通过旋转和平移求解了坐标的变换关系,但计算的过程中旋转和平移是分开计算的,那有没有一种方法,可以让旋转矩阵和平移向量合并到同一个矩阵里呢?
+前面几节中,小鱼带你一起学习了使用TF进行坐标的变换,也带你通过旋转和平移求解了坐标的变换关系,但计算的过程中旋转和平移是分开计算的,那有没有一种方法,可以让旋转矩阵和平移向量合并到同一个矩阵里呢?
 
 答案是有的,我们可以将$3*3$的旋转矩阵和$3*1$的平移矩阵进行组合,并添加一行(0,0,0,1)使其变成一个$4*4$的方阵,其组合方式如下:
 
@@ -31,7 +31,7 @@ $$
 T = \begin{bmatrix}{R}&{P}
 \\0&1\\\end{bmatrix} \tag{齐次矩阵}
 $$
-假设$^A_BT$表示A坐标系到B坐标的齐次变换,B坐标系下的点C坐标为$^B_CP$,求C在A坐标系下的坐标$^A_CP$
+假设$^A_BT$表示B坐标系到A坐标系的齐次变换,B坐标系下的点C坐标为$^B_CP$,求C在A坐标系下的坐标$^A_CP$
 
 我们将$^A_BT$乘$^B_CP$上,可得
 $$
@@ -40,7 +40,7 @@ $$
 \begin{bmatrix}{^B_CP}\\1\\\end{bmatrix} 
 = {^A_BR}{^B_CP}+^A_BP
 $$
-根据前面学习的平移+旋转复合坐标变换公式,正确的结果如下
+根据前面学习的平移+旋转复合坐标变换公式正确的结果如下
 $$
 ^A_CP = {^A_BR}{^B_CP}+^A_BP
 $$
@@ -54,17 +54,17 @@ $$
 
 ### 2.1.齐次变换矩阵的符号表示
 
-一般使用H或者T来表示齐次变换矩阵,矩阵的左上角标明参考坐标系,矩阵左下角标定目标坐标系,比如$^A_BT$表示A坐标系到B坐标系的变换关系(平移+旋转)
+一般使用H或者T来表示齐次变换矩阵,矩阵的左上角标明参考坐标系,矩阵左下角标明目标坐标系,比如$^A_BT$表示B坐标系到A坐标系的变换关系(平移+旋转)
 
 ### 2.2.齐次变换矩阵的逆的几何含义
 
-就像矩阵的逆一样,齐次变换矩阵也有逆,其逆也有对应的几何含义,比如
+就像矩阵的逆一样,齐次变换矩阵也有逆,其逆也有对应的几何含义,比如
 
-比如$^A_BT$表示A坐标系到B坐标系的变换关系
+比如$^A_BT$表示B坐标系到A坐标系的变换关系
 
 那么
 
-$^A_BT$的逆$^A_BT^{-1}=^B_AT$表示B坐标系到A坐标系的变换关系
+$^A_BT$的逆$^A_BT^{-1}=^B_AT$表示A坐标系到B坐标系的变换关系
 
 ### 2.3.齐次变换矩阵的乘法的几何含义
 
@@ -78,7 +78,7 @@ $^A_BT$的逆$^A_BT^{-1}=^B_AT$表示B坐标系到A坐标系的变换关系
 $$
 ^A_BT^B_CT=^A_CT
 $$
-比如当我们有一个六自由度的机械臂,知道每两个相邻关节之间的关系,那么就可以通过其次矩阵相乘的方法求出,关节6在关节0下的位置和姿态:
+比如当我们有一个六自由度的机械臂,知道两两相邻关节之间的关系,那么就可以通过其次矩阵相乘的方法求出,关节6在关节0下的位置和姿态:
 $$
 ^0_1T^1_2T^2_3T^3_4T^4_5T^5_6T=^0_6T
 $$