sogwms 6 жил өмнө
parent
commit
52fdde0f52

+ 31 - 65
README.md

@@ -1,90 +1,56 @@
-## RT-Robot
+# RT-Robot
 
 ## 1、介绍
 
-RT-Robot 是 RT-Thread 的机器人框架,希望能够支持智能小车、机械臂、飞控等各种不同类型的机器人。
+RT-Robot 是 RT-Thread 的机器人框架,希望能够支持智能小车、机械臂、无人机等各种不同类型的机器人。
 
 当前以智能车为主要目标,希望支持两轮差分驱动、四轮差分驱动、麦克纳姆轮驱动、经典 Ackerman (两轮差分,一方向连杆) 的小车底盘。
 
-### 1.1 目录结构
+当前功能特点:
+- 支持两轮差分驱动、四轮差分驱动、麦克纳姆轮驱动的小车底盘
 
-`rt-robot` 软件包目录结构如下所示:
+- 支持增量、位置式 PID
+- 支持单相、AB 相编码器
+- 支持双 PWM、单 PWM 的直流电机驱动,支持驱动舵机
+- 支持 PS2 遥控器
+- 支持 ANO_TC 匿名科创地面站
 
-```
-rt-robot
-│
-├─docs
-│      design.md            // 模块设计文档
-│      api.md               // API 说明文档
-│      samples.md           // 框架应用示例
-│
-├─controller
-│      controller.c         // 抽象控制器组件
-│      controller.h
-│      ps2_controller.c     // PS2 手柄模块
-│      ps2_controller.h
-│
-├─robot
-│      robot.c              // 抽象机器人组件
-│      robot.h
-│      mobile_robot.c       // 小车机器人模块
-│      mobile_robot.h
-│
-├─chassis
-│      chassis.c            // 小车底盘组件
-│      chassis.h
-│
-├─kinematics
-│      kinematics.c         // 小车动力学模型组件
-│      kinematics.h
-│
-├─wheel
-│      wheel.c              // 小车车轮组件
-│      wheel.h
-│
-├─encoder
-│      encoder.c            // 车轮编码器组件
-│      encoder.h
-│
-├─motor
-│      motor.c              // 车轮电机组件
-│      motor.h
-│      dc_motor.c           // 直流电机模块
-│      dc_motor.h
-│
-├─pid
-│      pid.c                // 车轮 PID 组件
-│      pid.h
-│
-├─README.md                 // 软件包使用说明
-│
-└─SConscript                // RT-Thread 默认的构建脚本
-```
+### 1.1 许可证
 
-### 1.2 依赖
+rt-robot 软件包遵循 Apache-2.0 许可,详见 LICENSE 文件。
 
+### 1.2 依赖
 - RT-Thread 3.1.x +
 
 ## 2、获取软件包
 
-使用 `rt-robot` 软件包需要在 BSP 目录下使用 menuconfig 命令打开 Env 配置界面,在 `RT-Thread online packages → system packages` 中选择 RT-Robot 软件包,操作界面如下图所示
+使用 `rt-robot` 软件包需要在 BSP 目录下使用 menuconfig 命令打开 Env 配置界面,在 `RT-Thread online packages → system packages` 中选择 RT-Robot 软件包,具体路径如下:
 
