Citirea și Scrierea Hardware#

When using the FTC® SDK, there are a variety of built in hardware classes which can be used to communicate with hardware on the robot such as DC Motors, Servos, and Sensors.

Crearea și Instanțarea Obiectelor Hardware#

Primul lucru necesar pentru a crea corect un obiect este importarea clasei acestuia. În Android Studio, dacă clasa este menționată fără a fi importată poți apăsa Alt+Enter pentru a o importa automat. După ce este importată clasa, urmatorul pas este să creezi obiectul:

private DcMotor liftMotor;

După ce obiectul este creat, acesta trebuie instanțat. Parte din superclasa OpMode este numită hardwareMap. hardwareMap este folosit în FTC SDK pentru a instanța obiecte, decât să apelezi un constructor.

Conține toate informațiile introduse în configurația Robot Controller-ului, precum numele hardware-ului și în ce port a fost introdus. Aici este un exemplu pentru instanțierea motorului pe care l-am creat mai sus:

liftMotor = hardwareMap.get(DcMotor.class, "Lift Motor");

Pentru orice senzor pe care Îl folosești, vei pasa acea clasă în locul unde este DcMotor.class. De exemplu, dacă liftMotor era un servomotor, Servo.class ar fi fost pasat în schimb.

Pentru al doilea argument, vei pasa orice nume pe care îl are dispozitivul î0n configurația din Robot Controller. hardwareMap va găsi pe ce port este conectat dispozitivul cu numele respectiv, care îți permite să accesezi hardware-ul.

Exemple Comune pentru Utilizarea Componentelor Hardware#

Motorul DC#

DcMotor leftMotor = hardwareMap.get(DcMotor.class, "Left Motor");
DcMotor rightMotor = hardwareMap.get(DcMotor.class, "Right Motor");

DcMotor elevatorMotor = hardware.get(DcMotor.class, "Elevator Motor");
DcMotor intakeMotor = hardware.get(DcMotor.class, "Intake Motor");

După ce un DcMotor este instanțat, există câteva variabile pe care trebuie să le setezi pentru a afecta felul în care un motor DC va rula. Primul din acestea este direcția:

leftMotor.setDirection(DcMotor.Direction.REVERSE);
rightMotor.setDirection(DcMotor.Direction.FORWARD);

Schimbarea direcției unui motor face exact lucrul la care te aștepți, îi schimbă direcția. Dacă o putere de 1 este aplicată unui motor în timp ce este setat în modul forward, se va roti într-o sigură direcție. Dacă este în reverse, o putere de 1 îl va roti în cealaltă direcție. Dacă îndrepti axul motorului înspre tine, forward este în sensul invers al acului de ceasornic (cu excepția motoarelor NereRest).

Apoi, exită două comportamente de putere 0 care pot fi configurate:

leftMotor.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
rightMotor.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.FLOAT);

Schimbarea acestei variabile afectează felul în care se comportă motorul DC când o putere de 0 este aplicată. BRAKE va forța motorul să încetinească dacă este în mișcare (nu va face motorul să își mențină poziția dacă nu este deja în mișcare), în timp ce FLOAT permite motorului să culiseze până la o oprire completă, lăsând frecarea fizică să facă toată munca.

În final, există 4 tipuri diferite de rulare care pot fi folosite cu motoarele DC:

leftMotor.setMode(DcMotor.RunMode.RUN_WITHOUT_ENCODER);
rightMotor.setMode(DcMotor.RunMode.RUN_USING_ENCODER);

elevatorMotor.setMode(DcMotor.RunMode.RUN_TO_POSITION);
intakeMotor.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);

Este important de reținut faptul ca valorile encoder-ului pot fi citite în oricare din aceste moduri, în cazul în care un encoder este conectat corect. Aceste moduri doar schimbă modul în care motorul reacționează la aceste valori ale encoder-ului. Documentația REV Robotics are un tutorial pentru aceste moduri de rulare.

Atenționare

RUN_TO_POSITION poate fi o metodă ușoară de a controla un mecanism bazat pe un singur motor, din moment ce ușurează toată munca controller-ului; însă, din moment ce fiecare motor este controlat independent, nu este recomandat să folosești această metodă pe mecanisme cu mai multe motoare, în special șasiuri.

Encodere#

Termen

Encoder#

Un encoder se referă la un dispozitiv care urmăreste mișcarea rotațională în jurul unui ax.

There are both absolute and relative encoders. An absolute encoder will report at exactly what angle the shaft is compared to its absolute „zero”. A relative encoder will report how far the shaft has rotated since it started tracking (for example, when autonomous starts). Relative encoders will have a quadrature output, whereas absolute encoders generally have analog or i2c outputs.

Encoderele sunt folosite pentru a găsi poziția robotului, sau a unui mecanism.

Deși toate motoarele legale FTC conțin encodere relative cuadratule, acestea trebuie conectate separat și nu sunt obligatorii. Encoderele externe pot fi folosite și conectate într-un port de encoder cât timp folosesc protocolul cuadratul de comunicare.

Accesarea encoderelor necesită apelarea unei metode din obiectul DcMotor, getCurrentPosition(), care returnează poziția curentă a encoderului conectat la port. Acest număr poate fi arbitrar la începutul unui opmode, și nu este resetat la 0 decât dacă STOP_AND_RESET_ENCODERS este folosit sau este restartat Expansion Hub-ul.

