BOXZ mini/zh
概述
材料清单
实验原理机器人小车种类比较多,如循迹,壁障,蓝牙遥控小车,电脑鼠等。但是其行走控制方式基本是一样的,无非就是前后左右四个方向运动。当然结构上会有一定区别,不同功能需要采用不同传感器,本次我们主要使用两轮驱动,通过控制两个轮子的旋转方向,实现前进后退,旋转等功能,当然还要加上万向轮,这样才能保持平衡。 该小车结构简单,主要包括三个方面:车轮、车身、控制系统。 1)车轮采用两个减速电机,扭力大,可PWN调速,控制简单。 2)车身采用亚克力板,大小:8cm*8cm*8cm。 3)整个控制系统包括四个部分:
因为BOXZ体积比较小,所以采用锂电池。
中央处理器是整个小车的核心,就像电脑的CPU,人的大脑,有一定思维能力,能够处理复杂事件。采用Microduino-Core作为核心。
小车采用Microduino-nRF24无线通讯方案,通讯速度响应快,控制范围:空阔地域大约100米。
采用Microduino-Motor直流电机驱动模块,一个模块能够驱动两个电机。同时结合Microduino-Robot底板,将中央处理器和直流电机模块连接起来。 文档调试过程将Microduino Core、Microduino USBTTL堆叠在一起.用数据线将写好的程序通过Microduino USBTTL上传到Microduino Core上。 注意:最好不要将所有模块堆叠在一起之后再上传程序 打开Aroduino IDE,若电脑中没有安装,则参照附录中的安装方法,先安装Aicroduino IDE。点击左上【文件】选项→点击【打开】。 浏览到项目程序地址,点击“Robot_v0.2.ino”程序打开 之后点击左上角的"√"进行编译,点击上边栏的工具,确认板卡(Microduino-Core)处理器(Atmega328P@16M,5V)和端口号(COMX)。三项都如图确认无误之后点击"→"按钮下载程序到开发板上 Joypad操作说明
Joypad开机设置 打开遥控器电源开关,按下复位按键(左边USB接口右边那个)进入系统,请在4S内按下【key1】按键,进入遥控器校准和控制选择模式。 360度最大幅度旋转两个摇杆,遥控板会读入摇杆的位置数据,摇动至示数不再变化即可 选择控制模式,可以通过【key3】按键来选择是控制四轴飞行器(Quad.)还是机器人(Robot),Robot模式可控制自平衡车和BOXZ mini,黑色表示选中。因此我们需要选择Robot模式。还可以通过【key4】按键来选择是否是体感控制模式,如果选择体感模式,你必须叠加Microduino-10DOF模块,选择“MPU ON”。如果是摇杆控制模式,选择“MPU OFF”。 这次搭建没有使用10DOF模块,因此选择MPU OFF模式; 选择完成后,通过【key2】按键退出配置,进入操作 将左上边控制开关打开(拨到上面),才能进行控制,你可以摇动摇杆,观察屏幕的变化 右边开关是幅度调节模式,开关拨到上面可以最大幅度控制Robot,否则只能小幅度控制。如果使用小幅度控制小车,右边摇杆拨到最大位置,小车速度也只能小范围变化,这样有助于稳定控制 当启动小车时,只需要用到右边的摇杆,摇杆的方向和平衡车的方向一致,你可以尝试摇杆控制是否正确。如果发现方向有问题,可以在Robot_v0.2前4行代码更改引脚定义 如果原来的引脚定义如下: 而此时左右旋转反了,可以更改为 如果最开始的引脚是情况2,那么方向错了就改成情况1就可以了。 打开BOXZ_mini小车上Microduino-Robot底板上的电源开关,拨到ON(左边),如果可以看到核心板上的红色led亮,说明供电正常。你可以愉快的玩耍了。
注意问题
小车程序说明#define motor_pin0A 7 //PWM
#define motor_pin0B 5
#define motor_pin1A 8 //PWM
#define motor_pin1B 6
#define FIX_THROTTLE_A 1 //-1 or 1
#define FIX_THROTTLE_B -1 //-1 or 1
#define REVERSE_THROTTLE 1 //-1 or 1
#define REVERSE_STEERING 1 //-1 or 1
#define MAX_THROTTLE 255 //最大油门 100~255
#define MAX_STEERING 200 //最大转向 100~512
//rf=======================================
#include <RF24Network.h>
#include <RF24.h>
#include <SPI.h>
// nRF24L01(+) radio attached using Getting Started board
RF24 radio(9, 10);
RF24Network network(radio);
const uint16_t this_node = 1; //设置本机ID
const uint16_t other_node = 0;
//--------------------------------
struct send_a //发送
{
uint32_t node_ms; //节点运行时间
};
unsigned long last_sent = 0; //定时器
//--------------------------------
struct receive_a //接收
{
uint32_t ms;
uint16_t rf_CH0;
uint16_t rf_CH1;
uint16_t rf_CH2;
uint16_t rf_CH3;
uint16_t rf_CH4;
uint16_t rf_CH5;
uint16_t rf_CH6;
uint16_t rf_CH7;
};
unsigned long clock; //主机运行时间
int tem_xuan = 0; //主机请求时序
//----------------------------
boolean node_STA = false;
float throttle;
float steering;
unsigned long safe_ms = millis();
void setup()
{
Serial.begin(115200);
pinMode(motor_pin0A, OUTPUT);
pinMode(motor_pin0B, OUTPUT);
pinMode(motor_pin1A, OUTPUT);
pinMode(motor_pin1B, OUTPUT);
//nRF==============================
SPI.begin(); //初始化SPI总线
radio.begin();
network.begin(/*channel*/ 70 , /*node address*/ this_node);
Serial.println("===========start===========");
}
int motor_vol[2];
// 主循环//////////////////////////////////////////////////////////////////////////
void loop()
{
//===============================================================
if (nRF(&throttle, &steering))
{
vorobot();
Serial.print(throttle);
Serial.print(",");
Serial.println(steering);
}
//===============================================================
if (safe_ms > millis()) safe_ms = millis();
if (millis() - safe_ms > 2000)
{
steering = 0;
throttle = 0;
digitalWrite(motor_pin0A, LOW);
digitalWrite(motor_pin0B, LOW);
digitalWrite(motor_pin1A, LOW);
digitalWrite(motor_pin1B, LOW);
}
}
void vorobot()
{
/*
if(node_STA)
{
}
*/
//===============================================================
int motor_speed = 0;
motor_speed = REVERSE_THROTTLE * throttle;
motor_vol[0] = motor_speed;
motor_vol[1] = motor_speed;
//----------------------------------
int motor_steer = 0;
motor_steer = REVERSE_STEERING * steering;
motor_vol[0] -= motor_steer / 2;
motor_vol[1] += motor_steer / 2;
for (int a = 0; a < 2; a++)
{
if (motor_vol[a] > MAX_THROTTLE)
{
motor_vol[0] -= (motor_vol[a] - MAX_THROTTLE);
motor_vol[1] -= (motor_vol[a] - MAX_THROTTLE);
}
else if (motor_vol[a] < -MAX_THROTTLE)
{
motor_vol[0] -= (MAX_THROTTLE + motor_vol[a]);
motor_vol[1] -= (MAX_THROTTLE + motor_vol[a]);
}
}
Serial.print(motor_vol[0]);
Serial.print(",");
Serial.print(motor_vol[1]);
Serial.println("");
motor_vol[0] *= FIX_THROTTLE_A;
motor_vol[1] *= FIX_THROTTLE_B;
motor_driver(0, -motor_vol[0]);
motor_driver(1, motor_vol[1]);
}
boolean motor_driver(int _motor_driver_num, int _motor_driver_vol)
{
switch (_motor_driver_num)
{
case 0:
if (_motor_driver_vol == 0)
{
//Serial.println("0 OFF");
digitalWrite(motor_pin0A, LOW);
digitalWrite(motor_pin0B, LOW);
}
else if (_motor_driver_vol > 0)
{
//Serial.println("0 Z");
analogWrite(motor_pin0A, _motor_driver_vol);
digitalWrite(motor_pin0B, LOW);
}
else
{
//Serial.println("0 F");
analogWrite(motor_pin0A, 255 + _motor_driver_vol);
digitalWrite(motor_pin0B, HIGH);
}
break;
case 1:
if (_motor_driver_vol == 0)
{
//Serial.println("1 OFF");
digitalWrite(motor_pin1A, LOW);
digitalWrite(motor_pin1B, LOW);
}
else if (_motor_driver_vol > 0)
{
//Serial.println("1 Z");
analogWrite(motor_pin1A, _motor_driver_vol);
digitalWrite(motor_pin1B, LOW);
}
else
{
//Serial.println("1 F");
analogWrite(motor_pin1A, 255 + _motor_driver_vol);
digitalWrite(motor_pin1B, HIGH);
}
break;
default :
return false;
}
return true;
}
boolean nRF(float * _speed, float * _turn)
{
network.update();
// Is there anything ready for us?
while ( network.available() )
{
// If so, grab it and print it out
RF24NetworkHeader header;
receive_a rec;
network.read(header, &rec, sizeof(rec));
clock = rec.ms; //接收主机运行时间赋值
float * _i = _speed;
_i[0] = map(rec.rf_CH1, 1000, 2000, -MAX_THROTTLE, MAX_THROTTLE);
_i = _turn;
_i[0] = map(rec.rf_CH0, 1000, 2000, -MAX_STEERING, MAX_STEERING);
node_STA = (rec.rf_CH7 > 1500 ? true : false); //接收请求时序赋值
{
//Serial.print("Sending...");
send_a sen = {
millis()
}; //把这些数据发送出去,对应前面的发送数组
RF24NetworkHeader header(0);
boolean ok = network.write(header, &sen, sizeof(sen));
safe_ms = millis();
if (ok)
{
return true;
//Serial.println("ok.");
}
else
{
return false;
//Serial.println("failed.");
}
}
safe_ms = millis();
}
}
Joypad程序说明#include "Arduino.h"
#include "def.h"
#include "time.h"
#include "bat.h"
#if defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega128RFA1__)
#include "mpu.h"
#endif
#include "joy.h"
#include "key.h"
#include "data.h"
#include "nrf.h"
#include "mwc.h"
#include "tft.h"
#include "eep.h"
#if defined(__AVR_ATmega128RFA1__)
#include <ZigduinoRadio.h>
#endif
//joypad================================
#include <Joypad.h>
//eeprom================================
#include <EEPROM.h>
//TFT===================================
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific
#include <SPI.h>
//rf====================================
#include <RF24Network.h>
#include <RF24.h>
#if defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega128RFA1__)
//MPU===================================
#include "Wire.h"
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#endif
//spi===================================
#include <SPI.h>
void setup()
{
// initialize serial communication at 115200 bits per second:
#ifdef Serial_DEBUG
Serial.begin(115200);
delay(100);
Serial.println("========hello========");
#endif
//---------------
key_init();
//---------------
#ifdef Serial_DEBUG
Serial.println("\n\r EEPROM READ...");
#endif
eeprom_read();
//---------------
#ifdef Serial_DEBUG
Serial.println("\n\r TFT INIT...");
#endif
TFT_init(true, tft_rotation);
//---------------
#ifdef Serial_DEBUG
Serial.println("\n\r TFT BEGIN...");
#endif
TIME1 = millis();
while (millis() - TIME1 < interval_TIME1)
{
TFT_begin();
if (!Joypad.readButton(CH_SWITCH_1))
{
#ifdef Serial_DEBUG
Serial.println("\n\rCorrect IN...");
#endif
//---------------
#ifdef Serial_DEBUG
Serial.println("\n\r TFT INIT...");
#endif
TFT_init(false, tft_rotation);
while (1)
{
if (!TFT_config())
break;
}
#ifdef Serial_DEBUG
Serial.println("\n\rCorrect OUT...");
#endif
//---------------
#ifdef Serial_DEBUG
Serial.println("\n\r EEPROM WRITE...");
#endif
eeprom_write();
}
}
//---------------
#ifdef Serial_DEBUG
Serial.println("\n\r TFT CLEAR...");
#endif
TFT_clear();
//---------------
#ifdef Serial_DEBUG
Serial.println("\n\r TFT READY...");
#endif
TFT_ready();
//---------------.l
if (mode_protocol) //Robot
{
SPI.begin(); //初始化SPI总线
radio.begin();
network.begin(/*channel*/ nrf_channal, /*node address*/ this_node);
}
else //QuadCopter
{
unsigned long _channel;
#if !defined(__AVR_ATmega128RFA1__)
switch (mwc_channal)
{
case 0:
_channel = 9600;
break;
case 1:
_channel = 19200;
break;
case 2:
_channel = 38400;
break;
case 3:
_channel = 57600;
break;
case 4:
_channel = 115200;
break;
}
#else if
_channel = mwc_channal;
#endif
mwc_port.begin(_channel);
}
//---------------
#ifdef Serial_DEBUG
Serial.println("===========start===========");
#endif
#if defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega128RFA1__)
if (mode_mpu) initMPU(); //initialize device
#endif
}
void loop()
{
// unsigned long time = millis();
#if defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega128RFA1__)
//MPU--------------------------------
if (mode_mpu)
getMPU();
#endif
//DATA_begin------------------------------
data_begin();
//DATA_send-------------------------------
if (millis() < time2) time2 = millis();
if (millis() - time2 > interval_time2)
{
if (mode_protocol) nrf_send(); //Robot
else data_send(); //QuadCopter
time2 = millis();
}
//节点查错-------------------------------
vodebug();
//BAT--------------------------------
if (time3 > millis()) time3 = millis();
if (millis() - time3 > interval_time3)
{
vobat();
time3 = millis();
}
//TFT------------------------------------
TFT_run();
//===================================
// time = millis() - time;
// Serial.println(time, DEC); //loop time
}
视频 |