CURVA SERPENTINOIDE

Autor: Juan González Gómez (Obijuan)

Fecha: 18-Enero-2015

Licencia: Licencia Creative Commons BY-SA para el texto e imágenes. GPL v2 para el software

Este notebook es una adaptación de esta página de la wiki donde se comenzó a documentar la curva y su implementación en octave/Matlab

Además de ampliar la información sobre la curva, quiero aprovechar para aprender los ipython notebooks

Introducción

La curva serpentinoide (o curva serpenoide, serpenoid curve en inglés) la descubrió el profesor Hirose en 1976 cuando realizaba su tesis doctoral en el Instituto de tecnología de Tokyo. Investigaba la biomecánica de las serpientes para su aplicación a la construcción de robots.

La curva serpentinoide es indispensable para el estudio y construcción de robots ápodos (gusanos y serpientes). El autor de este artículo la ha estudiado en su tesis doctoral para aplicarla a la locomoción de estos robots.

En este documento se describe la curva/onda serpentinoide, sus parámetros, sus propiedas y se presentan scripts en python para implementarla.

Curva serpentinoide continua

Definición

La curva serpentinoide es aquella cuya curvatura varía sinusoidalmente con la distancia a lo largo de la curva.

Su curvatura está dada por la ecuación:

$ K(s) = \frac{2\pi k}{l}\alpha\sin\left(\frac{2\pi k}{l}s\right) $ Ecuación de curvatura de la serpentinoide (**ec. 1**)

donde:

<table align = "left">

