fullmous 发表于 2016-3-20 22:01:24

介绍一款蓝牙遥控的小车机器人、制作与套材


   这是一款廉价的,易制作的,可供中小学兴趣班、课后活动班以及青少年电子技师活动采用的;单片机控制,蓝牙遥控的机器人小车套材。 套材为散件形式,青少年可以从电子元器件的焊接学起。通过安装调试最后参赛整个过程锻炼动手能力,创新能力;而且充满知趣。 涉及单片机的事就离不开编程。但计算机程序对大多是人学起来较难。本套材将程序已调试好,并已下载,所以无需卖家任何操作。小车的运行参数修改都通过手机蓝牙完成, 是互动性很强的,非常现代的一款电子科普器材。 小车采用了本人持有的实用新型专利的直流电机驱动方案,主要特点是直接使用直流电机,而无须变速齿轮箱,不用传统的轮子。其结果是大大降低了整机的成本。 电机由PWM信号驱动,优点是小车运行平滑,特别是转弯的动作;避免了简单驱动方式的扭动。其弧度可以通过调节两个电机的PWM参数,使其具有不同的转速, 从而向某一方向偏转。这种驱动方式的动力来自电机轴与地面的摩擦力。实践证明,在一般的平整、坚实地面上(没有沟棱),小车可以跑的很快。 这款套材将从动手能力,单片机知识,机器人互动性以及竞赛等多方面给青少年以培养。    
特点:
硬件结构
    采用独特的电机直接驱动方式。
软件结构
    串口接收使用中断方式;
    采用软件PWM控制电机转速,软件PWM由定时器2定时中断产生;
    因为Arduino除了两个外部中断,其他中断功能都没有提供,以上中断都是标准avrgcc的写法。其实,所有的Arduino不具备的能力都可以通过这种方式获得。


详情请登录:www.machmouse.com

xinhoujue 发表于 2016-3-21 20:19:52

广告!!!!!!鉴定完毕!!!!!

fullmous 发表于 2016-3-21 20:25:57

//蓝牙遥控小车
//Arduino 源程序
//定稿日期:2016-3-16
//程序功能简介:
//程序采用软件PWM方式,控制两支直流电机的运行行为,实现直行、后退、左转和右转动作。
//操作者使用Android手机的蓝牙功能发出指令,操控小车动作。
//操作者还通过蓝牙对小车的动作参数进行调试。
//使用自定义串口收发数据
//使用软件PWM,输出引脚可任意制定
//使用Atmega48芯片
//Arduio 版本1.0.5
#include <avr/io.h>
#include <avr/interrupt.h>
#include <EEPROM.h>
#include "usart.h"

unsigned int counter;   //PWM计数器
unsigned char wCnt = 0; //接收字计数
unsigned int pwm_LH;    //左电机高电平计数
unsigned int pwm_RH;    //右电机高电平计数
unsigned char lDirect;//左电机运转方向
unsigned char rDirect;//右电机运转方向
unsigned int LP = 0;
unsigned int RP = 0;
unsigned int LD = 0;
unsigned int RD = 0;

unsigned int PWM;        //存放当前PWM参数的整数型数组,全局变量

unsigned char inputString;         // 存输入数据字符串变量
boolean stringComplete = false;// 数据串结束标志

//定时器2初始化函数
void timer2_init()
{
cli();
TCCR2B = 0x00; //
TCNT2 = 0xF6; //
TCCR2A = 0x00;
TCCR2B = 0x02; //
TIMSK2 = 0x01; //定时器2中断允许
sei();
}


//定时器2中断服务函数
//PWM波形产生器
ISR(TIMER2_OVF_vect)
{
TCNT2 = 0xF6; //
counter++;
if (counter == 0x3ff)
{
    if (rDirect == 1)
      bitSet(PORTD,5);
    else
      bitSet(PORTD,4);

    if (lDirect == 1)
      bitSet(PORTD,7);
    else
      bitSet(PORTD,6);
    counter = 0;
}
if (counter == pwm_RH)
{
    bitClear(PORTD,4);
    bitClear(PORTD,5);
}
if (counter == pwm_LH)
{
    bitClear(PORTD,6);
    bitClear(PORTD,7);
}

}
//电机运行函数
void Move(unsigned int LS,unsigned char LD,unsigned int RS,unsigned char RD)
{            
asm("BCLR 7");//关中断
pwm_LH = LS;
pwm_RH = RS;
lDirect = LD;
rDirect = RD;
asm("BSET 7");//开中断       
}

