#pragma config(Sensor, S1, soundSensor, sensorSoundDB)
#pragma config(Sensor, S2, touchSensor, sensorTouch)
#pragma config(Sensor, S3, sonarSensor, sensorSONAR)
#pragma config(Sensor, S4, lightSensor, sensorLightActive)
/* Programul in limbajul NXC
/***********************************************************************************************
Prin acest program se pozitioneaza bratul de robot NXT, format din doua segmente rigide
de motoare NXT, intr-un punct din planul de lucru. In acest program demonstrativ se
bratul in cadranul I.
Inainte de a rula programul, trebuie sa se stabileasca orientarea fizica a celor doua
axe ale planului de lucru si sa se pozitioneze manual bratul in pozitia initiala
stabilita: cu cele doua segmente in prelungire, de-a lungul axei OX.
Nota: Compilatorul NXC folosit de BricxCC poate sa nu "inteleaga" expresiile
complexe semnaland o eroare la compilare: "error parsing expression". Din acest
motiv e nevoie ca astfel de expresii sa se descompuna in expresii simple si sa se
faca in mai multi pasi.*/
/**************************************************************************************/
// Constante
/*************************************************************************************/
// Valoarea de raportare a marimilor de intrare.
// Trebuie sa fie identica cu cea introdusa in fisierul in care s-au scalat coeficientii
#include <math.h>
#define DIM_MAX 20 // [cm]
// Coeficientii scalati
#define C1 5461
#define C2 27306
#define C3 8874
#define C4 17066
#define SH_C1C2 0
#define SH_C3C4 2
//#define COEF_C1C2 1
//#define COEF_C3C4 3
// Macro pentru scalarea variabilelor de intrare
#define Ks (32767/DIM_MAX)
#define SCAL(x) (x*Ks)
// "Viteza" stabilita pentru rotirea motoarelor
#define pwr 20
/**********************************************************************************************/
// Macrouri pentru multiplicare si impartire in C, pentru formatul Q15
/**********************************************************************************************/
#define MUL(a,b) ((a*b)>>15)
#define DIV(a,b) ((a<<15)/b)
// Macro pt trecerea din fractionar Q15 in procente, folosit pentru argumentele functiei acos din NXC
/* cu rotunjire, tinand cont de semn */
int sign(int a) {
if (a > 0)
return 1;
else if (a < 0)
return -1;
else
return 0;
}
#define SCALARE_100(a) (((a*100)>>14)+1*sign(a))>>1
// Macro-ul pt "breakpoint", realizat in lucrarea 1.
#define BREAKPOINT_AFISARE_VAR(string_x,x){\
TextOut(0,LCD_LINE1,string_x,true);\
NumOut(0,LCD_LINE2,x);\
Wait(1000);\
while(ButtonPressed(BTNCENTER,true)==0)\
{\
}\
}
short x_real, y_real; // coordonatele reale, in aceeasi unitate de masura
// folosita pentru DIM_MAX
short x, y; // coordonatele scalate
short r; // modulul vectorul de pozitie al punctului tinta
short r_patrat; // r la patrat
// Unghiurile, calculate cu functia acos din NXC rezulta in [grade].
// Tot in grade se vor introduce si unghiurile corespunzatoare pozitiei initiale
short arg1, arg2; // argumente ale functiei Acos, pt calculul
// unghiurilor gama si theta2
short theta1, theta2; // unghiurile celor doua segmente ale bratului
short theta1_ant, theta2_ant; // valorile unghiurlor coresp. poz.ant.
short D_theta1, D_theta2; // unghiurile cu care tb. rotite motoarele
// pentru obtinerea pozitiei
short theta, gama; // unghiuri auxiliare
short temp; // variabila pentru calcule intermediare
long temp_long; // variabila pentru calcule intermediare
int main()
{
// Initializare unghiuri coresp. pozitiei initiale a bratului
theta1_ant = 0; // [grade]
theta2_ant = 180; // [grade]
// Variabilele de intrare: coordonatele dorite, in [cm]
x_real = 14;
y_real = 0;
// Scalare variabile de intrare
x = SCAL(x_real);
y = SCAL(y_real);
// r^2 = x^2 + y^2.
// Variabila r^2 se pastreaza intr-o variabila, pt ca se refolosi in program.
r_patrat = MUL(x,x) + MUL(y,y);
temp_long = r_patrat << 15;
// Calcul theta = arccos(x/r). Inainte de impartirea x/r se testeaza daca x>=r.
// Aceasta deoarece numaratorul trebuie sa fie mai mic decat numitorul, pt a nu
// avea depasire in formatul Q15.
if (x>=r) // daca x>=r
temp = 32767; // rezultatul se satureaza la ~1, ie 32767
else
temp = DIV(x,r); // altfel, se face impartirea
temp = SCALARE_100(temp); // scalare in procente
// BREAKPOINT_AFISARE_VAR("theta= ",theta); //pt. debug
// Calcul argument arg1 = C1/r + C2*r (pentru unghiul gama)
// Ca sa evitam depasirea la impartire rearanjam expresia astfel:
/* arg1 = (C1+C2*r^2)/r, adica facem impartirea la sfarsit, stiind ca arg1 trebuie sa
rezulte geometric, in intervalul [-1,1].*/
temp = MUL(r,r);
temp = MUL(C2,temp)+ C1;
/* In situatia, posibila, in care numaratorul si numitorul ar fi egali, rezultatul ar trebui
sa fie ~1. Facem deci acelasi test ca la impartirea anterioara:*/
if (temp>=r) // daca x>=r
temp = 32767; // rezultatul se satureaza la ~1, ie 32767
else
temp = DIV(temp,r); // altfel, se face impartirea
arg1 = temp;
/* Inmultirea directa a argumentului arg1 cu coeficientul COEF_C1C2 folosit
la scalare. Daca COEF_C1C2 s-a ales ca putere a lui 2, se face deplasare (shift) la
stanga, in loc de inmultire directa */
arg1 = arg1 << SH_C1C2;
//arg1 = arg1 * COEF_C1C2;
// Calcul unghi gama:
arg1 = SCALARE_100(arg1); // scalare in procente (arg
// functiei Acos din NXC)
// BREAKPOINT_AFISARE_VAR("gama= ",gama); // pt. debug
// Calcul arg2 = C3 - C4*r^2, pt unghiul theta2:
temp = MUL(r,r);
arg2 = C3 - MUL(C4,temp);
arg2 = arg2 << SH_C3C4;
// arg2 = arg2 * COEF_C3C4;
// Calcul theta2:
arg2 = SCALARE_100(arg2); // scalare in procente (arg
// functiei Acos din NXC)
// BREAKPOINT_AFISARE_VAR("theta2= ",theta2); // pt. debug
// Calcul theta1 = gama + theta:
theta1 = gama + theta;
}
// BREAKPOINT_AFISARE_VAR("theta1= ",theta1); // pt. debug
// Calcul unghiurilor cu care trebuie rotite motoarele, fata de pozitia anterioara:
//D_theta1 = theta1 - theta1_ant;
//D_theta2 = theta2 - theta2_ant;