平衡车程序
[应用]两轮自平衡小车测试程序
两轮自平衡小车测试程序/********************************************************** *************// 两轮自平衡车最终版控制程序(6轴MPU6050+互补滤波+PWM电机)// 单片机STC12C5A60S2// 晶振:20M// 日期:2012.11.26 - ?*********************************************************** ************/#include <REG52.H>#include <math.h>#include <stdio.h>#include <INTRINS.H>typedef unsigned char uchar;typedef unsigned short ushort;typedef unsigned int uint;//******功能模块头文件*******#include "DELAY.H" //延时头文件//#include "STC_ISP.H" //程序烧录头文件#include "SET_SERIAL.H" //串口头文件#include "SET_PWM.H" //PWM头文件#include "MOTOR.H" //电机控制头文件#include "MPU6050.H" //MPU6050头文件//******角度参数************float Gyro_y; //Y轴陀螺仪数据暂存float Angle_gy; //由角速度计算的倾斜角度float Accel_x; //X轴加速度值暂存float Angle_ax; //由加速度计算的倾斜角度float Angle; //小车最终倾斜角度uchar value; //角度正负极性标记//******PWM参数*************int speed_mr; //右电机转速int speed_ml; //左电机转速int PWM_R; //右轮PWM值计算int PWM_L; //左轮PWM值计算float PWM; //综合PWM计算float PWMI; //PWM积分值//******电机参数*************float speed_r_l; //电机转速float speed; //电机转速滤波float position; //位移//******蓝牙遥控参数*************uchar remote_char;char turn_need;char speed_need;//*********************************************************//定时器100Hz数据更新中断//********************************************************* void Init_Timer1(void) //10毫秒@20MHz,100Hz刷新频率{ AUXR &= 0xBF; //定时器时钟12T模式TMOD &= 0x0F; //设置定时器模式TMOD |= 0x10; //设置定时器模式TL1 = 0xE5; //设置定时初值TH1 = 0xBE; //设置定时初值TF1 = 0; //清除TF1标志TR1 = 1; //定时器1开始计时}//*********************************************************//中断控制初始化//*********************************************************void Init_Interr(void){ EA = 1; //开总中断EX0 = 1; //开外部中断INT0EX1 = 1; //开外部中断INT1IT0 = 1; //下降沿触发IT1 = 1; //下降沿触发ET1 = 1; //开定时器1中断}//******卡尔曼参数************float code Q_angle=0.001;float code Q_gyro=0.003;float code R_angle=0.5;float code dt=0.01; //dt为kalman滤波器采样时间;char code C_0 = 1;float xdata Q_bias, Angle_err;float xdata PCt_0, PCt_1, E;float xdata K_0, K_1, t_0, t_1;float xdata Pdot[4] ={0,0,0,0};float xdata PP[2][2] = { { 1, 0 },{ 0, 1 } };//*********************************************************// 卡尔曼滤波//*********************************************************//Kalman滤波,20MHz的处理时间约0.77ms;void Kalman_Filter(float Accel,float Gyro){ Angle+=(Gyro - Q_bias) * dt; //先验估计Pdot[0]=Q_angle - PP[0][1] - PP[1][0]; // Pk-先验估计误差协方差的微分Pdot[1]=- PP[1][1];Pdot[2]=- PP[1][1];Pdot[3]=Q_gyro;PP[0][0] += Pdot[0] * dt; // Pk-先验估计误差协方差微分的积分PP[0][1] += Pdot[1] * dt; // =先验估计误差协方差PP[1][0] += Pdot[2] * dt;PP[1][1] += Pdot[3] * dt;Angle_err = Accel - Angle; //zk-先验估计PCt_0 = C_0 * PP[0][0];PCt_1 = C_0 * PP[1][0];E = R_angle + C_0 * PCt_0;K_0 = PCt_0 / E;K_1 = PCt_1 / E;t_0 = PCt_0;t_1 = C_0 * PP[0][1];PP[0][0] -= K_0 * t_0; //后验估计误差协方差PP[0][1] -= K_0 * t_1;PP[1][0] -= K_1 * t_0;PP[1][1] -= K_1 * t_1;Angle += K_0 * Angle_err; //后验估计Q_bias += K_1 * Angle_err; //后验估计Gyro_y = Gyro - Q_bias; //输出值(后验估计)的微分=角速度}//*********************************************************// 倾角计算(卡尔曼融合)//*********************************************************void Angle_Calcu(void){ //------加速度--------------------------//范围为2g时,换算关系:16384 LSB/g//角度较小时,x=sinx得到角度(弧度), deg = rad*180/3.14//因为x>=sinx,故乘以1.3适当放大Accel_x = GetData(ACCEL_XOUT_H); //读取X轴加速度Angle_ax = (Accel_x - 1100) /16384; //去除零点偏移,计算得到角度(弧度)Angle_ax = Angle_ax*1.2*180/3.14; //弧度转换为度,//-------角速度-------------------------//范围为2000deg/s时,换算关系:16.4 LSB/(deg/s)Gyro_y = GetData(GYRO_YOUT_H); //静止时角速度Y 轴输出为-30左右Gyro_y = -(Gyro_y + 30)/16.4; //去除零点偏移,计算角速度值,负号为方向处理//Angle_gy = Angle_gy + Gyro_y*0.01; //角速度积分得到倾斜角度.//-------卡尔曼滤波融合-----------------------Kalman_Filter(Angle_ax,Gyro_y); //卡尔曼滤波计算倾角/*//-------互补滤波-----------------------//补偿原理是取当前倾角和加速度获得倾角差值进行放大,然后与//陀螺仪角速度叠加后再积分,从而使倾角最跟踪为加速度获得的角度//0.5为放大倍数,可调节补偿度;0.01为系统周期10msAngle = Angle + (((Angle_ax-Angle)*0.5 + Gyro_y)*0.01);*/ }//*********************************************************//电机转速和位移值计算//*********************************************************void Psn_Calcu(void){ speed_r_l =(speed_mr + speed_ml)*0.5;speed *= 0.7; //车轮速度滤波speed += speed_r_l*0.3;position += speed; //积分得到位移position += speed_need;if(position<-6000) position = -6000;if(position> 6000) position = 6000;}static float code Kp = 9.0; //PID参数static float code Kd = 2.6; //PID参数static float code Kpn = 0.01; //PID参数static float code Ksp = 2.0; //PID参数//********************************************************* //电机PWM值计算//*********************************************************void PWM_Calcu(void){ if(Angle<-40||Angle>40) //角度过大,关闭电机{ CCAP0H = 0;CCAP1H = 0;return;}PWM = Kp*Angle + Kd*Gyro_y; //PID:角速度和角度PWM += Kpn*position + Ksp*speed; //PID:速度和位置PWM_R = PWM + turn_need;PWM_L = PWM - turn_need;PWM_Motor(PWM_L,PWM_R);}//*********************************************************//手机蓝牙遥控//*********************************************************void Bluetooth_Remote(void){ remote_char = receive_char(); //接收蓝牙串口数据if(remote_char ==0x02) speed_need = -80; //前进else if(remote_char ==0x01) speed_need = 80; //后退else speed_need = 0; //不动if(remote_char ==0x03) turn_need = 15; //左转else if(remote_char ==0x04) turn_need = -15; //右转else turn_need = 0; //不转}/*========================================================= =======*///*********************************************************//main//*********************************************************void main(){ delaynms(500); //上电延时Init_PWM(); //PWM初始化Init_Timer0(); //初始化定时器0,作为PWM时钟源Init_Timer1(); //初始化定时器1Init_Interr(); //中断初始化Init_Motor(); //电机控制初始化Init_BRT(); //串口初始化(独立波特率)InitMPU6050(); //初始化MPU6050delaynms(500);while(1){ Bluetooth_Remote();}}/*========================================================= ===*///********timer1中断***********************void Timer1_Update(void) interrupt 3{ TL1 = 0xE5; //设置定时初值10MSTH1 = 0xBE;//STC_ISP(); //程序下载Angle_Calcu(); //倾角计算Psn_Calcu(); //电机位移计算PWM_Calcu(); //计算PWM值speed_mr = speed_ml = 0;}//********右电机中断***********************void INT_L(void) interrupt 0{ if(SPDL == 1) { speed_ml++; } //左电机前进else { speed_ml--; } //左电机后退LED = ~LED;}//********左电机中断***********************void INT_R(void) interrupt 2{ if(SPDR == 1) { speed_mr++; } //右电机前进else { speed_mr--; } //右电机后退LED = ~LED;}。
简要描述平衡车的开发流程
简要描述平衡车的开发流程一、需求分析在开发平衡车之前,首先需要对需求进行深入分析。
这包括确定平衡车的使用场景、目标用户、功能需求等。
例如,平衡车可能会被用于个人出行、物流配送、旅游观光等不同场景,因此在设计时需要考虑到不同场景下的需求差异。
二、概念设计在需求分析的基础上,进行平衡车的概念设计。
这包括确定平衡车的整体架构、外观设计、运动学原理等。
例如,平衡车的整体架构可以包括底盘、车轮、电机、传感器等组成部分,外观设计则需要考虑到人机工程学、美学等因素。
三、详细设计在概念设计的基础上,进行平衡车的详细设计。
这包括确定各个组成部分的具体规格、尺寸、材料等。
例如,确定车轮的直径、电机的功率、传感器的类型等。
同时,还需要进行各个组成部分之间的接口设计,确保它们能够有效地协同工作。
四、零部件采购与制造根据详细设计的结果,进行零部件的采购与制造。
这包括选购合适的零部件供应商,确保零部件的质量和性能符合设计要求。
同时,还需要进行零部件的加工与组装,确保各个零部件能够正确地安装在平衡车上。
五、软件开发平衡车不仅涉及硬件的设计与制造,还需要进行相关的软件开发。
这包括编写控制算法、开发用户界面等。
控制算法是平衡车能够自动保持平衡的核心,需要根据传感器数据进行实时调整。
用户界面则提供了与平衡车进行交互的方式,可以通过手机APP或物理按钮进行控制。
六、系统集成与测试在零部件制造和软件开发完成后,进行系统集成与测试。
这包括将各个零部件组装到一起,并进行整体功能测试和性能测试。
例如,测试平衡车在不同地形上的稳定性和行驶性能,测试控制算法的响应速度和准确性等。
七、调试与优化根据测试结果,对平衡车进行调试和优化。
这包括调整控制算法的参数、优化电池管理系统等。
通过不断的调试与优化,提高平衡车的性能和稳定性。
八、生产与销售当平衡车的开发和调试完成后,可以进行批量生产和销售。
这包括制定生产计划、组织生产线、进行质量控制等。
同时,还需要进行市场推广和销售渠道的建立,将平衡车推向市场。
骑客平衡车用户使用手册说明书
感谢您选择并购买骑客平衡车!骑客平衡车是一款能自动保持平衡的高科技微型电动双轮平衡车。
请认真阅读《用户使用手册》了解驾驶骑客平衡车的安全警告和注意事项后再进行使用。
《用户使用手册》能帮助您迅捷地了解、使用和维护平衡车。
本说明书中图示仅供参考产品以实物为准当您在驾驶平衡车上路之时, 请先学习如何安全驾驶,以避免发生碰撞、摔倒和失去控制等危险。
您可以通过查看《用户使用手册》学习安全驾驶技术。
本《用户使用手册》向客户告知所有操作说明和注意事项, 平衡车产品使用者必须仔细阅读并按本说明书的要求操作, 如果产品使用者未按提示操作或违反警示内容,所产生的一切后果,本公司将不承担任何责任。
如果想得到产品的相关服务支持, 请拨打服务热线:400-0856-188。
1.1 关于本手册1.2 驾驶的风险1.3 驾驶前的准备工作1.4 文档相关说明 (03) (03) (03) (03)1、文档概述------------------------------------------------------------------ -----------032.1 平衡车车型描述2.2 平衡车车组件描述2.3 平衡车工作原理 (04) (05) (06)2、产品介绍------------------------------------------------------------------ -----------043.1 脚踏传感器3.2 显示板 (07) (07)3、平衡车控制及信息显示装置------------------------------------------------------ -----------074.1 驾驶者的重量限制4.2 续航里程4.3 速度限制4.4 APP/蓝牙 (08) (09) (09).................................................................................................................................................................104、安全使用平衡车------------------------------------------------------------- -----------08目录01025.1 平衡车操作步骤5.2 平衡车保护功能5.3 驾驶练习 (11) (14) (15)5、学习驾驶平衡车------------------------------------------------------------- -----------117.1 电池电量7.2 充电步骤7.3 温度过高或者过低情况7.4 运输电池时注意事项 (18) (19) (20) (20)7、电池使用说明--------------------------------------------------------------- -----------188.1 清洁8.2 存放 (21) (21)8、日常保养------------------------------------------------------------------ -----------216、驾驶安全指导--------------------------------------------------------------- -----------169、平衡车参数---------------------------------------------------------------- -----------2210、装箱单------------------------------------------------------------------ -----------3011、故障处理----------------------------------------------------------------- -----------311. 文档概述1.1 关于本手册为了您的驾驶安全,在使用平衡车之前请仔细阅读本手册, 确保能够按照正确的指导驾驶平衡车。
第3课 平衡车
第三课 平衡车
大家认不认识这个?
虽然只有两个轮子,但是人站在上面绝对不会摔 倒。想知道为什么吗?安静下来,仔细听。
平衡车的工作原理?
在平衡车内部安装了一个精密的电子仪 器—固态陀螺仪用来来判断车身所处的姿势状 态,根据已写入的程序通过平衡车内部的主板, 驱动马达来调整平衡车的平衡,这样人站在上 面就不会轻易的摔倒了。
平衡车程序流程图
开始
启动电机,左右 电机前进
延时5秒钟
启动电机,右边 电前进
启动电机,左 边电机后腿
左右电机停止
延时500毫秒
启动电机,左右 电机前进
延时5秒钟
目的: 让我们通过编程来控制平衡 车前进和转弯。 知识点: 一.1秒钟等于1000毫秒。 二.转向前的电机停止是为 了消除小车的惯性。
启动电机,左右 电机停止
结束
程序编写——编程界面
动态平衡原理图
让我们一起来制作一辆平衡车吧!
搭建步骤
程序编写——流程图
流程图是一种用图形来演示一个完整程序运行步骤的工 具,我们来简单了解一下。
开始/结束符号,表示一个 程序的开始和结束。
判断符号,用来表示程序运 行过程中需要判断的环节。
过程符号,用来演示程序运 行的每一个过程。
输入符号,用来表示程序运 行过程中需要进行数据输入 的环节。
两轮自平衡车源程序
//Variables for power and torque
#define TORQUE 9
#define POWER 0.95
#
//Set dip switches on the Sabertooth for simplified serial and 9600 Buadrate. Diagram of this on my Instructables page//
//THEN, press deadman switch, stand on it and bring it level to engage the "tiltstart"
//This version also has "Softstart" function
#include <SoftwareSerial.h>
int steergyroPin = 2; //steergyro analog input pin 2. x-rate to analog pin 2. This gyro allows software to "resist" sudden turns (i.e. when one wheel hits small object)
//I have just used the low res output from this gyro.
//int overallgainPin = 1; //overall gain analog pin 1. Gain knob to analog pin 1
int hiresgyroPin = 0; //hi res balance gyro input is analog pin 0. Y-rate 4.5 to analog pin 0
平衡车使用的方法
平衡车使用的方法
1、按照使用说明正确组装平衡车:
1 )取出车轮、上下梁,底柱和交流电机。
2)将底柱放入上下梁前方的半圆底座中,ban止底柱的四个话螺丝固定,注意固定牢固;
3)将前轮(大轮)安装在上下梁中间,并将防滑板放在轮上;
4)将后轮(小轮)安装在下梁上;
5)将交流电机安装在后轮两侧;
6)勾接剩余走线接口,连接可控硅和电池;
7)在安装完成后,可以检查一下。
2、使用步骤
1)由成年人帮助拿着平衡车,注意平稳,并开启平衡车的电源;
2)让使用者用一只脚把平衡车(前轮)前移一点,用另一只脚把脚踏板放下,体重转移到脚踏板上,双手放在把手上;
3)此时通过陀螺仪、油门、电脑等电子回路,会检测到外力及体重发生变化,电脑进行计算后控制硅从而产生电动驱动力使平衡车上升平稳,达到稳定运行的状态;
4)使用者按照需求稍微倾斜把手,电脑会接收到信号,使电机带动轮子行进方向,使用者逐渐去掌握平衡车;
5)使用之后记得把平衡车的电源关闭。
手动液压平衡车安全操作规程
手动液压平衡车安全操作规程一、操作前准备1.检查平衡车的外观情况,确保车身无明显变形、裂纹等破损,车轮无松动现象。
2.检查轮胎气压是否正常,并确保轮胎无明显磨损。
3.检查液压系统,确保油液无泄漏现象,油箱油面在合理范围内。
4.确保搬运货物的质量在平衡车的承载范围内,不得超载搬运。
二、安全操作1.操作前应穿着合适的工作服和安全鞋,不得穿拖鞋、裸露脚趾等不符合安全要求的服装。
2.操作前应调整平衡车的操作手柄到合适的高度,确保操作手柄能够舒适地握住,并注意手柄操作方向与车体运动方向的一致性。
4.操作过程中应注意周围环境,防止与其他人或物体发生碰撞,避免对他人造成伤害或损坏其他物品。
5.在行驶平衡车时,应保持平稳速度,不得突然加速或刹车,以防止平衡车失去平衡导致倾倒。
6.在行驶过程中,不得搬运货物时迅速转弯,应轻柔操作,避免因慢速转弯导致货物翻倒。
7.在操作液压平衡车时,应注意货物的堆放平衡,避免出现倾斜、塌落等情况。
8.操作结束后,应将平衡车停放在平坦稳固的地面上,并将操作手柄归位、液压把手降至安全位置。
三、应急处理1.在操作过程中,如发现平衡车有异常声音、异响、震动等情况,应立即停止操作,检查和排除故障。
2.在搬运过程中,如发现货物有异味、溶液渗漏等现象,应立即停止操作,采取相应措施。
3.如遇到突发情况(如火灾、地震等),应立即将平衡车停放在安全区域,并迅速撤离现场。
四、设备维护1.根据设备的使用说明书,定期进行润滑、加油、清洁等维护工作。
2.定期检查液压系统的密封件和软管,如发现老化、裂纹等情况,应及时更换。
3.设备停用时,应关闭油阀,保持液压系统的压力释放,防止发生意外伤害。
4.定期对设备进行全面检查、维修,确保设备的安全性和可靠性。
平衡车操作方法
平衡车操作方法
平衡车是一种电动代步工具,操作方法主要包括以下几步:
1. 上下车:站在平衡车两边,将一个脚放在车上,另一个脚跟随上车。
下车时,停车后双脚同时跨出。
2. 启动:按下电源开关,平衡车将自动进入平衡模式。
3. 平衡:站在车上时,双脚分别踩住车两侧的脚踏板,保持身体平衡,不要摇晃。
倾斜身体前进或后退,平衡车会相应地前进或后退。
4. 转向:倾斜身体左右两侧,平衡车会向相应的方向转向。
5. 刹车:停止倾斜身体,平衡车会自动停止运动。
按下刹车按钮或者停车时脚踩住地面即可停止。
6. 加速减速:倾斜身体来调整速度,倾斜角度越大,速度越快。
减速时,站直身体即可减小速度。
7. 下车:停车后,双脚同时跨出平衡车。
以上是平衡车的基本操作方法,使用前请务必阅读使用说明书,并在安全的环境
下进行操作。
平衡车的操作规程
平衡车的操作规程随着科技的不断发展,平衡车已经成为一种非常受欢迎的个人交通工具。
作为一种新型的移动设备,平衡车的操作规程对于骑行者来说至关重要。
正确的操作规程不仅能够保障骑行者的安全,还能够最大程度地发挥平衡车的性能。
本文将介绍平衡车的操作规程,以帮助骑行者正确、安全地使用平衡车。
一、佩戴安全装备在使用平衡车前,骑行者应佩戴合适的安全装备,包括头盔、护腕、护膝等。
这些安全装备能够有效保护骑行者的头部、手部和膝部,减少发生意外事故时的伤害。
二、正确上下车在上下平衡车时,骑行者应该站在平稳的地面上,并保持平衡车处于关闭状态。
先将一只脚踩在平衡车上,然后迅速将另一只脚也踩上,同时双手紧握着把手。
下车时,骑行者应先将一只脚放在地面上,然后再迅速将另一只脚放下。
三、学习基本动作在使用平衡车前,骑行者应该先学习掌握平衡车的基本动作,包括前进、后退、左转和右转。
为了减少意外事故的发生,初学者应在平坦没有障碍物的地方进行练习,直到能够熟练掌握这些基本动作。
四、注意平衡平衡车是通过控制重心来实现行驶的,因此保持身体的平衡非常重要。
骑行者应该始终保持身体的垂直状态,不要过度前倾或后倾。
当行驶中需要转弯时,骑行者应该适时地向左或向右倾斜身体,以便平衡车能够顺利转弯。
五、适应路况平衡车虽然是一种以个人为单位的交通工具,但在使用过程中仍然需要骑行者适应不同的路况。
在行驶过程中,骑行者应注意观察道路状况,避免行驶在不平坦、有障碍物或者交通繁忙的地区。
同时,在路口和人行横道等地方,骑行者也应该遵守交通规则,减速慢行,确保自己和他人的安全。
六、谨慎操作在使用平衡车时,骑行者应该保持谨慎的态度。
不得在行驶中玩耍或者进行其他分散注意力的活动,如听音乐、拍照等。
同时,骑行者应该避免在夜间或者能见度较低的情况下使用平衡车,以免发生安全事故。
七、维护保养为了确保平衡车的正常运行和使用寿命,骑行者应定期对平衡车进行维护保养。
包括检查轮胎气压、电池电量、车身和把手的稳固程度等。
派斯克平衡车说明书
派斯克平衡车说明书
1.START 键--开始测量如果代码C13设置l,合上轮罩测量开始﹐〈看10章改变操作模式〉如果在测量完毕轮罩打开的情况下按动START键,而定位制动处于工作状态时,这时车轮罩打开的情况下车轮也可转动,要确保车轮转动不会被工具或其他类似的物件所妨碍。
--车轮最多转动半圈就被制动,从而左侧校正面的平衡块能够安放在主轴的正上方。
2.STOP-键
(1)中断测量(2)清除错误代码
(3)如果输入完操作模式后,用STOP键,新的状态被自动地删除,以前的状态被重新建立。
1.OP键开始说明初步化运行
2.精确键,--高分辩度显示总读数1克代替5克或OZ替代(需把精确键按下)
(1)显示最小不平衡极限值以下的残余不平衡量:只要按下此键.实际不平衡值即可显示。
(2)标准平衡模式下显示不平衡值如果平衡模式Alu到ALU5被选择,按下精确键,然后按下功能键设定平衡模式。
(3)OP和UN程序中精确键作为转换键使用。
3.C健
(1)轻轻地按下此键,转换不平衡读数的主量单位〈克或盎司),用C3活动代号设置开机时单位。
(2)长时间按下此键,转换操作模式
4.轮胎类型功能键持续按下这个键旋转车轮,即可选择所需轮胎类型,松下
此键输入值即被存储。
5.平衡模式功能键持续按下这个键,旋转车轮﹐即可选择所需平衡模式,松开
此键,存储输入值。
平衡车使用指南
平衡车使用指南平衡车,也被称为电动平衡车、独轮平衡车,是一种便携式个人代步工具。
它以其独特的外观和便捷的操作,越来越受到人们的关注和喜爱。
本篇文章将向您介绍平衡车的使用指南,包括安全操作、充电注意事项以及保养常识等内容,旨在帮助您更好地使用平衡车。
一、平衡车的安全操作1. 穿戴安全装备:在骑行平衡车时,应穿戴适合的安全装备,如头盔、护膝、护肘等,以防止意外伤害。
2. 学习基本操作:在使用平衡车之前,务必熟悉平衡车的基本操作方法。
建议初学者先在平坦安全的地带进行练习,掌握前进、倒退、转弯等技巧。
3. 注意平衡:使用平衡车时,保持身体平衡是关键。
身体稍微向前倾斜可以使平衡车前进,稍稍向后倾可以使其停止或倒退。
4. 避免急转弯:在转弯时,避免急转弯,以免失去平衡。
应逐渐增加或降低转向角度,平稳过弯。
5. 注意路面状况:在使用平衡车时,要时刻注意路面的平整度和坡度。
避免在崎岖不平或过陡的路面上行驶,以免发生意外。
二、平衡车的充电注意事项1. 使用原装充电器:为了保证充电过程的安全性和效率,建议使用平衡车配套的原装充电器进行充电。
2. 避免长时间充电:平衡车的充电时间不宜过长,一般为3-4小时。
过长时间充电容易导致电池过热,影响电池寿命。
3. 避免过度放电:平衡车电池的电量过低时,应及时进行充电,避免过度放电导致电池容量下降。
4. 定期充电:即使不使用平衡车,也应定期进行电池充放电以保持电池活性。
建议每两个月进行一次完全充放电。
5. 避免过度充电:每次充电不宜超过满电状态。
过度充电会造成电池内部压力升高,增加电池爆炸的风险。
三、平衡车的保养常识1. 清洁平衡车:经常清洁平衡车的外观和内部零件,避免灰尘和脏物对平衡车的影响。
清洁时应使用干净的抹布,避免水进入内部。
2. 检查轮胎:定期检查平衡车的轮胎,确保其胎压正常。
胎压过低会影响骑行稳定性,胎压过高则会影响舒适度。
3. 定期检查螺丝:平衡车在使用过程中,螺丝松动是常见的问题。
帕顿平衡车说明书
帕顿平衡车说明书引言:帕顿平衡车是一款便捷、环保、智能的个人出行工具。
本说明书将为您详细介绍帕顿平衡车的使用方法、注意事项以及维护保养等相关内容,以确保您能够正确、安全地使用帕顿平衡车。
一、产品概述帕顿平衡车是一款基于自平衡控制技术的电动个人交通工具。
它采用了先进的陀螺仪和加速度计等传感器,在用户骑乘时能够实现自动平衡。
帕顿平衡车搭载了高性能锂电池,可提供长时间的续航能力。
同时,它还具备智能导航、智能防盗、智能语音等功能,为用户提供更加便捷、安全的出行体验。
二、使用方法1. 上下车:a. 在使用帕顿平衡车之前,请确保您已经熟悉平衡车的基本操作方法,并穿戴好安全防护装备;b. 当您准备上车时,双脚分别踩在车辆两侧的脚踏板上,保持平衡姿势,将身体重心放在脚踏板上;c. 当您准备下车时,先将脚踏板的一侧提起,将另一只脚平稳着地,再将另一只脚踏板提起,保持平衡姿势,然后小心地下车。
2. 前进、后退:a. 当您想要前进时,倾斜身体向前,帕顿平衡车将根据您的重心变化前进;b. 当您想要后退时,倾斜身体向后,帕顿平衡车将根据您的重心变化后退;c. 前进和后退的速度将根据您的倾斜程度改变,倾斜角度越大,速度越快。
3. 转向:a. 当您想要向左转时,向左倾斜身体;b. 当您想要向右转时,向右倾斜身体。
注意事项:1. 在使用帕顿平衡车之前,请确保您已经仔细阅读并理解本说明书的所有内容;2. 在使用过程中,请遵守交通法规,确保您的安全;3. 在使用帕顿平衡车时,建议佩戴安全头盔、护膝、护肘等防护装备,以减少意外伤害的发生;4. 请勿超过帕顿平衡车的最大承载重量,以免造成车辆损坏或人身伤害;5. 请勿在道路行驶时使用手机、听音乐等会分散注意力的行为,以确保您的安全;6. 在使用帕顿平衡车时,请注意周围环境,避免碰撞、摔倒等意外情况;7. 请勿将帕顿平衡车用于水中、泥泞地带等不适宜的环境,以免损坏车辆;8. 在长时间不使用帕顿平衡车时,请关闭电源,以节省电量。
自平衡小车程序
#include "DSP281x_Device.h" // Headerfile Include File#include "DSP281x_Examples.h" //#define HIST 16unsigned int k=0;static float adc_current_samples[6][HIST];//定义行为6,列为16的二维数组static float adclo=0.0;static Uint16 totsamples_0;unsigned int count;#define OCRMAX 1023unsigned int pwm;static float left_cof=1.00;static float right_cof=1.00;struct gyro_filter pitch_filter;static Uint16 mode=0x00;//0x00----balance mode; 0x01-------assist mode static Uint16 still=0x00; //still=1.0, no move; still=0.0,move. static Uint16 stand=0x00;static Uint16 last_balance_s0;static Uint16 samples[6],ticks;static float left_steer_cof=0.05;static float right_steer_cof=0.05;static float steer_lim=0.13;static float initial_angle=0.0000874;static float hard_speed_lim=0.90;static float bus_current;static float cmd;static float lpf_angle;static float lpf_angrate;static float lpf_steer_knob;static float left_motor_pwm, right_motor_pwm, steer_cmd;static float left_motor_pwm, right_motor_pwm, steer_cmd;static float batt_voltage1, ay, ax, in_steer_knob;static float pitch_rate;static float interval;static float timer0_seconds_conv;static float p_gain;static float d_gain;static float p1_gain;static float d1_gain;static float p0_gain;static float d0_gain;static float tp0,td0,tp1,td1,tp,td;static float d_step=0.0001;static float p_step;static float cor_bat;static float p_cmd,d_cmd;//next_cmd;static float sample_conv = 1.0/1024.0/(float)HIST*5.0;//=3.052exp(-4) static float sample_conv1 = 1.0/1024.0/(float)HIST*2.07;static float sample_conv2 = 1.0/1024.0/(float)HIST*1.9;static float sample_conv3 = 1.0/1024.0/(float)HIST*333.3*2.5;interrupt void T2_AD_isr(void);void InitEv(void);void InitAdc(void);void InitGpio(void);struct gyro_filter {float angle;float ay_bias;//float ax_bias;float rate_bias;float steer_knob_bias;float rate;float steer_knob;float curr_bias;float curr;Uint16 inited;};void check_mode (){if((!pitch_rate) && (!in_steer_knob)) mode = 0x00;else mode = 0x01; }void delay (void){ Uint16 xt;static Uint16 k_temp;for (xt=0;xt<15;xt++){k_temp++; }}void delay1(void){ Uint16 xt;static Uint16 k_temp;for (xt=0;xt<15000;xt++){k_temp++; }}int adc_collect_samples(Uint16 *samples, Uint16 *lasts0){unsigned int i,j;if (*lasts0 == totsamples_0) {return 0;//if no new adc samples, return with 0}*lasts0 = totsamples_0;for (i=0; i<6; i++) {Uint16 tot=0;for (j=0; j<HIST; j++){tot+=adc_current_samples[i][j];}samples[i] = tot;//samples[i]=Σadc_current_samples[i][j](j=1,2,...,ADC_HIST) }return 1;}Uint16 bat_judge( float x){if(x>4.30) return 0x5;//25.8else if(x>4.18) return 0x4;//25.1else if(x>4.07) return 0x3;//24.4else if(x>3.95) return 0x2;//23.7else if(x>3.83) return 0x1;//23.0else return 0x0;}void lpf_update(float *state, float tc, float interval, float input){float frac=interval/tc;if (frac>1.0) frac=1.0;*state = input*frac + *state * (1.0-frac);}float fmax(float a, float b){if (a>=b) {return a;} else {return b;}}float fmin(float a, float b){if (a<=b) {return a;} else {return b;}}float flim(float x, float lo, float hi){if (x>hi) return hi;if (x<lo) return lo;return x;}void gyro_init(struct gyro_filter *it){ it->inited =0x00;it->angle=0.0;it->ay_bias=0.0;// it->ax_bias=0.0;it->rate_bias=0.0;it->steer_knob_bias=0.0;it->rate=0.0;it->steer_knob=0.0;it->curr_bias=0.0;it->curr=0.0;lpf_angle=0.0;lpf_angrate=0.0;lpf_steer_knob=0.0;}void gyro_sample(struct gyro_filter *it, float in_rate,float in_y, float in_x, float in_steer,float curri,float interval){flim( in_y, -1.0,1.0);flim( in_x, -1.0,1.0);if (!it->inited) {it->angle=0.0;it->rate_bias = in_rate;it->ay_bias = in_y;it->curr_bias = curri;it->steer_knob_bias = in_steer;it->inited=1;return; }it->rate = in_rate - it->rate_bias;it->angle =in_y-it->ay_bias;//it->angle+(in_y-it->ay_bias)*last_ax-in_x*(last_ay-it->ay_bias); it->curr= curri-it->curr_bias;it->steer_knob= flim( in_steer-it->steer_knob_bias,-5.0,5.0);}void set_motor_idle(){GpioDataRegs.GPFDA T.bit.GPIOF12=1; //SD highGpioDataRegs.GPFDA T.bit.GPIOF13=1; //OE highstand =0x00;EvaRegs.T2CON.all =0x1440;gyro_init(&pitch_filter);return;}void set_motor(float level_left, float level_right){int leveli_left,leveli_right;if (fabs(level_left)<0.002 || fabs(level_right)<0.002) return;leveli_left = (int16)(level_left*OCRMAX);leveli_right = (int16)(level_right*OCRMAX);if (leveli_left<-(OCRMAX-2)) leveli_left=-(OCRMAX-2);if (leveli_left>OCRMAX-2) leveli_left=OCRMAX-2;if (leveli_right<-(OCRMAX-2)) leveli_right=-(OCRMAX-2);if (leveli_right>OCRMAX-2) leveli_right=OCRMAX-2;if(still) {GpioDataRegs.GPFDA T.bit.GPIOF12=0; // SD=0// asm("nop");while(GpioDataRegs.GPFDA T.bit.GPIOF12==1) continue;GpioDataRegs.GPADA T.bit.GPIOA13=1; //PORTC |= 0x50; //enable CCW0GpioDataRegs.GPBDA T.bit.GPIOB13=1;// delay();GpioDataRegs.GPADA T.bit.GPIOA14=1; //PORTC |= 0xa0; //disable CW0 GpioDataRegs.GPBDA T.bit.GPIOB14=1;//asm("nop");continue;still=0x00;}if (leveli_left<0) {EvaRegs.ACTRA.all=0x00C2;pwm=-leveli_left;}else {EvaRegs.ACTRA.all=0x002C;pwm=leveli_left;}if (leveli_right<0) {EvbRegs.ACTRB.all=0x002C;pwm=-leveli_right;}else {EvbRegs.ACTRB.all=0x00C2;pwm=leveli_right;}}void motor_ready(void){gyro_init(&pitch_filter);GpioDataRegs.GPADA T.bit.GPIOA13=1; //PORTC |= 0x50; //enable CCW0 GpioDataRegs.GPBDA T.bit.GPIOB13=1;GpioDataRegs.GPADA T.bit.GPIOA14=1; //PORTC |= 0xa0; //disable CW0 GpioDataRegs.GPBDA T.bit.GPIOB14=1;GpioDataRegs.GPFDA T.bit.GPIOF12=0; //SD lowGpioDataRegs.GPFDA T.bit.GPIOF13=0; //OE lowEvaRegs.T1CON.bit.TENABLE=1; //启动定时器T1EvbRegs.T3CON.bit.TENABLE=1; //启动定时器T3EvaRegs.T2CON.all =0x1440; // 16分频,使能定时器操作,连续增模式}void balance(void){ float steer_cmd_abs,temp_steer_cmd;unsigned int T2cnt;if (!adc_collect_samples(samples, &last_balance_s0))return;{T2cnt=EvaRegs.T2CNT; //读取定时器2的值ticks = OCRMAX * count + T2cnt;interval = timer0_seconds_conv * (float)ticks;}count=0;EvaRegs.T2CON.all = 0x1400; //关闭定时器2EvaRegs.T2CNT = 0x0000;EvaRegs.T2CON.all = 0x1440; //启动定时器2EvaRegs.GPTCONA.bit.T1TOADC = 2;ay = sample_conv1*samples[4]-sample_conv2*samples[0];//1.034pitch_rate = samples[1]*sample_conv3;in_steer_knob = (samples[2]+samples[3])*sample_conv;bus_current = samples[4]*sample_conv;batt_voltage1 = samples[5]*sample_conv;check_mode();if(!pitch_filter.inited){if(batt_voltage1<3.0) {set_motor_idle();return;}elsecor_bat=-0.857*batt_voltage1+4.58;//-0.857=(1-1.3)/(4.18-3.83),4.58=1+0.857*4.18 cor_bat=flim(cor_bat,1.0,1.3);}gyro_sample(&pitch_filter, pitch_rate,ay,ax,in_steer_knob,bus_current, interval); EvaRegs.GPTCONA.bit.T1TOADC = 0;if(!mode) {if(fabs(pitch_filter.angle)<initial_angle) {GpioDataRegs.GPADA T.bit.GPIOA14=0;GpioDataRegs.GPBDA T.bit.GPIOB14=0;GpioDataRegs.GPADA T.bit.GPIOA13=0;GpioDataRegs.GPBDA T.bit.GPIOB13=0;GpioDataRegs.GPFDA T.bit.GPIOF12=1;still=0x01;return; }EvaRegs.GPTCONA.bit.T1TOADC = 2;lpf_steer_knob = -pitch_filter.steer_knob;if(stand) {p_gain = fmax(p0_gain,p_gain-p_step);//0.1d_gain = fmin(d0_gain,d_gain+d_step);tp=tp0;td=td0; }else { p_gain = fmin(p1_gain,p_gain+p_step);d_gain = fmax(d1_gain,d_gain-d_step);//0.1tp=tp1;td=td1;}lpf_update(&lpf_angle,tp, interval, -pitch_filter.angle*cor_bat);//0.6lpf_update(&lpf_angrate,td, interval, -pitch_filter.rate*cor_bat);//0.5p_cmd=p_gain*lpf_angle*fabs(lpf_angle);d_cmd=d_gain*lpf_angrate;cmd=p_cmd + d_cmd;cmd=flim(cmd, -hard_speed_lim, hard_speed_lim);if(lpf_steer_knob>0.0) steer_cmd = flim(left_steer_cof * lpf_steer_knob*(1-fabs(cmd)), -steer_lim,steer_lim);else steer_cmd = flim(right_steer_cof * lpf_steer_knob*(1-fabs(cmd)),-steer_lim,steer_lim);steer_cmd_abs = fabs(steer_cmd);if ((lpf_steer_knob>0.0 && cmd>0.01)||(lpf_steer_knob<0.0 && cmd<-0.01))temp_steer_cmd = flim(steer_cmd+0.1*interval,-steer_cmd_abs,steer_cmd_abs); //?????????? else if ((lpf_steer_knob>0.0 && cmd<-0.01)||(lpf_steer_knob<0.0 && cmd>0.01))temp_steer_cmd = flim(steer_cmd-0.1*interval,-steer_cmd_abs,steer_cmd_abs); //?????????? else temp_steer_cmd=0.0;EvaRegs.GPTCONA.bit.T1TOADC = 0;if (cmd>=0.0) {left_motor_pwm = 1.0-cmd*left_cof - temp_steer_cmd;right_motor_pwm =1.0-cmd*right_cof + temp_steer_cmd;} else {left_motor_pwm = -(1.0+cmd*left_cof) + temp_steer_cmd;right_motor_pwm =-(1.0+cmd*right_cof)- temp_steer_cmd;}set_motor(left_motor_pwm, right_motor_pwm);}}void stabilize_analog(void){Uint16 samples[6];Uint16 i;Uint16 last_s0=0;for (i=0; i<HIST; ) {if (adc_collect_samples(samples, &last_s0)) i++;}}void stand_test(){if(GpioDataRegs.GPBDA T.bit.GPIOB6&&GpioDataRegs.GPBDA T.bit.GPIOB7) {stand=0x02;return;}else{if(GpioDataRegs.GPBDA T.bit.GPIOB6||GpioDataRegs.GPBDA T.bit.GPIOB7){stand=0x01;return;}else{stand=0x00;return;}}}void main(void){InitSysCtrl();EALLOW;DINT;IER = 0x0000; //禁止VPU中断并清除所有CPU中断标志位IFR = 0x0000;InitPieCtrl();InitPieVectTable();InitGpio();InitAdc();InitEv();EALLOW; // This is needed to write to EALLOW protected registersPieVectTable.T2PINT=&T2_AD_isr;EDIS; // This is needed to disable write to EALLOW protected registersPieCtrlRegs.PIEIER3.bit.INTx1=1;//T2pint中断IER |= M_INT1;//开启中断1PieCtrlRegs.PIEIER1.bit.INTx7=1;EINT; // Enable Global interrupt INTMERTM; // Enable Global realtime interrupt DBGMfor(;;){DisableDog();GpioDataRegs.GPADA T.bit.GPIOA12=1;GpioDataRegs.GPADA T.bit.GPIOA15=1;GpioDataRegs.GPBDA T.bit.GPIOB12=1;GpioDataRegs.GPBDA T.bit.GPIOB15=1;GpioDataRegs.GPFDA T.bit.GPIOF12=0; //SD low GpioDataRegs.GPFDA T.bit.GPIOF13=0; //OE lowGpioDataRegs.GPADA T.bit.GPIOA13=0;GpioDataRegs.GPADA T.bit.GPIOA14=0;GpioDataRegs.GPBDA T.bit.GPIOB13=0;GpioDataRegs.GPBDA T.bit.GPIOB14=0;InitAdc();stabilize_analog();InitEv();gyro_init(&pitch_filter);motor_ready();for(;;){balance();if(!stand) break;}set_motor_idle();}}interrupt void T2_AD_isr(void){if(k<16){adc_current_samples[0][k]=((float)AdcRegs.ADCRESULT0)*3.0/65520.0+adclo;adc_current_samples[1][k]=((float)AdcRegs.ADCRESULT1)*3.0/65520.0+adclo;adc_current_samples[2][k]=((float)AdcRegs.ADCRESULT2)*3.0/65520.0+adclo;adc_current_samples[3][k]=((float)AdcRegs.ADCRESULT3)*3.0/65520.0+adclo;adc_current_samples[4][k]=((float)AdcRegs.ADCRESULT4)*3.0/65520.0+adclo;adc_current_samples[5][k]=((float)AdcRegs.ADCRESULT5)*3.0/65520.0+adclo;k++;AdcRegs.ADCST.bit.INT_SEQ1_CLR=1; //清除状态字AdcRegs.ADCTRL2.bit.RST_SEQ1=1;//复位seq1EvaRegs.EV AIFRB.bit.T2PINT=1;//清除中断标志EvaRegs.EV AIMRB.bit.T2PINT=1;//中断允许PieCtrlRegs.PIEACK.bit.ACK3=1;//向cpu申请中断}else{totsamples_0++;k=0;count=totsamples_0;AdcRegs.ADCST.bit.INT_SEQ1_CLR=1; //清除状态字AdcRegs.ADCTRL2.bit.RST_SEQ1=1;//复位seq1EvaRegs.EV AIFRB.bit.T2PINT=1;//清除中断标志// EvaRegs.EV AIMRB.bit.T2PINT=1;//中断允许EvaRegs.GPTCONA.bit.T1TOADC = 0;}}//--------------------------------------------------------------------------- // InitEv://--------------------------------------------------------------------------- // This function initializes to a known state.//void InitEv(void){EALLOW;/*****************************//***********配置ACTR**********//*****************************//* EvaRegs.ACTRA.bit.CMP1ACT=2;//PW1引脚高电平有效EvaRegs.ACTRA.bit.CMP2ACT=1;//PWM2引脚低电平有效*//*****************************//*******配置死区寄存器********//*****************************/EvaRegs.DBTCONA.bit.DBT=5;//死区定时器周期为5EvaRegs.DBTCONA.bit.EDBT1=1;//死区定时器1使能EvaRegs.DBTCONA.bit.DBTPS=1;//死区定时器预定标因子,死区时钟为HSPCLK/2/*****************************//*********配置COMCONA*********//*****************************/CONA.bit.CENABLE=1;//使能比较单元的比较操作CONA.bit.CLD=2;//当给CMPR1赋新值时,立即装载CONA.bit.FCOMPOE=1;//全比较操作,PWM输出由相应的比较逻辑驱动/*****************************//**********设置T1CON**********//*****************************/EvaRegs.T1CON.bit.TMODE=2;//T1工作于连续增模式EvaRegs.T1CON.bit.TPS=3;//输入时钟预定标因子为X/8EvaRegs.T1CON.bit.TENABLE=1;//禁止定时器操作EvaRegs.T1CON.bit.TCLKS10=0;//使用内部时钟EvaRegs.T1CON.bit.TECMPR=1;//使能定时器比较操作/*****************************//**********设置T1PR等*********//*****************************/EvaRegs.T1PR =OCRMAX;EvaRegs.T1CNT = 0x0; ///定时器1初值设为0EvaRegs.CMPR1=pwm;EvaRegs.CMPR2=pwm;// EvaRegs.T1CON.bit.TENABLE=1; //启动定时器T1/* EvbRegs.ACTRB.bit.CMP7ACT=2;//PWM7引脚高电平有效EvbRegs.ACTRB.bit.CMP8ACT=1;//PWM8引脚低电平有效*//*****************************//*******配置死区寄存器********//*****************************/EvbRegs.DBTCONB.bit.DBT=5;//死区定时器周期为5EvbRegs.DBTCONB.bit.EDBT1=1;//死区定时器1使能EvbRegs.DBTCONB.bit.DBTPS=3;//死区定时器预定标因子,死区时钟为HSPCLK/8/*****************************//*********配置COMCONA*********//*****************************/CONB.bit.CENABLE=1;//使能比较单元的比较操作CONB.bit.CLD=2;//当给CMPR1赋新值时,立即装载CONB.bit.FCOMPOE=1;//全比较操作,PWM输出由相应的比较逻辑驱动/*****************************//**********设置T1CON**********//*****************************/EvbRegs.T3CON.bit.TMODE=2;//T1工作于连续增模式EvbRegs.T3CON.bit.TPS=3;//输入时钟预定标因子为X/8EvbRegs.T3CON.bit.TENABLE=1;//禁止定时器操作EvbRegs.T3CON.bit.TCLKS10=0;//使用内部时钟EvbRegs.T3CON.bit.TECMPR=1;//使能定时器比较操作/*****************************//**********设置T1PR等*********//*****************************/EvbRegs.T3PR =OCRMAX;EvbRegs.T3CNT = 0; ///定时器3初值设为0EvbRegs.CMPR4=pwm;EvbRegs.CMPR5=pwm;// EvbRegs.T3CON.bit.TENABLE=1;//启动定时器T3EvaRegs.GPTCONA.all=0;EvaRegs.T2PR =OCRMAX; // 定时器2的周期为20kEvaRegs.T2CMPR=0x0000;EvaRegs.T2CNT =0x0000; // Timer2 counter//EvaRegs.T2CON.all =0x1440;//16分频,使能定时器操作,连续增模式EvaRegs.EV AIMRB.bit.T2PINT = 1;//定时器2周期中断允许EvaRegs.EV AIFRB.bit.T2PINT = 1;//清除标志// EvaRegs.GPTCONA.bit.T1TOADC = 2;EDIS;}void InitAdc(void){//unsigned int p;// To powerup the ADC the ADCENCLK bit should be set first to enable// clocks, followed by powering up the bandgap and reference circuitry.// After a 5ms delay the rest of the ADC can be powered up. After ADC// powerup, another 20us delay is required before performing the first// ADC conversion. Please note that for the delay function below to// operate correctly the CPU_CLOCK_SPEED define statement in the// DSP28_Examples.h file must contain the correct CPU clock period in// nanoseconds. For example:AdcRegs.ADCTRL1.bit.RESET=1; //ADC模块软件复位// asm(" NOP");AdcRegs.ADCTRL1.bit.RESET=0; //这一句可要可不要,因为硬件会自动返回0AdcRegs.ADCTRL1.bit.SUSMOD=3; //仿真挂起的模式3 ??AdcRegs.ADCTRL1.bit.ACQ_PS=0x0; //决定启动转换新号SOC的脉冲宽度,SOC用于控制持续多长时间的采样开关闭合,SOC脉冲宽度大小为ADCLK周期的(ADCTRL(11:8)+1)倍AdcRegs.ADCTRL1.bit.CPS=0; //对外设时钟HSPCLK进行分频,1分频AdcRegs.ADCTRL1.bit.CONT_RUN=1;//连续运转模式AdcRegs.ADCTRL1.bit.SEQ_CASC=1;//级联模式,SEQ1和SEQ2工作时作为一个16位状态排序器(SEQ)//ADC模块控制寄存器3(ADCTRL3)AdcRegs.ADCTRL3.bit.ADCBGRFDN=3;//ADC带间隙和参考电路上电// for(p=0;p<10000;p++) asm(" NOP"); //延时等待ADC上电AdcRegs.ADCTRL3.bit.ADCPWDN=1; //ADC除间隙和参考电路之外的模拟电路上电// for(p=0;p<5000;p++) asm(" NOP"); //延时等待ADC上电AdcRegs.ADCTRL3.bit.ADCCLKPS=5; //内核时钟分频,产生ADC内核时钟ADCLK;ADCLK=HSPCLK/[30*(ADCTRL1.7+1)];ADCTRL1.7为AdcRegs.ADCTRL1.bit.CPS=0。
平衡车程序结构和数据融合、控制算法说明
认真读完整篇文档有利于您更好的理解整个平衡小车程序。
开发平台:MDK5.11、我们的代码使用MPU6050的INT的引脚每5ms触发的中断作为控制的时间基准,严格保证系统的时序!2.根据不同阶层的学习者,我们提供了复杂程度不同的代码:1.针对普通用户,提供了以下三个代码:MiniBalanceV5.0平衡小车源码(DMP版)MiniBalanceV5.0平衡小车源码(互补滤波版)MiniBalanceV5.0平衡小车源码(卡尔曼滤波版)以上代码除了使用DMP、卡尔曼滤波、互补滤波分别获取姿态角外,还提供了超声波避障代码。
2.针对入门用户,提供以下代码:MiniBalanceV5.0平衡小车源码(精简入门版)去除所有附加的代码,使用最少的代码量实现小车直立。
3.整个程序应用了STM32大量的资源:ADC模块:采集电阻分压后的电池电压,采集模拟CCD摄像头数据TIM1:初始化为PWM输出,CH1,CH4输出双路10KHZ的PWM控制电机TIM2:初始化为正交编码器模式,硬件采集编码器1数据TIM3:CH3初始化为超声波的回波采集接口。
TIM4:初始化为正交编码器模式,硬件采集编码器2数据USART1:通过串口1把数据发到串口调试助手USART3:通过串口3接收蓝牙遥控的数据,接收方式为中断接收。
并发送数据给app。
IIC:利用IO模拟IIC去读取MPU6050的数据,原理图上MPU6050链接的是STM32的硬件IIC接口,但是因为STM32硬件IIC不稳定,所以默认使用模拟IIC,大家可以自行拓展。
SPI:利用IO模拟SPI去驱动OLED显示屏,硬件SPI驱动NRF24L01GPIO:读取按键输入,控制LED,控制电机使能和正反转SWD:提供用于在线调试的SWD接口EXTI:由MPU6050的INT引脚每5ms触发一次中断,作为控制的时间基准4.程序主要用户文件说明如下:●Source Group1◆Startup_stm32f10x_md.s:stm32的启动文件●User◆Minibalance.c:放置主函数,并把超声波读取和人机交互等工作放在死循环里面。
基于PID控制的两轮平衡小车(附原理图和程序讲解)
课程设计题目基于PID控制的两轮平衡小车学院XXXXX 专业班级XXXXXX小组成员XXXX 指导教师XXXXX X年 XX 月 XXX小组成员介绍及分工小组成员信息小组成员分工目录机电系统实践与实验设计 (1)一、研究背景与意义 (2)二、平衡原理 (2)2.1 平衡车的机械结构 (2)2.2 自平衡车倾倒原因的受力分析 (3)2.3 平衡的方法 (3)三、两轮平衡小车总体设计 (4)3.1 整体构思 (4)3.2 姿态检测系统 (4)3.3 控制算法 (5)四、matlab建模及仿真 (6)4.1 机械模型建模及仿真(Matlab_simulink) (6)4.2 联合控制器仿真(理想状态PID) (8)五、硬件电路设计 (9)5.1、硬件电路整体框架 (9)5.2、系统运作流程介绍 (10)5.3、硬件电路模块 (10)5.31 电源供电部分 (10)5.32 主控制器部分: (10)5.33 传感器部分; (11)5.34 驱动电路部分 (11)5.35 蓝牙控制模块 (12)5.36 超声波检测模块 (13)5.37 寻迹模块 (13)六、软件控制模块 (14)6.1 系统软件设计结构 (14)6.2 整体初始化过程 (14)6.3 程序设计 (15)6.31 PID-三个参数的调整 (15)6.32 OLED显示信息 (16)6.33 PID-采集信息 (16)6.34 PID-数据计算 (17)6.35 PID-结果输出 (18)6.36 超声波避障 (18)6.37 蓝牙控制 (18)6.38 寻迹实现 (19)七、总结 (19)附录 (21)摘要:两轮自平衡车结合了两轮同轴、独立驱动、悬架结构的自平衡原理,是一种在微处理器控制下始终保持平衡的集智能化与娱乐性于一体的新型代步工具。
整车由底盘、动力装置、控制装置和转向装置组成。
机械结构采用了双轮双马达驱动;控制主要采用的是反馈调节,为了使车体更好的平衡,使用了PID调节方式;硬件上采用陀螺仪GY521 MPU-6050来采集车体的旋转角度以及旋转角加速度,采用加速度传感器来间接测量车体旋转角度,同时,加入超声波检测模块,使小车能够自动完成避障功能;通过在两轮平衡车上加入两个寻迹模块(光电传感器)来识别场地上的黑白线,使得两轮自平衡车能够沿着黑线进行寻迹完成循迹功能。
爱尔威S8Mini电动平衡车使用方法
爱尔威S8Mini电动平衡车使用方法
1、启动
1. 检查车体有无异常情况,确定车况正常后收起撑脚。
2. 打开车体电源总开关,听到“嘀”声提示音,S8mini进入助力状态。
3. 再用脚轻踩脚踏板,听见“嘀”声后,S8mini进入骑行状态并保持平衡,驾驶者即可上车骑行。
2、学习驾驶
站姿骑行
身体重心慢慢地向后倾斜
平衡重心
身体重心慢慢地向前倾斜
左腿靠近座椅前端向右用力使其向右转动右腿靠近座椅前端向左用力使其向左转动
身体重心向后移动使其停止
双脚先后放在S8mini脚踏板上。
控制好身体重心,不要前后晃动。
坐姿骑行
身体重心慢慢地向后倾斜平衡重心
身体重心慢慢地向前倾斜身体向右边转动
身体向左边转动
身体重心向后移动使其停止
双脚先后从S8mini脚踏板上面走下来。
控制好身体重心,不要前后晃动。
[文档可能无法思考全面,请浏览后下载,另外祝您生活愉快,工作顺利,万事如意!]。
手动液压平衡车操作规程
手动液压平衡车操作规程.txt
手动液压平衡车操作规程
1.安全事项
- 操作前应穿戴好安全装备,如安全帽、安全鞋等。
- 操作时应保持注意力集中,避免分心或走神。
- 在操作过程中,不得携带任何物品,以免影响平衡车的稳定性。
- 确保平衡车工作区域的地面平整稳固,不得有障碍物。
- 在停放平衡车时,应将液压系统置于安全状态,防止意外发生。
2.操作步骤
1) 启动平衡车
- 按下启动按钮,等待平衡车启动完成。
2) 调整液压系统
- 使用扳手或调节阀门,根据实际需求调整液压系统的压力和流量。
3) 载货前准备
- 确保要载货的货物均匀分布在平衡车的托盘上。
4) 起升货物
- 操作液压控制杆,将货物缓慢举升到所需高度。
5) 平衡车行驶
- 操作操纵杆,使平衡车前进、后退或转向,注意平稳驾驶。
6) 放下货物
- 缓慢操作液压控制杆,将货物放下到所需位置。
7) 停止平衡车
- 按下停止按钮,确保平衡车完全停止后才离开。
3.维护保养
- 定期检查液压系统是否正常运行,如发现异常及时修理。
- 清洁和润滑液压系统的各个部件,确保顺畅运转。
- 定期检查平衡车的各项功能,如制动系统、转向系统等。
4.紧急情况处理
- 在紧急情况下,立即停止平衡车并寻求帮助。
- 紧急情况包括但不限于液压系统故障、货物倾斜等。
请按照以上操作规程进行手动液压平衡车的操作,确保操作安全和顺利。
以上仅为操作规程,如需更多细节和实际操作指导,请参考平衡车的用户手册或咨询相关专业人士。
平衡车平衡原理 Arduino 库函数
平衡小车也是这样的过程,通过负反馈实现平衡。与上面保持木棒直立 比较则相对简单,因为小车有两个轮子着地,车体只会在轮子滚动的方向上发生 倾斜。控制轮子转动,抵消在一个维度上倾斜的趋势便可以保持车体平衡了。
angle,C_0,K1);
//获取 angle 角度和卡曼滤波
angleout();
//角度环 PD 控制
speedcc++;
if (speedcc >= 8)
//50ms 进入速度环控制
{
Outputs = balancecar.speedpiout(kp_speed,ki_speed,kd_speed,fron
//PD 角度环控制
}
(2)小车速度控制:使用PD(比例、微分)控制;
Outputs = ksi * (setp0 - positions) + ksp * (setp0 -
speeds_filter);
//速度环控制 PI
(3)小车方向控制:使用PD(比例、微分)控制。
turnoutput = -turnout * ktp - Gyro_z * ktd;//旋转PD算法 控制 融合速度和Z轴旋转定位。
可通过单片机软件实现上述控制算法。 在上面控制过程中,车模的角度控制和方向控制都是直接将输出电压 叠加后控制电机的转速实现的。而车模的速度控制本质上是通过调节 车模的倾角实现的,由于车模是一个非最小相位系统,因此该反馈控 制如果比例和速度过大,很容易形成正反馈,使得车模失控,造成系 统的不稳定性。因此速度的调节过程需要非常缓慢和平滑。
平衡车程序
//TWIN WHEELER MODIFIED FOR ARDUINO SIMPLIFIED SERIAL PROTOCOL TO SABERTOOTH V2//J. Dingley For Arduino 328 Duemalinove or similar with a 3.3V accessory power output//i.e. the current standard Arduino board.//designed for use with a rocker switch for steering as in original description on my "instructable":///id/Easy-build-self-balancing-skateboar drobotsegway-///XXXXXXXXXXXXXXXXX UPDATES May 2011 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX //NOTE this newer version has "tighter" balance algorithm//the value of ti has been increased to 3// If you open serial view window at 9600 baud, you can see values for angle etc (once tiltstart has engaged)//REMEMBER: Put one end down on floor, turn on, count to 5 (while it calibrates itself)//THEN, press deadman switch, stand on it and bring it level to engage the "tiltstart"//This version also has "Softstart" function#include <SoftwareSerial.h>//Variables for power and torque#define TORQUE 9#define POWER 0.95#//Set dip switches on the Sabertooth for simplified serial and 9600 Buadrate. Diagram of this on my Instructables page////Digital pin 13 is serial transmit pin to sabertooth#define SABER_TX_PIN 13//Not used but still initialised, Digital pin 12 is serial receive from Sabertooth#define SABER_RX_PIN 12//set baudrate to match sabertooth dip settings#define SABER_BAUDRATE 9600//simplifierd serial limits for each motor#define SABER_MOTOR1_FULL_FORWARD 127#define SABER_MOTOR1_FULL_REVERSE 1#define SABER_MOTOR2_FULL_FORWARD 255#define SABER_MOTOR2_FULL_REVERSE 128//motor level to send when issuing full stop command#define SABER_ALL_STOP 0SoftwareSerial SaberSerial = SoftwareSerial (SABER_RX_PIN,SABER_TX_PIN );void initSabertooth (void) {//initialise software to communicate with sabertoothpinMode ( SABER_TX_PIN, OUTPUT );SaberSerial.begin( SABER_BAUDRATE );//2 sec delay to let it settledelay (2000);SaberSerial.print(0, BYTE); //kill motors when first switched on}//setup all variables. Terms may have strange names but this software has evolved from bits and bobs done by other segway clone builders//xxx code that keeps loop time at 10ms per cycle of main program loop xxxxxxxxxxxxxxxint STD_LOOP_TIME = 9;int lastLoopTime = STD_LOOP_TIME;int lastLoopUsefulTime = STD_LOOP_TIME;unsigned long loopStartTime = 0;float level=0;float aa = 0.005; //this means 0.5% of the accelerometer reading is fed into angle of tilt calculation with every loop of program (to correct the gyro).//accel is sensitive to vibration which is why we effectively average it over time in this manner. You can increase aa if you want experiment. //too high though and the board may become too vibration sensitive. float Steering;float SteerValue;float SteerCorrect;float steersum;int Steer = 0;float accraw;float x_acc;float accsum;float x_accdeg;float gyrosum;float hiresgyrosum;float g;float s;float t;float gangleratedeg;float gangleratedeg2;int adc1;int adc4;int adc5;float gangleraterads;float ti = 3;float k1;int k2;int k3;int k4;float overallgain;float gyroangledt;float angle;float anglerads;float balance_torque;float softstart;float cur_speed;//float cycle_time = 0.01; //seconds per cycle - currently 10 milliseconds per loop of the program. If you change it a lot you can measure the pulse coming out of//digital pin 8 (one per program cycle) to reccalculate this variable. Need to know it as gyro measures rate of turning. Needs to know time between each measurement//so it can then work out angle it has turned through since the last measurement - so it can know angle of tilt from vertical.float cycle_time = 0.01;float Balance_point;float balancetrim;int balleft;int balright;float a0, a1, a2, a3, a4, a5, a6; //Sav Golay variables. The TOBB bot describes this neat filter for accelerometer called Savitsky Golay filter.//More on this plus links on my website.int i;int j;int tipstart;signed char Motor1percent;signed char Motor2percent;//analog inputs. Wire up the IMU as in my Instructable and these inputs will be valid.int accelPin = 4; //pin 4 is analog input pin 4. z-acc to analog pin 4 int gyroPin = 3; //pin 3 is analog balance gyro input pin. Y-rate to analog pin 3int steergyroPin = 2; //steergyro analog input pin 2. x-rate to analog pin 2. This gyro allows software to "resist" sudden turns (i.e. when one wheel hits small object)//I have just used the low res output from this gyro.//int overallgainPin = 1; //overall gain analog pin 1. Gain knob to analog pin 1int hiresgyroPin = 0; //hi res balance gyro input is analog pin 0. Y-rate 4.5 to analog pin 0//The IMU has a low res and a high res output for each gyro. Low res one used by software when tipping over fast and higher res one when tipping gently.//digital inputsint deadmanbuttonPin = 9; // deadman button is digital input pin 9 int balancepointleftPin = 7; //if digital pin 7 is 5V then reduce balancepoint variable. Allows manual fine tune of the ideal target balance pointint balancepointrightPin = 6; //if digital pin 6 is 5V then increase balancepoint variable. Allows manual fine tune of the ideal target balance pointint steeringvariableleftPin = 5; //digital pin5 Used to steerint steeringvariablerightPin = 4; //digital pin 4 Used to steer the other way.//digital outputsint oscilloscopePin = 8; //oscilloscope pin is digital pin 8 so you can work out the program loop time (currently about 5.5millisec)void setup() // run once, when the sketch starts {initSabertooth( );//analogINPUTSpinMode(accelPin, INPUT);pinMode(gyroPin, INPUT);pinMode(steergyroPin, INPUT);//pinMode(overallgainPin, INPUT);pinMode(hiresgyroPin, INPUT);//digital inputspinMode(deadmanbuttonPin, INPUT);digitalWrite(deadmanbuttonPin, HIGH); // turn on pullup resistorspinMode(balancepointleftPin, INPUT);digitalWrite(balancepointleftPin, HIGH); // turn on pullup resistorspinMode(balancepointrightPin, INPUT);digitalWrite(balancepointrightPin, HIGH); // turn on pullup resistorspinMode(steeringvariableleftPin, INPUT);digitalWrite(steeringvariableleftPin, HIGH); // turn on pullup resistorspinMode(steeringvariablerightPin, INPUT);digitalWrite(steeringvariablerightPin, HIGH); // turn on pullup resistors//digital outputspinMode(oscilloscopePin, OUTPUT);Serial.begin(9600); // HARD wired Serial feedback to PC for debugging in Wiring}void sample_inputs() {gyrosum = 0;steersum = 0;hiresgyrosum = 0;accraw = analogRead(accelPin); //read the accelerometer pin (0-1023)//Take a set of 7 readings very fastfor (j=0; j<7; j++) {adc1 = analogRead(gyroPin);adc4 = analogRead(steergyroPin);adc5 = analogRead(hiresgyroPin);gyrosum = (float) gyrosum + adc1; //sum of the 7 readingssteersum = (float) steersum + adc4; //sum of the 7 readingshiresgyrosum = (float)hiresgyrosum +adc5; //sum of the 7 readings }//k1 = analogRead(overallgainPin);k2 = digitalRead(steeringvariableleftPin);k3 = digitalRead(steeringvariablerightPin);k4 = digitalRead(deadmanbuttonPin);//overallgain = 0.5;balleft = digitalRead(balancepointleftPin);balright = digitalRead(balancepointrightPin);if (balleft == 0) balancetrim = balancetrim - 0.04; //if pressing balance point adjust switch then slowly alter the balancetrim variable by 0.04 per loop of the program//while you are pressing the switchif (balright == 0) balancetrim = balancetrim + 0.04; //same again in other directionif (balancetrim < -30) balancetrim = -30; //stops you going too far with thisif (balancetrim > 30) balancetrim = 30; //stops you going too far the other way// Savitsky Golay filter for accelerometer readings. It is better than a simple rolling average which is always out of date.// SG filter looks at trend of last few readings, projects a curve into the future, then takes mean of whole lot, giving you a more "current" value - Neat!// Lots of theory on this on net.a0 = a1;a1 = a2;a2 = a3;a3 = a4;a4 = a5;a5 = a6;a6 = (float) accraw;accsum = (float) ((-2*a0) + (3*a1) + (6*a2) + (7*a3) + (6*a4) + (3*a5) + (-2*a6))/21;//accsum isnt really a "sum" (it used to be once),//now it is the accelerometer value from the rolling SG filter on the 0-1023 scaledigitalWrite(oscilloscopePin, HIGH); //puts out signal to oscilloscope//****COMMENT THIS STEERING SECTION OUT IF YOU DONT WANT ANY STEERING FUNCTIONS TO BEGIN WITH. JUST KEEP THE COMMAND: SteerValue=512; and add a command: SteerCorrect = 0;//****COMMENT THIS STEERING SECTION OUT IF YOU DONT WANT ANY STEERING FUNCTIONS TO BEGIN WITH. JUST KEEP THE COMMAND: SteerValue=512; and add a command: SteerCorrect = 0;//****COMMENT THIS STEERING SECTION OUT IF YOU DONT WANT ANY STEERING FUNCTIONS TO BEGIN WITH. JUST KEEP THE COMMAND: SteerValue=512; and add a command: SteerCorrect = 0;//****COMMENT THIS STEERING SECTION OUT IF YOU DONT WANT ANY STEERING FUNCTIONS TO BEGIN WITH. JUST KEEP THE COMMAND: SteerValue=512; and add a command: SteerCorrect = 0;gangleratedeg2 = (float) ((steersum/7) - s) * 2.44; //divide by 0.41 as for low resolution balance gyro i.e. multiply by 2.44// NO steering wanted. Use second gyro to maintain a (roughly) straight line heading (it will drift a bit).if (k2 == 1 && k3 == 1) {//gangleratedeg2 = (float) ((steersum/7) - s) * 2.44; //divide by 0.41 as for low resolution balance gyro i.e. multiply by 2.44SteerCorrect = 0; //blocks the direction stabiliser unless rate of turn exceeds -10 or +10 degrees per secif (gangleratedeg2 > 10 || gangleratedeg2 < -10) { //resists turning if turn rate exceeds 10deg per secSteerCorrect = (float) 0.4 * gangleratedeg2; //vary the 0.4 according to how much "resistance" to being nudged off course you want.//a value called SteerCorrect is added to the steering value proportional to the rate of unwanted turning. It keeps getting//larger if this condition is till being satisfied i.e. still turning >10deg per sec until the change has been resisted.//can experiment with the value of 10. Try 5 deg per sec if you want - play around - this can probably be improved//but if you try to turn it fast with your hand while balancing you will feel it resisting you so it does work//also, when coming to a stop, one motor has a bit more friction than the other so as this motor stops first then as board//comes to standstill it spins round and you can fall off. This is original reason I built in this feature.//if motors have same friction you will not notice it so much.}//Serial.println(gangleratedeg2); //for debugging//delay(50);SteerValue = 512;}else {//i.e. we DO want to steer//steer one way SteerValue of 512 is straight aheadif (k2 == 0) {if (gangleratedeg2 < 55) { //will turn clockwise at 8 degrees per sec and if not, more power fed into steering until it does SteerValue = SteerValue + 2; }if (gangleratedeg2 > 55) {SteerValue = SteerValue - 2; } }//change the 5 and -5 values if you want faster turn rates. Could use a potentiometer to control these values so would have proportional control of steering//steer the other wayif (k3 == 0) {if (gangleratedeg2 < -55) { //will turn anticlockwise at 8 degrees per sec and if not, more power fed into steering until it doesSteerValue = SteerValue + 2; }if (gangleratedeg2 > -55) {SteerValue = SteerValue - 2; }}if (SteerValue < 1) {SteerValue = 1;}if (SteerValue > 1023) {SteerValue = 1023;}SteerCorrect = 0;}//*****END OF STEERING SECTION//*****END OF STEERING SECTION//*****END OF STEERING SECTION//*****END OF STEERING SECTION/*//for debugging. NOTE: when debugging with serial print commands to your PC the cycle time of program will slow down beyond the 5.5ms it is set up for and the//angle values etc can turn into nonsense even if there is nothing wrong with your code otherwiseSerial.print(k1);Serial.print(" ");Serial.print(k2);Serial.print(" ");Serial.print(k3);Serial.print(" ");Serial.print(k4);Serial.print(" ");Serial.print(balleft);Serial.print(" ");Serial.print(balright);Serial.println(" ");*///ACCELEROMETER notes for the 5 d of f Sparfun IMU I have used in my Instructable://300mV (0.3V) per G i.e. at 90 degree angle//Supply 3.3V is OK from Arduino NOT the 5V supply. Modern Arduinos have a 3.3V power out for small peripherals like this.//Midpoint is 1.58 Volts when supply to IMU is 3.3V i.e. 323 on the 0-1024 scale when read from a 0-5V Arduino analog input pin//not the 512 we are all perhaps more used to with 5V powered accel and gyro systems.//testing with voltmeter over 0-30 degree tilt range shows about 5.666mV per degree. Note: Should use the Sin to get angle i.e. trigonometry, but over our small//tilt angles (0-30deg from the vertical) the raw value is very similar to the Sin so we dont bother calculating it.// 1mv is 1024/5000 = 0.2048 steps on the 0-1023 scale so 5.666mV is 1.16 steps on the 0-1023 scale//THE VALUE OF 350 BELOW NEEDS TO BE VARIED BY TRIAL AND ERROR UNTIL MACHINE BALANCES EXACTLY LEVEL AS TIPSTART TAKES EFFECTx_accdeg = (float)((accsum - (340 + balancetrim))* (-0.862)); //approx 1.16 steps per degree so divide by 1.16 i.e. multiply by 0.862 (-0.862 actually as accel is backwards relative to gyro)if (x_accdeg < -72) x_accdeg = -72; //rejects silly values to stop it going berserk!if (x_accdeg > 72) x_accdeg = 72;/*//for debuggingSerial.print("accsum = ");Serial.println(accsum);Serial.print("balancetrim = ");Serial.println(balancetrim);Serial.print("x_accdeg = ");Serial.println(x_accdeg);*///GYRO NOTES://Low resolution gyro output: 2mV per degree per sec up to 500deg per sec. 5V = 1024 units on 0-1023 scale, 1Volt = 204.8 units on this scale. //2mV = 0.41 units = 1deg per sec// Hi res gyro output pin(from the same gyro): 9.1mV per degree per sec up to 110deg per sec on hires input. 5V = 1024 units on 0-1023 scale, 1Volt = 204.8 units on this scale.//9.1mV = 1.86 units = 1 deg per sec//Low res gyro rate of tipping reading calculated firstgangleratedeg = (float)(((gyrosum/7) - g)*2.44); //divide by 0.41 for low res balance gyro i.e. multiply by 2.44if (gangleratedeg < -450) gangleratedeg = -450; //stops crazy values entering rest of the programif (gangleratedeg > 450) gangleratedeg = 450;//debugging relic//Serial.print("gangleratedeg1 = ");//Serial.println(gangleratedeg);//..BUT...Hi res gyro ideally used to re-calculate the rate of tipping in degrees per sec, i.e. use to calculate gangleratedeg IF rate is less than 100 deg per secif (gangleratedeg < 100 && gangleratedeg > -100) {gangleratedeg = (float)(((hiresgyrosum/7) - t)*0.538); //divide by 1.86 i.e. multiply by 0.538if (gangleratedeg < -110) gangleratedeg = -110;if (gangleratedeg > 110) gangleratedeg = 110;}//debugging relic//Serial.print("gangleratedeg2 = ");//Serial.println(gangleratedeg);digitalWrite(oscilloscopePin, LOW); //cuts signal to oscilloscope pin so we have one pulse on scope per cycle of the program so we can work out cycle time.//Key calculations. Gyro measures rate of tilt gangleratedeg in degrees. We know time since last measurement is cycle_time (5.5ms) so can work out much we have tipped over since last measurement//What is ti variable? Strictly it should be 1. However if you tilt board, then it moves along at an angle, then SLOWLY comes back to level point as it is moving along//this suggests the gyro is slightly underestimating the rate of tilt and the accelerometer is correcting it (slowly as it is meant to).//This is why, by trial and error, I have increased ti to 1.2 at start of program where I define my variables.//experiment with this variable and see how it behaves. Temporarily reconfigure the overallgain potentiometer as an input to change ti and experiment with this variable//potentiometer is useful for this sort of experiment. You can alter any variable on the fly by temporarily using the potentiometer to adjust it and see what effect it hasgyroangledt = (float) ti * cycle_time * gangleratedeg;//x_accdeg = x_accdeg * (-1);gangleraterads = (float) gangleratedeg * 0.017453; //convert to radians - just a scaling issue from historyangle = (float) ((1-aa) * (angle + gyroangledt)) + (aa * x_accdeg);//aa allows us to feed a bit (0.5%) of the accelerometer data into the angle calculation//so it slowly corrects the gyro (which drifts slowly with tinme remember). Accel sensitive to vibration though so aa does not want to be too large.//this is why these boards do not work if an accel only is used. We use gyro to do short term tilt measurements because it is insensitive to vibration//the video on my instructable shows the skateboard working fine over a brick cobbled surface - vibration +++ !anglerads = (float) angle * 0.017453; //converting to radians again a historic scaling issue from past software//debugging//Serial.print("Angle = ");//Serial.println(angle);balance_torque = (float) (TORQUE * anglerads) + (POWER * gangleraterads); //power to motors (will be adjusted for each motor later to create any steering effects//balance torque is motor control variable we would use even if we just ahd one motor. It is what is required to make the thing balance only. //the values of 4.5 and 0.5 came from Trevor Blackwell's segway clone experiments and were derived by good old trial and error//I have also found them to be about right//We set the torque proportionally to the actual angle of tilt (anglerads), and also proportional to the RATE of tipping over (ganglerate rads)//the 4.5 and the 0.5 set the amount of each we use - play around with them if you want.//Much more on all this, PID controlo etc on my websitecur_speed = (float) (cur_speed + (anglerads * 6 * cycle_time)) * 0.999; //this is not current speed. We do not know actual speed as we have no wheel rotation encoders. This is a type of accelerator pedal effect: //this variable increases with each loop of the program IF board is deliberately held at an angle (by rider for example)//So it means "if we are STILL tilted, speed up a bit" and it keeps accelerating as long as you hold it tilted.//You do NOT need this to just balance, but to go up a slight incline for example you would need it: if board hits incline and then stops - if you hold it//tilted for long eneough, it will eventually go up the slope (so long as motors powerfull enough and motor controller powerful enough)//Why the 0.999 value? I got this from the SeWii project code - thanks! //If you have built up a large cur_speed value and you tilt it back to come to a standstill, you will have to keep it tilted back even when you have come to rest//i.e. board will stop moving OK but will now not be level as you are tiliting it back other way to counteract this large cur_speed value //The 0.999 means that if you bring board level after a long period tilted forwards, the cur_speed value magically decays away to nothing and your board//is now not only stationary but also level!level = (float)(balance_torque + cur_speed) * overallgain;//level = (float)balance_torque * overallgain; //You can omit cur speed term during testing while just getting it to initially balance if you want to//avoids confusion}void set_motor() {unsigned char cSpeedVal_Motor1 = 0;unsigned char cSpeedVal_Motor2 = 0;level = level * 200; //changes it to a scale of about -100 to +100 if (level < -100) {level = -100;}if (level > 100) {level = 100;}//debugging//Serial.print("level on -100 to +100 scale = ");//Serial.println(level);Steer = (float) SteerValue - SteerCorrect; //at this point is on the 0-1023 scale//SteerValue is either 512 for dead ahead or bigger/smaller if you are pressing steering switch left or right//SteerCorrect is the "adjustment" made by the second gyro that resists sudden turns if one wheel hits a small object for example.Steer = (Steer - 512) * 0.19; //gets it down from 0-1023 (with 512 as the middle no-steer point) to -100 to +100 with 0 as the middle no-steer point on scale//debugging//Serial.print("Steer on -100 to +100 scale is= ");//Serial.println(Steer);//set motors using the simplified serial Sabertooth protocol (same for smaller 2 x 5 Watt Sabertooth by the way)Motor1percent = (signed char) level + Steer;Motor2percent = (signed char) level - Steer;if (Motor1percent > 100) Motor1percent = 100;if (Motor1percent < -100) Motor1percent = -100;if (Motor2percent > 100) Motor2percent = 100;if (Motor2percent < -100) Motor2percent = -100;//if not pressing deadman button on hand controller - cut everything if (k4 > 0) {level = 0;Steer = 0;Motor1percent = 0;Motor2percent = 0;}cSpeedVal_Motor1 = map (Motor1percent,-100,100,SABER_MOTOR1_FULL_REVERSE, SABER_MOTOR1_FULL_FORWARD);cSpeedVal_Motor2 = map (Motor2percent,-100,100,SABER_MOTOR2_FULL_REVERSE, SABER_MOTOR2_FULL_FORWARD);SaberSerial.print (cSpeedVal_Motor1, BYTE);SaberSerial.print (cSpeedVal_Motor2, BYTE);/*//debuggingSerial.print("Motor1percent = ");Serial.print(Motor1percent);Serial.print (" level = ");Serial.println (level);Serial.print("Motor2percent = ");Serial.println(Motor2percent);Serial.print("cSpeedVal_Motor1 = ");Serial.println(cSpeedVal_Motor1);Serial.print("cSpeedVal_Motor2 = ");Serial.println(cSpeedVal_Motor2);*///delay(4); //4ms delay}void loop () {tipstart = 0;overallgain = 0;cur_speed = 0;level = 0;Steer = 0;balancetrim = 0;//Tilt board one end on floor. Turn it on. This 200 loop creates a delaywhile you finish turning it on and let go i.e. stop wobbling it about//as now the software will read the gyro values when there is norotational movement to find the zero point for each gyro. I could haveused a simple delay command.for (i=0; i<200; i++) {sample_inputs();}//now you have stepped away from baord having turned it on, we get7 readings from each gyro (and a hires reading from the balance gyro)g = (float) gyrosum/7; //gyro balance value when stationary i.e.1.35Vs = (float) steersum/7; //steer gyro value when stationary i.e.about 1.32Vt = (float) hiresgyrosum/7; //hiresgyro balance output whenstationary i.e. about 1.38V//we divide sum of the 7 readings by 7 to get mean for each//tiltstart routine now comes in. It is reading the angle fromaccelerometer. When you first tilt the board past the level point//the self balancing algorithm will go "live". If it did not have this,it would fly across the room as you turned it on (tilted)!while (tipstart < 5) {for (i=0; i<10; i++) {sample_inputs();}//x_accdeg is tilt angle from accelerometer in degreesif (x_accdeg < -12 || x_accdeg > -2) {//*****ADJUST THESE LIMITS TO SUIT YOUR BOARD SO TILTSTARTKICKS IN WHERE YOU WANT IT TO*******//MY IMU IS NOT QUITE VERTICALLY MOUNTEDtipstart = 0;overallgain = 0;cur_speed = 0;level = 0;Steer = 0;balancetrim = 0;}else {tipstart = 5;}}//overallgain = 0.5;overallgain = 0.3; //softstart value. Gain will now rise to final of 0.5 at rate of 0.005 per program loop.//i.e. it will go from 0.3 to 0.5 over the first 4 seconds after tipstart has been activatedangle = 0;cur_speed = 0;Steering = 512;SteerValue = 512;balancetrim = 0;//end of tiltstart code. If go beyond this point then machine is active //main balance routine, just loops forever. Machine is just trying to stay level. You "trick" it into moving by tilting one end down//works best if keep legs stiff so you are more rigid like a broom handle is if you are balancing it vertically on end of your finger//if you are all wobbly, the board will go crazy trying to correct your own flexibility.//NB: This is why a segway has to have vertical handlebar otherwise ankle joint flexibility in fore-aft direction would make it oscillate wildly. //NB: This is why the handlebar-less version of Toyota Winglet still has a vertical section you jam between your knees.while (1) {sample_inputs();set_motor();//XXXXXXXXXXXXXXXXXXXXX loop timing control keeps it at 100 cycles per second XXXXXXXXXXXXXXXlastLoopUsefulTime = millis()-loopStartTime;if (lastLoopUsefulTime < STD_LOOP_TIME) {delay(STD_LOOP_TIME-lastLoopUsefulTime);}lastLoopTime = millis() - loopStartTime;loopStartTime = millis();//XXXXXXXXXXXXXXXXXXXXXX end of loop timing control XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXserialOut_timing();//optional displays loop time on screen (first digit is time loop takes to run in millisec,//second digit is final time for loop including the variable added delay to keep it at 100Hz//XXXXXXXXXXXXXXXXXXXX softstart function: board a bit squishy when you first bring it to balanced point, then ride becomes firmer over next 4 seconds XXXXXXXXXXXXXXXif (overallgain < 0.5) {overallgain = (float)overallgain + 0.005;}if (overallgain > 0.5) {overallgain = 0.5;}//XXXXXXXXXXXXXXX end of softstart code XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}}void serialOut_timing(){static int skip=0;if (skip++==5) { //display every 500ms (at 100Hz)skip = 0;Serial.print(lastLoopUsefulTime); Serial.print(",");Serial.print(lastLoopTime); Serial.println("\\n");//XXXXXXXXXXXXXX put any variables you want printed to serial window in here XXXXXXXXXXXXXXXXXXXXXSerial.print("Motor1percent:");Serial.print(Motor1percent);Serial.print(" Motor2percent:");Serial.print(Motor2percent);Serial.print(" Angle degrees:");Serial.print(angle);Serial.print(" level:");Serial.println(level);//XXXXXXXXXXXXXX end of watch values in serial window XXXXXXXXXXXXXXXXXXXXXXXXXXX}}。
平衡车程序
平衡车程序平衡车程序#include"common.h"#include"include.h"voidanglecalculate;voidanglecontrol;voidspeedcontrol;voidspeedcontroloutput;voiddirectioncontrol;voiddirectioncontroloutput;voidmotoroutputr;voidmotoroutpu tl;voidpit_hander;voiddelay;voidstartccd;voidccd_get;uint8normalized_u8(uint16);voidinit_all;floatspeed_count=0;voidcenter_calculate;/***************角度控制参数值****************/#definecv_acce_offset1750//1775//1788//1845//1870//1830/ /1850//加速度计零偏值#definegravity_angle_ratio180/1960//加速度计角度转换系数1945#definecar_gyro_ratio_int1.5//可调在0.3左右,陀螺仪ad值与角速度的比例系数#definegravity_adjust_time_constant1//修正系数#defineangle_control_p12//20//可调,p值#definecar_angle_set0//平衡//小车角度设置#defineangle_control_d0.3//0.2//可调,d值0.1#definecar_angle_speed_set0//平衡//小车角速度设置#defineangle_control_out_max90//电机最大占空比#defineangle_control_out_min0//电机最小占空比,死区电压#definegyroscope_angle_sigma_frequency0.005//5ms/***************速度控制参数值****************/#definecar_speed_set0.5//0.5//1.5速度设置#definespeed_control_p150//20//50#definespeed_control_i1//0.1/ /0.01#definespeed_integral_max100#definespeed_integral_min1/****************方向控制参数值********************/#definedirection_control_p2//27//25//0.5小了3大#definedirection_control_d0.01//0.009//0.006//0.5//0.2//0.01//0.0 5//0.05uint16cy_gyro_zero,cx_gyro_zero;//陀螺仪零偏值intk,l=0,m=0;intaccvalue,gyrovalue;uint16gyro_ad_y,acc_ad,gyro_ad_x;//陀螺仪加速度计//ad 采集intg_n1mseventcount=0,g_fgravityangle=0;floatg_fcarangle=0,g_fcarspeed=0;floatg_fgyroscopeanglespeed=0,g_fgyroscopeangleintegral=0,g_fanglecontrolout=0,g_fspeedcontrolintegral=0;floatg_fspeedcontroloutold=0,g_fspeedcontroloutnew=0;floatg_direction_outold=0,g_direction_outnew=0;floatg_fspeedcontrolout=0,g_fspeedcontrol,g_fgyroscopeanglespeed;intg_nspeedcontrolperiod=0;intg_nspeedcontrolcount=0,g_ndirectioncontrolcount=0;intg_ndirectioncontrolout=0,g_ndirectioncontrolperiod=0;intg_ccddelta=45;//40//ccd黑白线阈值差intg_icenter;//ccd的中心intcenter=61;//目标中心(赛道中心)intg_width=30;//128//赛道宽intspeedcontrolflag=0;//速度控制标志位floatg_fgzroscopeanglespeed;//转向陀螺仪差值uint8line[128]={0};//ccd采集一次得到的数组floatfdeltavalue;//主函数voidmain(void){disableinterrupts;init_all;//初始化uint16gyro_ad_zero_y=0,gyro_ad_zero_x=0;delay_ms(1000);//获得陀螺仪x轴和y轴的零偏值for(k=0;k8)&0xff);//uart_putchar(uart1,angle1&0xff);////angle2=(uint16)(g_fgravityangle+200);//加速度计采样数据//uart_putchar(uart1,(angle2>>8)&0xff);//uart_putchar(uart1,angle2&0xff);////angle3=(uint16)(g_fcarangle+200);//融合数据//uart_putchar(uart1,(angle3>>8)&0xff);//uart_putchar (uart1,angle3&0xff);//}}//初始化voidinit_all{//电机脉冲输出初始化tpm_pwm_init(tpm0,tpm_ch0,20000,0);//e24//左tpm_pwm_init(tpm0,tpm_ch1,20000,0);//e25//左tpm_pwm_init(tpm0,tpm_ch2,20000,0);//e29//右tpm_pwm_init(tpm0,tpm_ch4,20000,0);//e31//右// adc_init(adc0_se9);//ptb1陀螺仪前后角速度adc_init (adc0_se14);//ptb2加速度计adc_init(adc0_se13);//ptb3陀螺仪左右角速度adc_init (adc0_dp0);//pte20线性ccdgpio_init(ptc8,gpo,0);//初始化si//c8gpio_init(ptc7,gpo,0);//初始化clk//c7gpio_init(ptb19,gpi,0);//编码器测向右gpio_init(ptc1,gpi,0);//编码器测向左gpio_init(pte0,gpo,1);//初始化ledtpm_pulse_init(tpm2,tpm_clkin0,tpm_ps_1);//计数//右//ptb16tpm_pulse_init(tpm1,tpm_clkin1,tpm_ps_1);//计数//左//pte30uart_init(uart1,19200);//ptc3(发送)c4(接收)startccd;pit_init_ms(pit1,5);//定时5ms后中断set_vector_handler(pit_vectorn,pit_hander);//设置中断复位函数到中断向量表里enable_irq(pit_irqn);//使能lptmr中断}//pit中断uint16gyro_ad_y,acc_ad;//inti,ii,iii;voidpit_hander(void){pit_flag_clear(pit1);//清中断标志位gyro_ad_y=adc_once(adc0_se9,adc_12bit);//ptb1acc_ad=adc_once(adc0_se14,adc_12bit);//ptc0 //for(i=0;i。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
// while(1)
// {
// uart_putchar(UART1,0xff); //UART1,TX接PTC4,RX接PTC3
// uart_putchar(UART1,0xff);//以上两个字节数据作为数据帧头
//
// angle1=(uint16)(g_fGyroscopeAngleIntegral+200); //陀螺仪采样
// uart_putchar(UART1,angle3 & 0xFF);
// }
}
//初始化
void init_all()
{
//电机 脉冲输出 初始化
tpm_pwm_init(TPM0,TPM_CH0,20000,0); //E24 //左
// }
int i;
while(1)
{
for(i=0; i<128; i++)
{
if( LINE[i]==0xFF)
{
LINE[i] = 0xFE; //遇到FF用FE替换即可
adc_init (ADC0_DP0); //PTE20 线性CCD
gpio_init(PTC8,GPO,0); //初始化SI //C8
gpio_init(PTC7,GPO,0); //初始化CLK //C7
gpio_turn(PTE0); //点亮LED
DELAY_MS(1000);
EnableInterrupts;
DELAY_MS(3000);
SpeedControlFlag=1;
// while(1)
// {
//;
int g_n1MsEventCount=0,g_fGravityAngle=0;
float g_fCarAngle=0,g_fCarSpeed=0;
float g_fGyroscopeAngleSpeed=0,g_fGyroscopeAngleIntegral=,g_fAngleControlOut=0,g_fSpeedControlIntegral=0;
#define GRAVITY_ANGLE_RATIO 180/1960 //加速度计角度转换系数 1945
#define CAR_GYRO_RATIO_INT 1.5 //可调在0.3左右,陀螺仪AD值与角速度的比例系数
#define GRAVITY_ADJUST_TIME_CONSTANT 1 //修正系数
init_all(); //初始化
uint16 gyro_ad_zero_y=0, gyro_ad_zero_x=0;
DELAY_MS(1000);
//获得陀螺仪X轴和Y轴的零偏值
for(k=0;k<=9;k++)
{
gyro_ad_zero_y += adc_once(ADC0_SE9, ADC_12bit); // PTB1
uint16 cy_gyro_zero,cx_gyro_zero; //陀螺仪零偏值
int k,l=0,m=0;
int accvalue, gyrovalue;
uint16 Gyro_ad_y,Acc_ad,Gyro_ad_x; //陀螺仪加速度计 //AD采集
#define SPEED_INTEGRAL_MIN 1
/****************方向控制参数值********************/
#define DIRECTION_CONTROL_P 2//27 //25//0.5 小了 3 大
#define DIRECTION_CONTROL_D 0.01//0.009//0.006//0.5 //0.2//0.01//0.05//0.05
#define ANGLE_CONTROL_P 12//20 //可调,P值
#define CAR_ANGLE_SET 0 //平衡 //小车角度设置
#define ANGLE_CONTROL_D 0.3//0.2 //可调,D值 0.1
// uart_putchar(UART1, (angle1>> 8 ) & 0xFF);
// uart_putchar(UART1,angle1 & 0xFF);
//
// angle2=(uint16)(g_fGravityAngle+200); //加速度计采样数据
void init_all();
float speed_count=0;
void Center_Calculate();
/***************角度控制参数值****************/
#define CV_ACCE_OFFSET 1750//1775//1788//1845//1870// 1830 //1850 //加速度计零偏值
// uart_putchar(UART1, (angle2>> 8 ) & 0xFF);
// uart_putchar(UART1,angle2 & 0xFF);
//
// angle3=(uint16)(g_fCarAngle+200); //融合数据
// uart_putchar(UART1, (angle3>> 8 ) & 0xFF);
float g_fGzroscopeAngleSpeed; //转向陀螺仪差值
uint8 LINE[128]={0}; //ccd采集一次得到的数组
float fDeltaValue;
//主函数
void main(void)
{
DisableInterrupts;
tpm_pwm_init(TPM0,TPM_CH1,20000,0); //E25 //左
tpm_pwm_init(TPM0,TPM_CH2,20000,0); //E29 //右
tpm_pwm_init(TPM0,TPM_CH4,20000,0); //E31 //右
gpio_init(PTB19,GPI,0); //编码器测向 右
gpio_init(PTC1,GPI,0); //编码器测向 左
gpio_init(PTE0,GPO,1); //初始化LED
tpm_pulse_init(TPM2,TPM_CLKIN0,TPM_PS_1); //计数 //右 //PTB16
//
adc_init(ADC0_SE9); //PTB1 陀螺仪 前后角速度
adc_init(ADC0_SE14); //PTB2 加速度计
adc_init(ADC0_SE13); //PTB3 陀螺仪 左右角速度
#include "common.h"
#include "include.h"
void AngleCalculate();
void AngleControl();
void SpeedControl();
void SpeedControlOutput();
void DirectionControl();
tpm_pulse_init(TPM1,TPM_CLKIN1,TPM_PS_1); //计数 //左 //PTE30
uart_init (UART1, 19200); //PTC3(发送) C4(接收)
#define SPEED_CONTROL_P 150 //20 //50
#define SPEED_CONTROL_I 1 //0.1 //0.01
#define SPEED_INTEGRAL_MAX 100
float g_fSpeedControlOutOld=0,g_fSpeedControlOutNew=0;
float g_direction_outold=0,g_direction_outnew=0;
float g_fSpeedControlOut=0,g_fSpeedControl,g_fGyroscopeAngleSpeed;
int g_nSpeedControlPeriod=0;
int g_nSpeedControlCount=0,g_nDirectionControlCount=0;
int g_nDirectionControlOut=0,g_nDirectionControlPeriod=0;
int g_ccddelta=45; //40 //CCD黑白线阈值差
#define GYROSCOPE_ANGLE_SIGMA_FREQUENCY 0.005 //5ms
/***************速度控制参数值****************/
#define CAR_SPEED_SET 0.5//0.5 //1.5 速度设置
gyro_ad_zero_x += adc_once(ADC0_SE13, ADC_12bit); // PTB3
}
cy_gyro_zero = gyro_ad_zero_y/10;
cx_gyro_zero = gyro_ad_zero_x/10;
void DirectionControlOutput();
void MotorOutputr();
void MotorOutputl();
void pit_hander();
void delay();
void StartCCD();
void ccd_get();
uint8 Normalized_U8(uint16);