如果你要做的机器人有重量限制,在同样的重量下,乐高 EV3 马达比直流马达有更大的扭力。这这一课里,你需要以下的零件:
1.Arduino MEGA 板。
2. 两只 EV3 大马达(需要两只去演示机器人的左拐和右拐功能)
3. 一只 Bricktronics 马达驱动,你可以在以下网站找到他的资料:
某宝也有售
4. 一个电池盒,里面有两只串联的 18650 充电锂电池。每只 18650 电池提供 3.7V 电压(译者按,这里我学生写错了一点点,应该是快没电的时候是 3.7V,满电的时候是 4.2V),Bricktronics 马达驱动只允许 7.2V 到 9.0V 电压。你也可以使用 6只串联 1.5V 5号电池。
按下图安装硬件: (由于没有 Bricktronic 马达驱动的图片,下图的面包板下面就当作是它的接线位置了)
http://www.zephan.top/arduinolessons/lesson5/lesson5.fzz
在以下网址下载 Bricktronics 马达驱动的 Header 档案:
https://github.com/wayneandlayne/BricktronicsMotor
按 "Clone or Download" 按键去下载这个 ZIP 档案。
用以下其中一个方法安装这个 ZIP 档案:
1. 如果你是使用 Arduino 官方 IDE,选择 "Project" -> "Libraries" -> "Install a zip library",或者:
2. 如果你使用 Visual Studio 作为 IDE,选择 "Add Library" -> "Install Arduino Libarary from ZIP file"
拷贝以下程序到相关档案里:
// ROBOTH.h
// We declare all variables(properties) and functions(methods) of the ROBOT object inside this header file
#ifndef _ROBOTH_h
#define _ROBOTH_h
#include "Arduino.h"
// Class for MOTOR
class MOTOR
{
public:
// Motor Type:
// "D" - DC Motor
// "E" - EV3 Motor
String gstrMotorType = "";
// bolVSpeed = true means: Use analogWrite(pin, value) to enable setting the speed of the DC motor
// On Arduino UNO, the following PINs support analogWrite: 3, 5, 6, 9, 10, 11
// On Arduino MEGA, the following PINS support analogWrite: 2-13, 44-46
// If all PINS support analogWrite are occupied, turn gbolVSpeed = false, which means that the Motor will run in FULL speed.
bool gbolVSpeed = true;
// Direction of the Motor, 1 or -1
int gintDir = 1;
// PIN No. for Input PIN 1
int gintInput1PIN = 0;
// PIN No. for Input PIN 2
int gintInput2PIN = 0;
// Initialize a Motor
void Init(int intMotorNo, String strMotorType, bool bolVSpeed, int intDir, int intInput1PIN, int intInput2PIN);
// Move a Motor
void Move(int intMotorNo, int intDir, int intSpeed);
// Stop a Motor
void Stop(int intMotorNo);
};
// Class for ROBOT
class ROBOT
{
public:
// Part A - Public vars
// A.1 LED Related vars
// Total No. of LED
int gintNoOfLED = 0;
// Pin No. of the LEDs, a Maximum of 10 LED is allowed
int garyLED[10];
// A.11 Motor Related vars
// Total No. of Motor, 0 - 10
int gintNoOfMotor = 0;
// Type of Each Motor
// "D" = DC Motor
// "S" = Step Motor
// "V" = Servo Motor
// "E" = EV3 Motor
String gaMotorType[10];
// Allow vary speed for each Motor
bool gaBolVSpeed[10];
// Direction for each Motor
int gaMDir[10];
// Input X PIN for each Motor
int gaInput1PIN[10];
int gaInput2PIN[10];
// Set Left / Right for each motor
// "L" - means this motor use in turn Left
// "R" - means this motor use in turn right
// "N" - means this is a special purpose motor, it is not connected to a wheel, and won't be used to turn left / turn right / MoveForward / MoveBackward the vehicle.
String gaLRN[10];
// Motor Object
MOTOR gaM[10];
// Part B - Init
void Init();
// Part C - Functions
// C1 - LED Related functions
// Turn On an LED
void LEDOn(int intLedNo);
// Turn Off an LED
void LEDOff(int intLedNo);
// C11 - Motor Related functions
// Move a Single Motor
// intDir: 1 or -1
// intSpeed: 0 to 255
void Move(int intMotorNo, int intDir, int intSpeed);
// Stop a Single Motor
void Stop(int intMotorNo);
// Move Robot
// MoveRobot only move motors with gaLRN = L or R
// floPowerL / floPowerR: -1.0 to 1.0, % of speed of the L/R wheel, if those wheels support variable speed, i.e. gbolVSpeed = true
// for example:
// floPowerL = 1, floPowerR = 1 means: Move Forward at full speed
// floPowerL = 1, floPowerR = -1 means: Left Wheel go forward at full speed, Right Wheel go backward at full speed, i.e. Turn Right at full speed.
// floPowerL = 1, floPowerR = 0.5 means: Left Wheel go forward at full speed, Right Wheel go forward at half speed, i.e. Go Forward And Right at the same time.
void MoveRobot(float floPowerL, float floPowerR);
// Stop Robot
void StopRobot();
private:
// Part D - Private Functions
// D1 - LED Related Private Functions
// Init. LED
void InitLED();
// D11 - Motor Related Private Functions
// Init. Motor
void InitMotor();
};
#endif
http://www.zephan.top/arduinolessons/lesson5/ROBOTH.h
以上是 ROBOTH.h
#include "ROBOTH.h"
#include "Arduino.h"
// Update the five pin assignments in the constructor below.
// The arguments are: enPin, dirPin, pwmPin, encoderPin1, encoderPin2
// There are a few considerations for pin assignments:
// A. pwmPin needs to be a pin with PWM capabilities (that is, it supports analogWrite)
// Uno: pins 3, 5, 6, 9, 10, and 11
// Mega 2560: pins 2 - 13 and 44 - 46
// B. There are three ways to connect the encoder pins (labeled T1/T2 on the board).
// ** Best performance: Both signals are connected to true interrupt pins (listed below).
// ** Good performance: The FIRST signal (T1) is connected to an interrupt pin, the second signal is a regular pin. This is the mode used for the Bricktronics Shield/Megashield. For this mode it is CRITICAL that the true interrupt pin is used for T1 and not T2.
// ** Low performance: Both signals are connected to non-interrupt pins.
// Regardless of which performance mode used, you MUST list the pin T1 before T2 in
// the constructor, otherwise the encoder will be connected backwards and the
// PID algorithm will get all confused and freak out.
// Location of true interrupt pins:
// Uno: pins 2 and 3
// Mega 2560: pins 2, 3, 21, 20, 19, and 18
// Since there are only 6 true interrupt pins, use Good Performance if there are 4 motors
// Bugs for a particular Arduino Mega 2560
// If mB use 34 as Dir pin and mC use 35 as Dir pin, mB always turn in same direction!!!!!
BricktronicsMotor BM[4] = {BricktronicsMotor(32, 38, 44, 2, 3), BricktronicsMotor(33, 35, 45, 20, 21), BricktronicsMotor(32, 38, 44, 2, 3), BricktronicsMotor(32, 38, 44, 2, 3)};
// Init Motor
void MOTOR::Init(int intMotorNo, String strMotorType, bool bolVSpeed, int intDir, int intInput1PIN, int intInput2PIN) {
gstrMotorType = strMotorType;
gbolVSpeed = bolVSpeed;
gintDir = intDir;
gintInput1PIN = intInput1PIN;
gintInput2PIN = intInput2PIN;
if (strMotorType == "D") {
// Set Pins Output
pinMode(gintInput1PIN, OUTPUT);
pinMode(gintInput2PIN, OUTPUT);
}
else if (strMotorType == "E") {
BM[intMotorNo - 1].begin();
}
}
// Motor.Move
void MOTOR::Move(int intMotorNo, int intDir, int intSpeed) {
// Calculate Final Direction of this Motor
int intFinalDir = gintDir * intDir;
if (gstrMotorType == "D") {
// Move for DC Motor
// Reset Speed if needed, since allowed value = 0 - 255
if (intSpeed < 0) {
intSpeed = 0 - intSpeed;
}
if (intSpeed > 255) {
intSpeed = 255;
}
// Move Motor
if (gbolVSpeed) {
// Allow Different Speed
if (intFinalDir == 1) {
analogWrite(gintInput1PIN, intSpeed);
digitalWrite(gintInput2PIN, LOW);
}
else {
digitalWrite(gintInput1PIN, LOW);
analogWrite(gintInput2PIN, intSpeed);
}
}
else {
// Use Maximum Speed;
if (intFinalDir == 1) {
digitalWrite(gintInput1PIN, HIGH);
digitalWrite(gintInput2PIN, LOW);
}
else {
digitalWrite(gintInput1PIN, LOW);
digitalWrite(gintInput2PIN, HIGH);
}
}
}
else if (gstrMotorType == "S") {
// Move for Step Motor
}
else if (gstrMotorType == "V") {
// Move for Servo Motor
}
else if (gstrMotorType == "E") {
// Move for EV3 Motor
BM[intMotorNo-1].setFixedDrive(int(intSpeed * intFinalDir));
}
}
// Motor.Stop
void MOTOR::Stop(int intMotorNo) {
if (gstrMotorType == "D") {
// Stop for DC Motor
digitalWrite(gintInput1PIN, LOW);
digitalWrite(gintInput2PIN, LOW);
}
else if (gstrMotorType == "S") {
// Move for Step Motor
}
else if (gstrMotorType == "V") {
// Move for Servo Motor
}
else if (gstrMotorType == "E") {
// Move for EV3 Motor
BM[intMotorNo - 1].brake();
}
}
// Init Robot
void ROBOT::Init() {
// Init LED, if any
InitLED();
// Init Motor
InitMotor();
}
// Init LED, if any
void ROBOT::InitLED() {
for (int i = 1; i <= gintNoOfLED; i++) {
pinMode(garyLED[i - 1], OUTPUT);
};
}
// Init Motor, if any
void ROBOT::InitMotor() {
for (int i = 1; i <= gintNoOfMotor; i++) {
if (gaMotorType[i - 1] == "D") {
// Init DC Motor
gaM[i - 1].Init(i, gaMotorType[i - 1], gaBolVSpeed[i - 1], gaMDir[i - 1], gaInput1PIN[i - 1], gaInput2PIN[i - 1]);
}
else if (gaMotorType[i - 1] == "E") {
gaM[i - 1].Init(i, gaMotorType[i - 1], gaBolVSpeed[i - 1], gaMDir[i - 1], gaInput1PIN[i - 1], gaInput2PIN[i - 1]);
}
};
}
// LED Related functions
// LED On
void ROBOT::LEDOn(int intLedNo) {
digitalWrite(garyLED[intLedNo - 1], HIGH);
}
// LED Off
void ROBOT::LEDOff(int intLedNo) {
digitalWrite(garyLED[intLedNo - 1], LOW);
}
// Motor Related functions
// Move a Single Motor
void ROBOT::Move(int intMotorNo, int intDir, int intSpeed) {
gaM[intMotorNo - 1].Move(intMotorNo, intDir, intSpeed);
}
// Stop a Single Motor
void ROBOT::Stop(int intMotorNo) {
gaM[intMotorNo - 1].Stop(intMotorNo);
}
void ROBOT::MoveRobot(float floPowerL, float floPowerR) {
int intSpeedL = abs((int)(255 * floPowerL));
int intSpeedR = abs((int)(255 * floPowerR));
int intDirL;
int intDirR;
if (floPowerL > 0)
intDirL = 1;
else
intDirL = -1;
if (floPowerR > 0)
intDirR = 1;
else
intDirR = -1;
for (int i = 1; i <= gintNoOfMotor; i++) {
if (gaLRN[i - 1] == "L") {
gaM[i - 1].Move(i, intDirL, intSpeedL);
}
else if (gaLRN[i - 1] == "R") {
gaM[i - 1].Move(i, intDirR, intSpeedR);
}
}
}
void ROBOT::StopRobot() {
for (int i = 1; i <= gintNoOfMotor; i++) {
if (gaLRN[i - 1] == "L" || gaLRN[i - 1] == "R") {
gaM[i - 1].Stop(i);
}
}
}
http://www.zephan.top/arduinolessons/lesson5/ROBOTH.cpp
以上是 ROBOTH.cpp
/*
Name: lesson5.ino
Created: 11/27/2017 8:39:28 PM
Author: Administrator
*/
// the setup function runs once when you press reset or power the board
#include "ROBOTH.h"
// Declare the ROBOT rbt1
ROBOT rbt1;
void setup() {
// Set vars for LED
// Set the no. of LED in this robot, if any
rbt1.gintNoOfLED = 0;
// Set the PIN numbers of those LEDs, if any
// rbt1.garyLED[0] = 13;
// Set vars for Motor
// Set No. of Motor
rbt1.gintNoOfMotor = 2;
// Set Motor Type for each Motor
// "D" for DC Motor
// "E" for EV3 Motor
rbt1.gaMotorType[0] = "E";
rbt1.gaMotorType[1] = "E";
// Set Vary Speed for each Motor
rbt1.gaBolVSpeed[0] = false;
rbt1.gaBolVSpeed[1] = false;
// Set Direction for each Motor
// If the direction of the Motor is not as expected, turn that value to -1
rbt1.gaMDir[0] = -1;
rbt1.gaMDir[1] = -1;
// Set Input PINs for each DC Motor
// For EV3 Motor, Set PINS in ROBOTH.cpp
//rbt1.gaInput1PIN[0] = 32;
//rbt1.gaInput2PIN[0] = 38;
//rbt1.gaInput1PIN[1] = 33;
//rbt1.gaInput2PIN[1] = 35;
// Set which motor(s) for turn left/right/forward/backward
rbt1.gaLRN[0] = "L";
rbt1.gaLRN[1] = "R";
// Init Robot
rbt1.Init();
}
// the loop function runs over and over again until power down or reset
void loop() {
// Both Motor Move forward
rbt1.Move(1, 1, 128);
rbt1.Move(2, 1, 128);
// For 1 second
delay(1000);
// Both Motor Stop
rbt1.Stop(1);
rbt1.Stop(2);
// For 1 second
delay(1000);
// Both Motor Move backward
rbt1.Move(1, -1, 128);
rbt1.Move(2, -1, 128);
// For 1 second
delay(1000);
// Both Motor Stop
rbt1.Stop(1);
rbt1.Stop(2);
// For 1 second
delay(1000);
// Robot Move Forward
rbt1.MoveRobot(1.0, 1.0);
// For 1 second
delay(1000);
// Robot Stop
rbt1.StopRobot();
// For 1 second
delay(1000);
// Robot Move Backward
rbt1.MoveRobot(-1.0, -1.0);
// For 1 second
delay(1000);
// Robot Stop
rbt1.StopRobot();
// For 1 second
delay(1000);
// Robot Turn Left at full speed
rbt1.MoveRobot(-1.0, 1.0);
// For 1 second
delay(1000);
// Robot Stop
rbt1.StopRobot();
// For 1 second
delay(1000);
// Robot Turn Right at half speed
rbt1.MoveRobot(0.5, -0.5);
// For 1 second
delay(1000);
// Robot Stop
rbt1.StopRobot();
// For 1 second
delay(1000);
}
http://www.zephan.top/arduinolessons/lesson5/lesson5.ino
以上是 lesson5.ino
编译并上传这个项目到 Arduino,你应该可以看到马达会按 loop() 里写的要求运动。
源代码已经自我解释了,你需要逐行的去看源代码,并且留意注释。
注意:【BricktronicsMotor】类有一个构建器,这让我们无法在 ROBOTH.h 里面去声明它,只能在 ROBOTH.cpp 里面使用这个构建器去设置它的对应 PINS。导致我们的源代码并不能完全按照【面向对象】的编程方式!
I2S(Inter—IC Sound)总线, 又称集成电路内置音频总线,是飞利浦公司为数字音频设备之间的音频数据传输而制定的一种总线标准。
Queue 库提供了一个通用的 C++ 动态队列实现,专为在 Arduino 项目中使用而定制。
本程序是小鹏物联网智能浇花套件的单机版程序(不连接物联网),供同学们参考。
ArrayList 类是一个 C++ 模板类,它提供了 ArrayList 的实现,以便轻松存储任何指定类型的值。它允许使用索引进行高效存储和检索,支持排序操作。
ESP32系列(包括ESP32-S3)搭载Xtensa双核处理器,默认情况下Arduino框架仅使用单核运行用户代码,通过多核编程,可以充分利用硬件资源来提升系统响应和性能。
在本文中,先解释 MSB(最高有效位)和 LSB(最低有效位)的概念,以及 MSBFIRST 和 LSBFIRST。然后展示了 MSBFIRST 和 LSBFIRST 的使用如何影响移位寄存器的输出。
TB6612是一款双路H桥型的直流电机驱动芯片,可以驱动两个直流电机并且控制其转速与方向,输入电压在3V~12V,因此在集成化、小型化的电机控制系统中,它可以作为理想的电机驱动器件。
Arduino-ESP32项目提供的Preferences库是一个专为ESP32设计的非易失性存储解决方案,它替代了传统的Arduino EEPROM库,提供了更强大、更可靠的数据存储功能。
本文介绍如何在Scratch中对EV3机器人进行开发。
在Arduino中,通过串行端口接收数字通常涉及使用Serial.read()、Serial.readString()、Serial.parseInt()等方法。