** $l$ ** Longitud total de la curva $ (l > 0) $ ** $s$ ** Es la variable. [Longitud del arco](http://es.wikipedia.org/wiki/Longitud_de_arco). Es la distancia a lo largo de la curva. $ s\in\left[0,l\right] $ ** $ k $ ** Número de ondulaciones. $ k > 0 $ ** $ \alpha $ ** Ángulo de serpenteo. $ \alpha\in\left[0,121\right] $

</table>

Ángulo de serpenteo $ \alpha $

El ángulo de serpenteo $ \alpha $ es la pendiente de la curva en el punto $ s = 0 $ y determina la forma que tendrá la curva.

En la figura 1 se muestra la forma para ángulos de serpenteo de 0, 30, 60 y 90. Para $ \alpha=0 $ es una recta situada sobre el eje x, de longitud $ l $. Al aumentar $ \alpha $ la curva se eleva, ganando en altura pero reduciéndose en anchura.

En la figura 2 se muestra la curva serpentinoide para $ \alpha=121 $ grados, que es su valor máximo. A partir de ahí se producen colisiones entre los puntos de la curva.

<table align = "left">

**Figura 1**: Forma de la curva serpentinoide para diferentes valores del ángulo de serpenteo ($ \alpha $)

</table>

<table align = "left">

**Figura 2**: Curva serpentinoide de ángulo de serpenteo ($ \alpha $) máximo. Se muestran dos ondulaciones ( $ k=2 $)

</table>

Animación de la variación de la forma con $ \alpha $

En esta animación se puede ver cómo varía la forma de una curva serpentinoide de longitud fija $ l $ y 2 ondulaciones ($ k = 2 $), para diferentes ángulos de serpenteo. Cuando $ \alpha $ es cero, la curva serpentinoide es una recta de longitud $ l $ apoyada sobre el eje x

<img src="images/gif/Serp_continuous_alpha_anim.gif" align = "left">

Número de ondulaciones ($ k $)

El parámetro $ k $ determina el número de ondulaciones de la curva serpentinoide.

En la figura 3 se han representado tres curvas con el mismo valor del ángulo de serpenteo ($ \alpha=70 $) y misma longitud $ l $, pero con diferentes valores de $ k $. Al aumentar k, aumenta el número de ondulaciones, disminuye la altura pero la anchura permanece constante

<table align = "left">

**Figura 3**: Forma una curva serpentinoide de longitud $ l $ para diferentes valores del parámetro $ k $, manteniendo fijo el valor de $ \alpha $ a 70

</table>

Animación de la variación de la forma con $ k $

En la siguiente animación se muestra cómo varía la forma de una curva serpentinoide continua de longitud fija $ l=1 $ y ángulo de serpenteo $ \alpha = 70 $ con el parámetro $ k $. Se puede apreciar una propiedad muy importante: La anchura en el eje x NO varía con k

<img src="images/gif/Serp_continuous_k_anim.gif" align = "left">

Longitud ($l$)

La longitud l de la curva determina su escala. En la figura 4 se muestra una curva serpentinoide con valores fijos del ángulo de serpenteo ($ \alpha $) y de las ondulaciones ($ k $) pero con distintas longitudes. La forma es la misma, pero escalada. Normalmente $ l $ es una constante, ya que los robots tienen longitud fija. Salvo que se trate de un robot modulare reconfigurable en cuyo caso puede aumentar por la adición de núevos módulos o disminuir por su separación

<table align = "left">

**Figura 4**: Forma de la curva serpentinoide con valores fijos del ángulo de serpenteo $ \alpha=70 $ y $ k=1 $ para diferentes valores de la longitud $ l $. La longitud determina la escala.

</table>

Puntos de interés

<table align = "left">

**Figura 5**: Situación de los puntos de máxima y nula curvatura en una serpentinoide de $k=2$ y $\alpha=70$

</table>

Puntos de mínima curvatura (curvatura 0)

Para una curva serpentinoide con ángulo de serpenteo mayor de cero ($ \alpha > 0 $), los puntos donde la curvatura es 0 son:

$ s = n\frac{l}{2k}$ con $ n = 0, 1, 2 ... $ Puntos curvatura mínima (**ec. 2**)

Demostración

Los puntos de la curva serpentinoide donde la curvatura es cero los calculamos igualando la ec. 1 a cero

$ K\left(s\right)=0 \Longrightarrow\ \frac{2\pi k}{l}\alpha\sin\left(\frac{2\pi k}{l}s\right) = 0$

Puesto que por definición, la longitud de la curva y el número de ondulaciones son distintos de cero ($ k > 0 $ y $ l > 0$) se tiene que:

$ \alpha\sin\left(\frac{2\pi k}{l}s\right) = 0 $

Y esta igualdad se cumple en dos casos:

  • Caso 1: $ \alpha = 0 $. Es el caso en el que la curva serpentinoide es una línea recta de longitud $ l $ apoyada sobre el eje x. Todos sus puntos tienen curvatura 0

  • Caso 2: $ \sin\left(\frac{2\pi k}{l}s\right) = 0 $ $ \Longrightarrow\ \frac{2\pi k}{l}s = \pi n$ con $ n = 0, 1, 2 ... \Longrightarrow\ s = n\frac{l}{2k}$ con $ n = 0, 1, 2 ... $

Puntos de máxima curvatura

Para una curva serpentinoide con ángulo de serpenteo mayor de cero ($\alpha > 0 $), los puntos de curvatura máxima son:

$ s = (2n + 1) \frac{l}{4k} $, con $ n = 0,1,2,3... $ Puntos curvatura máxima (**ec. 3**)

Demostración

Los puntos de máxima curvatura los obtendremos calculando los máximos y mínimos de la ecuación de curvatura de la serpentinoide (ec. 1). Para ello igualamos a cero el valor absoluto de la derivada de la ecuación de curvatura:

$ | \frac{dK(s)}{ds} | = 0 \Longrightarrow\ | \frac{d \left( \frac{2\pi k}{l}\alpha\sin\left(\frac{2\pi k}{l}s\right) \right) }{ds} | = 0 \Longrightarrow\ \left( \frac{2\pi k}{l} \right)^2 \alpha \cos\left( \frac{2\pi k}{l}s \right) = 0 \Longrightarrow\ \alpha \cos\left( \frac{2\pi k}{l}s \right) = 0 $

El caso $ \alpha = 0 $ es una línea recta, así que, para el resto de curvas donde $ \alpha > 0 $ se cumple que:

$ \cos\left( \frac{2\pi k}{l}s \right) = 0 $

y eso implica que:

$ \frac{2\pi k}{l}s = \frac{\pi}{2} + n\pi $

Despejando s obtenemos la condición:

$ s = (2n + 1) \frac{l}{4k} $, con $ n = 0,1,2,3... $

Pendiente de la curva $ \alpha_s $

<table align = "left">

**Figura 6**: $ \alpha_s $ en diferentes puntos de la curva serpentinoide

</table>

Denotamos la pendiente del vector tangente a la curva por el punto s como \alpha_s

Por definición, la curvatura se define como el ritmo de cambio del vector unidad tangente a la curva, es decir:

$ K(s)=\frac{d\alpha_{s}}{ds} $

A partir de esa ecuación calculamos la pendiente de la curva mediante integración:

$ \alpha_{s}=\alpha+\int_{0}^{s}K(s)ds $

llegando a la expresión:

$ \alpha_{s}=\alpha\cos\left(\frac{2\pi k}{l}s\right) $ Pendiente de la curva serpentinoide **ec. 4**

En la figura 6 se muestra el valor de $ \alpha_s $ sobre una curva serpentinoide. En los puntos de máxima curvatura $ \alpha_s = 0 $ y en los de curvatura nula $ |\alpha_s|=\alpha $

Formulación de la curva serpentinoide en coordenadas cartesianas

Las coordenadas cartesianas $ (x,y) $ de un punto $ s $ situado en la curva serpentinoide están dadas por las ecuaciones 5 y 6:

$ x\left(s\right)=\int_{0}^{s}\cos\left(\alpha\cos\left(\frac{2\pi k}{l}s\right)\right)ds $ Coordenada x de la curva serpentinoide **ec. 5**
$ y\left(s\right)=\int_{0}^{s}\sin\left(\alpha\cos\left(\frac{2\pi k}{l}s\right)\right)ds $ Coordenada y de la curva serpentinoide **ec. 6**

Estas integrales no tienen solución analítica, por lo que tienen que resolverse numéricamente

Demostración

Para su deducción hay que fijarse en el dibujo de la figura 7.

<table align = "left">

**Figura 7**: Cálculo de las coordenadas cartesianas de un punto $ s $ de la curva serpentinoide </tr> </table>

En ella aparece una curva serpeninoide y un punto genérico situado a una distancia $ s $. Sus coordenadas son $ x(s), y(s) $. La pendiente a la curva por el punto $ s $ es $ \alpha_s $. "Ampliando" el punto $ s $, vemos que está aproximado por un segmento de longitud $ ds $, que forma un ángulo $ \alpha_s $ con el eje x. Las proyecciones de este segmento son:

$$ dx=ds\ \cos\alpha_{s} $$ $$ dy=ds\ \sin\alpha_{s} $$

La abscisa del punto $ s $ se obtiene por tanto mediante la integración de los $ dx $ :

$ x\left(s\right)=\int_{0}^{s}dx= $

Aplicando la igualdad anterior para sustituir $ dx $ por $ ds $

$ = \int_{0}^{s}\cos\alpha_{s}ds = $

y finalmente se aplica la ec. 4:

$ =\int_{0}^{s}\cos\left(\alpha\cos\left(\frac{2\pi k}{l}s\right)\right)ds $

Llegamos al resultado final (ec. 5)

El razonamiento para obtener $ y(s) $ (ec. 6) es similar.

Formulación de la curva serpentinoide en python

In [8]:
import numpy as np
import scipy.integrate as spi
import matplotlib.pylab as plt
%matplotlib inline

Estas son las funciones que al ser integradas nos darán las funciones paramétricas con las coordenadas x,y:

In [9]:
#-- Alpha parameters should be given in degrees
def calphas(s, alpha, l = 1, k = 1, phi = 0):
    
    #-- Convert alpha and phi into radians
    alpha_rad = alpha * np.pi / 180.
    phi_rad = phi * np.pi / 180.
    
    return np.cos(alpha_rad * np.cos(2 * np.pi * k * s / l + phi_rad))

def salphas(s, alpha, l = 1, k = 1, phi = 0):
    
    #-- Convert alpha into radians
    alpha_rad = alpha * np.pi / 180.
    phi_rad = phi * np.pi / 180.
    
    return np.sin(alpha_rad * np.cos(2 * np.pi * k * s / l + phi_rad))

Estas son las funciones parametricas que nos dan las coordenadas x,y a partir de s

In [10]:
#-- Scalar functions. Variable s is a real number
def serp_x_scalar (s, alpha, l = 1, k = 1, phi = 0):
    return spi.quad(calphas, 0, s, args =(alpha, l, k, phi) )

def serp_y_scalar (s, alpha, l = 1, k = 1, phi = 0):
    return spi.quad(salphas, 0, s, args =(alpha, l, k, phi) )

Y por último esta es la función que tiene las coordenadas de una curva serpentinoide. La variable s es un array con todos los valores

In [11]:
def serp (s, alpha = 45, l = 1, k = 1, phi = 0):
    """Serpenoid curve
       Inputs:
         - alpha : winding angle (in degrees)
         - l : Curve length
         - k : Number of undulations
       S is the variable (it is an array). The x,y arrays are returned
    """
    
    #-- Results
    x = []
    y = []
    
    for i, vs in enumerate(s):
        x.append(serp_x_scalar(vs, alpha, l, k, phi)[0])
        y.append(serp_y_scalar(vs, alpha, l, k, phi)[0])
    return x,y

Probando la curva serpentinoide

Ejemplo de una curva serpentinoide con ángulo de serpenteo de 60 grados, longitud 1m y una única ondulación

In [12]:
#-- Obtener los puntos a lo largo de la curva
s = np.linspace(0, 1, 100)

#-- Obtener las coordenadas x,y
x, y = serp(s, alpha = 60, l = 1, k = 1)

#-- Dibujar la curva
plt.plot(x, y, linewidth = 3)
plt.grid()
plt.axis('equal')
plt.show()

Curva serpentinoide paramétrica: variando parametros

Modifica interactivamente los parámetros de la curva. Pulsa en el botón "DRAW" para ver la curva

In [15]:
from IPython.html import widgets # Widget definitions
from IPython.display import display # Used to display widgets in the notebook
In [31]:
widget_alpha = widgets.FloatSliderWidget()
widget_alpha.min = 0.0
widget_alpha.max = 121
widget_alpha.description = "Alpha"
widget_alpha.value = 60

widget_k = widgets.FloatSliderWidget()
widget_k.min = 0.1
widget_k.max = 20
widget_k.description = "k"
widget_k.value = 1


def draw_serp():
    #-- Obtener los puntos a lo largo de la curva
    s = np.linspace(0, 1, 100)

    #-- Obtener las coordenadas x,y
    x, y = serp(s, alpha = widget_alpha.value, l = 1, k = widget_k.value)

    #-- Dibujar la curva
    plt.plot(x, y, linewidth = 3)
    plt.grid()
    plt.axis('equal')
    plt.show()
    
    
button_draw = widgets.ButtonWidget(description="Draw!")


def on_button_draw_clicked(b):
    draw_serp()

button_draw.on_click(on_button_draw_clicked)    

display(widget_alpha)
display(widget_k)
display(button_draw)
draw_serp()

Bibliografía

  • S. Hirose. Biologically Inspired Robots (Snake-like Locomotor and Manipulator). Oxford Science Press, 1993.
  • Juan Gonzalez-Gomez, "Robótica Modular y Locomoción: Aplicación a Robots Ápodos". Tesis doctoral. Universidad Autónoma de Madrid. Noviembre-2008 Más información