Simulation d'une roue motorisée (roulement / glissement)

Programmation d'applications complexes
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Simulation d'une roue motorisée (roulement / glissement)

Message par graph100 »

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 8) ), 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 :mrgreen:

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
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
Avatar de l’utilisateur
Kwai chang caine
Messages : 6989
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Re: Simulation d'une roue motorisée (roulement / glissement)

Message par Kwai chang caine »

Impressionant !!! 8O

Marche niquel sous XP, pour une fois que j'arrive a voir un code graphique sans voir un message d'erreur
On dirait un code de professionnel ou comme a la télé 8)
Par professionnel, je veux dire un programme comme les utilisent les professionnels style ingénieurs, ou controle technique

Bien que je comprenne pas grand chose, bravo et merci 8)
ImageLe bonheur est une route...
Pas une destination

PureBasic Forum Officiel - Site PureBasic
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: Simulation d'une roue motorisée (roulement / glissement)

Message par graph100 »

Merci :D

Effectivement c'est un peu compliqué question calculs, mais il y a des parties facilement exploitables, le module de graphique par exemple.
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
jbernard13
Messages : 1501
Inscription : dim. 18/avr./2004 15:04
Localisation : sud de la france

Re: Simulation d'une roue motorisée (roulement / glissement)

Message par jbernard13 »

sous seven j'ai une erreur à la ligne 4 :
Structure point_d
   x.d
   y.d
EndStructure
Jbernard13
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: Simulation d'une roue motorisée (roulement / glissement)

Message par graph100 »

quelle est cette erreur ?
La seule que je vois disponible est que tu as un résident avec une structure du même nom déjà déclarée. Essais de changer le nom dans tout le code.
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
Répondre