“开源平衡车/zh”的版本间的差异
第81行: | 第81行: | ||
==平衡车搭建== | ==平衡车搭建== | ||
− | *''' | + | ==='''Step1'''=== |
− | [[File:Balancestep1.jpg||600px|center]] | + | *按图1-1所示将'''结构-A1'''和'''结构-A2'''对接 |
− | *'''Step2''' | + | [[File:Balancestep1-1.jpg||600px|center]] |
− | [[File:Balancestep2.jpg||600px|center]] | + | *按图1-2所示将'''结构-B1'''和'''结构-B2'''插在'''结构-A1'''两边 |
− | *'''Step3''': | + | [[File:Balancestep1-2.jpg||600px|center]] |
− | [[File:Balancestep3.jpg||600px|center]] | + | *步骤1完成后组成'''小车骨架''' |
− | *'''Step4''': | + | [[File:Balancestep1-3.jpg||600px|center]] |
− | [[File:Balancestep4.jpg||600px|center]] | + | ==='''Step2'''=== |
− | *''' | + | *按图2-1所示将2个'''步进电机'''与'''结构-C1'''对接,再用'''铜柱'''固定好 |
− | [[File:Balancestep5.jpg||600px|center]] | + | '''注意:'''注意图中所示电机接口方向,两个电机接口应该对称安装。 |
− | *'''Step6''' | + | [[File:Balancestep2-1.jpg||600px|center]] |
− | [[File:Balancestep6.jpg||600px|center]] | + | *步骤2完成后组成'''电机组件''' |
− | + | ==='''Step3'''=== | |
+ | *按图3-1将'''电机组件'''卡到'''小车骨架'''上,注意电机接口需要对应'''小车骨架'''的缺口,请按图中所示方向将'''电机组件'''卡入卡槽内 | ||
+ | [[File:Balancestep3-1.jpg||600px|center]] | ||
+ | *'''电机组件'''卡到位后,将'''结构-B1'''卡入卡槽缺口,卡紧'''电机组件''' | ||
+ | [[File:Balancestep3-2.jpg||600px|center]] | ||
+ | *步骤3完成后组成'''小车地盘''' | ||
+ | [[File:Balancestep3-3.jpg||600px|center]] | ||
+ | ==='''Step4'''=== | ||
+ | *按图4-1所示将'''车轴连接器'''固定在'''步进电机'''轴上,然后将'''车轮装在'''车轴连接器'''上,然后用'''螺丝'''固定紧 | ||
+ | [[File:Balancestep4-1.jpg||600px|center]] | ||
+ | *步骤4完成后小车如图4-2所示 | ||
+ | [[File:Balancestep4-2.jpg||600px|center]] | ||
+ | ==='''Step5'''=== | ||
+ | *按图5-1所示将'''2s电池'''放在'''小车地盘'''的槽内,然后将'''结构-C2'''插在'''小车地盘'''上面,将'''结构-C3'''插在'''小车地盘'''的底部 | ||
+ | [[File:Balancestep5-1.jpg||600px|center]] | ||
+ | *按图5-2说是用'''结构-A3'''、'''结构-C4'''和'''结构-C5'''卡紧小车上的部件 | ||
+ | [[File:Balancestep5-2.jpg||600px|center]] | ||
+ | *步骤5完成后小车如图5-3所示 | ||
+ | [[File:Balancestep5-3.jpg||600px|center]] | ||
+ | ==='''Step6'''=== | ||
+ | *将[[Microduino-Shield Stepper/zh]]用'''尼龙螺丝'''、'''尼龙螺柱'''和'''尼龙螺母'''固定在'''小车地盘'''顶部 | ||
+ | *将2.4G天线接到[[Microduino-Module nRF/zh]]上 | ||
+ | *然后将[[Microduino-Core+/zh]],[[Microduino-Module nRF/zh]]和[[Microduino-Module Motion/zh]]叠加到[[Microduino-Shield Stepper/zh]]上 | ||
+ | [[File:Balancestep6-1.jpg||600px|center]] | ||
+ | *然后按以下示意图用'''步进电机线'''连接'''步进电机'''和[[Microduino-Shield Stepper/zh]],请注意两个'''步进电机线'''的接口位置。 | ||
+ | [[File:Balancestep6-2.jpg||600px|center]] | ||
+ | '''注意''':在连接电机线的时候要注意方向,并稍微用力才能插入电机的接口,请按照图中方向插接。 | ||
[[File:Balancemotor.jpg||200px|center]] | [[File:Balancemotor.jpg||200px|center]] | ||
− | === | + | ==='''Step7'''=== |
− | *''' | + | *按图7-1所示将'''2s电池'''插入[[Microduino-Shield Stepper/zh]]的电池接口,小车即上电工作,扶起小车,小车即能保持平衡不倒 |
− | [[File: | + | [[File:Balancestep7-1.jpg||600px|center]] |
− | ''' | + | |
− | + | ==Joypad遥控指南== | |
− | *''' | + | |
− | [ | + | *搭建过程可参考以下页面:'''[https://www.microduino.cn/wiki/index.php/Microduino-Joypad_Getting_start/zh Joypad使用指南]''' |
− | *''' | + | |
− | + | *'''Joypad通讯模式配置'''* | |
− | *''' | + | *模式配置可参考以下页面:'''[https://www.microduino.cn/wiki/index.php/Microduino-Joypad_Getting_start/zh#.E9.80.9A.E8.AE.AF.E6.A8.A1.E5.BC.8F 通讯模式配置]''' |
− | + | **当我们使用[[Microduino-Module nRF/zh]]作为'''通讯模块'''时,Joypad对应选择'''nRF模式'''即可 | |
− | *'''Step | + | |
− | [ | + | *'''Joypad电池使用说明'''* |
− | * | + | *特别要注意的是电池使用说明:'''[https://www.microduino.cn/wiki/index.php/Microduino-Joypad_Getting_start/zh#Step-2_.E7.94.B5.E6.B1.A0.E9.80.9A.E7.94.B5 电池使用说明]''' |
− | [ | + | |
− | * | + | ==代码说明== |
+ | *在“user_def.h”文件是我们的配置文件 | ||
+ | *以下代码可以配置nRF模式下通道,需要保证和Joypad遥控器一致 | ||
+ | *Joypad的nRF模式通道配置可参考:[https://www.microduino.cn/wiki/index.php/Microduino-Joypad_Getting_start/zh#nRF.E6.A8.A1.E5.BC.8F.E9.80.9A.E9.81.93.E9.85.8D.E7.BD.AE nRF模式通道配置] | ||
+ | <source lang = "cpp"> | ||
+ | #define NRF_CHANNEL 70 //nRF通道 | ||
+ | </source> | ||
+ | |||
+ | |||
+ | *以下代码可以配置油门和转向对应通道 | ||
+ | *对应通道说明可参考:[https://www.microduino.cn/wiki/index.php/Microduino-Joypad_Getting_start/zh#Step-5_.E9.80.9A.E9.81.93.2F.E6.93.8D.E4.BD.9C.E8.AF.B4.E6.98.8E 通道/操作说明] | ||
+ | <source lang = "cpp"> | ||
+ | #define CHANNEL_THROTTLE 2 //油门通道 | ||
+ | #define CHANNEL_STEERING 1 //转向通道 | ||
+ | </source> | ||
+ | |||
+ | |||
+ | *以下代码可以修正两轮的转速比例 | ||
+ | **值得范围是-1到1之间 | ||
+ | **设置成-1,是最大转速比反转 | ||
+ | **设置成1,是最大转速比正转, | ||
+ | **如果小车不能走直线,应该将较慢的一边轮子的转速比例值降低 | ||
+ | <source lang = "cpp"> | ||
+ | #define motor_fixL 1 //速度修正 -1到1之间 | ||
+ | #define motor_fixR 1 //速度修正 -1到1之间 | ||
+ | </source> | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
==注意问题== | ==注意问题== |
2016年3月12日 (六) 15:08的版本
目录概述
两轮自平衡小车是一个集多种功能于一体的综合系统,是自动控制理论与动力学理论及技术相结合的研究课题,其关键问题是在完成自身平衡的同时,还能够适应各种环境下的控制任务。本教程将指导读者基于Microduino产品模块组建一个可以遥控的自平衡小车,能够实现两轮小车平衡直立和运动的功能,用户在制作完成后,可以在该平台上进行二次开发,实现更多有趣功能。 材料清单
程序下载从以下地址下载源程序 BalanceCar_Microduino 下载程序堆叠模块
配置环境
浏览到项目程序地址,点击“Joypad_Balance_Reception.ino”程序打开
点击“工具”,在板选项里面选择板卡(Microduino-Core+),在处理器选项里面选择处理器(Atmega644pa@16M,5V),再在端口选项里面选择正确的端口号,点击“”按钮下载程序到核心板上。
平衡车搭建Step1
Step2
注意:注意图中所示电机接口方向,两个电机接口应该对称安装。
Step3
Step4
Step5
Step6
注意:在连接电机线的时候要注意方向,并稍微用力才能插入电机的接口,请按照图中方向插接。 Step7
Joypad遥控指南
代码说明
#define NRF_CHANNEL 70 //nRF通道
#define CHANNEL_THROTTLE 2 //油门通道
#define CHANNEL_STEERING 1 //转向通道
#define motor_fixL 1 //速度修正 -1到1之间
#define motor_fixR 1 //速度修正 -1到1之间
注意问题
平衡车程序说明nrf设置部分 //nRF==============================
SPI.begin(); //初始化SPI总线
radio.begin();
//此处与Joypad上设定的通道数对应
network.begin(/*channel*/ 70, /*node address*/ this_node);
digitalWrite(LED, HIGH);
Serial.println("===========start===========");
端口设定 #define MOTOR_EN 4 //PORTB,0
#define MOTOR1_DIR A0 //PORTA,7
#define MOTOR1_STEP 5 //PORTB,1
#define MOTOR2_DIR A1 //PORTA,6
#define MOTOR2_STEP 6 //PORTB,2
#define MOTOR3_DIR A2 //PORTA,5
#define MOTOR3_STEP 7 //PORTB,3
#define MOTOR4_DIR A3 //PORTA,4
#define MOTOR4_STEP 8 //PORTD,6
与遥控器进行数据交换的数组 struct receive_a //接收
{
uint32_t ms;
uint16_t rf_CH0;
uint16_t rf_CH1;
uint16_t rf_CH2;
uint16_t rf_CH3;
uint16_t rf_CH4;
uint16_t rf_CH5;
uint16_t rf_CH6;
uint16_t rf_CH7;
};
PID控制实现 // PD的实施。 DT是毫秒
float stabilityPDControl(float DT, float input, float setPoint, float Kp, float Kd)
{
float error;
float output;
error = setPoint - input;
// Kd的两部分实施
//仅使用输入(传感器)的一部分而不是设定值输入输入(T-2)最大的一个
//而第二个使用该设定值,使之更有点侵略性设定点设定点(T-1)
output = Kp * error + (Kd * (setPoint - setPointOld) - Kd * (input - PID_errorOld2)) / DT; // + 错误 - PID_error_Old2
//Serial.print(Kd*(error-PID_errorOld));Serial.print("\t");
PID_errorOld2 = PID_errorOld;
PID_errorOld = input; // 误差为Kd值是唯一的输入组件
setPointOld = setPoint;
return (output);
}
//P控制实现。
float speedPControl(float input, float setPoint, float Kp)
{
float error;
error = setPoint - input;
return (Kp * error);
}
// PI实现。 DT是毫秒
float speedPIControl(float DT, float input, float setPoint, float Kp, float Ki)
{
float error;
float output;
error = setPoint - input;
PID_errorSum += constrain(error, -ITERM_MAX_ERROR, ITERM_MAX_ERROR);
PID_errorSum = constrain(PID_errorSum, -ITERM_MAX, ITERM_MAX);
output = Kp * error + Ki * PID_errorSum * DT * 0.001;
return (output);
}
PID算法-平衡控制 void robot()
{
//===============================================================
timer_value = millis();
// 新的DMP定位解决方案
fifoCount = mpu.getFIFOCount();
if (fifoCount >= 18)
{
if (fifoCount > 18) // 如果我们有一个以上的数据包,我们采取简单的路径:丢弃缓冲区
{
mpu.resetFIFO();
return;
}
loop_counter++;
slow_loop_counter++;
dt = (timer_value - timer_old);
timer_old = timer_value;
angle_adjusted_Old = angle_adjusted;
angle_adjusted = dmpGetPhi() + ANGLE_FIX;
Serial.println(angle_adjusted);
mpu.resetFIFO(); // 我们始终复位FIFO
// 我们计算估计机器人的速度
actual_robot_speed_Old = actual_robot_speed;
actual_robot_speed = (speed_m[1] - speed_m[0]) / 2; // 正面:前锋
// 角速度角度调整角度调整旧
int16_t angular_velocity = (angle_adjusted - angle_adjusted_Old) * 90.0;
// 我们利用机器人速度(T-1)或(T-2),以补偿该延迟
int16_t estimated_speed = actual_robot_speed_Old - angular_velocity;
//估计速度估计过滤滤速
estimated_speed_filtered = estimated_speed_filtered * 0.95 + (float)estimated_speed * 0.05;
//目标角速度PIC ONTROL dt的速度估计过滤油门Kp_thr Ki_thr
target_angle = speedPIControl(dt, estimated_speed_filtered, throttle, Kp_thr, Ki_thr);
//有限的输出 目标角度约束目标角度最大目标角度最大目标角度
target_angle = constrain(target_angle, -max_target_angle, max_target_angle);
if (pushUp_counter > 0) // pushUp mode?
target_angle = 10;
//我们整合输出(加速度)
control_output += stabilityPDControl(dt, angle_adjusted, target_angle, Kp, Kd);
control_output = constrain(control_output, -800, 800); // 限制最大输出控制
// 控制的转向部分的输出直接注射
motor1 = control_output + steering;
motor2 = -control_output + steering; //马达2反转
// 限制最大速度
motor1 = constrain(motor1, -500, 500);
motor2 = constrain(motor2, -500, 500);
// Is robot ready (upright?)
if ((angle_adjusted < 66) && (angle_adjusted > -66))
{
if (node_STA) // pushUp mode?
{
pushUp_counter++;
if (pushUp_counter > 60) // 0.3 seconds
{
// Set motors to 0 => disable steppers => robot
setMotorSpeed(0, 0);
setMotorSpeed(1, 0);
// We prepare the raiseup mode
Kp = KP_RAISEUP; // CONTROL GAINS FOR RAISE UP
Kd = KD_RAISEUP;
Kp_thr = KP_THROTTLE_RAISEUP;
control_output = 0;
estimated_speed_filtered = 0;
}
else
{
setMotorSpeed(0, motor1);
setMotorSpeed(1, motor2);
}
}
else
{
// NORMAL MODE
setMotorSpeed(0, motor1);
setMotorSpeed(1, motor2);
pushUp_counter = 0;
}
if ((angle_adjusted < 40) && (angle_adjusted > -40))
{
Kp = Kp_user; // Default or user control gains
Kd = Kd_user;
Kp_thr = Kp_thr_user;
Ki_thr = Ki_thr_user;
}
else
{
Kp = KP_RAISEUP; // CONTROL GAINS FOR RAISE UP
Kd = KD_RAISEUP;
Kp_thr = KP_THROTTLE_RAISEUP;
Ki_thr = KI_THROTTLE_RAISEUP;
}
}
else // Robot not ready, angle > 70º
{
setMotorSpeed(0, 0);
setMotorSpeed(1, 0);
PID_errorSum = 0; // Reset PID I term
Kp = KP_RAISEUP; // CONTROL GAINS FOR RAISE UP
Kd = KD_RAISEUP;
Kp_thr = KP_THROTTLE_RAISEUP;
Ki_thr = KI_THROTTLE_RAISEUP;
}
}
}
遥控器数据接收后选择数据控制平衡车的前后与左右 float * _i = _speed;
//CH1,CH0,CH7对应之前的发送/接收部分定义的数组
_i[0] = map(rec.rf_CH1, 1000, 2000, -MAX_THROTTLE, MAX_THROTTLE);
_i = _turn;
_i[0] = map(rec.rf_CH0, 1000, 2000, -MAX_STEERING, MAX_STEERING);
node_STA = (rec.rf_CH7 > 1500 ? true : false); //接收请求时序赋值
Joypad程序及说明Joypad部分 def.h中 定义了 uint8_t nrf_channal = 70; //0~125
nrf_channal为nrf通信的通道,joypad和Cube小车的代码中都会有该定义 当通道一致时则Joypad可与Cube小车成功连接。 在小车代码中会有如下程序段 //nRF==============================
SPI.begin(); //初始化SPI总线
radio.begin();
network.begin(/*channel*/ 70 , /*node address*/ this_node);
在data.h中 outBuf[0] = Joy1_x;
outBuf[1] = Joy1_y;
outBuf[2] = Joy_x;
outBuf[3] = Joy_y;
outBuf[4] = map(AUX[0], 0, 1, Joy_MID - Joy_maximum, Joy_MID + Joy_maximum);
outBuf[5] = map(AUX[1], 0, 1, Joy_MID - Joy_maximum, Joy_MID + Joy_maximum);
outBuf[6] = map(AUX[2], 0, 1, Joy_MID - Joy_maximum, Joy_MID + Joy_maximum);
outBuf[7] = map(AUX[3], 0, 1, Joy_MID - Joy_maximum, Joy_MID + Joy_maximum);
8位数组outBuf表示Joypad发出的8位数据,0位为右摇杆左右,1为右摇杆上下,2为左摇杆左右,3位左摇杆上下,4~7位对应AUX0~4 在nrf.h中 struct send_a //发送
{
uint32_t ms;
uint16_t rf_CH0;
uint16_t rf_CH1;
uint16_t rf_CH2;
uint16_t rf_CH3;
uint16_t rf_CH4;
uint16_t rf_CH5;
uint16_t rf_CH6;
uint16_t rf_CH7;
};
此处定义的send_a结构体位对应的0位要发送的数据 视频 |