历史上的今天

今天是:2024年11月09日(星期六)

正在发生

2019年11月09日 | 二轮平衡机器人控制器代码

发布者:VelvetDreamer 来源: 51hei关键字:二轮平衡机器人  控制器  Mega16 手机看文章 扫描二维码
随时随地手机看文章

//MCU:Mega16;晶振:8MHz;


//PWM:4KHz;滤波器频率:100Hz;系统频率:100Hz;10ms;


//二轮平衡机器人项目


#include


#include


#include


//#define checkbit(var,bit)     (var&(0x01<<(bit)))     /*定义查询位函数*/


//#define setbit(var,bit)     (var|=(0x01<<(bit)))     /*定义置位函数*/


//#define clrbit(var,bit)     (var&=(~(0x01<<(bit)))) /*定义清零位函数*/


//-------------------------------------------------------


//输出端口初始化


void PORT_initial(void)


{


DDRA=0B00000000;


PINA=0X00;


PORTA=0X00;


DDRB=0B00000000;


PINB=0X00;


PORTB=0X00;


DDRC=0B00010000;


PINC=0X00;


PORTC=0X00;


DDRD=0B11110010;


PIND=0X00;


PORTD=0X00;


}


//-------------------------------------------------------


//定时器1初始化


void T1_initial(void)        