//获取EEPROM数据函数
//功能:从EEPROM里顺序读出六个PWM参数,存入PWM数组
void GetData()
{
unsigned char bytes;        //暂时存放PWM参数的字节数组,全局变量
unsigned char i;
unsigned char j;
unsigned char k;
for (i = 0;i < 6;i++)                        //for 循环,读六个参数
{
    for (j = 0;j < 2;j++)                //内循环,每次读两个字节
    {
      k = i * 2 + 1 - j;                //地址计算
      bytes = EEPROM.read(k);        //EEPROM读操作
    }
    PWM = word(bytes, bytes);        //将读出的两个字节合成一个PWM整数数据
}
}

//数据发送函数
//功能:将一个整数拆分成四个ASCII代码,通过蓝牙串口发出的函数。
//例如:整数784,将拆分成;' ','7','8','4'四个字符
void Number(int val)
{
int tmp;                //中间变量
unsigned char i;                //循环计数变量
unsigned char buf;                //存字符数组

tmp = val / 1000;
buf = tmp + 0x30;        //获得千位

val = val % 1000;
tmp = val / 100;
buf = tmp + 0x30;        //获得百位

val = val % 100;
tmp = val / 10;
buf = tmp + 0x30;        //获得十位

val = val % 10;
buf = val + 0x30;        //获得个位

for (i = 0;i < 4;i++)
{
    if (buf == 0x30)        //从高位整理,如果是0,则转换成空格。
      buf = 0x20;
    else
      break;
}
Usart_Transmit(buf);      //通过蓝牙串口连续发出四个字符。
Usart_Transmit(buf);
Usart_Transmit(buf);
Usart_Transmit(buf);
}


void setup() {
timer2_init();
Usart_Init(9600);
sei();
PORTD = 0x00;
DDRD= 0xF0;
GetData();    //初始化PWM参数
}



void loop() {

unsigned char buf;                //存连续字符的数组
unsigned char index = 0;        //存索引值变量
unsigned char i;
unsigned char k;
unsigned int para;                //存PWM数据变量
delay(500);
if (stringComplete == true)   //分解手机传过来的参数
{                              //格式是:#n%dddd
    k = 0;                      //其中:n 为索引(地址);dddd 为数据
    index = 0;
    for (i = 0;i <= wCnt ;i++)
    {
      if (inputString == '%')
      {
      index = inputString - 0x30;//获得索引
      k = 0;
      }
      else
      {
      buf = inputString - 0x30;//获得数据
      k++;
      }
    }
    para = 0;
    for (i = 0;i < k-1;i++)
      para = para * 10 + buf;

    PWM = para;        //将得到的整数参数立即存入对应的PWM数组单元,修改当前运行参数
    buf = lowByte(para);   //将整数转换成两个字节。
    buf = highByte(para);
    index = index * 2;                //计算EEPROM地址
    EEPROM.write(index, buf);//写入EEPROM低位在前
    index++;
    EEPROM.write(index, buf);//高位在后

    stringComplete = false;
    wCnt = 0;
}
}


ISR(USART_RX_vect)
{
unsigned char command=0;
int i;
command = UDR0;             //接收数据
inputString = command;
wCnt++;
if (command == 13) {
    stringComplete = true;
    wCnt--;
}
else if (command == 10)
{
    stringComplete = false;
    wCnt = 0;
}
switch (command) {
case '@':
    GetData();        //从EEPROM中读出数据
    for (i = 0;i < 6;i++)
    {
      Number(PWM);        //通过蓝牙回传,Android手机上会有显示
    }
    wCnt = 0;
    break;
case '#':            //得到手机发回的修改参数数据
    break;
case'w' :   // 接收到 'w',前进
    LP = PWM;
    RP = PWM;
    LD = 1;
    RD = 1;
    wCnt = 0;
    break;
case'x' :   // 接收到 'x',后退
    LP = PWM;
    RP = PWM;
    LD = 0;
    RD = 0;
    wCnt = 0;
    break;
case'a' :   // 接收到 'a',左转
    LP = PWM;
    RP = PWM;
    LD = 0;
    RD = 1;
    wCnt = 0;
    break;
case'd' :   // 接收到 'd',右转
    LP = PWM;
    RP = PWM;
    LD = 1;
    RD = 0;
    wCnt = 0;
    break;
case's' :   // 接收到 's',停止电机
    LP = 0;
    RP = 0;
    LD = 1;
    RD = 1;
    wCnt = 0;
    break;
default:
    LP = 0;
    RP = 0;
    LD = 1;
    RD = 1;
}
Move(LP,LD,RP,RD);
}


此为蓝牙小车的源程序,Android App 也是自己开发,跟帖提问随问随答。
页: [1]
查看完整版本: 介绍一款蓝牙遥控的小车机器人、制作与套材