Darstellung der Bewegung eines Ruders¶
Grafische Darstellung der Ruder¶
Die folgenden Funktionen werden zur grafischen Darstellung des Ruders benötigt. Die wichtigste davon ist plotRuder, welche die Punkte miteinander verbindet, die das Ruder definieren. Die Funktion setGrafikrahmen sieht etwas sperrig aus. Sie dient nur dazu, dass das Programm den Grafikrahmen etwas weiter aussen setzt als gerade auf den äussersten Punkten, die dargestellt werden sollen. initGrafik hat die Aufgabe ein Grafikfenster zu öffnen.
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
def initGrafik():
fig,ax = plt.subplots()
ax.axis('equal')
return ax
def setGrafikrahmen(x,y):
# das folgende soll den Grafikrahmen etwas grösser machen als das Grafikobjekt
xmin = min(x); xmax = max(x); Lx = xmax - xmin; Mx = 0.5*(xmax + xmin)
ymin = min(y); ymax = max(y); Ly = ymax - ymin; My = 0.5*(ymax + ymin)
Ls = 1.2
xmin = Mx - 0.5*Ls*Lx; xmax = Mx + 0.5*Ls*Lx;
ymin = My - 0.5*Ls*Ly; ymax = My + 0.5*Ls*Ly;
return [xmin, xmax, ymin, ymax]
def plotRuder(x,y,colr,ax):
markers_on = [0, 1, 2]
ax.plot(x, y, '-o', color=colr, markevery=markers_on,linewidth=2.5)
#ax.axis(setGrafikrahmen(x,y))
plt.xlabel('x-Richtung [m]')
plt.ylabel('y-Richtung [m]')
return
font = {'family': 'serif',
'color': 'darkred',
'weight': 'normal',
'size': 16,
}
def getCl(): # Farbreihe
cl = ['g', 'c', 'b' , 'm', 'r', 'y', 'grey','k',
'g', 'c', 'b' , 'm', 'r', 'y', 'grey','k']
return cl
def getC2(): # Farbreihe
c2 = ['g', 'c', 'b' , 'm', 'r', 'y', 'grey','k',
'g', 'c', 'b' , 'm', 'r', 'y', 'grey','k']
return c2
Mathematische Darstellung der Ruder¶
Wir stellen die Ruder als Vektoren dar. Ebenso ihr Aufhänge- und Drehpunkt, der deutsch Dolle genannt wird und englisch Pin. Als x-Richtung wählen wir die Fahrtrichtung des Bootes. Die y-Richtung wählen wir in Fahrrichtung links, rechtwinklig dazu. Den Teil des Ruders von der Dolle zum Ruderblatt bezeichenen wir in diesem Programmcode als äusseren Hebel Ha und den Teil von der Dolle zum Rudergriff als inneren Hebel Hi.
An einem Boot können sowohl die Position der Dolle als auch die Länge des äusseren und des inneren Hebels variiert werden. Sie sind deshalb in diesem Code Input-Grössen.
Die Dolle definieren wir mit dem Ortsvektor $\vec{P_{pin}}$. Für den äusseren Hebel $\vec{r_{a}}$ verwenden wir einen Richtungsvektor der Länge 1, den wir mit der Hebellänge Ha multplizieren. Der innere Hebel $\vec{r_{a}}$ verläuft in die entgegengesetzte Richtung mit der Länge Hi. Wenn wir diese beiden Vektoren zum Ortsvektor der Dolle addieren erhalten wir die Ortsvektoren für das Ruderblatt $\vec{R_{a}}$ und den Griff $\vec{R_{i}}$.
Wir beginnen in der Funktion setRuder die mathematische Darstellung in der Position, in welcher das Ruder rechtwinklig zum Boot genau in der y-Richtung verläuft.
$$ \vec{e_{y}}= \begin{bmatrix} 0 \\ 1 \end{bmatrix}$$$$ \vec{r_{a}}= H_a \cdot \vec{e_{y}} $$$$ \vec{r_{i}}= -H_i \cdot \vec{e_{y}} $$$$\vec{R_{a}} = \vec{P_{pin}} + \vec{r_{a}} $$$$\vec{R_{i}} = \vec{P_{pin}} + \vec{r_{i}} $$Für ausschliesslich grafische Zwecke generieren wir in der Funktion setOar ein Ruderblatt in Form einer Ellipse. Damit erhält man die nachfolgende Grafik des Ruders.
def setOar(): # das Ruderblatt wird als halbe Ellipse in y-Richtung definiert
ox = 0.2; oy = 0.4 # Längen in x- und in y-Richtung
φ = np.linspace(-0.5*np.pi, 0.5*np.pi, 10) # φ durchläuft Halbkreis
oar = np.array([ox * np.cos(φ), oy + oy * np.sin(φ),]) # Ellipse
return oar
def setRuder():
Ha = 3.0 # äussere Hebellänge
Hi = 1.0 # innere Hebellänge
raV = Ha * np.array([0, 1]) # Vektor Ruder aussen = Ha*(0,1)
riV = -Hi/Ha * raV # Vektor Ruder innen = -ha*(0,1)
PpinV = np.array([0, 2]) # Ortsvektor der Dolle (engl.: Pin)
RaV = PpinV + raV # OrtsVektor Ruder aussen
RiV = PpinV + riV # OrtsVektor Ruder innen
oar = setOar() # ein Ruderblatt generieren
oar[0] = oar[0] + RaV[0] # Ruderblatt an RaV Ruderende verschieben
oar[1] = oar[1] + RaV[1]
Ruder = np.vstack((RiV,PpinV,RaV)).T # alle Punkte des Ruders zusammenfügen
Ruder = np.concatenate((Ruder,oar),axis=1) # Ruderblatt anfügen
return Ruder,PpinV
# ----- main program ---------------------------------------------------
R,Ppin = setRuder()
Rx = R[0] # die x-Komponenten des Ruders
Ry = R[1] # die y-Komponenten des Ruders
ax = initGrafik()
plotRuder(Rx,Ry,"green",ax)
ax.axis([-1, 1, 0.5, 6.2])
plt.text(-0.45, 4.0, r'$\vec{r_{a}}$', fontdict=font)
plt.text( 0.20, 1.8, r'$\vec{P_{Pin}}$',fontdict=font)
plt.text(-0.45, 1.3, r'$\vec{r_{i}}$', fontdict=font)
Drehung der Ruder¶
Für die Drehung der Ruder kann die Drehmatrix verwendet werden: $$\vec{c} = \mathbf{D}(\theta) \cdot \vec{b} $$
$$\begin{bmatrix} c_x \\ c_y \end{bmatrix} = \begin{bmatrix} cos\theta & -sin\theta \\ sin\theta & cos\theta \end{bmatrix} \begin{bmatrix} b_x \\ b_y \end{bmatrix}$$Um eine Drehung mit der Matrix durchzuführen, muss sich der Drehpunkt im Nullpunkt befinden. Ist die Dolle nicht im Nullpunkt, so können temporär die Dolle und die zu drehenden Vektoren durch eine Verschiebung um den Ortsvektor -$\vec{P_{pin}}$ in diese Position gebracht werden.
Mit der Funktion D im Code kann die Drehung vollzogen werden. Programmtechnisch enthält das Ruder mehrere Vektoren, die in einer Matrix zusammengfasst sind, nämlich für den Griff, für die Dolle, für das äussere Ruderende sowie mehrere Punkt für das Ruderblatt. Die Funktion V ist dazu da, eine Vektorverschiebung durchzuführen.
def D(b,φ): # Drehmatrix
c = np.array([np.cos(φ)*b[0] - np.sin(φ)*b[1],
np.sin(φ)*b[0] + np.cos(φ)*b[1],])
return c
def V(a,v): # Vektorverchiebung
b = np.zeros_like(a)
b[0] = a[0] + v[0]
b[1] = a[1] + v[1]
return b
# ----- main program ---------------------------------------------------
R0 = V(R,-Ppin) # Dolle in den Nullpunkt verschieben
φ = 0.5*np.pi # Initalwinkel
xmin= 1.0e10
xmax = -xmin
ax1 = initGrafik()
col = getCl()
R1 = D(R0,-0.35*np.pi); plotRuder(R1[0],R1[1],col[0],ax1)
xmin = min(np.amin(R1[0]),xmin)
xmax = max(np.amax(R1[0]),xmax)
for j in [1,2,3,4,5,6,7]:
dφ = 0.1*np.pi
φ = φ + dφ
R1 = D(R1,dφ);
plotRuder(R1[0],R1[1],col[j],ax1)
xmin = min(np.amin(R1[0]),xmin)
xmax = max(np.amax(R1[0]),xmax)
print('Der grösste und kleinets x-Wert: ','xmin =',xmin,'xmax =',xmax,)
dx = np.array([xmin, xmax])
dy = np.array([4.1, 4.1])
ax1.plot(dx, dy, '-o')
Kinematik und Hebelwirkung¶
Bei einem Fahrrad kann die abgewickelte Länge einer Pedalumdrehung gemessen werden und ebenso die Fortbewegung als Folge der Radumdrehung. Wir stellen nun die analoge Überlegung für den Rudervorgang mit dem Boot an. Wir nehmen hypothetisch an, das Boot sei auf Rädern und das Ruder tauche in ein hypothetisches Medium, das in x-Richtung ein Festkörper sei, und in y-Richtung eine Flüssigkeit, um die kreisförmige Ruderbewegung zu ermöglichen. Das Boot wird durch das (in erster Näherung) starre Rudgestänge forwärts geschoben. Wie beim Fahhrad kann nun die zurück gelegte Disntanz gut gemessen,resp. berechnet werden:
Von der kreisförmigen Ruderbewegung trägt einzig die Komponente in der x-Richtung etwas zur Fortbewegung des Bootes bei. Für einen Ruderschlag kann diese Distanz abschliessend berechnet werden. Sie ist abhängig vom Winkel, der überstrichen wird, und von der Länge des äusseren Ruderhebels. Mit dem Computerprogramm können der minimale und maximale x-Punkt je aus den Daten herausgelesen werden, woraus sich die zurückgelegte Distanz ergibt. In der Grafik ist sie mit einem Liniensegment über den Ruderpositionen eingetragen.
Die so gefundene Fortbewegungsdistanz pro Ruderschlag ist kinematisch die maximal mögliche Distanz, die pro Ruderschlag zurückgelegt werden kann. Ist das Boot im Wasser, hat man nicht mehr die idealen Voraussetzungen, wie mit der hypothtischen Festkörperumgebung. Die maximal mögliche Distanz verringert sich, da das Ruder im Wasser nicht alle kinetische Energie auf die Bootsfortbewegung übertragen kann.
Erste Folgerungen¶
Daraus ergeben sich eine Reihe von Folgerungen:
- beschränkt man sich auf die Kinematik, welche die geometrischen Zusammenhänge der Bewegung analysiert, so sind möglichst lange äussere Hebelarme von Vorteil sowie möglichst grosse Ruderblätter auch, um dem "Festkörperideal" nahe zu kommen.
- die Physik berücksichtigt zusätzlich die Kräfte, und es ist heraus zu finden, in welcher Kombination der Krafteinsatz effizient ist.
- nicht alle Optimierungsvorschläge aus Kinematik und Physik können vom Athleten leicht umgesetzt werden. Die Physiologie berücksichtigt die Möglichkeiten des menschlichen Körpers, sowohl bezüglich der Körperbewegungen als auch bezüglich der Energieabgabe.
Im Folgenden wird es darum gehen, diese drei Aspekte auf einem möglichst je ähnlichen Stand zu berücksichtigen und Optimierungen für den Rudervorgang zu finden.
Konsequenzen des Ruders auf die Kräfte¶
Kraftverlauf am Innenhebel¶
Das Ruder dreht sich um eine Drehachse und führt daher immer kreisförmige Bewegungen aus. Die Last am Ruderblatt im Wasser fällt durch den Wasserwiderstand in der Richtung der Blattnormalen an, welche die kreisförmige Ruderbewegung mitmacht. Auf der Kraftseite am Rudergriff stammen die Käfte für einen Ruderschlag aus den Bewegungen der Beine, des Rückens und der Arme des Athleten. Alle drei Teilbewegungen verlaufen im Boot in erster Linie entlang der x-Achse und machen die kreisförmige Bewegung des Rudergriffes nicht mit.
Wir stellen nun die Situation mit dem inneren Hebel auf der Griffseite dar.
def setRuder_2():
Ha = 3.0 # äussere Hebellänge
Hi = 1.0 # innere Hebellänge
raV = Ha * np.array([0, 1]) # Vektor Ruder aussen = Ha*(0,1)
riV = -Hi/Ha * raV # Vektor Ruder innen = -ha*(0,1)
PpinV = np.array([0, 0]) # Ortsvektor der Dolle (engl.: Pin)
RiV = PpinV + riV # OrtsVektor Ruder innen
Ruder = np.vstack((RiV,PpinV)).T # Griff und Dolle des Ruders zusammenfügen
return Ruder,PpinV
Wir nehmen hypothetisch an, dass über den ganzen Ruderschlag der Athlet eine Kraft der Grösse 1 aufbringt, die genau in die x-Richtung am Innenhebel zieht. Diese Zugkraft wird in zwei Kraftvektoren zerlegt, der eine Vektor ist normal zum Innenhebel und der andere parallel dazu. Diese Parallelkomponente leistet keinen Beitrag, das Ruder zu drehen und ist für die Vorwärtsbewegung verloren.
def getVdecomposition(p):
f = np.array([1, 0]) # Kraftvektor des Ruderers
fn = np.linalg.norm(f)# Betrag von f
rr = p[:,0] - p[:,1] # Richtungsvektor Innenhebel
rr = rr/np.linalg.norm(rr) # Betrag von rr
n = np.array([-rr[1], rr[0]]) # Normalvektor zu rr
α = np.arccos(np.dot(-f/fn, rr)) # Winkel zur x-Achse
rr = rr*fn*np.cos(α) # Kraft parallel zum Hebel
n = n*fn*np.sin(α) # Kraft normal zum Hebel
return f,n,-rr
In der folgenden Grafik stellt der blaue Vektor die eingesetzte Kraft des Athleten dar, die in diesem Beispiel immer gleich gross bleibt. Dieser Vektor ist in Komponenten aufgeteilt. Der rote Normalvektor zum Innenhebel ist der Beitrag, der das Ruder dreht. Der schwarze Vektor parallel zur Hebelachse steht für die Vorwärtsbewegung nicht zur Verfügung.
# ----- main program ---------------------------------------------------
R,Ppin = setRuder_2()
R2 = V(R,-Ppin) # Dolle in den Nullpunkt verschieben
φ = 0.5*np.pi # Initalwinkel
ax2 = initGrafik()
co2 = getC2()
φ_ = np.array([])
f_ = np.array([])
n_ = np.array([])
for j in [0,1,2,3,4,5,6,7,8,9]:
if j==0 : dφ = -0.4*np.pi
else: dφ = 0.08*np.pi
φ = φ + dφ
R2 = D(R2,dφ);
ax2.plot(R2[0], R2[1], '-o', color=co2[j],linewidth=1.0)
f,n,rr = getVdecomposition(R2)
ri = np.array([R2[0,0], R2[1,0]])
plt.quiver(ri[0],ri[1], f[0],f[1], color='b', angles='xy', scale_units='xy',scale=4)
plt.quiver(ri[0],ri[1], n[0],n[1], color='r', angles='xy', scale_units='xy',scale=4)
plt.quiver(ri[0],ri[1], rr[0],rr[1],color='k', angles='xy', scale_units='xy',scale=4)
φ_ = np.append(φ_,[φ])
f_ = np.append(f_,[np.linalg.norm(f)])
n_ = np.append(n_,[np.linalg.norm(n)])
ax2.plot( [0,0], [0,0], '-bo',linewidth=1.0,label="Krafteinsatz des Athleten (in x-Richtung)")
ax2.plot( [0,0], [0,0], '-ro',linewidth=1.0,label="Normalkraft, nutzbar zur Vorwärtsbewegung ")
ax2.plot( [0,0], [0,0], '-ko',linewidth=1.0,label="Kraft tangential zum Ruder ")
plt.legend(bbox_to_anchor=(0, 1.05), loc=3,ncol=1, borderaxespad=0.0)
def grd(β): return β*180.0/np.pi # Winkelumrechnung von rad --> grad
def rad(β): return β*np.pi/180 # Winkelumrechnung von grad --> rad
fig,ax3 = plt.subplots()
ax3.plot( grd(φ_), (f_), '-bo',linewidth=1.0,label="Krafteinsatz des Athleten (in x-Richtung)")
ax3.plot( grd(φ_), (n_), '-ro',linewidth=1.0,label="Normalkraft, nutzbar zur Vorwärtsbewegung ")
fxx = n_*np.cos(φ_)
#ax3.plot( grd(φ_), (fxx), '-ro',linewidth=1.0,label="xKomponente Aussenhebel im Wasser ")
plt.xlabel('Ruderwinkel (grd)')
plt.ylabel('Kraft')
plt.legend(bbox_to_anchor=(0, 1.05), loc=3,ncol=1, borderaxespad=0.0)
ax3.axis([0, 180, 0, 1.2])
ax3.grid(True)
Kraftverlauf am Aussenhebel¶
Der Kraftverlauf am Innenhebel ist die Eingangsgrösse für den Kraftverlauf am Aussenhebel. Die Normalkraft am Innenhebel fällt auch am Aussenhebel als Normalkraft an, die als Normale zum Ruderblatt Wasserwiderstand erzeugt. Der Wasserwiderstand ist der "Haltepunkt", der das Ruderblatt "im Wasser fixiert" und damit die Vorwärtsbewegung des Bootes ermöglicht. Nun ist diese "Fixierung" natürlich nicht perfekt. Nimmt man hypothetisch an, die Fixierung des Ruderblattes wäre perfekt, so kann man geometrisch die Weglänge berechnen, um die das Boot mit einem Ruderschlag maximal nach vorwärts geschoben werden kann. Von der Kreisbewegung, die das Ruderblatt beschreibt, ist es wieder nur die x-Komponente, die zur Vorwärtsbewegung des Bootes beiträgt.
Die Normalkraft am Ruderblatt ist vom Betrag her gleich gross wie die Normalkraft am Griff, modifiziert durch die Längenverhältnisse von Innen- zu Aussenhebel gemäss dem Hebelgesetz. Davon ist es wiederum nur die x-Komponente, welche die wirksame Antriebskraft ist, die das Boot antreibt.
def getVdecomposition_2(p):
ex = np.array([1, 0]) # Einheitsvektor in x-Richtung
ey = np.array([0, 1]) # Einheitsvektor in y-Richtung
f = 1*np.array([1, 0]) # Kraftvektor des Ruderers
fn = np.linalg.norm(f)# Betrag von f
rr = (p[:,2] - p[:,1]) # Richtungsvektor Aussenhebel
rr = rr/np.linalg.norm(rr) # rr-Einheitsvektor
n = np.array([-rr[1], rr[0]]) # Normalvektor zu rr
n = n*fn # Kraft normal zum Hebel
fx = np.array([np.dot(ex, n), 0]) # Kraft in x-Richtung
return n,fx
ax5 = initGrafik()
R3 = D(R0,-0.5*np.pi);
for ix in [0,1,2,3,4,5,6,7]:
a_phi = φ_[ix]
a_fn = n_[ix]
R3 = D(R3,0.1*np.pi);
plotRuder(R3[0],R3[1],col[ix],ax5)
n,fx = getVdecomposition_2(R3)
ri = np.array([R3[0,7], R3[1,7]])
plt.quiver(ri[0],ri[1],fx[0],fx[1],color='b', angles='xy', scale_units='xy',scale=1)
plt.quiver(ri[0],ri[1], n[0],n[1], color='r', angles='xy', scale_units='xy',scale=1)
#ax5.axis([-2, 4,-3, 1])