Şasiyi sür
Bu sayfada iki motorlu şasiyi tank ve arcade kontrolüyle, dört motorlu mecanum şasiyi üç eksenle sürecek ve sürüşü yumuşatacaksın.
Başlamadan önce
- Her motoru tek başına denedin ve yönünü düzelttin. Bkz. Motoru sür.
- Bu sayfa iki motorlu şaside sol motor için 16 ve 17, sağ motor için 18 ve 21 numaralı pinleri kullanır. Pinleri kendi kartına göre değiştir.
Şasi, robotu birlikte hareket ettiren motorlardır. Aynı şasi farklı kumanda düzenleriyle sürülebilir. Probot Blocks'ta tank sürüş ve arcade sürüş blokları aynı kodu üretir: Sürüş programı yaz.
Tank kontrolüyle sür
Tank kontrolünde her çubuk bir tarafı sürer: sol çubuk sol motoru, sağ çubuk sağ motoru.
- Dört pin numarasını programın başına yaz.
- Sağ motor ters monte edildiyse
RIGHT_INVERTEDdeğerinitruebırak, değilsefalseyap. teleopLoop()içinde iki çubuğun Y değerini iki motora ver.- Kodu yükle, Init'e, sonra Start'a bas.
#define PROBOT_WIFI_AP_SSID "Probot"
#define PROBOT_WIFI_AP_PASSWORD "Probot1234"
#define PROBOT_WIFI_AP_CHANNEL 1
#include <probot.h>
// Pinleri kendi kartına göre değiştir
#define LEFT_RPWM 16
#define LEFT_LPWM 17
#define RIGHT_RPWM 18
#define RIGHT_LPWM 21
// Motor yönü ters ise true yap
#define LEFT_INVERTED false
#define RIGHT_INVERTED true
// BTS7960 tarzı çift PWM'li sürücüyü sürer: -1 (geri) .. +1 (ileri)
void setMotor(uint8_t rpwmPin, uint8_t lpwmPin, float power, bool inverted) {
if (inverted) power = -power;
int duty = (int)(fabsf(power) * 255.0f);
if (duty > 255) duty = 255;
if (power > 0.02f) { analogWrite(rpwmPin, duty); analogWrite(lpwmPin, 0); }
else if (power < -0.02f) { analogWrite(rpwmPin, 0); analogWrite(lpwmPin, duty); }
else { analogWrite(rpwmPin, 0); analogWrite(lpwmPin, 0); }
}
void stopMotors() {
setMotor(LEFT_RPWM, LEFT_LPWM, 0.0f, false);
setMotor(RIGHT_RPWM, RIGHT_LPWM, 0.0f, false);
}
void robotInit() {
pinMode(LEFT_RPWM, OUTPUT);
pinMode(LEFT_LPWM, OUTPUT);
pinMode(RIGHT_RPWM, OUTPUT);
pinMode(RIGHT_LPWM, OUTPUT);
stopMotors();
}
void robotEnd() {
stopMotors(); // Stop'ta motorlar güvenli konuma
}
void autonomousInit() {}
void autonomousLoop() {}
void teleopInit() {}
void teleopLoop() {
auto js = probot::io::joystick_api::makeDefault();
// Her çubuk bir tarafı sürer
setMotor(LEFT_RPWM, LEFT_LPWM, js.getLeftY(), LEFT_INVERTED);
setMotor(RIGHT_RPWM, RIGHT_LPWM, js.getRightY(), RIGHT_INVERTED);
}
Sonuç: İki çubuğu birlikte ileri itince robot ileri gider. Yalnız sol çubuğu itince robot sağa döner. Çubukları bırakınca robot durur.
Arcade kontrolüyle sür
Arcade kontrolünde bir çubuk ileri-geri, öbür çubuk dönüşü sürer. Çoğu sürücüye tanktan daha tanıdık gelir.
- Tank kontrolüyle sür bölümündeki programı aç.
- Programdaki
teleopLoop()'u aşağıdakiyle değiştir. - Kodu yükle, Init'e, sonra Start'a bas.
void teleopLoop() {
auto js = probot::io::joystick_api::makeDefault();
float fwd = js.getLeftY(); // sol çubuk: ileri / geri
float turn = js.getRightX(); // sağ çubuk: dönüş, sağa artı
setMotor(LEFT_RPWM, LEFT_LPWM, fwd + turn, LEFT_INVERTED);
setMotor(RIGHT_RPWM, RIGHT_LPWM, fwd - turn, RIGHT_INVERTED);
}
Sonuç: Sol çubuğu itince robot ileri gider. Sağ çubuğu sağa yatırınca robot sağa döner.
Toplam 1'i geçebilir. Örneğin tam ileri giderken sağa kırınca sol motora 1'den büyük bir değer gider. setMotor bu değeri 255'e sınırlar, motor en çok tam güçte döner.
Şasiyi bir sınıfa taşı
Şasi bir sınıfta olunca otonom ve öbür kodlar pin ya da formül görmez, yalnız arcade() çağırır. Aşağıdaki program Motoru sür sayfasındaki motor_t sınıfını kullanır.
#define PROBOT_WIFI_AP_SSID "Probot"
#define PROBOT_WIFI_AP_PASSWORD "Probot1234"
#define PROBOT_WIFI_AP_CHANNEL 1
#include <probot.h>
// BTS7960 tarzı çift PWM'li sürücüyü sürer: -1 (geri) .. +1 (ileri)
void setMotor(uint8_t rpwmPin, uint8_t lpwmPin, float power, bool inverted) {
if (inverted) power = -power;
int duty = (int)(fabsf(power) * 255.0f);
if (duty > 255) duty = 255;
if (power > 0.02f) { analogWrite(rpwmPin, duty); analogWrite(lpwmPin, 0); }
else if (power < -0.02f) { analogWrite(rpwmPin, 0); analogWrite(lpwmPin, duty); }
else { analogWrite(rpwmPin, 0); analogWrite(lpwmPin, 0); }
}
class motor_t {
public:
motor_t(uint8_t rpwm, uint8_t lpwm, bool inverted = false)
: _rpwm(rpwm), _lpwm(lpwm), _inverted(inverted) {}
void init() { pinMode(_rpwm, OUTPUT); pinMode(_lpwm, OUTPUT); stop(); }
void set(float power) { setMotor(_rpwm, _lpwm, power, _inverted); }
void stop() { setMotor(_rpwm, _lpwm, 0.0f, false); }
private:
uint8_t _rpwm, _lpwm;
bool _inverted;
};
class drive_base_t {
public:
drive_base_t(motor_t& left, motor_t& right) : _left(left), _right(right) {}
void init() { _left.init(); _right.init(); }
void stop() { _left.stop(); _right.stop(); }
// fwd: ileri artı, turn: sağa artı
void arcade(float fwd, float turn) {
_left.set(fwd + turn);
_right.set(fwd - turn);
}
private:
motor_t& _left;
motor_t& _right;
};
motor_t left_motor(16, 17);
motor_t right_motor(18, 21, true); // sağ motor ters monte
drive_base_t drive_base(left_motor, right_motor);
void robotInit() { drive_base.init(); }
void robotEnd() { drive_base.stop(); } // Stop'ta şasi durur
void autonomousInit() {}
void autonomousLoop() {}
void teleopInit() {}
void teleopLoop() {
auto js = probot::io::joystick_api::makeDefault();
drive_base.arcade(js.getLeftY(), js.getRightX());
}
Sonuç: Robot arcade örneğindeki gibi sürülür. Fonksiyonlarda pin numarası kalmaz.
Mecanum şasiyi sür
Mecanum tekerlekli şasinin dört motoru vardır. Robot ileri-geri gider, yerinde döner ve yana kayar. Sol çubuk ileri-geri ve yana kaymayı, sağ çubuk dönüşü sürer.
- Dört motorun pinlerini
motor_tsatırlarına yaz. - Ters dönen motorun satırına üçüncü değer olarak
trueekle. - Kodu yükle, Init'e, sonra Start'a bas.
- Robotu önce yalnız ileri, sonra yalnız yana, sonra yalnız dönerek dene.
#define PROBOT_WIFI_AP_SSID "Probot"
#define PROBOT_WIFI_AP_PASSWORD "Probot1234"
#define PROBOT_WIFI_AP_CHANNEL 1
#include <probot.h>
// BTS7960 tarzı çift PWM'li sürücüyü sürer: -1 (geri) .. +1 (ileri)
void setMotor(uint8_t rpwmPin, uint8_t lpwmPin, float power, bool inverted) {
if (inverted) power = -power;
int duty = (int)(fabsf(power) * 255.0f);
if (duty > 255) duty = 255;
if (power > 0.02f) { analogWrite(rpwmPin, duty); analogWrite(lpwmPin, 0); }
else if (power < -0.02f) { analogWrite(rpwmPin, 0); analogWrite(lpwmPin, duty); }
else { analogWrite(rpwmPin, 0); analogWrite(lpwmPin, 0); }
}
class motor_t {
public:
motor_t(uint8_t rpwm, uint8_t lpwm, bool inverted = false)
: _rpwm(rpwm), _lpwm(lpwm), _inverted(inverted) {}
void init() { pinMode(_rpwm, OUTPUT); pinMode(_lpwm, OUTPUT); stop(); }
void set(float power) { setMotor(_rpwm, _lpwm, power, _inverted); }
void stop() { setMotor(_rpwm, _lpwm, 0.0f, false); }
private:
uint8_t _rpwm, _lpwm;
bool _inverted;
};
class mecanum_t {
public:
mecanum_t(motor_t& fl, motor_t& fr, motor_t& bl, motor_t& br)
: _fl(fl), _fr(fr), _bl(bl), _br(br) {}
void init() { _fl.init(); _fr.init(); _bl.init(); _br.init(); }
void stop() { _fl.stop(); _fr.stop(); _bl.stop(); _br.stop(); }
// fwd: ileri artı, strafe: sağa kayma artı, rotate: sağa dönüş artı
void drive(float fwd, float strafe, float rotate) {
float fl = fwd + strafe + rotate;
float fr = fwd - strafe - rotate;
float bl = fwd - strafe + rotate;
float br = fwd + strafe - rotate;
// En büyük değer 1'i geçerse hepsini aynı oranda küçült, yön korunur
float mx = fmaxf(fmaxf(fabsf(fl), fabsf(fr)), fmaxf(fabsf(bl), fabsf(br)));
if (mx > 1.0f) { fl /= mx; fr /= mx; bl /= mx; br /= mx; }
_fl.set(fl); _fr.set(fr);
_bl.set(bl); _br.set(br);
}
private:
motor_t& _fl;
motor_t& _fr;
motor_t& _bl;
motor_t& _br;
};
// Pinleri kendi kartına göre değiştir
motor_t fl_motor(10, 11); // ön sol
motor_t fr_motor(12, 13); // ön sağ
motor_t bl_motor(14, 15); // arka sol
motor_t br_motor(16, 17); // arka sağ
mecanum_t mecanum(fl_motor, fr_motor, bl_motor, br_motor);
void robotInit() { mecanum.init(); }
void robotEnd() { mecanum.stop(); } // Stop'ta dört motor durur
void autonomousInit() {}
void autonomousLoop() {}
void teleopInit() {}
void teleopLoop() {
auto js = probot::io::joystick_api::makeDefault();
mecanum.drive(js.getLeftY(), js.getLeftX(), js.getRightX());
}
Dikkat
Bu pinler ESP32-S3 içindir; düz ESP32'de GPIO6-11 flash belleğe bağlıdır, kullanma. Dört motor sekiz PWM pini kullanır ve ESP32-S3'ün sekiz LEDC kanalını doldurur; bu şasiye servo eklenemez.
Sonuç: Sol çubuğu ileri itince robot ileri gider, sağa yatırınca sağa kayar. Sağ çubuğu sağa yatırınca robot yerinde sağa döner. Bir hareket ters çıkarsa o harekette yanlış dönen motorun satırına true ekle.
Dört motorun toplamı 1'i geçebilir. Kod bu durumda dört değeri de en büyüğüne böler. Böylece motorlar arasındaki oran ve hareketin yönü korunur.
Sürüşü yumuşat
Çubuk değerini olduğu gibi motora vermek çalışır ama sürüş sert olur. Aşağıdaki iki yöntem hassas manevrayı kolaylaştırır.
Değerin küpünü al. Çubuğun küçük hareketleri motora daha az güç verir, uca doğru güç hızla artar. Çubuk yarıdayken çıkış 0,125 olur. Probot Blocks'taki hassas güç bloğu aynı fonksiyonu üretir.
// Çubuk değerinin küpü: düşük hızda hassas, yüksekte tam güç (işaret korunur)
float hassasGuc(float x) { return x * x * x; }
void teleopLoop() {
auto js = probot::io::joystick_api::makeDefault();
drive_base.arcade(hassasGuc(js.getLeftY()), hassasGuc(js.getRightX()));
}
hassasGuc fonksiyonunu teleopLoop()'un dışına, üstüne yaz.
Daha hafif bir etki için x * fabsf(x) kullan. İşaret yine korunur.
Değişimi sınırla. Çubuk bir anda tam ileri itilince motora bir anda tam güç gider. Tekerlek patinaj yapar ya da robot sarsılır. Aşağıdaki kod çıkışın bir turda en çok 0,05 değişmesine izin verir.
// Hedefe en fazla max_step kadar yaklaş
float slew(float target, float current, float max_step) {
float diff = constrain(target - current, -max_step, max_step);
return current + diff;
}
float drive_out = 0.0f;
void teleopInit() { drive_out = 0.0f; } // her teleop başında sıfırla
void teleopLoop() {
auto js = probot::io::joystick_api::makeDefault();
drive_out = slew(js.getLeftY(), drive_out, 0.05f); // tur başına en fazla 0.05
drive_base.arcade(drive_out, js.getRightX());
}
max_step küçüldükçe sürüş yumuşar ama robot geç tepki verir. Değeri robotta deneyerek seç.
Hangi şasiyi seçmeli
Çoğu yarışma görevi için tank şasi yeter ve en az sorun çıkarır. Tank ile arcade arasındaki fark yalnız kumanda düzenidir, donanım aynıdır. Yana kayma gerçekten gerekiyorsa mecanum düşün. Mecanum mekanik olarak daha karmaşıktır ve tekerlekler kaymaya daha yatkındır.
Sorun mu var?
- Robot ileri yerine dönüyor: Bir motor ters dönüyor. O motorun ters değerini değiştir. Bkz. Motorun yönünü düzelt.
- Robot dönüşte ters tarafa gidiyor: Arcade formülünde
turnişaretini değiştir ya da sol ve sağ motorun yerini değiştir. - Çubuk bırakılınca robot kayıyor: Ölü bölgeyi büyüt. Bkz. Ölü bölgeyi ayarla.