Important

Nu există o terminologie standard când utilizezi encodere cuadratule. SDK-ul folosește „CPR” sau Citiri Pe Revoluție implicit. S-ar putea să vezi și documente care menționează „PPR” sau Pulsuri Pe Revoluție. Un puls poate fi echivalentul a între 1 si 4 citiri ale SDK-ului. Ai grijă când citești documentațiile!

Atenționare

Encoderele cu CPR mare, precum REV Through Bore Encoder, poate pierde pași dacă sunt conectate la porturile 1 si 2. În plus, apelurile la getVelocity() pe un obiect DcMotorEx poate suprasolicita programul cu citiri excesive CPR, din cauza numărului returnat care este un număr întreg de 16 biți.

Servomotoare#

Servo relicServo = hardwareMap.get(Servo.class, "Release Servo");

După instanțierea unui Servo, există două funcții principale care pot fi apelate: setPosition() și getPosition().

releaseServo.setPosition(0.75);
telemetry.addData("Release Servo Target", releaseServo.getPosition());

setPosition() sets the position of the servo. The SDK will use a built-in control loop with the servo’s potentiometer to drive the servo to that position and hold that position. setPosition() takes in a double between 0 and 1, where 0 is the servo’s lower limit of rotation and 1 is the servo’s upper limit of rotation. Everything between is directly proportional, so 0.5 is the middle, 0.75 is 3/4 the way up, etc.

getPosition() does not return the servo’s current position, rather its current target position. If a variable for the servo’s current target position is stored properly, this function should never be needed.

Servomotor cu Rotație Continuă#

CRServo intakeServo = hardwareMap.get(CRServo.class, "Intake Servo");

Un servomotor CR are o metodă principală: setPower(). Aceasta funcționeaza foarte similar cu setPower()-ul DcMotor-ului, adică 0 îl face să se oprească, 1 îl face să se miște la viteză maximă, -1 îl face să se rotească în sens invers la viteză maximă, și restul între aceste valori.:

intakeServo.setPower(0.75);

IO Digital#

DigitalChannel digitalDevice = hardwareMap.get(DigitalChannel.class, "digital device");

Un DigitalChannel are câteva metode principale. setMode() este folosit pentru a seta un port ca OUTPUT sau INPUT, getState() returnează starea curentă a port-ului (merge doar în modul INPUT), iar setState() setează starea port-ului (merge doar în modul OUTPUT).

Sfat

Port-urile digitale încep implicit în modul INPUT

Pericol

Porturile digitale sunt setate la valoarea HIGH implicit, prin legarea unui rezistor între port și 3.3V. Astfel, toate dispozitivele digitale trebuie să fie conectate la pin-ul digital de împământare când este închis, apoi să fie lasat deconectat când este deschis. Pentru senzori de limită, acest lucru înseamnă conectarea unui contact la împământare și al altui contact la portul digital. Conectarea greșită (3.3V la portul digital) poate cauza instabilitate și să îți facă expansion hub-ul să dea crash.

Input Analog#

AnalogInput analogInput = hardwareMap.get(AnalogInput.class, "analog input");

AnalogInput are o metodă principală: getVoltage() care este folosit pentru a obține tensiunea curentă aplicată portului.

Notă

Deși getMaxVoltage() returnează 3.3v, porturile de intrare analog ale expansion și control hub-urilor pot face fața cu ușurintă până la 5v.

De Reținut Despre Viteza de Apelare Hardware#

Orice apel hardware pe care îl faci (fie că este să setezi puterea unui motor, setarea poziției unui servomotor, citirea unui encoder, etc.) va lua aproximativ 3 millisecunde pentru a se executa, cu excepția apelurilor I2C, care pot lua până la 7ms. Acest lucru se întâmplă deoarece, în spate, SDK-ul trebuie să facă mai multe apeluri pentru a efectua o operație I2C.

Notă

Când folosești un Control Hub, s-ar putea să vezi apeluri hardware mai rapide deoarece Control Hub-ul folosește o conexiune directă UART la placa Lynx în loc să treacă prin USB și un „om la mijloc” FTDI cum se întâmplă când folosești un telefon.

These times may seem fast, but they add up quickly. Consider a control loop to drive forward for N encoder counts while maintaining heading using the IMU. This would require 5 normal hardware calls (4 set power + 1 read encoder) and an I2C call (IMU) which means that the loop cycle would take approximately 22ms to execute, and thus run at approximately 45Hz.

Asta înseamnă ca este important să menții un număr cât mai restrâns de apeluri hardware pentru a menține buclele de control rapide. De exemplu, nu citi un senzor de mai multe ori într-o buclă. În schimb, citește-o o dată și stocheaza valoarea într-o variabilă dacă ai nevoie să o folosești înca o data în alte puncte în aceeași bucla de control.

Folosind un apel hardware de citire bulk poate rezolva această problemă. O citire bulk ia 3ms să se execute ca orice alt apel hardware, însă returnează mai multe date. Ca să poți folosi citiri bulk, trebuie să folosești SDK v5.4 sau mai nou. Citește Bulk Reads pentru mai multe informații.