BB8球形机器人制作教程
还记得《星球大战:原力觉醒》中呆萌可爱的BB8球形机器人吗?来上车吧,老司机教你亲手将这个萌货制造出来!本教程旨在以低成本、简单易行的方式结合以3D打印技术制作BB8机器人,供有兴趣爱好者参考。
1. 结构篇
BB8机器人由球体和头部两部分构成,其中球体和头部通过磁铁连接。球体内部由驱动机构和控制摆杆构成。驱动机构驱动球体实现前后左右4个方向的运动;控制摆杆在一定角度内摆动,经由磁铁传动至头部实现头部的摆动。
BB8机器人的结构和外观由SolidWorks设计完成。SolidWorks是法国达索公司旗下的一款基于特征、参数化、实体建模的设计工具。
1.0 材料
进行结构设计之前首先选择合适的标准配件。
球体外壳选用亚克力球制作,后续将进行打磨、喷漆、上光油等流程。
控制摆杆通过舵机实现一定角度内的摆动,舵机可选用数字舵机或模拟舵机。数字舵机和模拟舵机的区别在于:模拟舵机需要持续的PWM控制信号维持转动角度,而数字舵机只需要输入PWM控制信号改变转动角度。这里我们选用数字舵机。
驱动机构由直流减速电机、电机驱动和小车轮构成。电机驱动选用L298N作为主驱动芯片的驱动模块,其具有驱动能力强、发热量低、抗干扰能力强的特点。
BB8机器人的无线数据通讯通过蓝牙方式完成。这里我们选用主从一体BLE蓝牙模块。
1.1 step 1
运用SolidWorks对BB8球形机器人各结构进行建模。
首先依据图纸尺寸对BB8机器人球体和头部外观进行建模:
对舵机、舵盘和舵机支架进行建模并装配:
对直流减速电机、电机驱动和小车轮进行建模并装配:
1.2 step 2
设计BB8机器人驱动机构的底盘和托物架。
底盘前后两端通过2个万向球与球体内部相切接触,使得车轮与球体内部持续摩擦保持恒定驱动力,并保持运动姿态稳定。底盘下部设计托物架,以放置电路板、电池和配重物等。放置配重物,结构重心尽可能向下,以使车轮与球体内部更好接触并保持运动姿态稳定。
1.3 step 3
设计BB8机器人头部和控制摆杆。
控制摆杆一端通过紧固螺栓固定于舵机支架,一端通过紧固螺栓固定于顶盘。在顶盘转动方向上放置2颗强磁铁。建模时注意仿真分析检查是否干涉:调节底盘上凸台高度使得舵机舵盘轴心位于球体中心,调节摆杆长度使得强磁铁紧贴于球体内部而不干涉。头部设计转盘通过3颗万向球、2颗强磁铁相切吸合于球体外部。
1.4 step 4
BB8机器人结构建模、总体装配完成后,再进行运动仿真、干涉检查。
设置外观、布景和光源,利用SolidWorks渲染工具PhotoView360对BB8机器人进行渲染。
1.5 step 5
对BB8机器人结构件进行3D打印。
运用SolidWorks输出结构件的.stl格式三维数据文件。可选择SLA、FDM等方式的3D打印工艺:SLA即光固化成型,主要材料为光敏树脂,精度高、成型快、技术成熟、成本高;FDM即熔融沉积成型,主要材料为ABS和PLA,精度低、成型慢、成本低。这里我们选择电商平台的SLA工艺的3D打印定制。
3D打印完成后的结构件:
1.6 step 6
对BB8机器人球体和头部外观进行彩绘喷漆。
将用于制作球体的亚克力球用砂纸进行打磨。打磨完毕,用清水将亚克力球表面冲洗干净,并晾干。晾干后,将亚克力球置于通风干燥处喷底漆。底漆选择白漆,喷漆时在距离球面30cm处来回均匀喷漆。
将亚克力球置于通风干燥处,待白色底漆完全干透。用美纹胶带将球面完全覆盖。以3D打印的球体外观为模板用铅笔在球面描摹。外观描摹完毕,将喷漆部分的胶带用美工刀剔除。选择对应颜色的漆,喷第二层漆。待第二层漆完全干透后,将喷过漆的部分再用美纹胶带完全覆盖。再在球面进行外观描摹,剔除胶带,喷漆,晾干。如此,依次将白色漆、银色漆、黄色漆喷至球体外部。待喷漆全部完成,再在球面喷光油,以使球体外观更加光洁平整并保护底漆。
以同样的流程,对BB8机器人头部外观进行喷漆。完成对BB8机器人整体外观的彩绘喷漆。
1.7 step 7
将BB8机器人的眼睛、天线用热熔胶与头部粘合,将万向球、强磁铁等组装完毕。
将BB8机器人球体内部结构组装完毕,最后进行球体和头部的整体装配。
2. 硬件篇
BB8机器人硬件的设计思路为:主控电路板上电后通过蓝牙透传模块,与手机APP建立无线连接。再依据手机APP下发的指令控制舵机和电机驱动模块,电机驱动模块驱动2个电机。
选择锂电池作为硬件系统的电源,并可持续充放电。
BB8机器人的硬件电路由Altium Designer设计完成,Altium Designer是Altium公司推出的一体化电子产品开发系统。
2.1 SCH设计
BB8机器人的硬件电路主控MCU选择TI德州仪器的msp430g2553,20引脚TSSOP封装。
之所以选择此芯片,在于其超低功耗、小尺寸、低成本。其次,我们手头上刚好有一块闲置的TI LaunchPad开发板,可以作为此芯片的仿真调试器。
我们需要用到msp430g2553内部的超低功耗低频 (LF) 振荡器、16位定时器 (Timer_A) 、通用串行通信接口 (USCI) 和10路GPIO。
硬件电路电源选择锂离子电池,并设计充放电电路。主控MCU和蓝牙透传模块工作电压为3.3V,舵机工作电压为4.8V - 7.2V、舵机PWM电压为5.0V,电机驱动模块驱动电压为5V - 35V。
故选择≥7.4V的锂离子电池,并设计两级降压电路,使得电源相关电路能稳定输出≥7.4V、5.0V、3.3V三种电压。
主控MCU设计按键复位电路,预留Spy-Bi-Wire仿真调试接口。
红绿2个LED灯指示系统工作状态。
主控MCU上的通用串行通信接口 (USCI) 的RXD、TXD,分别连接至蓝牙透传模块的TXD、RXD。
主控MCU上的7路GPIO经由光耦合器,分别连接至电机驱动模块的ENA、ENB、IN1、IN2、IN3、IN4和舵机的PWM输入端。
采用光耦进行耦合连接:其一,是为了将主控MCU和其他功能模块进行电气隔离;其二,是为了进行电平转换,主控MCU为3.3V电平系统而其他功能模块为5.0V电平系统,通过光耦合器可实现控制信号从3.3V到5.0V的电平转换。
2.2 PCB设计
主控电路板原理图绘制完毕后,开始进行PCB设计。
依据BB8机器人的结构参数,设计PCB板外形尺寸为100mm × 50mm,装配尺寸为90mm × 40mm。依据各元器件封装尺寸进行PCB布局布线,尽可能将各接口端子、开关按键往PCB板边缘布局。
将设计完成的PCB板,导出制板文件交由厂家生产制造。
对生产完成的PCB板进行品质检验,确认合格后开始PCB焊接。
2.3 硬件装配
PCB板焊接完成后,将主控电路板和电源、各功能模块进行连接。
锂离子电池连接至主控电路板P1端子,并注意电源正负极性。蓝牙透传模块连接至P2端子。TI LaunchPad仿真调试器连接至P4端子。电机驱动模块连接至P5端子,2直流减速电机分别连接至电机驱动板的输出端子OUT A、OUT B。舵机连接至P7端子。
BB8机器人的内部硬件构成:
优化建议: 主控MCU的其他端口可扩展加速度计和陀螺仪,对BB8机器人的运动状态进行实时监测。通过PID算法修正运动姿态。
3. 软件篇
BB8机器人软件的控制流程为:主控MCU完成上电复位/按键复位后,进行系统初始化。系统初始化完毕,读取串口数据判断是否接收到蓝牙透传指令:收到,解析指令后执行指令完成动作;未收到,继续执行原来指令完成动作。如此,程序循环运行。
BB8机器人的软件程序由IAR Embedded Workbench开发完成。IAR Embedded Workbench是瑞典IAR Systems公司专为微处理器开发的一个集成开发环境,支持ARM、AVR、MSP430等芯片内核平台。
3.1 调试工具
选择TI MSP-EXP430G2 LaunchPad作为仿真器对BB8机器人的软件进行仿真调试。
MSP-EXP430G2 LaunchPad 是一款易于使用的闪存编程器和调试工具,它提供了在MSP430 超值系列器件上进行开发所需的一切内容。它提供了具有集成仿真功能的 14/20引脚 DIP 插座目标板,可通过 Spy-Bi-Wire(2 线 JTAG)协议对系统内置的 MSP430 超值系列器件进行快速编程和调试。由于 MSP430 闪存的功耗极低,因此无需外部电源即可在数秒内擦除闪存并对其进行编程。
将MSP-EXP430G2 LaunchPad跳线组J3的VCC、TEST、RST和跳线J6的GND,分别连接至主控电路板端子P4对应端口。在对主控电路板进行上电仿真调试时,请务必断开VCC的连接。
3.2 系统配置
对主控MCU进行时钟配置及系统初始化。
往寄存器DCOCTL和BCSCTL1写入DCO (数字控制振荡器) 校正数据,配置数字控制振荡器时钟DCOCLK = 12MHz。
由主控MCU的数据手册知:系统复位后,寄存器BCSCTL2的SELMx = 0、DIVMx = 0,即主系统时钟MCLK = DCOCLK = 12MHz。寄存器BCSCTL2的SELS = 0、DIVSx = 0,即子系统时钟SMCLK = DCOCLK = 12MHz。寄存器BCSCTL1的XTS = 0,配置寄存器BCSCTL3的LFXT1Sx = 2,低频时钟选择为VLOCLK (内部超低功耗低频振荡器时钟),即辅助时钟ACLK = VLOCLK = 12KHz。
#include "config.h"
void CLK_config(void)
{
int i = 0;
BCSCTL1 = CALBC1_12MHZ;
DCOCTL = CALDCO_12MHZ;
BCSCTL2 |= SELM_0 + DIVM_0 + DIVS_0;
BCSCTL3 |= LFXT1S_2;
while((IFG1&OFIFG) != 0)
{
IFG1 &= ~OFIFG;
for(i=0xff; i>0; i--);
}
}
void WDT_init(void)
{
WDTCTL = WDTPW + WDTHOLD;
}
void Port_init(void)
{
P1DIR |= BIT0 + BIT6;
P1OUT &= ~(BIT0 + BIT6);
P1OUT &= ~BIT0;
P1OUT |= BIT6;
}
配置通用串行通信接口 (USCI) ,波特率:9600kbps、8位数据位、1位停止位、不校验。
使能串口USCI_A0接收中断,响应可屏蔽中断。USCI_A0接收中断服务函数中:等待串口数据接收完成后,将标志位UCA0RXIFG清0。若变量USCIA0_Get_Flag = 0 (即蓝牙透传指令解析完毕) ,立即读取串口数据,并置USCIA0_Get_Flag = 1;若变量USCIA0_Get_Flag = 1 (即蓝牙透传指令未解析) ,则不读取串口数据。
#include "USCI.h"
unsigned char USCIA0_Get_Flag;
unsigned char USCIA0_Get_Data;
void UART_init(void)
{
P1DIR &= ~BIT1;
P1DIR |= BIT2;
P1SEL |= BIT1 + BIT2;
P1SEL2 |= BIT1 + BIT2;
UCA0CTL1 |= UCSWRST;
UCA0CTL1 |= UCSSEL_2;
UCA0BR0 = 0xE2;
UCA0BR1 = 0x04;
UCA0MCTL = 0x00;
UCA0CTL1 &= ~UCSWRST;
UC0IE |= UCA0RXIE;
__bis_SR_register(GIE);
}
void UART_SendChar(unsigned char Ch)
{
UCA0TXBUF = Ch;
while((IFG2 & UCA0TXIFG) == 0);
}
unsigned char UART_ReceiveChar(void)
{
unsigned char Ch = 0;
while((IFG2 & UCA0RXIFG) == 0);
IFG2 &= ~UCA0RXIFG;
Ch = UCA0RXBUF;
return Ch;
}
void UART_SendString(unsigned char *str)
{
while(*str != '\0')
{
UART_SendChar(*str);
str++;
}
}
#pragma vector = USCIAB0RX_VECTOR
__interrupt void USCIA0_RX_ISR(void)
{
while((IFG2 & UCA0RXIFG) == 0);
IFG2 &= ~UCA0RXIFG;
if(USCIA0_Get_Flag == 0)
{
USCIA0_Get_Data = UCA0RXBUF;
USCIA0_Get_Flag = 1;
}
}
配置16位定时器 (Timer_A),增计数模式下的复位/置位模式,比较输出。
配置为3路50Hz的PWM输出,2路输出至L298N电机驱动模块的ENA、ENB,1路输出至舵机的控制信号输入端。
#include "Timer_A.h"
#include "config.h"
void PWM_config(void)
{
P2DIR |= BIT0 + BIT1 + BIT3 + BIT5;
P2OUT |= BIT0 + BIT1 + BIT3 + BIT5;
P2DIR |= BIT2 + BIT4;
P2SEL |= BIT2 + BIT4;
P2SEL2 &= ~(BIT2 + BIT4);
TA1CTL |= TASSEL_2 + ID_2 + MC_0 + TACLR;
TA1CCR0 = 60000;
TA1CCTL1 = OUTMOD_7;
TA1CCR1 = 0;
TA1CCTL2 = OUTMOD_7;
TA1CCR2 = 0;
TA1CTL |= MC_1;
P2DIR |= BIT6;
P2SEL |= BIT6;
P2SEL &= ~BIT7;
P2SEL2 &= ~(BIT6 + BIT7);
TA0CTL |= TASSEL_2 + ID_2 + MC_0 + TACLR;
TA0CCTL0 |= CCIE;
TA0CCR0 = 60000;
TA0CCTL1 = OUTMOD_7;
TA0CCR1 = 4500;
TA0CTL |= MC_1;
}
void PWM_Control_1(unsigned int Val)
{
TA1CCR1 = Val;
TA1CCR2 = Val;
TA1CTL |= MC_1;
}
void PWM_Control_0(unsigned int Val)
{
TA0CTL |= MC_0 + TACLR;
TA0CCR1 = Val;
TA0CTL |= MC_1;
}
unsigned char Capture_count = 0;
#pragma vector = TIMER0_A0_VECTOR
__interrupt void TIMER0_A0_ISR(void)
{
if(Capture_count < 50)
{
Capture_count++;
}
else
{
P1OUT ^= BIT0;
P1OUT ^= BIT6;
Capture_count = 0;
}
}
舵机的旋转角度由输入的PWM脉宽控制,周期为20ms (即50Hz),0.5ms - 2.5ms的脉宽电平对应舵机0° - 180°的控制角度,且成线性关系。
直流减速电机的运转速度由输入至ENA、ENB的PWM脉宽控制,周期为20ms (即50Hz);运转方向由IN1、IN2、IN3、IN4的输入电平控制。
控制舵机旋转角度时,逐级输出PWM。配合以电机M1、M2的正转、反转、停止,实现BB8机器人的前进、后退、左转、右转、停止等动作。
void Servo_Angle_Control(unsigned char angle, unsigned char preangle)
{
unsigned char angle_temp;
angle_temp = preangle;
if(preangle < angle)
{
while(angle_temp < angle)
{
angle_temp++;
PWM_Control_0((unsigned int)(1500 + 33.3333333 * angle_temp));
delay_ms(20);
}
}
else if(preangle > angle)
{
while(angle_temp > angle)
{
angle_temp--;
PWM_Control_0((unsigned int)(1500 + 33.3333333 * angle_temp));
delay_ms(20);
}
}
else
{
PWM_Control_0((unsigned int)(1500 + 33.3333333 * angle_temp));
delay_ms(20);
}
}
void Motor_Speed_Control(int vL, int vR)
{
if(vL >= 0 && vR >= 0)
{
IN1_0; IN2_1;
IN3_0; IN4_1;
}
else if(vL >= 0 && vR < 0)
{
IN1_1; IN2_0;
IN3_0; IN4_1;
}
else if(vL < 0 && vR >= 0)
{
IN1_0; IN2_1;
IN3_1; IN4_0;
}
else if(vL < 0 && vR < 0)
{
IN1_1; IN2_0;
IN3_1; IN4_0;
}
if(vL < 0)
{
vL = -vL;
}
vL = (int)((float)vL / 255 * 60000);
PWM_Control_1(vL);
}
3.3 蓝牙透传
对蓝牙透传模块进行参数配置。
将HC05主从一体蓝牙透传模块的TXD、RXD、VCC、GND,分别连接至MSP-EXP430G2 LaunchPad板载仿真器的RXD、TXD、VCC、GND。
蓝牙透传模块上电后长按按键KEY,此时状态指示灯STA慢闪 (1秒闪1次) 。蓝牙透传模块进入AT指令状态,此时波特率固定为9600kbps。在PC端通过串口调试工具,键入相应AT指令完成配置。
3.4 控制逻辑
主控程序通过轮询方式实现对蓝牙透传指令的解析。解析完毕,执行指令完成对应动作。
工程文件内已集成IIC总线、MPU6050加速度计和陀螺仪的驱动程序,及姿态解算算法。可进行相应功能扩展,以优化系统运动姿态。
#include "io430.h"
#include "config.h"
#include "USCI.h"
#include "Timer_A.h"
int main(void)
{
char str[80];
USCIA0_Get_Flag = 0;
USCIA0_Get_Data = 0;
unsigned char CMD = 0;
unsigned char Speed_init = 0;
unsigned char Speed_control = 150;
unsigned char Angle_control = 90;
WDT_init();
CLK_config();
Port_init();
UART_init();
PWM_config();
Servo_Angle_Control(Angle_control, Angle_control);
while(1)
{
if(USCIA0_Get_Flag)
{
CMD = USCIA0_Get_Data;
USCIA0_Get_Flag = 0;
}
else if(CMD == 'v')
{
CMD = 't';
}
else if(CMD == 'h')
{
Speed_control = 240;
CMD = 't';
}
else if(CMD == 'm')
{
Speed_control = 160;
CMD = 't';
}
else if(CMD == 'l')
{
Speed_control = 100;
CMD = 't';
}
else if(CMD == '1')
{
Servo_Angle_Control(110, Angle_control);
Angle_control = 110;
Speed_init = 80;
while(CMD == '1')
{
if(USCIA0_Get_Flag)
{
CMD = USCIA0_Get_Data;
USCIA0_Get_Flag = 0;
}
else if(Speed_init < Speed_control)
{
Speed_init++;
Motor_Speed_Control(Speed_init, Speed_init);
delay_ms(10);
}
else
{
Motor_Speed_Control(Speed_control, Speed_control);
delay_ms(10);
}
}
while(Speed_init > 80)
{
Speed_init--;
Motor_Speed_Control(Speed_init, Speed_init);
delay_ms(10);
}
Servo_Angle_Control(90, Angle_control);
Angle_control = 90;
}
else if(CMD == '2')
{
Motor_Speed_Control(-Speed_control, Speed_control);
delay_ms(10);
}
else if(CMD == '3')
{
Motor_Speed_Control(Speed_control, -Speed_control);
delay_ms(10);
}
else if(CMD == '4')
{
Servo_Angle_Control(70, Angle_control);
Angle_control = 70;
Speed_init = 80;
while(CMD == '4')
{
if(USCIA0_Get_Flag)
{
CMD = USCIA0_Get_Data;
USCIA0_Get_Flag = 0;
}
else if(Speed_init < Speed_control)
{
Speed_init++;
Motor_Speed_Control(-Speed_init, -Speed_init);
delay_ms(10);
}
else
{
Motor_Speed_Control(-Speed_control, -Speed_control);
delay_ms(10);
}
}
while(Speed_init > 80)
{
Speed_init--;
Motor_Speed_Control(-Speed_init, -Speed_init);
delay_ms(10);
}
Servo_Angle_Control(90, Angle_control);
Angle_control = 90;
}
else if(CMD == '5' && Angle_control < 140)
{
Servo_Angle_Control(140, Angle_control);
Angle_control = 140;
}
else if(CMD == '6' && Angle_control > 50)
{
Servo_Angle_Control(50, Angle_control);
Angle_control = 50;
}
else if(CMD == '7')
{
Servo_Angle_Control(90, Angle_control);
Angle_control = 90;
}
else if(CMD == '8')
{
}
else if(CMD == '9')
{
}
else
{
Motor_Speed_Control(0, 0);
delay_ms(10);
}
}
}
3.5 蓝牙连接
BB8机器人的实时控制由手机APP实现,在应用商店搜索蓝牙串口助手下载。
打开APP,设置透传指令并保存。开启手机蓝牙后搜索设备,连接名为BB8_Link的设备 (蓝牙透传模块) 。蓝牙配对连接成功后,蓝牙透传模块上的状态指示灯STA双闪 (1次闪2下,2秒闪1次) 。
3.6 结语
BB8机器人的软件程序链接编译完成后,通过Launchpad板载仿真器烧录至主控电路板。
将主控电路板重启,待各状态指示灯显示正常,即可开启萌物BB8的操控之旅。
你的原力觉醒了吗?
— END —
|