Cinemática Inversa III
Cinemática Inversa para un Brazo Robot de 5 grados de libertad.
Programado en FreeBasic (implementación de OpenGL)
En los apartados "Cinemática I" y "Cinemática II" nos movíamos siempre sobre los ejes X e Y, y lo aplicábamos al brazo tipo Scara. Ahora es el momento de subir el nivel y pasar a calcular una cinemática inversa aplicada a las 3 dimensiones para un brazo robot antropomorfo de 4 ó 5 grados de libertad. En realidad es mucho más sencillo de lo que parece porque vamos a seguir usando las mismas fórmulas que anteriormente pero antes de pasar a ellas tenemos que hacer unos ajustes para que el brazo entre en la nueva dimensión. El eje X se mantendrá en la misma posición sobre el plano, el eje Y pasará a convertirse en la profundidad y el eje Z en la altura.
Conocemos los ejes XYZ y la longitud de las articulaciones. Con estos datos hemos de averiguar todos los ángulos del brazo robot. Lo primero de todo es hallar el ángulo de giro de todo el brazo. Sólo hemos de hacer lo siguiente:
Ya tenemos un resultado. Ahora viene la parte un poco liosa, se trata de entender los conceptos:
Para facilitarnos los cálculos, como ya tenemos resuelto la cinemática inversa para 3 grados de libertad, vamos a hacer una especie de equivalencia, donde sólo tendremos que calcular un eje X ficticio y otro eje Y ficticio; se llamarán Xprima e Yprima. Xprima e Yprima en realidad son los ejes X e Y visto en dos dimensiones, como hacíamos con el brazo Scara; en la imagen de arriba puedes comprobarlo. Veamos cómo hacemos la reconversión.
Primero calculamos el Módulo formado por los catetos X e Y:
Modulo = Sqr( (X^2) + (Y^2) )
Después hacemos una reconversión de variables, las cuales nos hará de puente para usar el mismo método de resolución de ángulos que en Cinemática II.
Xprima = Modulo
Yprima = Z
Ahora podemos resolver el resto de los ángulos de la misma forma que en el apartado anterior. Tenemos Xprima e Yprima que hemos deducido del espacio 3D, y añadimos la variable AlturaH que es la distancia entre la base (suelo) y el hombro del brazo. Todo lo que sigue ahora es prácticamente igual que en el apartado Cinemática II.
Como ves en la imagen, hemos resuelto el ángulo de giro de todo el brazo, el ángulo del brazo, el ángulo del antebrazo y ángulo de la muñeca [pitch]. Si añadimos el giro de la muñeca [roll] (éste ángulo no afecta al resto de los ángulos del brazo, por tanto no afecta a la cinemática inversa) pasamos a tener 5 grados de libertad. Las pinzas o terminal no se cuenta como grado de libertad pero sí has de tenerlo presente como parte de la longitud de la muñeca a efectos de cálculos; es decir, la longitud de la muñeca total es la suma de la longitud de la muñeca real más la longitud del terminal o pinzas.
Programé un pequeño script en modo calculadora (no gráfico) que computa la cinemática inversa según los datos que le entras y muestra los ángulos como resultado. Procediendo de esta manera se aprecia mejor el funcionamiento; para más información clic aquí.
Implementando OpenGL.
Dibujar simples líneas en 3D era mucho más complicado de lo que me imaginaba, así que aprendí a implementar "OpenGL" para visualizar el brazo robot en 3D. Más abajo, en esta página, encontrarás un enlace para que puedas bajarte el código fuente y ejecutable de "BrazoSimple".
Nota Importante:
Si al ejecutar el simulador el brazo se mueve con demasiada lentitud significa que tu tarjeta de vídeo está configurada para tener mucho "Antialiasing".
Esto no tiene nada que ver con la potencia de tu ordenador: Haz clic aquí para más información.
(Si usas antivirus Avast has de añadir una exclusión para poder ejecutarlo. Para analizar este o cualquier otro archivo puedes hacer clic aquí)
- Clic aquí y explico cómo sacar los datos por el puerto RS232 o por un puerto serie virtual.
- Clic aquí y obtendrás código fuente y ejecutable de un brazo con datos alfanuméricos en pantalla.
Sobre el programa.
Expongo las referencia del material que fui extrayendo hasta conseguir el código fuente. La aparente complejidad del código es debido al interface gráfico, realizado con OpenGL; es muy sencillo de manejar desde "FreeBasic". Los encabezamientos son siempre los mismos. Yo comencé con tres cubos y luego modifiqué las dimensiones de los cubos para formar el brazo robot. Con el tiempo añadí la muñeca.
El programa está escrito en "FreeBasic", concretamente en FreeBasic IDE (FBIDE), y puedes descargarlo desde este lugar:
(Elige "FBIde + FreeBASIC installer".)
- http://fbide.freebasic.net/download -
Clic aquí para ver un tutorial rápido sobre la instalación.
En FreeBasic se puede manejar punteros, crear estructuras de datos y está orientado a objetos al igual que C++.
Todas las versiones de FreeBasic viene con una carpeta llamada "NeHe" (Neón Helio). Está un poco escondida ..\FreeBasic\examples\GL\NeHe. Es todo un curso sobre OpenGL y prácticamente todo lo que sé lo aprendí estudiando esos códigos de ejemplo en forma de lecciones.
Cuando ejecutes el programa podrás mover el brazo de la siguiente manera:
Teclas:
A D —–> Mueve linealmente el brazo sobre el eje X.
Q E —–> Mueve linealmente el brazo sobre el eje Y.
W S —-> Mueve linealmente el brazo sobre el eje Z.
Z X —–> Cabeceo de la muñeca. (Pitch.)
C V —–> Balanceo de la muñeca. (Roll.)
N M —-> Abre/cierra las pinzas.
Pulsar "Esc" para salir del programa.
Si al compilar te da error o estás bajo plataforma Linux ves al final de esta página.
El programa: Código Fuente.
The translation could modify the code. Use the code without translating or download the program by clicking the link above or clic here.#Include Once "GL/gl.bi"
#Include Once "GL/glu.bi"
#Include Once "GL/glut.bi"
#Include Once "fbgfx.bi"
#Include Once "createtex.bi"
Declare Sub InverseK
Declare Sub DibujaBrazo
'--------------- Declaración de variables ------------------
Dim Shared As Double Pi, Rad, Grad, Balance, Cabeceo, AngGiro, AngBrazo,_
AngAntBr, AngMunecA, AngMunecB
Dim Shared As Integer LongBrazo, LongAntBr, LongMunec, LongDedos, AlturaH
Dim Shared As Single Xreal, Yreal, Zreal
Dim Shared As Single LHombro, LBrazo, LAntBr, LMunec, LDedos, DistDedos=.11,_
EscenaX, EscenaY, Distancia, Espacio
Dim As Single EjeX, EjeY, EjeZ
'---------Configurar escenario para el OpenGL---------
Screen 12, 16, , 2 ' Este encabezamiento de OpenGL siempre se repite.
glClearColor 0.0, 0.0, 0.0, 0.0 ' No hay que asustarse al ver este tipo de código
glMatrixMode GL_PROJECTION ' porque cada vez que implementas OpenGL se copia
glViewport 0, 0, 640, 480 ' y pega esta parte.
gluPerspective 45.0, 640.0/480.0, 0.1, 100.0
gluLookAt 0,0,1, 0,0,0, 0,1,0
glMatrixMode GL_MODELVIEW
glLoadIdentity
glClearColor 0.0, 0.0, 0.0, 0.5
glClearDepth 1.0
glEnable GL_DEPTH_TEST
glDepthFunc GL_LEQUAL
glHint GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST
'-----Carga de Variables------
Pi = Atn(1) * 4
Rad = Pi / 180
Grad = 180 / Pi
'-=-=- Ajustes del Brazo: Dimensiones, distancias, etc. -=-=-
AlturaH = 200 ' Altura del Hombro. (Distancia del suelo hasta la articulación del hombro.)
LongBrazo = 250 ' Longitud Brazo. Puedes modificar si quieres las dimensiones
LongAntBr = 300 ' Longitud AnteBrazo. de las articulaciones del brazo robot.
LongMunec = 100 ' Longitud Muñeca.
LongDedos = 50 ' Longitud Pinzas.
XReal=(300) ' Posición Inicial X. Situamos el brazo robot en un punto del espacio.
YReal=( 0) ' Posición Inicial Y. Si modificas estos valores procura que esté dentro
ZReal=(150) ' Posición Inicial Z. del área de trabajo del brazo robot.
Cabeceo=-90 ' Ang. Pitch inicial de la Muñeca.
Balance=0
EscenaX=0 ' Perspectiva Inicial del Escenario.
EscenaY=0
'------ No tocar los valores de estas variables --------------------
LHombro = AlturaH /100
LBrazo = LongBrazo/100 ' Equivalente en dimensiones de OpenGL.
LAntBr = LongAntBr/100 ' No tocar aquí.
LMunec = LongMunec/100 ' Aunque depende de la configuración de
LDedos = LongDedos/100 ' OpenGL, las medidas suelen ser unas 100
Espacio = LBrazo+LAntBr ' veces más pequeñas que la original y
' suelen, no siempre, incluir decimales.
'-------------------------------------------------------------------
'-=-=-=-=-=- Programa Principal -=-=-=-=-=-
While Not MultiKey(FB.SC_ESCAPE)
InverseK ' Ir a la Cinemática Inversa para calcular la posición de los ángulos.
' Control del Brazo mediante el teclado.
If MultiKey(FB.SC_A) Then Xreal=Xreal-1
If MultiKey(FB.SC_D) Then Xreal=Xreal+1
If MultiKey(FB.SC_S) Then Yreal=Yreal-1
If MultiKey(FB.SC_W) Then Yreal=Yreal+1
If MultiKey(FB.SC_Q) Then Zreal=Zreal-1
If MultiKey(FB.SC_E) Then Zreal=Zreal+1
If MultiKey(FB.SC_C) Then Balance=Balance-.5
If MultiKey(FB.SC_V) Then Balance=Balance+.5
If MultiKey(FB.SC_Z) Then Cabeceo=Cabeceo-.5
If MultiKey(FB.SC_X) Then Cabeceo=Cabeceo+.5
If MultiKey(FB.SC_N) Then
If DistDedos>.11 Then DistDedos=DistDedos-.005
EndIf
If MultiKey(FB.SC_M) Then
If DistDedos<.4 Then DistDedos=DistDedos+.005
EndIf
If MultiKey(FB.SC_LEFT) Then EscenaX=EscenaX-.5
If MultiKey(FB.SC_RIGHT) Then EscenaX=EscenaX+.5
If MultiKey(FB.SC_UP) Then EscenaY=EscenaY+.5
If MultiKey(FB.SC_DOWN) Then EscenaY=EscenaY-.5
If MultiKey(FB.SC_PAGEUP) Then Distancia=Distancia+.1
If MultiKey(FB.SC_PAGEDOWN) Then Distancia=Distancia-.1
Wend
End
Sub InverseK '----------------------Cinemática Inversa----------------
Dim As Double Afx, Afy, LadoA, LadoB, Alfa, Beta, Gamma, Modulo, Hipotenusa, Xprima, Yprima
Static As Single Xaux, Yaux, Zaux, Baux, Caux
'----Ang Giro (en Grados)----------- ' En todos los lenguajes de programación, las
AngGiro = (Atan2(Yreal, Xreal))*Grad ' funciones trigonométricas las resuelve en
'----------------------------------- ' radianes. OpenGL necesita los valores en grados
' sexagesimales, por eso multiplicamos por 'Grad'.
Modulo = Sqr(Abs(Xreal^2)+Abs(Yreal^2))
Xprima=Modulo
Yprima=Zreal
Afx=Cos(Rad*Cabeceo)*(LongMunec+LongDedos)
LadoB=Xprima-Afx
Afy=Sin(Rad*Cabeceo)*(LongMunec+LongDedos)
LadoA=Yprima-Afy-AlturaH
Hipotenusa=Sqr((LadoA^2)+(LadoB^2))
Alfa=Atan2(LadoA,LadoB)
Beta=ACos( ((LongBrazo^2)-(LongAntBr^2)+(Hipotenusa^2))/(2*LongBrazo*Hipotenusa) )
'----Ang BRAZO (en Grados).------------
AngBrazo= (Alfa+Beta)*Grad
'--------------------------------------
Gamma=ACos( ((LongBrazo^2)+(LongAntBr^2)-(Hipotenusa^2))/(2*LongBrazo*LongAntBr) )
'----Ang ANTEBRAZO (en Grados).--------
AngAntBr=(-((180*Rad)-Gamma))*Grad
'--------------------------------------
'----Ang MUÑECAS (en Grados).----------
AngMunecA= Cabeceo-AngBrazo-AngAntBr
AngMunecB= Balance ' Balance no afecta a la IK*, por eso se
'-------------------------------------- ' carga directamente.
' *(IK=Inverse Kinematics=Cinemática Inversa)
If (Str(AngBrazo)="-1.#IND") Or (Str(AngAntBr)= "-1.#IND") Then
Xreal=Xaux ' Si hay ángulos imposibles pasa a posición anterior.
Yreal=Yaux
Zreal=Zaux
Balance=Baux
Cabeceo=Caux
InverseK ' En caso de error, se llama a sí misma para repetir el cálculo
' con los valores anteriores correctos.
EndIf
Xaux=Xreal
Yaux=Yreal
Zaux=Zreal
Baux=Balance
Caux=Cabeceo
DibujaBrazo ' Llama al procedimiento que dibuja el brazo robot con OpenGL,
' con los valores de los ángulos calculados.
End Sub
Sub DibujaBrazo
' -------Animación OpenGL--------------------
glClear(GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT) ' Es una especie de CLS en OpenGL.
glLoadIdentity
'---------- Espacio --------------------
glTranslatef 0.0, 0.0, Distancia-10 ' Esta parte nos permite mover todo
glRotatef 35, 1.0, 0.0, 0.0 ' el escenario en los ejes X e Y.
glRotatef EscenaX, 0.0, 1.0, 0.0
glRotatef EscenaY, 1.0, 0.0, 0.0
' ---------- Hombro ---------------------
glBegin(GL_QUADS)
glColor3f 0.2, 0.2, 0.3 ' Crea la superficie del suelo.
glVertex3f Espacio, -LHombro, Espacio
glVertex3f -Espacio, -LHombro, Espacio
glVertex3f -Espacio, -LHombro, -Espacio
glVertex3f Espacio, -LHombro, -Espacio
glEnd
glRotatef AngGiro, 0.0, 1.0, 0.0
glBegin(GL_QUADS) ' Crea el hombro del brazo.
glColor3f 0.1, 0.2, 0.4
glVertex3f 0.4, 0.0, -0.6
glVertex3f -0.4, 0.0, -0.6 ' Al igual que un cubo tiene 6 facetas (caras)
glVertex3f -0.4, 0.0, 0.6 ' aquí "dibujamos" las 6 facetas de la
glVertex3f 0.4, 0.0, 0.6 ' articulación del hombro.
' Todo esto se repite en adelante con cada
glColor3f 0.2, 0.2, 0.4 ' articulación. Sólo cambia el tamaño y color.
glVertex3f 0.4, -LHombro, 0.6
glVertex3f -0.4, -LHombro, 0.6
glVertex3f -0.4, -LHombro, -0.6
glVertex3f 0.4, -LHombro, -0.6 ' Tal como lo he configurado, las unidades
' están comprendidas entre -1.0 y +1.0 por
glColor3f 0.2, 0.1, 0.4 ' eso todo está en decimal. Si multiplicas
glVertex3f 0.4, 0.0, 0.6 ' por 100 tienes el tamaño real.
glVertex3f -0.4, 0.0, 0.6
glVertex3f -0.4, -LHombro, 0.6
glVertex3f 0.4, -LHombro, 0.6
glColor3f 0.1, 0.2, 0.5
glVertex3f 0.4, -LHombro, -0.6
glVertex3f -0.4, -LHombro, -0.6
glVertex3f -0.4, 0.0, -0.6
glVertex3f 0.4, 0.0, -0.6
glColor3f 0.2, 0.1, 0.5
glVertex3f -0.4, 0.0, 0.6
glVertex3f -0.4, 0.0, -0.6
glVertex3f -0.4, -LHombro, -0.6
glVertex3f -0.4, -LHombro, 0.6
glColor3f 0.3, 0.2, 0.5
glVertex3f 0.4, 0.0, -0.6
glVertex3f 0.4, 0.0, 0.6
glVertex3f 0.4, -LHombro, 0.6
glVertex3f 0.4, -LHombro, -0.6
glEnd()
'------------- Brazo ----------------
glTranslatef 0.0, 0.0, 0.0
glRotatef AngBrazo, 0.0, 0.0, 1.0 ' Cada vez que veas un glRotatef significa que
' la figura gira en un plano del espacio; aquí
glColor3f 0.0, 1.0, 0.0 ' representa el movimiento de una articulación.
glutSolidSphere 0.6, 11, 11
glBegin(GL_QUADS) ' Crea las 6 facetas (caras) del brazo.
glColor3f 1.0, 0.0, 0.0
glVertex3f LBrazo, 0.3, -0.4
glVertex3f 0.0, 0.3, -0.4
glVertex3f 0.0, 0.3, 0.4
glVertex3f LBrazo, 0.3, 0.4
glColor3f 1.0, 0.5, 0.0
glVertex3f LBrazo, -0.3, 0.4
glVertex3f 0.0, -0.3, 0.4
glVertex3f 0.0, -0.3, -0.4
glVertex3f LBrazo, -0.3, -0.4
glColor3f 1.0, 0.0, 0.5
glVertex3f LBrazo, 0.3, 0.4
glVertex3f 0.0, 0.3, 0.4
glVertex3f 0.0, -0.3, 0.4
glVertex3f LBrazo, -0.3, 0.4
glColor3f 1.0, 0.2, 0.0
glVertex3f LBrazo, -0.3, -0.4
glVertex3f 0.0, -0.3, -0.4
glVertex3f 0.0, 0.3, -0.4
glVertex3f LBrazo, 0.3, -0.4
glColor3f 1.0, 0.7, 0.2
glVertex3f 0.0, 0.3, 0.4
glVertex3f 0.0, 0.3, -0.4
glVertex3f 0.0, -0.3, -0.4
glVertex3f 0.0, -0.3, 0.4
glColor3f 1.0, 0.8, 0.3
glVertex3f LBrazo, 0.3, -0.4
glVertex3f LBrazo, 0.3, 0.4
glVertex3f LBrazo, -0.3, 0.4
glVertex3f LBrazo, -0.3, -0.4
glEnd()
'----------- Ant.Brazo -----------
glTranslatef LBrazo, 0.0, 0.0
glRotatef AngAntBr, 0.0, 0.0, 1.0
glColor3f 0.0, 0.0, 1.0
glutSolidSphere 0.5, 11, 11
glBegin(GL_QUADS) 'Crea las 6 facetas del antebrazo.
glColor3f 0.0, 1.0, 0.0
glVertex3f LAntBr, 0.3, -0.3
glVertex3f 0.0, 0.3, -0.3
glVertex3f 0.0, 0.3, 0.3
glVertex3f LAntBr, 0.3, 0.3
glColor3f 0.1, 1.0, 0.2
glVertex3f LAntBr, -0.3, 0.3
glVertex3f 0.0, -0.3, 0.3
glVertex3f 0.0, -0.3, -0.3
glVertex3f LAntBr, -0.3, -0.3
glColor3f 0.2, 1.0, 0.5
glVertex3f LAntBr, 0.3, 0.3
glVertex3f 0.0, 0.3, 0.3
glVertex3f 0.0, -0.3, 0.3
glVertex3f LAntBr, -0.3, 0.3
glColor3f 0.4, 1.0, 0.2
glVertex3f LAntBr, -0.3, -0.3
glVertex3f 0.0, -0.3, -0.3
glVertex3f 0.0, 0.3, -0.3
glVertex3f LAntBr, 0.3, -0.3
glColor3f 0.0, 1.0, 0.5
glVertex3f 0.0, 0.3, 0.3
glVertex3f 0.0, 0.3, -0.3
glVertex3f 0.0, -0.3, -0.3
glVertex3f 0.0, -0.3, 0.3
glColor3f 0.3, 1.0, 0.2
glVertex3f LAntBr, 0.3, -0.3
glVertex3f LAntBr, 0.3, 0.3
glVertex3f LAntBr, -0.3, 0.3
glVertex3f LAntBr, -0.3, -0.3
glEnd()
'------------- Muñeca -------------
glTranslatef LAntBr, 0.0, 0.0
glRotatef AngMunecA, 0.0, 0.0, 1.0
glRotatef AngMunecB, 1.0, 0.0, 0.0
glColor3f 1.0, 0.0, 0.0
glutSolidSphere 0.4, 13, 13
glBegin(GL_QUADS) ' Crea las 6 facetas de la muñeca.
glColor3f 0.0, 0.0, 1.0
glVertex3f LMunec, 0.3, -0.2
glVertex3f 0.0, 0.3, -0.2
glVertex3f 0.0, 0.3, 0.2
glVertex3f LMunec, 0.3, 0.2
glColor3f 0.2, 0.0, 1.0
glVertex3f LMunec, -0.3, 0.2
glVertex3f 0.0, -0.3, 0.2
glVertex3f 0.0, -0.3, -0.2
glVertex3f LMunec, -0.3, -0.2
glColor3f 0.0, 0.3, 1.0
glVertex3f LMunec, 0.3, 0.2
glVertex3f 0.0, 0.3, 0.2
glVertex3f 0.0, -0.3, 0.2
glVertex3f LMunec, -0.3, 0.2
glColor3f 0.0, 0.4, 1.0
glVertex3f LMunec, -0.3, -0.2
glVertex3f 0.0, -0.3, -0.2
glVertex3f 0.0, 0.3, -0.2
glVertex3f LMunec, 0.3, -0.2
glColor3f LMunec, 0.0, 1.0
glVertex3f 0.0, 0.3, 0.2
glVertex3f 0.0, 0.3, -0.2
glVertex3f 0.0, -0.3, -0.2
glVertex3f 0.0, -0.3, 0.2
glColor3f 0.2, 0.2, 1.0
glVertex3f LMunec, 0.3, -0.2
glVertex3f LMunec, 0.3, 0.2
glVertex3f LMunec, -0.3, 0.2
glVertex3f LMunec, -0.3, -0.2
glEnd()
'------------ Dedos-------------
glTranslatef LMunec, 0.0, DistDedos
glBegin(GL_QUADS) ' Crea la 6 facetas de la primera pinza.
glColor3f 0.0, 0.6, 0.5
glVertex3f LDedos, 0.1, -0.1
glVertex3f 0.0, 0.1, -0.1
glVertex3f 0.0, 0.1, 0.1
glVertex3f LDedos, 0.1, 0.1
glColor3f 0.0, 0.8, 0.4
glVertex3f LDedos, -0.1, 0.1
glVertex3f 0.0, -0.1, 0.1
glVertex3f 0.0, -0.1, -0.1
glVertex3f LDedos, -0.1, -0.1
glColor3f 0.0, 0.5, 0.3
glVertex3f LDedos, 0.1, 0.1
glVertex3f 0.0, 0.1, 0.1
glVertex3f 0.0, -0.1, 0.1
glVertex3f LDedos, -0.1, 0.1
glColor3f 0.0, 0.4, 0.4
glVertex3f LDedos, -0.1, -0.1
glVertex3f 0.0, -0.1, -0.1
glVertex3f 0.0, 0.1, -0.1
glVertex3f LDedos, 0.1, -0.1
glColor3f 0.0, 0.3, 0.5
glVertex3f 0.0, 0.1, 0.1
glVertex3f 0.0, 0.1, -0.1
glVertex3f 0.0, -0.1, -0.1
glVertex3f 0.0, -0.1, 0.1
glColor3f 0.0, 0.2, 0.6
glVertex3f LDedos, 0.1, -0.1
glVertex3f LDedos, 0.1, 0.1
glVertex3f LDedos, -0.1, 0.1
glVertex3f LDedos, -0.1, -0.1
glEnd()
glTranslatef 0.0, 0.0, DistDedos*(-2)
glBegin(GL_QUADS) ' Crea la 6 facetas de la segunda pinza.
glColor3f 0.0, 0.6, 0.5
glVertex3f LDedos, 0.1, -0.1
glVertex3f 0.0, 0.1, -0.1
glVertex3f 0.0, 0.1, 0.1
glVertex3f LDedos, 0.1, 0.1
glColor3f 0.0, 0.8, 0.4
glVertex3f LDedos, -0.1, 0.1
glVertex3f 0.0, -0.1, 0.1
glVertex3f 0.0, -0.1, -0.1
glVertex3f LDedos, -0.1, -0.1
glColor3f 0.0, 0.5, 0.3
glVertex3f LDedos, 0.1, 0.1
glVertex3f 0.0, 0.1, 0.1
glVertex3f 0.0, -0.1, 0.1
glVertex3f LDedos, -0.1, 0.1
glColor3f 0.0, 0.4, 0.4
glVertex3f LDedos, -0.1, -0.1
glVertex3f 0.0, -0.1, -0.1
glVertex3f 0.0, 0.1, -0.1
glVertex3f LDedos, 0.1, -0.1
glColor3f 0.0, 0.3, 0.5
glVertex3f 0.0, 0.1, 0.1
glVertex3f 0.0, 0.1, -0.1
glVertex3f 0.0, -0.1, -0.1
glVertex3f 0.0, -0.1, 0.1
glColor3f 0.0, 0.2, 0.6
glVertex3f LDedos, 0.1, -0.1
glVertex3f LDedos, 0.1, 0.1
glVertex3f LDedos, -0.1, 0.1
glVertex3f LDedos, -0.1, -0.1
glEnd()
Flip '<----- Muestra el gráfico en el monitor. -------
Sleep 5 ' Una pausa para que el brazo se mueva a una velocidad adecuada.
End Sub
Tres últimas cosas:
* 1.) Según la versión del compilador de Freebasic, en las funciones "MultiKey()" puede dar problemas. Si te da fallo en esa función tendrías que cambiar todos los "FB.SC_" por "SC_", o al revés (según el caso), y asunto resuelto.
Ejemplo:
If MultiKey(FB.SC_A) Then Xreal=Xreal-1
por
If MultiKey(SC_A) Then Xreal=Xreal-1
Así con todas las funciones "MultiKey()".
* 2.) La última versión del compilador FreeBasic puede darte un error al compilar si tienes un "windows.bi" de otra versión estando en la misma carpeta que el código fuente. Lo que has de hacer es eliminar el "windows.bi" de dicha carpeta (sólo si el código fuente y "windows.bi" está en la misma carpeta). En los programas de descarga lo dejo para poder ser compatible con versiones anteriores, pero si te sale el Error 58 has de eliminar "windows.bi" de la carpeta que acompaña al código fuente.
Ejemplos de tipos de errores del compilador en las últimas versiones:
* 3.) Este programa funciona correctamente en plataformas Windows. Si compilas el programa bajo Linux o estás con otro sistema operativo no-Windows aunque te permita emular Windows el brazo robot no tendrá en cuenta los límites y llegado a este punto desaparece del monitor. Cuando pides al brazo que vaya a un lugar donde no puede alcanzar, normalmente el brazo se para en ese límite y no sigue. Pero en Linux y otras plataformas esto no lo podrá tener en cuenta porque en el programa, cuando da un "error de función fuera de rango", espera el mensaje: "-1.#IND". Hay que hacer la sustitución de "-1.#IND" por "1.#QNAN" (normalmente), ó "Inf" o bien "NaN" dentro del procedimiento "Inversek". Desconozco la sintaxis concreta.