Simulation d'une roue motorisée (roulement / glissement)
Publié : mer. 30/janv./2013 2:15
Bon, j'ai retrouvé un code que j'ai fait il y a un moment, je l'avais fait dans l'objectif très (trop) ambitieux d'aboutir à un genre de simulateur de conduite automobile (pourquoi pas pour faire un jeu au final
), en conséquence, il est (je trouve) très propre, lisible, et commenté un minimum.
Comme il allait moisir dans un coin de mon pc, je le poste ici.
Ce code simule le comportement d'une roue.
Avec frottement sur le sol, glissement et roulement.
Il y a aussi un module de graphique assez pratique, automatique.
Je suis ouvert à tout commentaire

Comme il allait moisir dans un coin de mon pc, je le poste ici.
Ce code simule le comportement d'une roue.
Avec frottement sur le sol, glissement et roulement.
Il y a aussi un module de graphique assez pratique, automatique.
Je suis ouvert à tout commentaire

Code : Tout sélectionner
;{ structure
Structure point_d
x.d
y.d
EndStructure
Structure car
pos.point_d
EndStructure
Structure wheel
pos.point_d
vit.point_d
acc.point_d
angle.d
angle_O.d
angle_OO.d
vitesse_roue.d
Couple.d
couple_resistant.d
force.d
force_limite.d
rayon.d
largeur.d
densite.d
J.d
M.d
time.d
time_new.d
time_delta.d
k_fluide.d
k_frottement.d
k_frottement_glissant.d
etat.b ; 0 = roulement, 1 = glissement
EndStructure
Structure pt
color.l
List pt.d()
EndStructure
Structure Graph
pos.point_d
dimension.POINT
nb_point.l
List list_des_pt.pt()
maxi.d
mini.d
ratio_w.d
ratio_h.d
Nom.s
EndStructure
;}
;{ param
#_2PI = #PI * 2
Global Screen_w = 1200
Global Screen_h = 800
Global Gravite.d = 9.81
Global NewList Car_list.car()
;}
;{ procedure
Procedure.d Maxi_delta(value.d, delta.d)
If delta = 0
ProcedureReturn Round(value, #PB_Round_Up) + 0.5
Else
p10.d = Pow(10, Round(Log10(Abs(delta)), #PB_Round_Down))
ProcedureReturn Round(value / p10, #PB_Round_Up) * p10
EndIf
EndProcedure
Procedure.d Mini_delta(value.d, delta.d)
If delta = 0
ProcedureReturn Round(value, #PB_Round_Down) - 0.5
Else
p10.d = Pow(10, Round(Log10(Abs(delta)), #PB_Round_Down))
ProcedureReturn Round(value / p10, #PB_Round_Down) * p10
EndIf
EndProcedure
;//// unité : cm ////
Procedure.i Wheel_Init(x, y)
*roue.wheel = AllocateMemory(SizeOf(wheel))
*roue\rayon = 50 ; cm
*roue\largeur = 1 ; cm
*roue\densite = 2.7 ; alu
*roue\M = 1000 * *roue\densite * #PI * Pow(*roue\rayon * 0.01, 2) * *roue\largeur * 0.01
; Debug "masse = " + StrD(*roue\m, 3) + " kg"
*roue\J = *roue\m * Pow(*roue\rayon * 0.01, 2) / 2
; Debug "J = " + StrD(*roue\j, 3) + " kg.m²"
*roue\angle = #PI / 4
*roue\angle_O = 0
*roue\angle_OO = 0
*roue\pos\x = x
*roue\pos\y = y
*roue\Couple = 0
*roue\k_fluide = 0.5
*roue\k_frottement = 0.5
*roue\k_frottement_glissant = 0.35
; Acier / acier : 0,2 (0,15)- 0.3
; Acier / glace : 0,02 (0,02)
; Acier / bronze : 0,1 (0,05) avec lubrification onctueuse.
; Acier / garnitures de freins : 0,4 (0,25) (pression maxi 20 MPa, T°<200°C)
; Pneu / route sèche : 0,8 (0,5)
; Pneu / route mouillée : 0,5 (0,35)
*roue\time = ElapsedMilliseconds() / 1000
ProcedureReturn *roue
EndProcedure
Procedure Wheel_Draw(*roue.wheel)
DrawingMode(#PB_2DDrawing_Outlined)
Circle(*roue\pos\x, *roue\pos\y, *roue\rayon, #White)
; Circle(*roue\pos\x, *roue\pos\y, *roue\rayon - 1, #Black)
Circle(*roue\pos\x, *roue\pos\y, 4 * *roue\rayon / 5, #White)
; Circle(*roue\pos\x, *roue\pos\y, *roue\rayon - 1, #Black)
DrawingMode(#PB_2DDrawing_Default)
tmp = 1
For index = 1 To 16
LineXY(*roue\pos\x + 4 * *roue\rayon * Cos(*roue\angle + index * #PI / 8) / 5, *roue\pos\y + 4 * *roue\rayon * Sin(*roue\angle + index * #PI / 8) / 5, *roue\pos\x + *roue\rayon * Cos(*roue\angle + index * #PI / 8), *roue\pos\y + *roue\rayon * Sin(*roue\angle + index * #PI / 8), #White)
If tmp = 1
Circle(*roue\pos\x + *roue\rayon * Cos(*roue\angle + (index + 0.5) * #PI / 8), *roue\pos\y + *roue\rayon * Sin(*roue\angle + (index + 0.5) * #PI / 8), *roue\rayon * 0.18, #Black)
Else
Circle(*roue\pos\x + 4 * *roue\rayon * Cos(*roue\angle + (index + 0.5) * #PI / 8) / 5, *roue\pos\y + 4 * *roue\rayon * Sin(*roue\angle + (index + 0.5) * #PI / 8) / 5, *roue\rayon * 0.135, #Black)
EndIf
tmp = -tmp
Next
LineXY(*roue\pos\x, *roue\pos\y, *roue\pos\x + *roue\rayon * Cos(*roue\angle + #PI / 16), *roue\pos\y + *roue\rayon * Sin(*roue\angle + #PI / 16), #White)
EndProcedure
Procedure Wheel_Process(*roue.wheel)
*roue\time_new = ElapsedMilliseconds() / 1000
*roue\time_delta = *roue\time_new - *roue\time
compteur = 0
delta_omega.d = 0
Repeat
old_delta_omega.d = delta_omega
*roue\couple_resistant = *roue\k_fluide * (*roue\angle_O + delta_omega)
; calcul de l'accélération angulaire
*roue\angle_OO = (*roue\Couple - *roue\couple_resistant) / *roue\J ; principe fondamental de la dynamique avec les moments
; calcul de la vitesse angulaire
delta_omega = *roue\angle_OO * *roue\time_delta
compteur + 1
Until Abs(delta_omega - old_delta_omega) < 0.00001 Or compteur > 10
*roue\angle_O = *roue\angle_O + delta_omega
; calcul de l'angle
*roue\angle = *roue\angle + *roue\angle_O * *roue\time_delta
; angle compris entre 0 et 2PI
*roue\angle = Mod(*roue\angle, #_2PI)
*roue\vitesse_roue = *roue\angle_O * *roue\rayon * 0.01
; effort maximal transmis entre la roue et la route
If *roue\etat = 0
*roue\force_limite = *roue\m * Gravite * *roue\k_frottement
Else
*roue\force_limite = *roue\m * Gravite * *roue\k_frottement_glissant
EndIf
new_vitesse.d = *roue\vit\x + Sign(*roue\vitesse_roue - *roue\vit\x) * (*roue\force_limite / *roue\M) * *roue\time_delta
If Sign(*roue\vitesse_roue - new_vitesse) <> Sign(*roue\vitesse_roue - *roue\vit\x)
; alors on a trop ajouté de force, et on passe en roulement
*roue\etat = 0
; en roulement la vitesse de la roue = vitesse réelle
old_vitesse.d = *roue\vit\x
*roue\vit\x = *roue\vitesse_roue
*roue\acc\x = (*roue\vit\x - old_vitesse) / *roue\time_delta
; FAUX
*roue\force = *roue\acc\x * *roue\M
Else
; glissement : la force est la force maxi applicable
*roue\etat = 1
*roue\force = *roue\force_limite
; calcul de l'accélération du chassis (non visible)
*roue\acc\x = Sign(*roue\vitesse_roue - *roue\vit\x) * *roue\force_limite / *roue\M
; calcul de la vitesse chassis
*roue\vit\x = *roue\vit\x + *roue\acc\x * *roue\time_delta
EndIf
; calcul de la position chassis
*roue\pos\x = *roue\pos\x + (*roue\vit\x * *roue\time_delta) * 100
; *roue\pos\x = *roue\pos\x + (*roue\angle_O * *roue\rayon * 0.01 * *roue\time_delta) * 100
; on gère les sorties d'écran
If *roue\pos\x - *roue\rayon > Screen_w : *roue\pos\x = - *roue\rayon + 1 : EndIf
If *roue\pos\x + *roue\rayon < 0 : *roue\pos\x = Screen_w + *roue\rayon - 1 : EndIf
*roue\time = *roue\time_new
EndProcedure
Procedure Wheel_Show_carac(*roue.wheel)
DrawText(0, 0, "Angle = " + StrD(*roue\angle, 6))
DrawText(0, 20, "Angle_O = " + StrD(*roue\angle_O, 6))
DrawText(0, 40, "Angle_OO = " + StrD(*roue\angle_OO, 6))
DrawText(180, 0, "Pos X = " + StrD(*roue\pos\x, 6))
DrawText(180, 20, "Vit X = " + StrD(*roue\vit\x, 6))
DrawText(180, 40, "Vit X roue = " + StrD(*roue\vitesse_roue, 6))
DrawText(180, 60, "Acc X = " + StrD(*roue\acc\x, 6))
DrawText(360, 0, "Couple = " + StrD(*roue\Couple, 6))
DrawText(360, 20, "k_fluide = " + StrD(*roue\k_fluide, 6))
DrawText(360, 40, "k_frott = " + StrD(*roue\k_frottement, 6))
If *roue\etat
DrawText(360, 60, "GLISSEMENT")
Else
DrawText(360, 60, "ROULEMENT")
EndIf
DrawText(540, 0, "time = " + StrD(*roue\time, 3))
DrawText(540, 20, "time_delta = " + StrD(*roue\time_delta, 3))
DrawText(720, 0, "Flèches DROITE / GAUCHE :")
DrawText(720, 20, "Modification du coefficient de frottement fluide")
DrawText(720, 40, "Flèches HAUT / BAS & PadNum 1 / 0 :")
DrawText(720, 60, "Modification lente & rapide du Couple appliqué sur la route")
EndProcedure
;{ Graphique
Procedure.i Graph_Init(x, y, width, height, nb_point, Nom.s = "")
*graph.Graph = AllocateMemory(SizeOf(Graph))
InitializeStructure(*graph, Graph)
*graph\pos\x = x
*graph\pos\y = y
*graph\dimension\x = width
*graph\dimension\y = height
*graph\nb_point = nb_point
*graph\ratio_w = *graph\dimension\x / *graph\nb_point
*graph\Nom = Nom
ProcedureReturn *graph
EndProcedure
Procedure.i Graph_AddSerie(*graph.Graph, color.l) ; retourne l'adresse de la série. A conserver pour ajouter des points
*new_serie.i = AddElement(*graph\list_des_pt())
InitializeStructure(*new_serie, pt)
*graph\list_des_pt()\color = color
ProcedureReturn *new_serie
EndProcedure
Procedure.i Graph_FreeSerie(*graph.Graph, *adresse_serie.i) ; retourne l'adresse de la série. A conserver pour ajouter des points
ChangeCurrentElement(*graph\list_des_pt(), *adresse_serie)
FreeList(*graph\list_des_pt()\pt())
DeleteElement(*graph\list_des_pt())
EndProcedure
Procedure Graph_AddPoint(*graph.Graph, *adresse_serie.i, value.d)
ChangeCurrentElement(*graph\list_des_pt(), *adresse_serie)
LastElement(*graph\list_des_pt()\pt())
AddElement(*graph\list_des_pt()\pt())
*graph\list_des_pt()\pt() = value
If ListSize(*graph\list_des_pt()\pt()) > *graph\nb_point
FirstElement(*graph\list_des_pt()\pt())
DeleteElement(*graph\list_des_pt()\pt())
EndIf
EndProcedure
Procedure Graph_Draw(*graph.Graph)
Line(*graph\pos\x - 1, *graph\pos\y - 1, *graph\dimension\x + 2, 1, #Green)
Line(*graph\pos\x - 1, *graph\pos\y - 1, 1, *graph\dimension\y + 2, #Green)
Line(*graph\pos\x - 1, *graph\pos\y - 1 + *graph\dimension\y + 2, *graph\dimension\x + 2, 1, #Green)
Line(*graph\pos\x - 1 + *graph\dimension\x + 2, *graph\pos\y - 1, 1, *graph\dimension\y + 2, #Green)
If *graph\Nom
Protected titre$ = " " + *graph\Nom + " "
Protected w = TextWidth(titre$), h = TextHeight(titre$)
Protected x.d = *graph\pos\x + *graph\dimension\x / 2 - w / 2, y.d = *graph\pos\y - h / 2
DrawText(x ,y , titre$, #Green)
Line(x - 1, y - 1, w + 1, 1, #Green)
Line(x - 1, y - 1, 1, h + 1, #Green)
Line(x - 1, y - 1 + h + 1, w + 2, 1, #Green)
Line(x - 1 + w + 1, y - 1, 1, h + 2, #Green)
EndIf
DrawText(*graph\pos\x + *graph\dimension\x + 2, *graph\pos\y - 1, StrD(*graph\maxi), #Green)
DrawText(*graph\pos\x + *graph\dimension\x + 2, *graph\pos\y - 1 + *graph\dimension\y + 2 - TextHeight(" "), StrD(*graph\mini), #Green)
*graph\ratio_h = *graph\dimension\y / (*graph\maxi - *graph\mini)
mini.d = *graph\mini
If Sign(*graph\maxi) <> Sign(*graph\mini)
Line(*graph\pos\x, *graph\pos\y + *graph\dimension\y + mini * *graph\ratio_h, *graph\dimension\x, 1, #Green)
DrawText(*graph\pos\x + *graph\dimension\x + 2, *graph\pos\y + *graph\dimension\y + mini * *graph\ratio_h - TextHeight(" ") / 2, "0", #Green)
EndIf
*graph\maxi = -Infinity()
*graph\mini = Infinity()
ForEach *graph\list_des_pt()
index = 0
ForEach *graph\list_des_pt()\pt()
If *graph\list_des_pt()\pt() > *graph\maxi : *graph\maxi = *graph\list_des_pt()\pt() : EndIf
If *graph\list_des_pt()\pt() < *graph\mini : *graph\mini = *graph\list_des_pt()\pt() : EndIf
Line(*graph\pos\x + index * *graph\ratio_w, *graph\pos\y + *graph\dimension\y - (*graph\list_des_pt()\pt() - mini) * *graph\ratio_h, 1, 1, *graph\list_des_pt()\color)
index + 1
Next
If LastElement(*graph\list_des_pt()\pt())
DrawText(*graph\pos\x + *graph\dimension\x + 2, *graph\pos\y + *graph\dimension\y - (*graph\list_des_pt()\pt() - mini) * *graph\ratio_h - TextHeight(" ") / 2, StrD(*graph\list_des_pt()\pt()), *graph\list_des_pt()\color)
EndIf
Next
delta.d = *graph\maxi - *graph\mini
*graph\maxi = Maxi_delta(*graph\maxi, delta)
*graph\mini = Mini_delta(*graph\mini, delta)
If delta = 0 : delta = 1 : EndIf
EndProcedure
;}
;}
InitSprite()
InitKeyboard()
If OpenWindow(0, 0, 0, Screen_w, Screen_h, "Circuit", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
If OpenWindowedScreen(WindowID(0), 0, 0, Screen_w, Screen_h, 0, 0, 0)
EndIf
EndIf
;{ Init
*roue.wheel = Wheel_Init(Screen_w / 4, Screen_h / 5)
; *roue2.wheel = Wheel_Init(Screen_w / 4, Screen_h / 5)
*graph_vit_X.Graph = Graph_Init(Screen_w / 30, 1.6 * Screen_h / 5, 1.20 * Screen_w / 3, Screen_h / 5, 1000, "Vitesse Roue et Axe Roue")
*ad_vit_X.i = Graph_AddSerie(*graph_vit_X, RGB(200, 200, 255))
*ad_vit_X_roue.i = Graph_AddSerie(*graph_vit_X, RGB(100, 100, 255))
*graph_angle_O.Graph = Graph_Init(Screen_w / 30, 2.7 * Screen_h / 5, 1.20 * Screen_w / 3, Screen_h / 5, 1000, "Vitesse angulaire")
*ad_angle_O.i = Graph_AddSerie(*graph_angle_O, #Blue)
*graph_couple.Graph = Graph_Init(Screen_w / 30, 3.8 * Screen_h / 5, 1.20 * Screen_w / 3, Screen_h / 5, 1000, "Couple exercé sur l'axe")
*ad_couple.i = Graph_AddSerie(*graph_couple, #Red)
*graph_force.Graph = Graph_Init(Screen_w / 30 + Screen_w / 2, 1.6 * Screen_h / 5, 1.20 * Screen_w / 3, Screen_h / 5, 1000, "Force et Force limite")
*ad_force.i = Graph_AddSerie(*graph_force, RGB(200, 255, 200))
*ad_force_limite.i = Graph_AddSerie(*graph_force, RGB(100, 255, 100))
*graph_acc.Graph = Graph_Init(Screen_w / 30 + Screen_w / 2, 2.7 * Screen_h / 5, 1.20 * Screen_w / 3, Screen_h / 5, 1000, "Accélération axe, et Accélération Roue")
*ad_acc.i = Graph_AddSerie(*graph_acc, #Blue)
*ad_acc_reelle.i = Graph_AddSerie(*graph_acc, RGB(200, 200, 255))
bip = 0
;}
Repeat
Delay(10)
event = WindowEvent()
ExamineKeyboard()
If KeyboardReleased(#PB_Key_Escape)
event = #PB_Event_CloseWindow
EndIf
; #### COUPLE
If KeyboardPushed(#PB_Key_Up)
*roue\Couple + 0.1
; *roue2\Couple + 0.1
EndIf
If KeyboardPushed(#PB_Key_Down)
*roue\Couple - 0.1
; *roue2\Couple - 0.1
EndIf
; #### COUPLE
If KeyboardPushed(#PB_Key_Pad1)
*roue\Couple + 1
; *roue2\Couple + 1
EndIf
If KeyboardPushed(#PB_Key_Pad0)
*roue\Couple - 1
; *roue2\Couple - 1
EndIf
; #### K_fluide
If KeyboardPushed(#PB_Key_Left)
*roue\k_fluide + 0.1
; *roue2\k_fluide + 0.1 / 2
EndIf
If KeyboardPushed(#PB_Key_Right)
*roue\k_fluide - 0.1
; *roue2\k_fluide - 0.1 / 2
EndIf
Wheel_Process(*roue)
; Wheel_Process(*roue2)
; on ajoute les donneés dans un graphique
Graph_AddPoint(*graph_vit_X, *ad_vit_X, *roue\vit\x)
Graph_AddPoint(*graph_vit_X, *ad_vit_X_roue, *roue\vitesse_roue)
Graph_AddPoint(*graph_angle_O, *ad_angle_O, *roue\angle_O)
Graph_AddPoint(*graph_couple, *ad_couple, *roue\Couple)
Graph_AddPoint(*graph_force, *ad_force, *roue\force)
Graph_AddPoint(*graph_force, *ad_force_limite, *roue\force_limite)
Graph_AddPoint(*graph_acc, *ad_acc, *roue\acc\x)
Graph_AddPoint(*graph_acc, *ad_acc_reelle, *roue\angle_OO * *roue\rayon * 0.01)
;{ dessin
ClearScreen(0)
If StartDrawing(ScreenOutput())
Wheel_Draw(*roue)
; Wheel_Draw(*roue2)
;{ dessin du sol
Line(1, Screen_h / 5 + *roue\rayon, Screen_w, 1, #Green)
;}
Wheel_Show_carac(*roue)
Graph_Draw(*graph_couple)
Graph_Draw(*graph_angle_O)
Graph_Draw(*graph_vit_X)
Graph_Draw(*graph_force)
Graph_Draw(*graph_acc)
StopDrawing()
EndIf
FlipBuffers()
;}
Until event = #PB_Event_CloseWindow
End