-[![选中 RT-Robot 软件包](docs/figures/rt-robot-menuconfig.png)](https://github.com/RT-Thread-packages/paho-mqtt/blob/master/docs/figures/select_mqtt_package.png)
+```shell
+RT-Thread online packages
+    system packages  --->
+         [*] RT-Robot: RT-Thread robots development platform  --->
+            Version (latest) --->
+```
 
-选择合适的配置项后,使用 `pkgs --update` 命令下载软件包并添加到工程中即可。
+配置完成后让 RT-Thread 的包管理器自动更新,或者使用 pkgs --update 命令更新包到 BSP 中。
 
 ## 3、使用 rt-robot
 
-- 框架设计说明,请参考 [设计手册](docs/design.md)。
-- 完整的 API 文档,请参考 [API 手册](docs/api.md)。
-- 详细的示例介绍,请参考 [示例文档](docs/samples.md) 。
+- 软件包详细介绍,请参考 [软件包介绍](docs/introduction.md)
 
-## 4、注意事项
+- 如何从零开始使用,请参考 [用户指南](docs/user-guide.md)
+- 框架设计说明,请参考 [设计手册](docs/design.md)
+- 完整的 API 文档,请参考 [API 手册](docs/api.md)
+- 详细的示例介绍,请参考 [示例文档](docs/samples.md)
 
-- 当前框架正在逐步实现,各种类型的小车还在一步步测试,欢迎大家提 PR 一起完善
+## 4、注意事项
 
+- 当前框架正在逐步完善,欢迎大家来提 PR
 
 ## 5、联系方式 & 感谢
 
-- 维护:RT-Thread 开发团队
-- 主页:https://github.com/RT-Thread-packages/rt-robot
+| 维护     | 主页       | 邮箱  | 
+| -------- | ---------- | --- | 
+| Wu Han | http://wuhanstudio.cc   | wuhanstudio@hust.edu.cn |
+| sogwms | https://github.com/sogwms | sogwyms@gmail.com |

+ 2 - 0
docs/README.md

@@ -10,5 +10,7 @@
 | ------------------------------------------------------------ | -------- |
 | [design.md](./design.md) | 设计说明 |
 | [api.md](./api.md) | API 说明 |
+| [introduction.md](./introduction.md) | 详细介绍 |
 | [samples.md](./samples.md) | 应用示例 |
+| [user-guide.md](./user-guide.md) | 用户指南 |
 

+ 218 - 15
docs/api.md

@@ -1,12 +1,6 @@
 # RT-Robot API 介绍
 
-在各个模块硬件测试通过后,会一步步将稳定的 API 添加到这里,现在大家可以参照[例程](./samples.md)里面提供的方法进行初始化和控制。
-
-
-
-## 控制器 API (controller)
-
-不同手柄按键指令与机器人运动指令间的转换。
+## 协议 API (protocol)
 
 
 
@@ -18,32 +12,241 @@
 
 #### 1 车底盘 API (chassis)
 
+```c
+chassis_t chassis_create(wheel_t* c_wheel, kinematics_t c_kinematics);
+```
+
+创建车底盘
+
+|**参数**     | **描述**                 |
+| :------- | :------------------- |
+| c_wheel  | 车轮对象数组 |
+| c_kinematics | 动力学模型对象 |
+| **返回** | **--**             |
+|   |  |
+
+```c
+rt_err_t chassis_set_velocity(chassis_t chas, struct velocity target_velocity);
+```
+
+设置小车底盘速度
+
+|**参数**     | **描述**                 |
+| :------- | :------------------- |
+| chas  | 车底盘对象 |
+| target_velocity | 预设速度(x,y,w)。x、y速度单位为m/s,w单位为rad/s|
+| **返回** | **--**             |
+|   |  |
 
+```c
+rt_err_t chassis_set_rpm(chassis_t chas, rt_int16_t target_rpm[]);
+```
+
+设置小车底盘车轮速度(单位:转/分)
+
+|**参数**     | **描述**                 |
+| :------- | :------------------- |
+| chas  | 车底盘 |
+| target_rpm | 预设速度(转每分) |
+| **返回** | **--**             |
+|   |  |
 
 ##### 1.1 车轮 API (wheel)
 
-闭环车轮的运动。
+```c
+wheel_t wheel_create(motor_t w_motor, encoder_t w_encoder, controller_t w_controller, float radius, rt_uint16_t gear_ratio);
+```
+
+创建车轮
+
+|**参数**     | **描述**                 |
+| :------- | :------------------- |
+| w_motor  | 电机对象 |
+| w_encoder | 编码器对象 |
+| w_controller | 控制器对象 |
+| radius | 车轮直径 |
+| gear_ratio | 电机减速比 |
+| **返回** | **--**             |
+|   |  |
+
+```c
+rt_err_t wheel_set_speed(wheel_t whl, double speed);
+```
+
+设定车轮速度
+
+|**参数**     | **描述**                 |
+| :------- | :------------------- |
+| whl  | 车轮对象 |
+| speed | 速度(单位:m/s) |
+| **返回** | **--**             |
+|   |  |
+
+```c
+rt_err_t wheel_set_rpm(wheel_t whl, rt_int16_t rpm);
+```
 
+设定车轮速度
 
+|**参数**     | **描述**                 |
+| :------- | :------------------- |
+| whl  | 车轮对象 |
+| rpm | 速度(单位:rpm |
+| **返回** | **--**             |
+|   |  |
 
 **1.1.1 电机 API (motor)**
 
-电机控制相关。
+**直流电机**
 
-**1.1.2 编码器 API (encoder)**
+```c
+dual_pwm_motor_t dual_pwm_motor_create(char *pwm1, int pwm1_channel, char *pwm2, int pwm2_channel);
+```
 
-获取编码器信息。
+创建双 PWM 驱动方式电机
+
+|**参数**     | **描述**                 |
+| :------- | :------------------- |
+| pwm1  | pwm设备名 |
+| pwm1_channel | pwm通道 |
+| pwm2 | pwm设备名 |
+| pwm2_channel | pwm通道 |
+| **返回** | **--**             |
+|   |  |
+
+```c
+single_pwm_motor_t  single_pwm_motor_create(char *pwm, int channel, rt_base_t pin1, rt_base_t pin2);
+```
+
+创建单 PWM 驱动方式电机
+
+|**参数**     | **描述**                 |
+| :------- | :------------------- |
+| pwm  | pwm设备名 |
+| channel | pwm通道 |
+| pin1 | 控制引脚1 |
+| pin2 | 控制引脚2 |
+| **返回** | **--**             |
+|   |  |
+
+**舵机**
+
+```c
+servo_t servo_create(const char * pwm, int channel, float angle, rt_uint32_t pluse_min, rt_uint32_t pluse_max);
+```
+
+创建舵机
 
-**1.1.3 PID API (PID)**
+|**参数**     | **描述**                 |
+| :------- | :------------------- |
+| pwm  | pwm 设备名 |
+| channel | pwm 通道 |
+|angle|角度范围|
+| pluse_min | 最小脉宽 (单位:ns);传入 RT_NULL 则设为默认值 |
+| pluse_max | 最大脉宽 (单位:ns);传入 RT_NULL 则设为默认值|
+| **返回** | **--**             |
+|   |  |
 
-闭环控制。
+```c
+rt_err_t servo_set_angle(servo_t servo, float angle);
+```
 
+设定舵机转动角度
 
+|**参数**     | **描述**                 |
+| :------- | :------------------- |
+| servo  | pwm 设备名 |
+| angle | 转动角度 (从零至最大值,最大值取决于 create 时传入的 angle 参数)|
+| **返回** | **--**             |
+|   |  |
+
+
+**1.1.2 编码器 API (encoder)**
+
+获取编码器信息。
+
+```c
+ab_phase_encoder_t ab_phase_encoder_create(rt_base_t pin_a, rt_base_t pin_b, rt_uint16_t pulse_revol);
+```
+
+创建AB相编码器
+
+|**参数**     | **描述**                 |
+| :------- | :------------------- |
+| pin_a  | A相引脚 |
+| pin_b | B相引脚 |
+| pulse_revol | 车轮转一圈输出的脉冲数 |
+| **返回** | **--**             |
+|   |  |
+
+```c
+single_phase_encoder_t single_phase_encoder_create(rt_base_t pin, rt_uint16_t pulse_revol);
+```
+
+创建单相编码器
+
+|**参数**     | **描述**                 |
+| :------- | :------------------- |
+| pin  | 引脚 |
+| pulse_revol | 车轮转一圈输出的脉冲数 |
+| **返回** | **--**             |
+|   |  |
+
+**1.1.3 控制器 API (controller)**
+
+```c
+inc_pid_controller_t    inc_pid_controller_create(float kp, float ki, float kd, rt_uint16_t sample_time);
+```
+
+创建增量式 PID 控制器
+
+|**参数**     | **描述**                 |
+| :------- | :------------------- |
+| kp  | 参数Kp值 |
+| ki | 参数Ki值 |
+| kd | 参数Kd值 |
+| sample_time | 计算周期 |
+| **返回** | **--**             |
+|   |  |
+
+```c
+pos_pid_controller_t    pos_pid_controller_create(float kp, float ki, float kd, rt_uint16_t sample_time);
+```
+
+创建位置式 PID 控制器
+
+|**参数**     | **描述**                 |
+| :------- | :------------------- |
+| kp  | 参数Kp值 |
+| ki | 参数Ki值 |
+| kd | 参数Kd值 |
+| sample_time | 计算周期 |
+| **返回** | **--**             |
+|   |  |
 
 ##### 1.2 动力学模型 API (kinematics)
 
-小车速度 (x, y, w) 与各个电机转速 (rpm1, rpm2, rpm3, rpm4) 之间的相互转换。
+```c
+kinematics_t    kinematics_create(enum base k_base, float length_x, float length_y, float wheel_radius);
+```
+
+创建动力学模型
+
+|**参数**     | **描述**                 |
+| :------- | :------------------- |
+| k_base  | 类型 |
+| length_x | X轴两轮间距 |
+| length_y | Y轴两轮间距 |
+| wheel_radius | 车轮直径 |
+| **返回** | **--**             |
+|   |  |
 
+_小车速度 (x, y, w) 与各个电机转速 (rpm1, rpm2, rpm3, rpm4) 之间的相互转换。_
 
+```c
+rt_int16_t*     kinematics_get_rpm(struct kinematics kin, struct velocity target_vel);
+```
 
-#### 2 传感器 API (sensor)
+```c
+struct velocity kinematics_get_velocity(struct kinematics kin, struct rpm current_rpm);
+```

+ 12 - 45
docs/design.md

@@ -1,79 +1,50 @@
 # RT-Robot 设计说明
 
-## 顶层框架设计
+## 1 智能车体系结构
 
-这个框架的顶层模块当前有 controller 和 robot,通过 controller 接收和发送指令来控制 robot。
+rt-robot 将智能车平台分为两个部分:车底盘和动力学模型
 
-- robot 是抽象出的机器人模块,为了适配智能小车、机械臂、飞控等各种不同类型的机器人。
-
-- controller 是抽象出的控制器模块,可以适配 PS2 手柄、蓝牙手柄、飞控手柄等不同类型的控制器。
-
-![](./figures/top-level.png)
-
-### 1 控制器模块 (controller) 
-
-控制器对机器人做出控制的流程是一个适配器模式。例如, PS2 手柄控制智能小车的流程:
-
-![](./figures/adapter_mode.png)
-
-- PS2 手柄模块内会用 enum 维护自己的按键值,例如 PS2_BTN_L1_PRESSED 表示 L1 被按下
-
-- 智能小车模块内也会有自己的控制指令,例如 CAR_CMD_FORWARD 表示控制小车向前运动
-
-那么 PS2 手柄的按键值是怎么对应到小车的运动呢?这需要在初始化的时候通过控制器的 bind 函数,将手柄的按键值和小车的运动关联起来,例如将 PS2_BTN_L1_PRESSED 和 CAR_CMD_FORWARD 关联起来,当 PS2 手柄的 L1 按键被按下后,我们就可以知道应当控制小车向前运动。
-
-因此,控制器模块在此处起到一个适配器的作用,将手柄的按键值转换为小车的运动,其实也就是初始化的时候起到定义自己喜欢的按键功能的作用。
-
-### 2 机器人模块 (robot) 
-
-我们下面以智能小车 (mobile robot) 为例,小车模块当前主要分为车底盘 (chassis) 和传感器 (sensor),例如一个智能小车会包含两轮差分驱动底盘,和一些陀螺仪加速度计等传感器,整体框架图如下图所示。
-
-![](./figures/mobile_robot.png)
-
-#### 2.1 车底盘模块 (chassis)
+### 1.1 车底盘模块 (chassis)
 
 车底盘模块的作用在于定义小车的底盘类型,例如有多少个可以控制的轮子、小车的长宽等物理属性、运动学模型。例如两轮的车底盘搭配两轮差分动力学模型,我们就得到了两轮差分驱动的小车。
 
 车底盘模块下面又包括车轮 (wheel) 模块和动力学模型模块 (kinematics)。
 
-##### 2.1.1 车轮模块 (wheel)
+#### 1.1.1 车轮模块 (wheel)
 
-车轮模块需要实现一个能够闭环控制的车轮,因此需要用到电机、编码器和 PID算法。
+车轮模块需要实现一个能够闭环控制的车轮,因此需要用到电机、编码器和 闭环控制算法。
 
-###### 2.1.1.1 电机模块 (motor)
+##### 1.1.1.1 电机模块 (motor)
 
 电机模块需要为不同电机提供统一的接口,能够实现闭环电机转速控制,包括:
 
 - 直流电机
 - 舵机
-
 - 步进电机
-- CAN电机
+- CAN接口电机
 - 直流无刷电机
 
-###### 2.1.1.2 编码器模块 (encoder)
+##### 1.1.1.2 编码器模块 (encoder)
 
 编码器模块需要为不同编码器提供统一的接口,能够测量得到当前电机的转速、运动方向等,包括:
 
 - 单相编码器
 - AB相编码器
 
-###### 2.1.1.3 PID 模块 (PID)
+##### 1.1.1.3 车轮速度闭环控制器模块 (e.g. PID)
 
-PID模块需要利用当前编码器测得的转速,和目标设定值,实现对电机的闭环控制,包括:
+控制器模块需要利用当前编码器测得的转速,和目标设定值,实现对电机的闭环控制,包括:
 
 - 增量式PID
+- 位置式PID
 
-##### 2.1.2 动力学模型模块 (kinematics)
+#### 1.1.2 动力学模型模块 (kinematics)
 
 动力学模块包含各种小车物理学模型,需要实现小车运动速度 (Vx, Vy, w) 与不同电机转速 (rpm1, rpm2, rpm3, rpm4) 之间的双向切换,包括:
 
 - 两轮差分驱动
-
 - 四轮差分驱动
-
 - 麦克纳姆轮驱动
-
 - Ackerman模型
 
 当前我们的小车坐标系定义如下:
@@ -81,7 +52,3 @@ PID模块需要利用当前编码器测得的转速,和目标设定值,实
 ![](./figures/coordinates.png)
 
 除了全局坐标系外,我们定义了小车的前进方向为 Xr,与前进方向垂直的方向为 Yr,以小车车头逆时针旋转方向为旋转角速度 w 的正方向。
-
-#### 2.2 传感器模块 (sensor)
-
-Coming soon

BIN
docs/figures/adapter_mode.png


BIN
docs/figures/mecanum-chassis.png


BIN
docs/figures/mecanum-movement.png


BIN
docs/figures/mecanum-wheel.png


BIN
docs/figures/mobile_robot.png


BIN
docs/figures/rt-robot-menuconfig.png


BIN
docs/figures/top-level.png


+ 67 - 0
docs/introduction.md

@@ -0,0 +1,67 @@
+# RT-Robot 详细介绍
+
+**RT-Robot 是 RT-Thread 的机器人框架,希望能够支持智能小车、机械臂、无人机等各种不同类型的机器人。**
+
+## 软件包目录结构
+```shell
+.
+|-- README.md                       // 说明
+|-- SConscript                      // 构建脚本
+|-- chassis                         // 底盘模块
+|-- controller                      // 控制器模块
+|-- docs                            // 文档
+|-- encoder                         // 编码器模块
+|-- kinematics                      // 动力学模型模块
+|-- motor                           // 电机模块
+|-- protocol                        // 协议模块(上位机/遥控器)
+`-- wheel                           // 车轮模块
+```
+
+## 软件包功能特点
+
+rt-robot 当前只支持智能小车,特点如下:
+
+- 支持两轮差分驱动、四轮差分驱动、麦克纳姆轮驱动的小车底盘
+
+- 支持增量、位置式 PID
+- 支持单相、AB 相编码器
+- 支持双 PWM、单 PWM 的直流电机驱动,支持驱动舵机
+- 支持 PS2 遥控器
+- 支持 ANO_TC 匿名科创地面站
+
+## 小车动力学模型
+
+为了控制小车运动,必然要建立运动学模型,rt-robot 当前支持以下模型:
+
+- TWO_WD 两轮差分驱动
+
+- FOUR_WD 四轮差分驱动
+- MECANUM 麦克纳姆轮驱动
+- ACKERMANN 后轮驱动调速,
+前轮通过连杆控制方向
+
+运动型机器人根据其物理学模型又包括 **Holonomic** 和 **Non-Holonomic** 。
+
+**两轮差分驱动小车** 就是典型的Non-Holonomic,因为它的控制自由度(controllable degree of freedom)小于整体自由度(total degrees of freedom),小车的整体自由度有3个,X,Y坐标的运动以及当前朝向(Orientation),但是它的控制自由度只有2个:加速度和旋转角度。 **麦克纳姆轮驱动的小车** 则属与于Holonomic,它的控制自由度(controllable degree of freedom)等于整体自由度(total degrees of freedom)因为它可以在平面坐标系内沿任意方向移动。下面我们重点介绍麦克纳姆轮驱动的小车。
+
+### 1 麦克纳姆轮驱动
+
+麦克纳姆(Mecanum)轮驱动的小车属于Holonomic,它的特点在于小车可以保持车头方向不变,就在平面坐标系内沿各个方向自由移动。
+
+我们首先了解一下麦克纳姆轮,其实它主要是在传统的轮子上增加了滚轮,这样传统车轮无法实现的横向移动就可以通过滚轮完成,而滚轮的安装方式有两种:左旋和右旋,如下图所示:
+
+![](./figures/mecanum-wheel.png)
+
+图1.1 麦克纳姆轮不同安装方式
+
+通过合理搭配左旋和右旋的麦克纳姆轮,就可以实现不同的运动组合。 **组装时一定要确保四个轮子上滚轮的转动轴汇聚于底板中心** ,这样控制才不会出现漂移,后面的理论分析也都是基于这一假设的。
+
+![](./figures/mecanum-chassis.png)
+
+图1.2 麦克纳姆轮安装方式
+
+通过速度分解控制四个轮子的转速,就可以实现不同方向的运动。
+
+![](./figures/mecanum-movement.png)
+
+图1.3 麦克纳姆轮驱动小车运动分解

+ 109 - 72
docs/samples.md

@@ -1,11 +1,11 @@
 # RT-Robot 使用示例
 
-使用 rt-robot 框架的初始化流程包括:
+使用 rt-robot 框架的初始化智能车流程包括:
 
-- 1 初始化车轮 (为车轮添加电机、编码器、PID)
-  - 1.1 初始化电机 
-  - 1.2 初始化编码器
-  - 1.3 初始化 PID 
+- 1 初始化车轮 (为车轮添加电机、编码器、控制器)
+  - 1.1 初始化车轮电机 
+  - 1.2 初始化车轮编码器
+  - 1.3 初始化车轮控制器
   
 - 2 初始化动力学模型
 
@@ -14,79 +14,116 @@
 下面是两轮差分控制的小车初始化示例代码:
 
 ```C
-// 1. Initialize two wheels - left and right
-wheel_t* c_wheels = (wheel_t*) rt_malloc(sizeof(wheel_t) * 2);
-if (c_wheels == RT_NULL)
+// MOTOR
+#define LEFT_FORWARD_PWM            "pwm4"
+#define LEFT_FORWARD_PWM_CHANNEL    3
+#define LEFT_BACKWARD_PWM           "pwm4"
+#define LEFT_BACKWARD_PWM_CHANNEL   4
+
+#define RIGHT_FORWARD_PWM           "pwm2"
+#define RIGHT_FORWARD_PWM_CHANNEL   3
+#define RIGHT_BACKWARD_PWM          "pwm2"
+#define RIGHT_BACKWARD_PWM_CHANNEL  4
+
+// ENCODER
+#define LEFT_ENCODER_A_PHASE_PIN    31      // GET_PIN(B, 15)
+#define LEFT_ENCODER_B_PHASE_PIN    34      // GET_PIN(C, 2)
+#define RIGHT_ENCODER_A_PHASE_PIN   36      //
+#define RIGHT_ENCODER_B_PHASE_PIN   8       //
+#define PULSE_PER_REVOL           2000      // Real value 2000
+#define ENCODER_SAMPLE_TIME         50
+
+// CONTROLLER PID
+#define PID_SAMPLE_TIME             50
+#define PID_PARAM_KP                6.6
+#define PID_PARAM_KI                6.5
+#define PID_PARAM_KD                7.6
+
+// WHEEL
+#define WHEEL_RADIUS             0.066
+#define GEAR_RATIO                  36
+
+// CAR
+chassis_t chas;
+
+#define WHEEL_DIST_X                 0
+#define WHEEL_DIST_Y              0.13
+
+// Car Thread
+#define THREAD_PRIORITY             10
+#define THREAD_STACK_SIZE          512
+#define THREAD_TIMESLICE             5
+
+static rt_thread_t tid_car = RT_NULL;
+
+static void command_register_all(void);
+void init_laser_and_gimbal(void);
+
+void car_thread(void *param)
 {
-    LOG_D("Failed to malloc memory for wheels");
-}
-
-// 1.1 Create two motors
-motor_t left_motor  = motor_create(left_motor_init,  left_motor_enable,  left_motor_disable,  left_motor_set_speed,  DC_MOTOR);
-motor_t right_motor = motor_create(right_motor_init, right_motor_enable, right_motor_disable, right_motor_set_speed, DC_MOTOR);
-
-// 1.2 Create two encoders
-encoder_t left_encoder  = encoder_create(LEFT_ENCODER_PIN, PULSE_PER_REVOL);
-encoder_t right_encoder = encoder_create(RIGHT_ENCODER_PIN, PULSE_PER_REVOL);
-
-// 1.3 Create two pid contollers
-pid_control_t left_pid  = pid_create();
-pid_control_t right_pid = pid_create();
-
-// 1.4 Add two wheels
-c_wheels[0] = wheel_create(left_motor,  left_encoder,  left_pid,  WHEEL_RADIUS, GEAR_RATIO);
-c_wheels[1] = wheel_create(right_motor, right_encoder, right_pid, WHEEL_RADIUS, GEAR_RATIO);
-
-// 2. Iinialize Kinematics - Two Wheel Differential Drive
-kinematics_t c_kinematics = kinematics_create(TWO_WD, WHEEL_DIST_X, WHEEL_DIST_Y, WHEEL_RADIUS);
-
-// 3. Initialize Chassis
-chas = chassis_create(c_wheels, c_kinematics);
-
-// 4. Set Sample time
-encoder_set_sample_time(chas->c_wheels[0]->w_encoder, SAMPLE_TIME);
-encoder_set_sample_time(chas->c_wheels[1]->w_encoder, SAMPLE_TIME);
-pid_set_sample_time(chas->c_wheels[0]->w_pid, PID_SAMPLE_TIME);
-pid_set_sample_time(chas->c_wheels[1]->w_pid, PID_SAMPLE_TIME);
+    // TODO
 
-// 5. Enable Chassis
-chassis_enable(chas);
+    struct velocity target_velocity;
 
-// Turn left
-target_vel.linear_x = 0;   // m/s
-target_vel.linear_y = 0;    // m/s
-target_vel.angular_z = PI / 4; // rad/s
+    target_velocity.linear_x = 0.00f;
+    target_velocity.linear_y = 0;
+    target_velocity.angular_z = 0;
+    chassis_set_velocity(chas, target_velocity);
 
-chassis_set_velocity(chas, target_vel);
-rt_thread_mdelay(500);
+    // Open loop control
+    // controller_disable(chas->c_wheels[0]->w_controller);
+    // controller_disable(chas->c_wheels[1]->w_controller);
 
-// Turn right
-target_vel.linear_x = 0;   // m/s
-target_vel.linear_y = 0;    // m/s
-target_vel.angular_z = - PI / 4; // rad/s
-
-chassis_set_velocity(chas, target_vel);
-rt_thread_mdelay(500);
-
-// Go straight
-target_vel.linear_x = 0.06;   // m/s
-target_vel.linear_y = 0;    // m/s
-target_vel.angular_z = 0;
-
-chassis_set_velocity(chas, target_vel);
-
-// Stop
-target_vel.linear_x = 0.0;   // m/s
-target_vel.linear_y = 0;    // m/s
-target_vel.angular_z = 0; // rad/s
-
-chassis_set_velocity(chas, target_vel);
-rt_thread_mdelay(500);
+    while (1)
+    {
+        rt_thread_mdelay(50);
+        chassis_update(chas);
+    }
+}
 
-while(1)
+void car_init(void *parameter)
 {
-    chassis_update(chas);
-    rt_thread_mdelay(50);
+    // 1. Initialize two wheels - left and right
+    wheel_t* c_wheels = (wheel_t*) rt_malloc(sizeof(wheel_t) * 2);
+    if (c_wheels == RT_NULL)
+    {
+        LOG_D("Failed to malloc memory for wheels");
+    }
+
+    // 1.1 Create two motors
+    dual_pwm_motor_t left_motor   = dual_pwm_motor_create(LEFT_FORWARD_PWM, LEFT_FORWARD_PWM_CHANNEL, LEFT_BACKWARD_PWM, LEFT_BACKWARD_PWM_CHANNEL);
+    dual_pwm_motor_t right_motor  = dual_pwm_motor_create(RIGHT_FORWARD_PWM, RIGHT_FORWARD_PWM_CHANNEL, RIGHT_BACKWARD_PWM, RIGHT_BACKWARD_PWM_CHANNEL);
+
+    // 1.2 Create two encoders
+    ab_phase_encoder_t left_encoder  = ab_phase_encoder_create(LEFT_ENCODER_A_PHASE_PIN, LEFT_ENCODER_B_PHASE_PIN, PULSE_PER_REVOL, ENCODER_SAMPLE_TIME);
+    ab_phase_encoder_t right_encoder = ab_phase_encoder_create(RIGHT_ENCODER_A_PHASE_PIN, RIGHT_ENCODER_B_PHASE_PIN, PULSE_PER_REVOL, ENCODER_SAMPLE_TIME);
+
+    // 1.3 Create two pid contollers
+    inc_pid_controller_t left_pid  = inc_pid_controller_create(PID_PARAM_KP, PID_PARAM_KI, PID_PARAM_KD, PID_SAMPLE_TIME);
+    inc_pid_controller_t right_pid = inc_pid_controller_create(PID_PARAM_KP, PID_PARAM_KI, PID_PARAM_KD, PID_SAMPLE_TIME);
+
+    // 1.4 Add two wheels
+    c_wheels[0] = wheel_create((motor_t)left_motor,  (encoder_t)left_encoder,  (controller_t)left_pid,  WHEEL_RADIUS, GEAR_RATIO);
+    c_wheels[1] = wheel_create((motor_t)right_motor, (encoder_t)right_encoder, (controller_t)right_pid, WHEEL_RADIUS, GEAR_RATIO);
+
+    // 2. Iinialize Kinematics - Two Wheel Differential Drive
+    kinematics_t c_kinematics = kinematics_create(TWO_WD, WHEEL_DIST_X, WHEEL_DIST_Y, WHEEL_RADIUS);
+
+    // 3. Initialize Chassis
+    chas = chassis_create(c_wheels, c_kinematics);
+
+    // 4. Enable Chassis
+    chassis_enable(chas);
+
+    // thread
+    tid_car = rt_thread_create("tcar",
+                              car_thread, RT_NULL,
+                              THREAD_STACK_SIZE,
+                              THREAD_PRIORITY, THREAD_TIMESLICE);
+
+    if (tid_car != RT_NULL)
+    {
+        rt_thread_startup(tid_car);
+    }
 }
-
 ```

+ 132 - 0
docs/user-guide.md

@@ -0,0 +1,132 @@
+# RT-Robot 用户指南
+
+本节主要介绍 rt-robot 框架的基本使用流程,并对重要的 API 和结构体进行说明。(组件思想)
+
+## 准备工作
+
+首先需要下载 rt-robot 软件包,并将软件包加入到项目中。在 BSP 目录下使用 menuconfig 命令打开 env 配置界面,在 RT-Thread online packages → system packages 中选择 RT-Robot 软件包,操作界面如下图所示:
+
+![rt-robot 软件包配置](./figures/rt-robot-menuconfig.png)
+
+```shell
+RT-Thread online packages
+    system packages  --->
+         [*] RT-Robot: RT-Thread robots development platform  --->
+            Version (latest) --->
+```
+
+Version: 配置软件包版本号。
+
+选择完成后,使用 `pkgs --update` 命令下载软件包并更新用户配置。
+
+## 使用流程
+
+使用 rt-robot 框架的初始化智能车流程如下:
+
+- 1 初始化车轮 (为车轮添加电机、编码器、控制器)
+  - 1.1 初始化车轮电机 
+  - 1.2 初始化车轮编码器
+  - 1.3 初始化车轮控制器
+
+- 2 初始化动力学模型
+
+- 3 初始化车底盘 (为底盘添加车轮、动力学模型)
+
+- 4 底盘控制
+
+### 1 初始化车轮
+
+车轮由电机、编码器、控制器三个组件组成。首先需要创建它们,然后再组成车轮。
+
+#### 电机
+
+电机有许多的类型和驱动方式,rt-robot 对此进行了抽象并针对不同类型和驱动方式的电机给出了各自的创建接口。用户调用对应的接口就可以创建出对应的电机对象。相应的创建API请参考 [api.md](./api.md)
+
+#### 编码器
+
+编码器有单相和AB相之分,rt-robot 对此给出了不同的创建接口,用户调用对应的接口就可以创建出对应的编码器对象。相应的创建API请参考 [api.md](./api.md)
+
+#### 控制器
+
+控制器本质上来说是一种算法,用来稳定系统输出(在此为车轮速度)。常见的控制算法为PID,其有增量式和位置式之分,rt-robot 对此有不同的创建接口。用户调用对应的接口就可以创建出对应的控制器对象。相应的创建API请参考 [api.md](./api.md)
+
+#### 创建车轮
+
+每个车轮都是由电机、编码器、控制器三个组件组成。在完成组件创建拿到组件对象后就可以调用如下接口创建车轮了。
+
+_创建接口:_
+```C
+wheel_t     wheel_create(motor_t w_motor, encoder_t w_encoder, controller_t w_controller, float radius, rt_uint16_t gear_ratio);
+```
+- w_motor 电机对象
+- w_encoder 编码器对象
+- w_controller 控制器对象
+- radius 车轮直径
+- gear_ratio 减速比
+
+此只是创建一个车轮,多个车轮需要多次创建
+
+### 2 初始化动力学模型
+
+"凡系统必有结构,系统结构决定系统功能"。
+虽然小车的物理结构各不相同,但是同样作为小车底板,都能实现相同或相似的运动,
+因此我们对小车的常见运动进行抽象,提供统一的接口,适配不同小车底板。不同车底
+板最主要的区别在于物理模型,例如两轮驱动、四轮驱动等
+。对此 rt-robot 有相应的动力学模型。现抽象出的动力学模型有以下四种类型:
+- TWO_WD 两轮差分驱动
+- FOUR_WD 四轮差分驱动
+- MECANUM 麦克纳姆轮驱动
+- ACKERMANN 后轮驱动调速,
+前轮通过连杆控制方向
+
+_创建接口:_
+```C
+kinematics_t    kinematics_create(enum base k_base, float length_x, float length_y, float wheel_radius);
+```
+- k_base 类型
+- length_x X轴两车轮间距(单位: m)
+- length_y Y轴两车轮间距(单位: m)
+- wheel_radius  车轮直径(单位:m)
+
+### 3 初始化车底盘
+
+在创建了足够的车轮和相应的动力学模型后,就可以创建底盘了。底盘的创建比较简单,只要调用 ```chassis_t   chassis_create(wheel_t* c_wheel, kinematics_t c_kinematics);``` 接口即可,其两个参数分别是 车轮对象数组 和 动力学模型对象。
+
+### 4 底盘控制
+
+在以上创建完成后, 我们就拿到了一个车底盘对象。在控制底盘运动前,还需要调用底盘使能接口(```rt_err_t    chassis_enable(chassis_t chas);```)使能车底盘。使能完成后,就可以调用相应接口控制底盘运动了。底盘的**主要控制接口**如下:
+```c
+struct velocity
+{
+    float linear_x;  // m/s
+    float linear_y;  // m/s
+    float angular_z; // rad/s
+};
+
+rt_err_t chassis_set_velocity(chassis_t chas, struct velocity target_velocity);
+```
+target_velocity 为底盘的速度,该速度有X、Y、Z三个分量,其分别是底盘的X轴线速度,Y轴线速度,Z轴转速。当前我们的小车坐标系定义如下:
+
+![](./figures/coordinates.png)
+
+X轴正方向为小车车头方向,以小车车头逆时针旋转方向为旋转角速度 w 的正方向。
+
+## 遥控器 / 上位机
+
+在使用遥控器/上位机之前必须先调用接口 '```rt_err_t command_init(chassis_t chas);```' 初始化 command 以便能够处理各种命令。
+
+遥控器和上位机有很多选择,当前 rt-robot 直接支持 PS2 遥控器和 ANO 上位机。在使用对应的遥控器/上位机之前需要先初始化它们。
+
+PS2 初始化接口:
+```c
+void ps2_init(rt_base_t cs_pin, rt_base_t clk_pin, rt_base_t do_pin, rt_base_t di_pin);
+```
+参数 xx_pin 分别为相应的引脚号。
+
+ANO 初始化接口:
+```c
+int ano_init(void *param);
+```
+参数 param 为字符设备名(e.g. "uart1")
+
+**初始化完成后就可以直接使用了。**