{


TCCR1A|=(1<

TCCR1B|=(1<

}


//-------------------------------------------------------


//定时器2初始化


void T2_initial(void)        //T2:计数至OCR2时产生中断


{


OCR2=0X4E;        //T2:计数20ms(0X9C)10ms(0X4E)时产生中断;


TIMSK|=(1<

TCCR2|=(1<

}


//-------------------------------------------------------


//外部中断初始化


void INT_initial(void)


{


MCUCR|=(1<

GICR|=(1<

}


//-------------------------------------------------------


//串口初始化;


void USART_initial( void )


{        


UBRRH = 0X00;


UBRRL = 51;        //f=8MHz;设置波特率:9600:51;19200:25;


UCSRB = (1<

UCSRC = (1<

UCSRB|=(1<


//-------------------------------------------------------


//串口发送数据;


void USART_Transmit( unsigned char data )


{


while ( !( UCSRA & (1<缓冲器为空;


UDR = data;        //将数据放入缓冲器,发送数据;



//-------------------------------------------------------


//串口接收数据中断,确定数据输出的状态;


#pragma interrupt_handler USART_Receive_Int:12


static char USART_State;


void USART_Receive_Int(void)


{


USART_State=UDR;//USART_Receive();


}


//-------------------------------------------------------


//计算LH侧轮速:INT0中断;


//-------------------------------------------------------


static int speed_real_LH;


//-------------------------------------------------------


#pragma interrupt_handler SPEEDLHINT_fun:2


void SPEEDLHINT_fun(void)


{


if (0==(PINB&BIT(0)))


{


speed_real_LH-=1;


}


else


{


speed_real_LH+=1;



}


//-------------------------------------------------------


//计算RH侧轮速,:INT1中断;


//同时将轮速信号统一成前进方向了;


//-------------------------------------------------------


static int speed_real_RH;


//-------------------------------------------------------


#pragma interrupt_handler SPEEDRHINT_fun:3


void SPEEDRHINT_fun(void)


{


if (0==(PINB&BIT(1)))


{


speed_real_RH+=1;


}


else


{


speed_real_RH-=1;



}


//-------------------------------------------------------


//ADport采样:10位,采样基准电压Aref


//-------------------------------------------------------


static int AD_data;


//-------------------------------------------------------


int ADport(unsigned char port)


{


ADMUX=port;


ADCSRA|=(1<

while(!(ADCSRA&(BIT(ADIF))));


AD_data=ADCL;


AD_data+=ADCH*256;


AD_data-=512;


return (AD_data);


}


//*


//-------------------------------------------------------


//Kalman滤波,8MHz的处理时间约1.8ms;


//-------------------------------------------------------


static float angle, angle_dot; //外部需要引用的变量


//-------------------------------------------------------


static const float Q_angle=0.001, Q_gyro=0.003, R_angle=0.5, dt=0.01;


//注意:dt的取值为kalman滤波器采样时间;


static float P[2][2] = {


{ 1, 0 },


{ 0, 1 }


};


static float Pdot[4] ={0,0,0,0};


static const char C_0 = 1;


static float q_bias, angle_err, PCt_0, PCt_1, E, K_0, K_1, t_0, t_1;


//-------------------------------------------------------


void Kalman_Filter(float angle_m,float gyro_m)        //gyro_m:gyro_measure


{


angle+=(gyro_m-q_bias) * dt;


Pdot[0]=Q_angle - P[0][1] - P[1][0];


Pdot[1]=- P[1][1];


Pdot[2]=- P[1][1];


Pdot[3]=Q_gyro;


P[0][0] += Pdot[0] * dt;


P[0][1] += Pdot[1] * dt;


P[1][0] += Pdot[2] * dt;


P[1][1] += Pdot[3] * dt;


angle_err = angle_m - angle;


PCt_0 = C_0 * P[0][0];


PCt_1 = C_0 * P[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 * P[0][1];


P[0][0] -= K_0 * t_0;


P[0][1] -= K_0 * t_1;


P[1][0] -= K_1 * t_0;


P[1][1] -= K_1 * t_1;


angle        += K_0 * angle_err;


q_bias        += K_1 * angle_err;


angle_dot = gyro_m-q_bias;


}


//*/


/*


//-------------------------------------------------------


//互补滤波


//-------------------------------------------------------


static float angle,angle_dot; //外部需要引用的变量


//-------------------------------------------------------        


static float bias_cf;


static const float dt=0.01;


//-------------------------------------------------------


void complement_filter(float angle_m_cf,float gyro_m_cf)


{


bias_cf*=0.998;        //陀螺仪零飘低通滤波;500次均值;


bias_cf+=gyro_m_cf*0.002;


angle_dot=gyro_m_cf-bias_cf;


angle=(angle+angle_dot*dt)*0.90+angle_m_cf*0.05;        


//加速度低通滤波;20次均值;按100次每秒计算,低通5Hz;


}


*/        


//-------------------------------------------------------


//AD采样;


//以角度表示;


//加速度计:1.2V=1g=90°;满量程:1.3V~3.7V;


//陀螺仪:0.5V~4.5V=-80°~+80°;满量程5V=200°=256=200°;


//-------------------------------------------------------


static float gyro,acceler;


//-------------------------------------------------------


void AD_calculate(void)


{


acceler=ADport(2)+28;        //角度校正


gyro=ADport(3);        


acceler*=0.004069;        //系数换算:2.5/(1.2*512); // 5/(1.2*1024);5为参考电压5V;1.2V灵敏度对应加速度1g;1024为AD精度


acceler=asin(acceler);        //反正弦求角度


gyro*=0.00341;        //角速度系数:(3.14/180)* 100/512=0.01364;//(3.14/180)*    (200*0.025)/1024*0.025既5/1024*0.025        


//求得角速度 单位 角度/秒


Kalman_Filter(acceler,gyro);        //卡尔曼滤波 带入角度。角速度


//complement_filter(acceler,gyro);


}


//-------------------------------------------------------


//PWM输出


//-------------------------------------------------------


void PWM_output (int PWM_LH,int PWM_RH)


{


if (PWM_LH<0)


{


PORTD|=BIT(6);


PWM_LH*=-1;


}


else


{


PORTD&=~BIT(6);


}


if (PWM_LH>252)


{


PWM_LH=252;


}


if (PWM_RH<0)


{


PORTD|=BIT(7);


PWM_RH*=-1;


}


else


{


PORTD&=~BIT(7);


}


if (PWM_RH>252)


{


PWM_RH=252;


}


OCR1AH=0;


OCR1AL=PWM_LH;        //OC1A输出;


OCR1BH=0;


OCR1BL=PWM_RH;        //OC1B输出;


}


//-------------------------------------------------------


//计算PWM输出值


//车辆直径:76mm; 12*64pulse/rev; 1m=3216pulses;


//-------------------------------------------------------        


//static int speed_diff,speed_diff_all,speed_diff_adjust;


//static float K_speed_P,K_speed_I;


static float K_voltage,K_angle,K_angle_dot,K_position,K_position_dot;


static float K_angle_AD,K_angle_dot_AD,K_position_AD,K_position_dot_AD;


static float position,position_dot;


static float position_dot_filter;


static float PWM;


static int speed_output_LH,speed_output_RH;


static int Turn_Need,Speed_Need;


//-------------------------------------------------------        


void PWM_calculate(void)        


{


if ( 0==(~PINA&BIT(1)) )        //左转


{


Turn_Need=-40;


}


else if ( 0==(~PINB&BIT(2)) ) //右转


{


Turn_Need=40;


}


else        //不转


{


Turn_Need=0;


}


if ( 0==(~PINC&BIT(0)) )        //前进


{


Speed_Need=-2;


}


else if ( 0==(~PINC&BIT(1)) )        //后退 


{


Speed_Need=2;


}


else        //不动


{


Speed_Need=0;


}


K_angle_AD=ADport(4)*0.007;


K_angle_dot_AD=ADport(5)*0.007;


K_position_AD=ADport(6)*0.007;


K_position_dot_AD=ADport(7)*0.007;


position_dot=PWM*0.04;


position_dot_filter*=0.9;        //车轮速度滤波


position_dot_filter+=position_dot*0.1;        


position+=position_dot_filter;


//position+=position_dot;        


position+=Speed_Need;


if (position<-768)        //防止位置误差过大导致的不稳定


{


position=-768;


}


else if  (position>768)


{


position=768;


}


PWM = K_angle*angle *K_angle_AD + K_angle_dot*angle_dot *K_angle_dot_AD + 


K_position*position *K_position_AD + K_position_dot*position_dot_filter *K_position_dot_AD;


speed_output_RH = PWM;// - Turn_Need;


speed_output_LH = - PWM;// - Turn_Need ;


/*


speed_diff=speed_real_RH-speed_real_LH;        //左右轮速差PI控制;


speed_diff_all+=speed_diff;


speed_diff_adjust=(K_speed_P*speed_diff+K_speed_I*speed_diff_all)/2;


*/


PWM_output (speed_output_LH,speed_output_RH);        


}


//-------------------------------------------------------


//定时器2中断处理


//-------------------------------------------------------


static unsigned char temp;


//-------------------------------------------------------


#pragma interrupt_handler T2INT_fun:4


void T2INT_fun(void)        


{


AD_calculate();


PWM_calculate();


if(temp>=4)        //10ms即中断;每秒计算:100/4=25次;


{        


if (USART_State==0X30)        //ASCII码:0X30代表字符'0'


{


USART_Transmit(angle*57.3+128);


USART_Transmit(angle_dot*57.3+128);


USART_Transmit(128);        


}


else if(USART_State==0X31)        //ASCII码:0X30代表字符'1'


{


USART_Transmit(speed_output_LH+128);


USART_Transmit(speed_output_RH+128);        


USART_Transmit(128);


}


else if(USART_State==0X32)        //ASCII码:0X30代表字符'2'

[1] [2]
关键字:二轮平衡机器人  控制器  Mega16 引用地址:二轮平衡机器人控制器代码

上一篇:AVR单片机经典使用经验
下一篇:ATMEGA16L实现时间和温度的循环显示程序分享

推荐阅读

  2017年年末,国家能源局、国务院扶贫办联合发布了《关于下达“十三五”第一批光伏扶贫项目计划的通知》,并正式下发“十三五”第一批光伏扶贫项目,作为国家级贫困县的山西省代县便出现在首批扶贫名单之中。“十三五”第一批光伏扶贫项目计划显示,代县建档立卡贫困村236个,帮扶户数6483个,计划建设光伏电站数量217座,建设规模达42.8MW。   代县...
  涡轮流量计安装直管段要求  正确地选择安装点和正确安装流量计都是非常重要的环节,若安装环节失误轻者影响测量精度,重者会影响流量计的使用寿命,甚至会损坏流量计。  涡轮流量计安装对直管段的要求是非常重要的。它的详细要求如下:  1、流量计对安装点上的上下游直管段一定的要求,否则会影响测量精度。  2、若流量计安装点上的上游有渐缩...
据悉,随着液晶面板价格的持续“上涨”,韩系面板双雄 LGD 和三星显示(SDC)接连宣布延迟 LCD 液晶面板停产计划,中国厂商也在不断提升产能。 了解到,自 6 月开始,电视液晶面板全面涨价,截至目前仍没有停止上涨的步伐。中小尺寸电视液晶面板价格上涨幅度最为迅猛,32 英寸至 55 英寸电视液晶面板价格上涨幅度皆超过 40%,其中 55 英寸价格...
11月8日,闻泰科技官方公众号发布消息,称闻泰科技旗下得尔塔科技广州园区已进入复工复产的关键阶段,从市场的良率、效率等各方面都达到了特定客户的基本要求。此外,珠海基地未来也将投产,产能将大幅度提升。广州得尔塔是由闻泰科技今年向欧菲光收购的资产,此前为苹果公司供应光学模组。这一收购由闻泰科技与格力创投按7:3比例共同出资,双方于4月成立...

史海拾趣

问答坊 | AI 解惑

运放经典

本帖最后由 paulhyde 于 2014-9-15 04:26 编辑 运放经典 运放经典  …

查看全部问答∨

Linux发行版,你了解么?

作者:孙天泽,华清远见嵌入式学院金牌讲师。 从1991年诞生的那天起,Linux内核就在全世界的黑客们精心呵护下不断发展壮大。很多Linux Fans想为Linux内核做贡献,但或许是包括技术在内的等等原因,你的Ideas不一定会被内核容纳。对于操作系统来 ...…

查看全部问答∨

PC可以直接使用手机显示屏吗?

有个工控设备,其中内置一台个人电脑(PC全内置主板),需要配备显示器和键盘。 因为安装空间太小,容纳不了普通CRT或笔记本LCD显示器。况且,该设备的用户界面很简单,只需要控制串口通讯以及操作一个简单的ACCESS数据库,使用带触摸的2.5~3.5寸 ...…

查看全部问答∨

维纶触摸屏MT6系列产品问题

前几日使用维纶触摸屏MT6100I系列产品,大约7天后发现故障: 基本症状如下: 黑屏与维纶手型标志交替闪动. 咨询厂家说: 没有遇到此类情况. 把屏返回厂家说,测试了几天,没有发现故障. 大约7天后,另外一个工地,同样的屏出现了同样的故障.即黑屏与维纶手 ...…

查看全部问答∨

Stellaris ICDI ND manual(811国产板使用说明书)

附:stellaris_icdi_switch转换工具的使用说明…

查看全部问答∨

INOUT引脚:在FPGA中使用方法

INOUT引脚: 1.FPGA IO在做输入时,可以用作高阻态,这就是所说的高阻输入; 2.FPGA IO在做输出时,则可以直接用来输入输出。 芯片外部引脚很多都使用inout类型的,为的是节省管腿。就是一个端口同时做输入和输出。 inout在具体实现上一般用 ...…

查看全部问答∨

STM32F407 以太网如何配置?

如题,官方评估板的例程带了RLos, 我用UDPTCPdbg工具调试,在局域网里传送文件,工具上显示速率只有几十K,想弄个裸奔的程序再试试,有没有弄过的指点下。先谢谢了!…

查看全部问答∨

关于失调电流和偏置电流的区别

OFFSET current:失调电流、BIAS  current:偏置电流 选择运放的时候,看见这两个参数,他们的区别是什么呢?搞不懂啊, 实际运用中用的到吗? …

查看全部问答∨

问一个C语言结构体赋值的问题

在请问一下,我定义一个 srtuct  a { unsigned char a1; unsigned char a2; unsigned char a3; unsigned char a4; }aa; 现在我想把一个数组,比如unsigned char b[4]={0,1,2,3}; 分别赋给结构体里的a1,a2,a3,a4有没有方便的办 ...…

查看全部问答∨
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved