女人自慰AV免费观看内涵网,日韩国产剧情在线观看网址,神马电影网特片网,最新一级电影欧美,在线观看亚洲欧美日韩,黄色视频在线播放免费观看,ABO涨奶期羡澄,第一导航fulione,美女主播操b

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

自平衡機器人的制作教程

454398 ? 來源:工程師吳畏 ? 2019-08-23 09:15 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

第1步:理論

自平衡機器人的制作教程

自平衡機器人的問題是倒立擺的問題。為了抵消機器人向前或向后下落的力,我們需要一種機制,使其重心直接保持在其樞轉(zhuǎn)點的上方。這個樞軸點將是我們的輪軸。我們的反作用策略將通過驅(qū)動機器人的車輪沿其下降的方向進行。

然而,問題是停在那里。如果我們有一個簡單的反饋回路來檢查機器人正朝著哪個方向下降并沿著那個方向驅(qū)動車輪,那么我們的機器人將會固有地振蕩并崩潰。

因此我們的戰(zhàn)略將涉及實施PID控制器來驅(qū)動車輪以受控的數(shù)學(xué)方式來回,響應(yīng)機器人下落的方向,它下降的速度,到目前為止傾斜的量,以及所有這三個變量之間的關(guān)系。

有關(guān)如何實現(xiàn)的細節(jié)將在本教程的PID部分進一步說明。

步驟2:構(gòu)建軸和控制中心的Chasis

機箱:

將膠合板切成3塊,每塊寬9厘米,長14.5厘米,這些將成為機器人底盤的三個平臺。

在每個平臺的角落鉆6mm孔,距離邊緣10mm(見圖)。

標(biāo)記三個平臺:頂部,中部和底部。

在頂級平臺上鉆出Arduino Uno和L298N驅(qū)動板的孔。

測量中間平臺的中心點,并標(biāo)出小型面包板的區(qū)域以及用于連接器的位置(參見圖表)。

安裝在底部平臺上的電機的鉆孔,以及電機上的電線孔(見圖)。

將M6螺紋桿切成四個25厘米的小塊。

將每個部件滑入平臺的相應(yīng)孔中,用M6墊圈和M6螺母固定每個孔的兩側(cè)。

您的平臺應(yīng)相距約9厘米,剩余長度應(yīng)從頂部平臺伸出。

測量每個平臺的傾斜角度,并調(diào)整每個螺母,使其全部與地面齊平。

縱向切割其中一個廚房海綿,并將每個橡膠到頂部平臺的兩半作為保險杠。此步驟僅用于測試。

軸:

在您的中心鉆一個6毫米的洞車輪。

將30毫米M6螺紋桿滑入孔中。用M6墊圈和M6螺母固定外端,并用另一個M6螺母固定內(nèi)端。

將聯(lián)軸器安裝到M6螺紋桿的內(nèi)端,并擰緊固定螺釘將其固定到位。

耦合器的開口端連接到電機軸上,并擰緊固定螺釘將其固定到位。確保兩個輪子與電機本身的距離相同。

從卷筒上切下兩根40厘米長的電源線,然后將它們焊接到電機的端子上。

拿起5毫米木螺釘,按照底盤構(gòu)造階段制作的導(dǎo)孔,將電機連接到底部平臺。

將電機穿過底部平臺的中心孔。

控制中心:

下載本節(jié)頂部的dxf文件(bug lounge cut file.dxf)。

激光切割出2mm有機玻璃的文件。

根據(jù)本節(jié)頂部的圖表組裝零件。

將廚房海綿放在底部平臺上(如果需要,可以用膠水或雙層膠帶)。

將控制中心放在海綿上。

擠壓海綿,將兩塊小木塊(約15x15毫米)放在控制中心和中間平臺之間。它是一種易于拆卸的方式來放入和放出我們的控制箱。我們在上面的圖片上實現(xiàn)。

第3步:構(gòu)建電路

電機驅(qū)動器

L298N的使能引腳用于控制使用PWM(脈沖寬度調(diào)制)的電機速度,而驅(qū)動器的In1-4引腳用于切換電機的方向。以下是描述本節(jié)頂部Fritzing圖的說明。

將L298N的EnA引腳連接到Arduino的數(shù)字引腳6.

將In1引腳連接到數(shù)字引腳5,將In2引腳連接到數(shù)字引腳3.

將L298N的EnB引腳連接到Arduino的數(shù)字引腳11.

將In3引腳連接到數(shù)字引腳13,將In4引腳連接到數(shù)字引腳12.

取下5V_EN跳線,以便為Arduino提供驅(qū)動器的電源。

將5V螺絲端子從L298N連接到Arduino的Vin引腳。

將其中一個電機的正負電源線連接到MotorA螺絲端子。

將其他電機的正負電源線連接到MotorB螺絲端子。

切掉另一根電源線,將紅線連接到L298N的VMS引腳,黑線連接到L298N的GND引腳。紅線的另一端應(yīng)連接到Wago連接器。

將螺絲端子放在迷你面包板的末端。

切掉另一根電源線并將其連接到母筒插孔。然后紅色端應(yīng)連接到Wago連接器,以完成電路一直到L298N的VMS引腳,而黑色端將進入我們之前放入迷你面包板的螺絲端子。

將Arduino的GND引腳連接到與迷你面包板中的母筒插孔相同的線路中。這將確保我們的系統(tǒng)基礎(chǔ)全部連接。

在迷你面包板上放置另一個螺絲端子,將我們之前放入L298N的GND引腳的另一端連接到此端子。確保它也連接到我們在上一步中建立的地線。我們的接地電路現(xiàn)在應(yīng)該完整了。 (如果這部分令人困惑,請查看圖像。)

BNO055絕對定向傳感器

BNO055是一款9自由度傳感器。它將來自加速度計,陀螺儀和磁力計的數(shù)據(jù)融合到絕對3D方向。 BNO055使用I2C通信,因此我們將它連接到Arduino Uno的A5和A4引腳。這將根據(jù)您選擇使用的Arduino的類型而改變。

將標(biāo)題條焊接到IMU的分線板中。

將IMU放在迷你面包板上。

使用跨接電纜將Arduino的5V引腳連接到迷你面包板。

將IMU的Vin引腳與來自迷你面包板上的Arduino的5V電纜串聯(lián)。

將IMU的GND引腳與來自迷你面包板上的Arduino的GND引腳串聯(lián)。

用更長的跨接電纜將其從IMU的SCL引腳連接到Arduino的A5引腳(它兼作SCL引腳)。

再用一根長跨接電纜將其從IMU的SDA引腳連接到Arduino的A4引腳(兼作SDA引腳)。

HC-SR04超聲波傳感器

HC-SR04傳感器是超聲波測距模塊,提供2cm至400cm的測量功能,精度為3mm。它的工作原理是發(fā)送脈沖,并檢測接收脈沖所需的時間。通過該脈沖測量的距離可以分解為一個簡單的等式:距離=(高水平時間*聲速)/2

將HC-SR04的VCC引腳與來自迷你面包板上的Arduino的5V電纜串聯(lián)。

將HC-SR04的GND引腳與來自迷你面包板上Arduino的GND電纜串聯(lián)。

將HC-SR04的Trig引腳連接到Arduino的Digital 4引腳。

將HC-SR04的Echo引腳連接到Arduino的Digital 2引腳。

使用第二個HC-SR04重復(fù)步驟1到4,但這次使用數(shù)字引腳7作為Trig,數(shù)字引腳8作為Echo。

電源

O 你的電機需要12V和每個約2安培,所以我們將使用外部電源來提供這種電力。 arduino本身將由電機驅(qū)動器的5V輸出供電。

切出5米來自電源線軸的長鏈。

剝?nèi)蓚?cè)的兩端。將電源螺絲端子的另一端連接到另一端。

裝配

將電子裝配到機箱很簡單。只需按照您在機箱構(gòu)造步驟中制作的導(dǎo)孔即可。

使用5mm木螺釘并使用塑料上的安裝孔將Arduino連接到頂部平臺案件。

取7mm墊片,將它們放在L298N電機驅(qū)動器下方,然后將M4螺栓穿過安裝孔并穿過墊片。

迷你面包板下面應(yīng)該有一塊雙面膠帶。取下此貼片的覆蓋物,將迷你面包板粘在中間平臺的中央。確保IMU位于平臺的中心,您可能需要調(diào)整面包板才能這樣做。

取另一塊雙面膠帶,將Wago連接器連接到中間平臺的邊緣。

使用扎帶將陰筒固定在其中一根螺桿上。

出于測試目的,將清潔海綿切成兩半并將每一半連接到頂部平臺的兩側(cè),使用橡皮筋將其固定到位。您可以在機器人獨立后立即將其移除,但在此之前,這將使我們的電子設(shè)備免受損壞。

第4步:編碼:設(shè)置怪物類

為了以一種易于被其他開發(fā)者構(gòu)建的方式編程我們的Monster,我們將它作為一個類實現(xiàn)/圖書館。一個類由頭文件(.h)和源文件(.cpp)組成。頭文件定義了類中的所有內(nèi)容,而源文件包含實際的代碼實現(xiàn)。

我們將從頭文件開始:

#ifndef Monstro_h

#define Monstro_h

#include “Arduino.h”

class Monstro {

public:

Monstro(int leftForward, int leftBackward, int leftSpeedPin,

int rightForward, int rightBackward, int rightSpeedPin,

int trigA, int echoA, int trigB, int echoB);

// Behavior

bool Update();

void Initialize();

private:

};

#endif

我們在這里所做的就是設(shè)置帶有構(gòu)造函數(shù)的頭文件,該構(gòu)造函數(shù)接收我們將用于與我們的傳感器和驅(qū)動程序交互的引腳。稍后我們將在介紹每個組成部分時添加此內(nèi)容。

#include Arduino.h語句只是確保我們可以訪問Arduino語言提供的常量和類型。

我們將使用Update()函數(shù)在主循環(huán)期間調(diào)用某些行為,并且Initialize()函數(shù)確保我們的傳感器和電機準(zhǔn)備就緒。在后面的步驟中有更多相關(guān)內(nèi)容。

我們的源文件將反映此頭文件:

#include “Arduino.h”

#include “monstro.h”

Monstro::Monstro(int leftForward, int leftBackward, int leftSpeedPin,

int rightForward, int rightBackward, int rightSpeedPin,

int trigA, int echoA, int trigB, int echoB)

{

}

// Behavior

void Monstro::Initialize() {

}

bool Monstro::Update() {

}

再次,我們在這里所做的只是設(shè)置裸源文件的骨骼,同時確保我們在這里也包含Arduino.h引用,以及對頭文件的引用,以便我們也可以訪問它的定義。

步驟5:測量傾角(IMU)

由于Adafruit程序員編寫的庫,實現(xiàn)BNO055的代碼非常簡單。我們將使用Adafruit_BNO055驅(qū)動程序庫以及Adafruit統(tǒng)一傳感器庫。

讓我們首先更新我們的頭文件以與IMU交互。

#ifndef Monstro_h

#define Monstro_h

#include “Arduino.h”

#include

#include

#include

class Monstro {

public:

Monstro(int leftForward, int leftBackward, int leftSpeedPin,

int rightForward, int rightBackward, int rightSpeedPin,

int trigA, int echoA, int trigB, int echoB);

// Behavior

bool Update();

void Initialize();

// IMU

volatile double xTilt;

volatile double yTilt;

volatile double zTilt;

private:

// IMU

Adafruit_BNO055 _bno;

void initializeIMU();

void readIMU();

};

#endif

我們在頭文件中添加了一些內(nèi)容。

首先,你會注意到三個include語句,它們確保我們可以訪問Adafruit庫以及imumaths.h庫,它們在實現(xiàn)IMU讀取時將需要它們的功能。

我們還添加了公共變量xTilt,yTilt和zTilt。這些是我們將在每個更新周期中存儲從IMU檢索的數(shù)據(jù)的地方。請注意,我們已將它們標(biāo)記為volatile,這是因為我們將在本教程后面的計時器中斷中使用它們。

我們還添加了一個BNO055對象(_bno),一個初始化函數(shù)來設(shè)置它,以及一個在更新周期中使用的讀取函數(shù)。

現(xiàn)在讓我們在源文件中實現(xiàn)這些功能:

#include “Arduino.h”

#include “monstro.h”

Monstro::Monstro(int leftForward, int leftBackward, int leftSpeedPin,

int rightForward, int rightBackward, int rightSpeedPin,

int trigA, int echoA, int trigB, int echoB)

{

}

// Behavior

void Monstro::Initialize() {

initializeIMU();

}

bool Monstro::Update() {

readIMU();

}

// IMU

void Monstro::initializeIMU() {

_bno = Adafruit_BNO055(55);

if (!_bno.begin())

{

Serial.print(“No BNO055 detected”);

while (1);

}

delay(1000);

_bno.setExtCrystalUse(true);

}

void Monstro::readIMU() {

sensors_event_t event;

_bno.getEvent(&event);

xTilt = event.orientation.x;

yTilt = event.orientation.y;

zTilt = event.orientation.z;

}

我們現(xiàn)在已經(jīng)實現(xiàn)了我們的IMU功能:

我們在我們的主Initialize()函數(shù)中包含了IMU初始化,并在我們的主Update()函數(shù)中包含了IMU讀取。

我們還實現(xiàn)了IMU初始化的代碼,我們與BNO055進行了接口

最后在readIMU()函數(shù)內(nèi)部實現(xiàn)了機器人絕對定位的讀取。將三個傾斜分配給我們的內(nèi)部變量。

步驟6:電機控制

實現(xiàn)電機代碼控制將涉及比IMU代碼更多的邏輯。這是因為它將從我們稍后將在本教程中編寫的PID算法接收其值。

所以讓我們從更新頭文件開始:

#ifndef Monstro_h

#define Monstro_h

#include “Arduino.h”

#include

#include

#include

class Monstro {

public:

Monstro(int leftForward, int leftBackward, int leftSpeedPin,

int rightForward, int rightBackward, int rightSpeedPin,

int trigA, int echoA, int trigB, int echoB);

// Behavior

bool Update();

void Initialize();

// IMU

volatile double xTilt;

volatile double yTilt;

volatile double zTilt;

private:

// IMU

Adafruit_BNO055 _bno;

void initializeIMU();

void readIMU();

// Motors

int _leftForward;

int _leftBackward;

int _leftSpeedPin;

int _rightForward;

int _rightBackward;

int _rightSpeedPin ;

void initializeMotors();

void setMotors(int leftMotorSpeed, int rightMotorSpeed);

};

#endif

新行位于頭文件的底部,位于注釋“Motors”下。我們定義的私有變量將引用每個電機控制的引腳(方向引腳和速度引腳)。我們還包括兩個功能,一個用于初始化電機,另一個用于實際更改電機的速度和方向。

現(xiàn)在讓我們更新源文件以反映這些變化:

#include “Arduino.h”

#include “monstro.h”

Monstro::Monstro(int leftForward, int leftBackward, int leftSpeedPin,

int rightForward, int rightBackward, int rightSpeedPin,

int trigA, int echoA, int trigB, int echoB)

{

_leftForward = leftForward;

_leftBackward = leftBackward;

_leftSpeedPin = leftSpeedPin;

_rightForward = rightForward;

_rightBackward = rightBackward;

_rightSpeedPin = rightSpeedPin;

}

// Behavior

void Monstro::Initialize() {

initializeIMU();

initializeMotors();

}

bool Monstro::Update() {

readIMU();

}

// IMU

void Monstro::initializeIMU() {

_bno = Adafruit_BNO055(55);

if (!_bno.begin())

{

Serial.print(“No BNO055 detected”);

while (1);

}

delay(1000);

_bno.setExtCrystalUse(true);

}

void Monstro::readIMU() {

sensors_event_t event;

_bno.getEvent(&event);

xTilt = event.orientation.x;

yTilt = event.orientation.y;

zTilt = event.orientation.z;

}

// Motors

void Monstro::initializeMotors() {

pinMode(_leftForward, OUTPUT);

pinMode(_leftBackward, OUTPUT);

pinMode(_leftSpeedPin, OUTPUT);

pinMode(_rightForward, OUTPUT);

pinMode(_rightBackward, OUTPUT);

pinMode(_rightSpeedPin, OUTPUT);

}

void Monstro::setMotors(int leftMotorSpeed, int rightMotorSpeed) {

if (rightMotorSpeed 《= 0) {

digitalWrite(_rightBackward, LOW);

digitalWrite(_rightForward, HIGH);

analogWrite(_rightSpeedPin, abs(rightMotorSpeed));

}

else {

digitalWrite(_rightBackward, HIGH);

digitalWrite(_rightForward, LOW);

analogWrite(_rightSpeedPin, rightMotorSpeed);

}

if (leftMotorSpeed 《= 0) {

digitalWrite(_leftBackward, LOW);

digitalWrite(_leftForward, HIGH);

analogWrite(_leftSpeedPin, abs(leftMotorSpeed));

}

else {

digitalWrite(_leftBackward, HIGH);

digitalWrite(_leftForward, LOW);

analogWrite(_leftSpeedPin, leftMotorSpeed);

}

}

更新如下:

我們現(xiàn)在已經(jīng)在構(gòu)造函數(shù)中分配了私有pin變量值,因此用戶可以根據(jù)特殊設(shè)置。

我們已將電機初始化添加到一般的Initialize()函數(shù)中。

我們已經(jīng)實現(xiàn)了電機初始化程序,其中包括將引腳設(shè)置為輸出。

我們已經(jīng)定義了我們的功能,它將實際啟動電機setMotors()。根據(jù)傳遞給該功能的值(-255至255),電機將以不同的速度和不同的方向開始旋轉(zhuǎn)。這些值將由PID算法在下一節(jié)中生成。

步驟7:PID算法實現(xiàn)

現(xiàn)在我將介紹更復(fù)雜的代碼部分:PID控制器算法。

這種算法用于許多自動控制應(yīng)用程序。它可以調(diào)節(jié)各種過程,從流量和溫度到調(diào)平和速度。基本上它是一個封閉的反饋循環(huán),它接受一個變量作為 輸入 并在嘗試中產(chǎn)生 輸出 將 輸入 驅(qū)動到特定的 設(shè)定點 。

PID代表比例,積分和微分。這些術(shù)語中的每一個都以不同方式影響控制器響應(yīng)。它們將產(chǎn)生一個輸出,驅(qū)動我們的電機以保持我們的機器人平衡。

比例是控制器中的主要驅(qū)動術(shù)語。它會根據(jù)誤差(在我們的例子中是測量角度和所需角度之間的差異)改變控制器輸出。如果誤差變大,那么該項的增益將按比例增加。

積分術(shù)語會根據(jù)錯誤隨時間的累積影響我們的機器人對錯誤的響應(yīng)。如果在給定時間段內(nèi)誤差很大,則增加/減少將以快速速率發(fā)生。同樣,如果誤差很長一段時間,則變化將以較慢的速度發(fā)生。您可以將此視為基于系統(tǒng)過去行為的響應(yīng)。

派生術(shù)語根據(jù)錯誤的變化率生成輸出。這轉(zhuǎn)換為當(dāng)前誤差與先前誤差之差除以采樣周期。這個術(shù)語將有助于預(yù)測機器人的平衡在下一次閱讀中的反應(yīng)。您可以將此術(shù)語視為系統(tǒng)將來如何表現(xiàn)的預(yù)測性響應(yīng)。

因此,既然我們已經(jīng)基本了解了PID控制器在理論上的工作原理,那么我們就去吧提前并將其實施到我們的課堂中。我們可以從更新標(biāo)題開始:

#ifndef Monstro_h

#define Monstro_h

#include “Arduino.h”

#include

#include

#include

class Monstro {

public:

Monstro(int leftForward, int leftBackward, int leftSpeedPin,

int rightForward, int rightBackward, int rightSpeedPin,

int trigA, int echoA, int trigB, int echoB);

// Behavior

bool Update();

void Initialize();

void ComputeBalance();

// IMU

volatile double xTilt;

volatile double yTilt;

volatile double zTilt;

private:

// IMU

Adafruit_BNO055 _bno;

void initializeIMU();

void readIMU();

// Motors

int _leftForward;

int _leftBackward;

int _leftSpeedPin;

volatile int _leftSpeed = 0;

int _rightForward;

int _rightBackward;

int _rightSpeedPin ;

volatile int _rightSpeed = 0;

void initializeMotors();

void setMotors(int leftMotorSpeed, int rightMotorSpeed);

// PID

volatile float previous_error = 0, integral = 0;

volatile int motorPower;

float sampleTime = 0.005;

double outMin, outMax;

double _Kp, _Ki, _Kd;

volatile float Setpoint = 0, Input, Output;

void initializePID();

void SetTunings(double Kp, double Ki, double Kd);

void SetOutputLimits(double Min, double Max);

};

#endif

這里有很多新代碼,大部分內(nèi)容乍一看都難以理解,所以我會詳細說明:

盡可能看到我們在我們的類中添加了另一個公共函數(shù):ComputeBalance()。該功能將在定時器中斷中調(diào)用,并由我們的PID控制器算法組成。

我們還包含了一些我們將在實際實現(xiàn)中使用的變量,比如previous_error,以及我們需要在迭代之間存儲的積分。

在主Update()循環(huán)中調(diào)用setMotors()函數(shù)時,motorPower將用于驅(qū)動電機。

sampleTime是我們在幾秒鐘內(nèi)調(diào)用ComputeBalance函數(shù)的頻率。

變量outMin和outMax將幫助我們將輸出約束到我們的電機能夠讀取的值(在我們的例子中,這些值將是-255到255,但是在某些情況下我們可能需要更改這些值。

_Kp,_Ki和_Kd是我們的比例,積分和微分常數(shù)。這些算法的每個部分都會乘以。

設(shè)定點是我們想要的角度,如果我們的機器人想要保持平衡,它應(yīng)該設(shè)置為0.輸入是我們將從IMU的傾斜中讀取的,輸出是PID算法將給我們的。

我們還有一個初始化函數(shù),以及另外兩個函數(shù)來幫助我們調(diào)整算法。

現(xiàn)在讓我們進入PID控制器的源代碼實現(xiàn)。這部分完全沒有完成,我們已經(jīng)寫好了這個算法的一些變體,但目前這個版本似乎在我們當(dāng)前的設(shè)置中效果最好:

#include “Arduino.h”

#include “monstro.h”

Monstro::Monstro(int leftForward, int leftBackward, int leftSpeedPin,

int rightForward, int rightBackward, int rightSpeedPin,

int trigA, int echoA, int trigB, int echoB)

{

leftForward = leftForward;

_leftBackward = leftBackward;

_leftSpeedPin = leftSpeedPin;

_rightForward = rightForward;

_rightBackward = rightBackward;

_rightSpeedPin = rightSpeedPin;

}

// Behavior

void Monstro::Initialize() {

initializeIMU();

initializeMotors();

initializePID();

}

bool Monstro::Update() {

readIMU();

setMotors(motorPower, motorPower);

}

// IMU

void Monstro::initializeIMU() {

_bno = Adafruit_BNO055(55);

if (!_bno.begin())

{

Serial.print(“No BNO055 detected”);

while (1);

}

delay(1000);

_bno.setExtCrystalUse(true);

}

void Monstro::readIMU() {

sensors_event_t event;

_bno.getEvent(&event);

xTilt = event.orientation.x;

yTilt = event.orientation.y;

zTilt = event.orientation.z;

}

// Motors

void Monstro::initializeMotors() {

pinMode(_leftForward, OUTPUT);

pinMode(_leftBackward, OUTPUT);

pinMode(_leftSpeedPin, OUTPUT);

pinMode(_rightForward, OUTPUT);

pinMode(_rightBackward, OUTPUT);

pinMode(_rightSpeedPin, OUTPUT);

}

void Monstro::setMotors(int leftMotorSpeed, int rightMotorSpeed) {

if (rightMotorSpeed 《= 0) {

digitalWrite(_rightBackward, LOW);

digitalWrite(_rightForward, HIGH);

analogWrite(_rightSpeedPin, abs(rightMotorSpeed));

}

else {

digitalWrite(_rightBackward, HIGH);

digitalWrite(_rightForward, LOW);

analogWrite(_rightSpeedPin, rightMotorSpeed);

}

if (leftMotorSpeed 《= 0) {

digitalWrite(_leftBackward, LOW);

digitalWrite(_leftForward, HIGH);

analogWrite(_leftSpeedPin, abs(leftMotorSpeed));

}

else {

digitalWrite(_leftBackward, HIGH);

digitalWrite(_leftForward, LOW);

analogWrite(_leftSpeedPin, leftMotorSpeed);

}

}

// PID

void Monstro::initializePID() {

SetOutputLimits(-250, 250);

SetTunings(25, 0.5, 275);

}

void Monstro::ComputeBalance() {

Input = zTilt;

// Compute error variables

float error = Input - Setpoint;

// Calculate proportional component

float proportional = error * _Kp;

// Calculate integral component

integral += error * _Ki;

integral = constrain(integral, outMin, outMax); // limit wind-up

// Calculate derivative component

float derivative = (error - previous_error) * _Kd;

// Save variables for next error computation

previous_error = error;

// Add up PID

Output = proportional + integral + derivative;

// Limit to PWM constraints

Output = constrain(Output, outMin, outMax);

// Motor control

motorPower = Output;

// give up if there is no chance of success

if (Input 《 -40 || Input 》 40) motorPower = 0;

}

void Monstro::SetTunings(double Kp, double Ki, double Kd) {

_Kp = Kp;

_Ki = Ki;

_Kd = Kd;

}

void Monstro::SetOutputLimits(double Min, double Max) {

if (Min 》 Max) return;

outMin = Min;

outMax = Max;

}

讓我們回顧一下我們的變化:

我們包括了Update()循環(huán)內(nèi)部的setMotors()函數(shù)。這將確保每次主回路運行時我們的電機旋轉(zhuǎn),并根據(jù)PID控制器(motorPower)提供的輸出更新速度。

initializePID()函數(shù)被添加到我們的主Initialize()函數(shù)中。它用于設(shè)置常量,并設(shè)置我們的最小和最大輸出。

ComputeBalance()函數(shù)本身就是PID計算發(fā)生的地方。它首先將我們機器人的zTilt作為輸入。然后我們通過檢查輸入和設(shè)定點之間的差異來計算誤差(如果我們保持機器人平衡,則應(yīng)該為0)。然后,我們通過將它與誤差相乘來計算比例項。接下來將誤差*積分常數(shù)加到我們的積分項中,并將其約束到我們的最大值和最小值,以限制此項可能導(dǎo)致的上升(如果我們的機器人跌落了一段時間,我們想要將其恢復(fù)原狀沒有它表現(xiàn)得很瘋狂)。然后通過檢查當(dāng)前誤差與我們上次測量誤差之間的差異,并將其乘以導(dǎo)數(shù)常數(shù)來計算導(dǎo)數(shù)。然后,我們將當(dāng)前錯誤保存為最后一個錯誤,并將我們的術(shù)語加在一起以計算輸出。此輸出現(xiàn)在可以分配給motorPower,它將被讀取以在主Update()循環(huán)中驅(qū)動我們的電機。最后但并非最不重要的是,我們還希望確保將motorPower轉(zhuǎn)為0,以防我們的機器人傾斜超出可以恢復(fù)的程度,這樣當(dāng)它跌落時它不會繼續(xù)旋轉(zhuǎn)車輪并自行毀壞。

步驟8:調(diào)整PID常量

有一些已建立的調(diào)整PID常數(shù)的數(shù)學(xué)策略,如Ziegler- Nichols方法,或Cohen-Coon方法。但是,我們發(fā)現(xiàn)很難在我們的系統(tǒng)中實現(xiàn)這些方法,因此選擇了一些更簡單的規(guī)則進行調(diào)優(yōu):

將所有常量設(shè)置為零。然后慢慢增加_Kp,直到機器人開始振蕩。如果傾斜到一側(cè),即使它落到另一側(cè),也要確保它始終是正確的。

定期增加_Kd,直到您注意到振蕩開始減少。

增加_Ki,以便在機器人真正失去平衡時響應(yīng)更快,而在距離設(shè)定點稍微偏離時更慢。這可以改善增加_Kd時減少的反應(yīng)時間。

從這一點微調(diào)常數(shù),直到機器人可以無限期地保持其平衡。

上傳到本節(jié)開頭的gif也可以作為視覺指南。至于這些常數(shù)的效果。我們發(fā)現(xiàn)它作為一種可視化調(diào)整工具非常有用。

步驟9:超聲波傳感器

超聲波傳感器代碼是特別是每個設(shè)置和錯誤類型。因此,我們不會將其包含在這個教學(xué)中。但是,對于所有類型的運動,整體邏輯是相同的:將Setpoint變量更改為大于0,機器人將以一種方式行進,將其更改為低于0,機器人將以另一種方式行進。您還可以將常數(shù)乘以每個車輪的速度,以使機器人左右轉(zhuǎn)動。

(更新:進一步考慮后,本節(jié)將很快詳細說明)

步驟10:使用Monster庫

現(xiàn)在我們已經(jīng)對所有編碼的庫進行了編碼,我們可以在簡單的Arduino草圖中使用它。

我們將通過導(dǎo)入庫頭來實現(xiàn),構(gòu)造Monster類的一個實例,并使用Timer Interrupt(來自TimerOne.h庫)定期調(diào)用ComputeBalance()函數(shù)。

實施代碼如下:

#include “monstro.h”

#include

Monstro meuMonstro(13, 12, 11, 3, 5, 6, 13, 12, 8, 7);

void setup()

{

// COM

Serial.begin(9600);

// Timer Interrupt

Timer1.initialize(5000);

Timer1.attachInterrupt(BalanceRobot);

meuMonstro.Initialize();

}

void loop()

{

meuMonstro.Update();

}

void BalanceRobot() {

meuMonstro.ComputeBalance();

}

將此上傳到您的Arduino,將公桶插孔插入機器人母筒插孔供電,機器人應(yīng)開始自行平衡。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 機器人
    +關(guān)注

    關(guān)注

    213

    文章

    29817

    瀏覽量

    213369
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    工業(yè)機器人的特點

    的基礎(chǔ),也是三者的實現(xiàn)終端,智能制造裝備產(chǎn)業(yè)包括高檔數(shù)控機床、工業(yè)機器人、自動化成套生產(chǎn)線、精密儀器儀表、智能傳感器、汽車自動化焊接線、柔性自動化生產(chǎn)線、智能農(nóng)機、3D 打印機等領(lǐng)域。而智能制造裝備中工業(yè)
    發(fā)表于 07-26 11:22

    盤點#機器人開發(fā)平臺

    地瓜機器人RDK X5開發(fā)套件地瓜機器人RDK X5開發(fā)套件產(chǎn)品介紹 旭日5芯片10TOPs算力-電子發(fā)燒友網(wǎng)機器人開發(fā)套件 Kria KR260機器人開發(fā)套件 Kria KR260-
    發(fā)表于 05-13 15:02

    詳細介紹機場智能指路機器人的工作原理

    ,配備高性能的電機和傳動裝置,為機器人提供穩(wěn)定的動力輸出。通過精確的電機控制算法,機器人可以實現(xiàn)前進、后退、轉(zhuǎn)彎等各種動作,并且能夠根據(jù)不同的地面狀況和行走需求,靈活調(diào)整行走速度和姿態(tài)。 平衡與穩(wěn)定性
    發(fā)表于 05-10 18:26

    【「# ROS 2智能機器人開發(fā)實踐」閱讀體驗】機器人入門的引路書

    ROS的全稱:Robot Operating System 機器人操作系統(tǒng) ROS的 目的 :ROS支持通用庫,是通信總線,協(xié)調(diào)多個傳感器 為了解決機器人里各廠商模塊不通用的問題,讓機器人快速開發(fā)
    發(fā)表于 04-30 01:05

    海康機器人布局關(guān)節(jié)機器人業(yè)務(wù)

    關(guān)節(jié)機器人領(lǐng)域迎來一位實力選手。繼布局移動機器人機器視覺業(yè)務(wù)后,海康機器人正在拓展新的產(chǎn)品線。
    的頭像 發(fā)表于 03-20 10:47 ?780次閱讀

    名單公布!【書籍評測活動NO.58】ROS 2智能機器人開發(fā)實踐

    【「# ROS 2智能機器人開發(fā)實踐」閱讀體驗】+擬標(biāo)題 注意事項 1、活動期間如有作弊、灌水等違反電子發(fā)燒友論壇規(guī)則的行為一經(jīng)發(fā)現(xiàn)將立即取消獲獎資格 2、活動結(jié)束后獲獎名單將在論壇公示請活動參與者
    發(fā)表于 03-03 14:18

    寧德時代機器人團隊成立,探索多元科技領(lǐng)域

    寧德時代近期加大對機器人領(lǐng)域的投入,已在上海組建了一支數(shù)十的專業(yè)團隊,專注于機器人本體、控制算法以及人機交互技術(shù)。該團隊的目標(biāo)是推動機械臂、AGV等工業(yè)
    的頭像 發(fā)表于 02-13 15:27 ?658次閱讀

    寧德時代機器人團隊成立

    寧德時代在機器人領(lǐng)域的布局正逐步展開。去年底,該公司開始加大對機器人領(lǐng)域的投入,并已在上海組建了一支由數(shù)十構(gòu)成的團隊,專注于機器人本體
    的頭像 發(fā)表于 02-12 09:22 ?625次閱讀

    【「具身智能機器人系統(tǒng)」閱讀體驗】2.具身智能機器人的基礎(chǔ)模塊

    具身智能機器人的基礎(chǔ)模塊,這個是本書的第二部分內(nèi)容,主要分為四個部分:機器人計算系統(tǒng),自主機器人的感知系統(tǒng),自主機器人的定位系統(tǒng),自主機器人
    發(fā)表于 01-04 19:22

    【「具身智能機器人系統(tǒng)」閱讀體驗】2.具身智能機器人大模型

    近年來,人工智能領(lǐng)域的大模型技術(shù)在多個方向上取得了突破性的進展,特別是在機器人控制領(lǐng)域展現(xiàn)出了巨大的潛力。在“具身智能機器人大模型”部分,作者研究并探討了大模型如何提升機器人的能力,大模型存在
    發(fā)表于 12-29 23:04

    【「具身智能機器人系統(tǒng)」閱讀體驗】1.初步理解具身智能

    的進步。2000年中國國防科技大學(xué)研制出國內(nèi)第一臺仿型具身智能機器人“先行者”以來,國內(nèi)在該領(lǐng)域的研究與開發(fā)工作逐漸加速。 “先行者”機器人的開發(fā),不僅成為中國類
    發(fā)表于 12-28 21:12

    從市場角度對機器人的基本解讀

    人工智能機器人發(fā)展至今,幾乎都是從學(xué)術(shù)方面對機器人進行定義詮釋。現(xiàn)今機器人市場化發(fā)展程度已逐步進入多領(lǐng)域不同場景的融合應(yīng)用,對實際市場已經(jīng)可以發(fā)揮一定的使用價值。為更快的增強
    的頭像 發(fā)表于 12-07 01:06 ?613次閱讀
    從市場角度對<b class='flag-5'>機器人</b>的基本解讀

    鴻蒙機器人與鴻蒙開發(fā)板聯(lián)動演示

    鴻蒙機器人與鴻蒙開發(fā)板聯(lián)動演示,機器人的角色為迎賓機器人,開發(fā)板負責(zé)人賓客出現(xiàn)監(jiān)聽
    發(fā)表于 12-02 14:55

    開源項目!用ESP32做一個可愛的無用機器人

    簡介 作者在完成碩士論文答辯后,利用空閑時間制作了一個他一直想做的機器人——可愛無用機器人。 無用機器人原理是一個連接到開關(guān)的電機,通過邏輯門控制。當(dāng)開關(guān)被推到“開”時,
    發(fā)表于 09-03 09:34

    開源項目!用ESP32做一個可愛的無用機器人

    簡介 作者在完成碩士論文答辯后,利用空閑時間制作了一個他一直想做的機器人——可愛無用機器人。 無用機器人原理是一個連接到開關(guān)的電機,通過邏輯門控制。當(dāng)開關(guān)被推到“開”時,
    發(fā)表于 08-30 14:50