
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