Catégories
Jeu vidéo ROBLOX ROBLOX-NIVEAU03

Création d’une boutique

Améliore ton jeu par des dispositifs comme par exemple une boutique.


Créer une boutique

Dans beaucoup de jeux, les joueurs peuvent acheter des objets, des vêtements, des pouvoirs ou des accessoires. La boutique sert donc à donner plus d’objectifs au joueur : gagner de l’argent dans le jeu, choisir quoi acheter et améliorer son personnage. Une boutique rend aussi le jeu plus vivant et plus intéressant.

Dans Roblox Studio, on peut construire des décors, placer des objets et ajouter des menus à l’écran. Avec le langage de programmation Lua, nous apprendrons à donner des actions aux objets et à créer les règles du jeu.

La démarche pour la construction de ta boutique sera progressive :

  • D’abord, nous apprendrons à créer l’interface de la boutique : une fenêtre avec des boutons et les noms des objets à vendre.
  • Ensuite, nous programmerons l’argent du joueur avec une variable. Puis, nous coderons les achats : lorsqu’un joueur clique sur un bouton, le programme vérifie s’il a assez d’argent. Si oui, il paie et reçoit l’objet. Sinon, un message lui indique qu’il lui manque des pièces.

Ce projet te permettra de découvrir plusieurs notions importantes en programmation : les variables, les conditions, les événements, les fonctions et l’organisation d’un vrai projet numérique. À la fin, tu disposeras d’une boutique fonctionnelle dans Roblox.

Création de la boutique :

Pout ta boutique crée :

  • une fenêtre sur ta boutique avec les options à acheter
  • un bouton pour ouvrir et fermer la fenêtre de ta boutique
  • un localscript pour gérer l’ouverture de ta boutique

Création d’un écran utilisateur pour représenter la boutique, sous StaterGui demande la création d’un ScreenGui

Sous ScreenGui crée un Frame :

Déplace et agrandit le Frame pour prendre la place de ta boutique :

Modifie les propriétés, la couleur, le contour, la transparence du Frame :

Renomme les objets de ta botique :

Sous FrameStore rajoute un TextLabel pour le titre de ta boutique :

Dans le TextLabel rajoute le titre de la boutique :

Maintenant, tu vas rajouter des boutons pour chaque Item de ta boutique :

Tu dois obtenir ce résultat :

Tu peux rajouter une image pour certain élément de ta boutique :

Recherche une image dans la boîte à outil :

Récupère l’identifiant de l’image par un clic droit sur l’image :

Copie l’identifiant dans la propriété Image de ton ImageLabel :

Sous ScreenStore crée un ImageButton qui te permettra d’ouvrir ou fermer ta boutique :

Recherche dans la boîte à outil une image pour représenter ta boutique :

Par le clic droit demande à copier l’identifiant de l’image que tu colle dans la propriété Image de ton ImageButton :

Sous ScreenStore demande la création d’un LocalScript :

Renomme ton LocalScript et tu dois obtenir ce résultat :

Maintenant, tu peux modifier le script pour ouvrir ou fermer la boutique :

-- récupération du bouton pour ouvrir la boutique
local openButton = script.Parent.OpenButton
-- récupération du frame de la boutique	
local frameStore = script.Parent.FrameStore

-- on cache le frame de la boutique au lancement du jeu par defaut	
frameStore.Visible = false

-- on écoute l'événement de clic sur le bouton pour ouvrir ou fermer la boutique
openButton.MouseButton1Click:Connect(function()
	frameStore.Visible = not frameStore.Visible
end)

Crée un tableau de points

Objectif : Créé un tableau de scores de Points

Créer un script pour afficher un tableau de score au joueur sous ServerScriptService :

Renommer le script leaderstats :

Saisir le code suivant pour un affichage d’une barre de scores de Points :

-- récupérer le service sur les joueurs
local players = game:GetService("Players")

-- écouteur d'un nouveau joueur
players.PlayerAdded:Connect(function(player)
	-- créer un dossier leaderstats
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player
end)

Si tu lances ton jeu une barre s’affiche :

Si le score ne s’affiche pas vérifie :

Rajoute à ton script un score à afficher :

-- récupérer le service sur les joueurs
local players = game:GetService("Players")

-- écouteur d'un nouveau joueur
players.PlayerAdded:Connect(function(player)
	-- créer un dossier leaderstats
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player
	-- créer un score de Points
	local score = Instance.new("IntValue")
	score.Parent = leaderstats
	score.Name = "Points"
	score.Value = 10
end)

Le score s’affiche si tu lances ton jeu :


GAGNER DES POINTS

Créer un Part avec un ClickDetector afin que le joueur puisse gagner des points, exemple à reproduire sur tous les objets que tu souhaites dans ton jeu :

Exemple d’un script pour augmenter le score si le joueur click sur un ClickDetector :

Sasie le code suivant- dans le script :

-- récupérer le ClickDetector du Part
local clickDetector = script.Parent.ClickDetector

-- écouter l'événement de clic du Clickdetector
clickDetector.MouseClick:Connect(function(player)
	-- ajouter 10 Points au joueur
	player:WaitForChild("leaderstats").Points.Value += 10

end)

Lance ton jeu, maintenant à chaque clic le score de points augmente de 10 :


Acheter

Sur l’écran de sa boutique, le joueur clic sur l’item de son achat. Le LocalScript de la boutique demande via une RemoteFunction la possibilité de l’achat de l’item. Un script sur le serveur vérifie le nombre de point et la disponibilité de l’item.

Mis en place de l’échange entre le Localscript de la boutique et le serveur par un RemoteFunction :

Renomme RemoteFunction par RemoteBuy :

Puis modifie le script StoreScript lié à ta boutique :

-- récupération du bouton pour ouvrir la boutique
local openButton = script.Parent.OpenButton
-- récupération du frame de la boutique	
local frameStore = script.Parent.FrameStore

-- on cache le frame de la boutique au lancement du jeu par defaut	
frameStore.Visible = false

-- on écoute l'événement de clic sur le bouton pour ouvrir ou fermer la boutique
openButton.MouseButton1Click:Connect(function()
	frameStore.Visible = not frameStore.Visible
end)

-- on récupère le bouton de la lampe dans la boutique
local lampButton = script.Parent.FrameStore.LampButton
-- on récupère le RemoteEvent pour acheter la lampe
local remoteBuy = game:GetService("ReplicatedStorage"):WaitForChild("RemoteBuy")
-- on écoute le clic sur le bouton de la lampe pour l'acheter
lampButton.MouseButton1Click:Connect(function(itemName)
	-- on envoie une requête au serveur pour acheter la lampe
	local success, message = remoteBuy:InvokeServer("lamp")
	-- on affiche le message de retour du serveur 
	print(success, message)	
end)

Puis demande à créer un Script sur le serveur sous ServerScriptService afin de valider l’achat :

Renomme ton Script en storeScript:

Ecris ce code dans le script storeScript :

-- récupérer le RemoteFunction RemoteBuy
local remoteBuy = game:GetService("ReplicatedStorage"):WaitForChild("RemoteBuy")

-- écouter l'événement de requête d'achat du joueur
remoteBuy.OnServerInvoke = function(player, value)
	-- vérifier si le joueur a assez de points pour acheter l'objet
	local points = player:WaitForChild("leaderstats").Points.Value
	
	return true, " Achat confirmé !"
end

Lance ton jeu pour vérifier le bon fonctionnement de l’achat, tu trouveras le message de l’acquittement de l’achat dans la console.

Modifie le script storeScript pour vérifier si le joueur dispose d’assez de points pour l’achat et la disponibilité du stock :

-- récupérer le RemoteFunction RemoteBuy
local remoteBuy = game:GetService("ReplicatedStorage"):WaitForChild("RemoteBuy")

local ITEMS = {
	["lamp"] = { price = 5, stock = 2 },
	["run"] = { price = 10, stock = 1 },
	["visible"] = { price = 15, stock = 1 }
}

-- écouter l'événement de requête d'achat du joueur
remoteBuy.OnServerInvoke = function(player, value)
	-- vérifier si le joueur a assez de points pour acheter l'objet
	
	local item = ITEMS[value]

	-- Vérification stock
	if not item or item.stock <= 0 then
                return false, value .. " : Item indisponible "
	end

	-- Vérification points du joueur
	local points = player:WaitForChild("leaderstats").Points.Value
	if points < item.price then
		return false, "Points insuffisants (" .. points .. "/" .. item.price .. ")"
	end

	-- Transaction confirmée
	player.leaderstats.Points.Value -= item.price
	item.stock -= 1
	return true, "Achat confirmé !"
	
end

Rajoute sur l’écran de ta boutique un message pour indiquer au joueur la confirmation de son achat ou non :

Renomme ton TextLabel en MsgLabel :

Modifie le script storeScript pour afficher le message :

-- récupération du bouton pour ouvrir la boutique
local openButton = script.Parent.OpenButton
-- récupération du frame de la boutique	
local frameStore = script.Parent.FrameStore

-- on cache le frame de la boutique au lancement du jeu par defaut	
frameStore.Visible = false

-- on écoute l'événement de clic sur le bouton pour ouvrir ou fermer la boutique
openButton.MouseButton1Click:Connect(function()
	frameStore.Visible = not frameStore.Visible
end)

-- on récupère le bouton de la lampe dans la boutique
local lampButton = script.Parent.FrameStore.LampButton
-- on récupère le RemoteEvent pour acheter la lampe
local remoteBuy = game:GetService("ReplicatedStorage"):WaitForChild("RemoteBuy")

local msg = script.Parent.FrameStore.MsgLabel

-- on écoute l'événement de clic sur le bouton de la lampe pour l'acheter
lampButton.MouseButton1Click:Connect(function(itemName)
	-- on envoie une requête au serveur pour acheter la lampe
	local success, message = remoteBuy:InvokeServer("lamp")
	-- on affiche le message de retour du serveur sur l'acran de la boutique
	msg.Text = message
end)

Lance ton jeu pour vérifier si le message s’affiche correctement après un achat :


Création d’un outil

A mettre à la main du joueur et à présenter dans la boutique

Sous Workspace créer un outil Tool :

Renommer Tool en Lamp :

Maintenant, dessine une lampe en utilisant plusieurs parts que tu assembleras :

Colorise et choisis tes matériaux pour tes parts qui composera ta lampe, puis crée un Union de tes parts et renome l’objet obtenu en Handle :

Rajoute un SpotLight à ta lampe :

Modifie les propriétés de SpotLight pour orienter correctement le faisceau lumineux de ta lampe :

Lance ton jeu, le joueur doit pouvoirt attraper la lampe et vérifie que celle-ci est correctement orientée :

Je constate que la lampe n’est pas correctement orientée, je modifie le Grip de mon Tool pour l’orienter correctement :


AFFICHER L’OUTIL DANS LA BOUTIQUE

L’objectif est de présenter la lampe dans la boutique.

Dans un premier déplace ton outil Tool lampe sous ReplicatedStorage :

Puis tu vas modifier l’écran de ta boutique.

Supprimer le ImageLabel et remplace par un ViewportFrame :

Modifie le LocalScript StoreScript de la boutique :

-- récupération du bouton pour ouvrir la boutique
local openButton = script.Parent.OpenButton
-- récupération du frame de la boutique	
local frameStore = script.Parent.FrameStore

--[[
*** Rendre le viewport 3D de la lampe visible dans la boutique	
]]
local replicatedStorage = game:GetService("ReplicatedStorage")
local lamp = replicatedStorage:WaitForChild("Lamp")
local viewport = script.Parent.FrameStore.ViewportFrame
-- Nettoyage
viewport:ClearAllChildren()
-- Clone de l'objet
local clone = lamp:Clone()
clone.Parent = viewport
-- Caméra
local camera = Instance.new("Camera")
viewport.CurrentCamera = camera
camera.Parent = viewport
local center
local size
-- Calcul de la position de la caméra (adapté à la taille de l'objet)
if clone:IsA("Model") then
	size = clone:GetExtentsSize()
	center = clone:GetPivot().Position
else
	size = clone.Size
	center = clone.Position
end
-- Position de la caméra (à adapter selon la taille de l'objet)
camera.CFrame = CFrame.new(
	center + Vector3.new(size.X, size.Y, size.Z) * 0.8,
	center
)

-- on cache le frame de la boutique au lancement du jeu par defaut	
frameStore.Visible = false

-- on écoute l'événement de clic sur le bouton pour ouvrir ou fermer la boutique
openButton.MouseButton1Click:Connect(function()
	frameStore.Visible = not frameStore.Visible
end)

-- on récupère le bouton de la lampe dans la boutique
local lampButton = script.Parent.FrameStore.LampButton
-- on récupère le RemoteEvent pour acheter la lampe
local remoteBuy = game:GetService("ReplicatedStorage"):WaitForChild("RemoteBuy")

local msg = script.Parent.FrameStore.MsgLabel

-- on écoute l'événement de clic sur le bouton de la lampe pour l'acheter
lampButton.MouseButton1Click:Connect(function(itemName)
	-- on envoie une requête au serveur pour acheter la lampe
	local success, message = remoteBuy:InvokeServer("lamp")
	-- on affiche le message de retour du serveur sur l'acran de la boutique
	msg.Text = message
end)

Orienter l’image de l’outil pour une présentation optimum au joueur :


Mettre l’outil dans l’inventaire du joueur

Lors de l’achat de la lampe, mettre celle-ci dans l’inventaire.

Afin d’optimiser notre code, éviter des erreurs de saisie, tu vas centraliser tout ce que on appelle constante. Ces constantes sont des valeurs fixes et utilisées dans plusieurs parties du code.

Sous ReplicatedStorage crée un ModuleScript pour stocker toutes tes constantes :

local Constants = {}

Constants.POWER_RUN_MORE = "Run more"
Constants.LAMP = "Torch"
Constants.VISIBILITY = "Visibility"
Constants.MAX_SPEED = 50

return Constants

Modifie le LocalScript StoreScript de la boutique pour rajouter l’appel aux constantes :

local Constants = require(game.ReplicatedStorage.Constants)

-- récupération du bouton pour ouvrir la boutique
local openButton = script.Parent.OpenButton
-- récupération du frame de la boutique	
local frameStore = script.Parent.FrameStore

--[[
*** Rendre le viewport 3D de la lampe visible dans la boutique	
]]
local replicatedStorage = game:GetService("ReplicatedStorage")
local lamp = replicatedStorage:WaitForChild("Lamp")
local viewport = script.Parent.FrameStore.ViewportFrame
-- Nettoyage
viewport:ClearAllChildren()
-- Clone de l'objet
local clone = lamp:Clone()
clone.Parent = viewport
-- Caméra
local camera = Instance.new("Camera")
viewport.CurrentCamera = camera
camera.Parent = viewport
local center
local size
-- Calcul de la position de la caméra (adapté à la taille de l'objet)
if clone:IsA("Model") then
	size = clone:GetExtentsSize()
	center = clone:GetPivot().Position
else
	size = clone.Size
	center = clone.Position
end
-- Position de la caméra (à adapter selon la taille de l'objet)
camera.CFrame = CFrame.new(
	center + Vector3.new(size.X, size.Y, size.Z) * 0.8,
	center
)

-- on cache le frame de la boutique au lancement du jeu par defaut	
frameStore.Visible = false

-- on écoute l'événement de clic sur le bouton pour ouvrir ou fermer la boutique
openButton.MouseButton1Click:Connect(function()
	frameStore.Visible = not frameStore.Visible
end)

-- on récupère le bouton de la lampe dans la boutique
local lampButton = script.Parent.FrameStore.LampButton
-- on récupère le RemoteEvent pour acheter la lampe
local remoteBuy = game:GetService("ReplicatedStorage"):WaitForChild("RemoteBuy")

local msg = script.Parent.FrameStore.MsgLabel

-- on écoute l'événement de clic sur le bouton de la lampe pour l'acheter
lampButton.MouseButton1Click:Connect(function(itemName)
	-- on envoie une requête au serveur pour acheter la lampe
	local success, message = remoteBuy:InvokeServer("lamp")
	-- on affiche le message de retour du serveur sur l'acran de la boutique
	msg.Text = message
end)

Modifie le script storeScript sous ServerScriptService pour rajouter le module des constantes :

-- récupérer le module Constants
local Constants = require(game.ReplicatedStorage.Constants)

-- récupérer le RemoteFunction RemoteBuy
local remoteBuy = game:GetService("ReplicatedStorage"):WaitForChild("RemoteBuy")

-- écouter l'événement de requête d'achat du joueur
remoteBuy.OnServerInvoke = function(player, value)
	-- vérifier si le joueur a assez de points pour acheter l'objet
	local points = player:WaitForChild("leaderstats").Points.Value
	
	return true, " Achat confirmé !"
end

Modifie le script storeScript sous ServerScriptService, pour rajouter le contrôle des points, rajouter un tableau de tous les item de la boutique :

-- récupérer le module Constants
local Constants = require(game.ReplicatedStorage.Constants)
-- récupérer le RemoteFunction RemoteBuy
local remoteBuy = game:GetService("ReplicatedStorage"):WaitForChild("RemoteBuy")

local ITEMS = {
	[Constants.LAMP] = { price = 5, power = 10 , stock = 2 },
	[Constants.POWER_RUN_MORE] = { price = 10, power = 10, stock = 2 },
	[Constants.VISIBILITY] = { price = 15, power = 10, stock = 1 }
}

-- écouter l'événement de requête d'achat du joueur
remoteBuy.OnServerInvoke = function(player, value)
	-- vérifier si le joueur a assez de points pour acheter l'objet	
	local item = ITEMS[value]
	
        -- Vérification stock
	if not item or item.stock <= 0 then
		return false, value .. " : Item indisponible "
	end

	-- Vérification points du joueur
	local points = player:WaitForChild("leaderstats").Points.Value
	if points < item.price then
		return false, "Points insuffisants (" .. points .. "/" .. item.price .. ")"
	end

	-- Vérification si le joueur possède déjà l'item
	local newitem = player.leaderstats:FindFirstChild(Constants.POWER_RUN_MORE)
	if not newitem then
		newitem = Instance.new("IntValue")
		newitem.Parent = player.leaderstats
		newitem.Name = value	
	end
	newitem.Value += item.power
	
	-- Transaction confirmée
	player.leaderstats.Points.Value -= item.price
	item.stock -= 1

	return true, "Achat confirmé !"
	
end

Modifie le script pour rajouter la lampe dans l’inventaire du joueur :

local Constants = require(game.ReplicatedStorage.Constants)

-- récupération du bouton pour ouvrir la boutique
local openButton = script.Parent.OpenButton
-- récupération du frame de la boutique	
local frameStore = script.Parent.FrameStore

--[[
*** Rendre le viewport 3D de la lampe visible dans la boutique	
]]
local replicatedStorage = game:GetService("ReplicatedStorage")
local lamp = replicatedStorage:WaitForChild("Lamp")
local viewport = script.Parent.FrameStore.ViewportFrame
-- Nettoyage
viewport:ClearAllChildren()
-- Clone de l'objet
local clone = lamp:Clone()
clone.Parent = viewport
-- Caméra
local camera = Instance.new("Camera")
viewport.CurrentCamera = camera
camera.Parent = viewport
local center
local size
-- Calcul de la position de la caméra (adapté à la taille de l'objet)
if clone:IsA("Model") then
	size = clone:GetExtentsSize()
	center = clone:GetPivot().Position
else
	size = clone.Size
	center = clone.Position
end
-- Position de la caméra (à adapter selon la taille de l'objet)
camera.CFrame = CFrame.new(
	center + Vector3.new(size.X, size.Y, size.Z) * 0.8,
	center
)

-- on cache le frame de la boutique au lancement du jeu par defaut	
frameStore.Visible = false

-- on écoute l'événement de clic sur le bouton pour ouvrir ou fermer la boutique
openButton.MouseButton1Click:Connect(function()
	frameStore.Visible = not frameStore.Visible
end)

-- on récupère le bouton de la lampe dans la boutique
local lampButton = script.Parent.FrameStore.LampButton
-- on récupère le RemoteEvent pour acheter la lampe
local remoteBuy = game:GetService("ReplicatedStorage"):WaitForChild("RemoteBuy")

local msg = script.Parent.FrameStore.MsgLabel

local player = game.Players.LocalPlayer

-- on écoute l'événement de clic sur le bouton de la lampe pour l'acheter
lampButton.MouseButton1Click:Connect(function(itemName)
	if not player then return end
	if not lamp then return end
	
	-- on envoie une requête au serveur pour acheter la lampe
	local success, message = remoteBuy:InvokeServer(Constants.LAMP)
	-- on affiche le message de retour du serveur sur l'acran de la boutique
	msg.Text = message
        -- ajouter la lampe dans l'inventaire du joueur
	if success then
		local backpack = player:WaitForChild("Backpack")
		lamp.Parent = player:WaitForChild("Backpack")		
	end
end)

Courir plus vite

Modifie le localScript ScreenStore pour générer le pouvoir courir plus vite :

local Constants = require(game.ReplicatedStorage.Constants)

-- récupération du bouton pour ouvrir la boutique
local openButton = script.Parent.OpenButton
-- récupération du frame de la boutique	
local frameStore = script.Parent.FrameStore

--[[
*** Rendre le viewport 3D de la lampe visible dans la boutique	
]]
local replicatedStorage = game:GetService("ReplicatedStorage")
local lamp = replicatedStorage:WaitForChild("Lamp")
local viewport = script.Parent.FrameStore.ViewportFrame
-- Nettoyage
viewport:ClearAllChildren()
-- Clone de l'objet
local clone = lamp:Clone()
clone.Parent = viewport
-- Caméra
local camera = Instance.new("Camera")
viewport.CurrentCamera = camera
camera.Parent = viewport
local center
local size
-- Calcul de la position de la caméra (adapté à la taille de l'objet)
if clone:IsA("Model") then
	size = clone:GetExtentsSize()
	center = clone:GetPivot().Position
else
	size = clone.Size
	center = clone.Position
end
-- Position de la caméra (à adapter selon la taille de l'objet)
camera.CFrame = CFrame.new(
	center + Vector3.new(size.X, size.Y, size.Z) * 0.8,
	center
)

-- on cache le frame de la boutique au lancement du jeu par defaut	
frameStore.Visible = false

-- on écoute l'événement de clic sur le bouton pour ouvrir ou fermer la boutique
openButton.MouseButton1Click:Connect(function()
	frameStore.Visible = not frameStore.Visible
end)

-- on récupère le bouton de la lampe dans la boutique
local lampButton = script.Parent.FrameStore.LampButton
-- on récupère le RemoteEvent pour acheter la lampe
local remoteBuy = game:GetService("ReplicatedStorage"):WaitForChild("RemoteBuy")

local msg = script.Parent.FrameStore.MsgLabel

local player = game.Players.LocalPlayer

local humanoid
local leaderstats
local walkSpeed
local MAXSPEED = Constants.MAX_SPEED or 50
local function setup(character)
	humanoid = character:WaitForChild("Humanoid")
	leaderstats = player:FindFirstChild("leaderstats")
	walkSpeed = humanoid.WalkSpeed
end

player.CharacterAdded:Connect(setup)

if player and player.Character then
	setup(player.Character)
end
-- on écoute l'événement de clic sur le bouton de la lampe pour l'acheter
lampButton.MouseButton1Click:Connect(function(itemName)
	if not player then return end
	if not lamp then return end
	
	-- on envoie une requête au serveur pour acheter la lampe
	local success, message = remoteBuy:InvokeServer(Constants.LAMP)
	-- on affiche le message de retour du serveur sur l'acran de la boutique
	msg.Text = message
        -- ajouter la lampe dans l'inventaire du joueur
	if success then
		local backpack = player:WaitForChild("Backpack")
		lamp.Parent = player:WaitForChild("Backpack")		
	end
end)

-- on récupère le bouton pour le pouvoir de courir plus vite
runButton.MouseButton1Click:Connect(function(itemName)
	if not player then return end
	if not leaderstats then return end
	-- on envoie une requête au serveur pour le pouvoir courir plus vite
	local success, message = remoteBuy:InvokeServer(Constants.POWER_RUN_MORE)
	-- on affiche le message de retour du serveur sur l'acran de la boutique
	msg.Text = message
end)

Vérifie que tu disposes bien du pouvoir de courir plus vite :


Ajouter le pouvoir de courir plus vite


Sur la boutique programmer le bouton « Courrir plus vite »

Objectif :

✔ programmer le bouton de la boutique « courir plus vite »
✔ envoyer une demande au serveur pour acheter le pouvoir
✔ recevoir une réponse succès ou pas
✔ activer un pouvoir avec le clavier par la touche R

Le principe du pouvoir :

Le joueur peut :

  • acheter un pouvoir “courir plus vite”
  • appuyer sur R pour l’activer
  • utiliser ce pouvoir un certain nombre de fois

Programme le clic sur le bouton « courir plus vite » :

Modifie le localScript StoreScript et ajoute en fin du script :

-- on récupère le bouton pour le pouvoir de courir plus vite
runButton.MouseButton1Click:Connect(function(itemName)
	if not player then return end
	if not leaderstats then return end
	-- on envoie une requête au serveur pour le pouvoir courir plus vite
	local success, message = remoteBuy:InvokeServer(Constants.POWER_RUN_MORE)
	-- on affiche le message de retour du serveur sur l'acran de la boutique
	msg.Text = message
end)

Programme pour que le joueur court plus vite sur l’appui de la touche R :

Modifie le localScript StoreScript et ajoute en fin du script :

--[[
	Traitement des touches du clavier pour activer/désactiver les pouvoirs du joueur
]]
-- Connecte l'événement du clavier
local UserInputService = game:GetService("UserInputService")
local runMore = false
-- Récupère l'évènement du clavier
UserInputService.InputBegan:Connect(function(input, gameProcessed)
	if not player then return end
	if not humanoid then return end
	-- Vérifie si l'évènement est un clavier
	if input.KeyCode ~= Enum.KeyCode.Unknown then
		-- Ferme l'écran de la boutique
		frameStore.Visible = false
		-- Vérifie si la touche appuyée est R
		if input.KeyCode == Enum.KeyCode.R and not gameProcessed then
			if runMore then
				runMore = false
				humanoid.WalkSpeed = walkSpeed
			else
				-- Vérifie si le leaderstats existe et le pouvoir de courir plus vite
				if leaderstats and leaderstats:FindFirstChild(Constants.POWER_RUN_MORE) then
					local run = leaderstats:FindFirstChild(Constants.POWER_RUN_MORE)
					-- si le pouvoir est actif
					if run.Value > 0 then

						humanoid.WalkSpeed = MAXSPEED
						run.Value -= 1
						runMore	= true
					end
				end
			end
		end

	end

end)

A chaque utilisation de la touche R pour courir plus vite, le pouvoir diminue :


Fermeture automatique de la boutique

Fermer automatiquement la boutique en cliquant en dehors de la fen,être de la boutique ou en utilisant une touche du clavier.

Crée un TextButton dans un Frame qui couvre tout l’écran :

Renomme le TextButton en Background.

Donne une priorité à la fenêtre de la boutique et aux boutons de la boutique :

Modifie le localScript StoreScript :

-- on récupère le background de l'interface de la boutique
local background = script.Parent.FrameBackground.Background
--[[
	Affichage ou non de la boutique sur l'appui de l'icone de la boutique 
]]
-- on cache le frame de la boutique au lancement du jeu par defaut	
frameStore.Visible = false
background.Interactable = false

-- on écoute l'événement de clic sur le bouton pour ouvrir ou fermer la boutique
openButton.MouseButton1Click:Connect(function()
	frameStore.Visible = not frameStore.Visible
	background.Interactable = frameStore.Visible
	frameStore.MsgLabel.Text = "Choisis ton option"
end)

background.MouseButton1Click:Connect(function()
	frameStore.Visible = false
	-- rendre non cliquable
	background.Interactable = frameStore.Visible
end)

et lors de l’appui d’une touche :

--[[
	Traitement des touches du clavier pour activer/désactiver les pouvoirs du joueur
]]
-- Connecte l'événement du clavier
local UserInputService = game:GetService("UserInputService")
local runMore = false
-- Récupère l'évènement du clavier
UserInputService.InputBegan:Connect(function(input, gameProcessed)
	if not player then return end
	if not humanoid then return end
	-- Vérifie si l'évènement est un clavier
	if input.KeyCode ~= Enum.KeyCode.Unknown then
		-- Ferme l'écran de la boutique
		frameStore.Visible = false
		background.Interactable = frameStore.Visible	
		-- Vérifie si la touche appuyée est R
		if input.KeyCode == Enum.KeyCode.R and not gameProcessed then
			if runMore then
				runMore = false
				humanoid.WalkSpeed = walkSpeed
			else
				-- Vérifie si le leaderstats existe et le pouvoir de courir plus vite
				if leaderstats and leaderstats:FindFirstChild(Constants.POWER_RUN_MORE) then
					local run = leaderstats:FindFirstChild(Constants.POWER_RUN_MORE)
					-- si le pouvoir est actif
					if run.Value > 0 then

						humanoid.WalkSpeed = MAXSPEED
						run.Value -= 1
						runMore	= true
					end
				end
			end
		end

	end

end)
Catégories
PAGES MEMBRES

Protégé : CLEMENT PASSARD

Ce contenu est protégé par un mot de passe. Pour le voir, veuillez saisir votre mot de passe ci-dessous :

Catégories
Construct 3

Construct 3 Flappy Bird

Réalisation d’un jeu 2D pour comprendre le fonctionnement de Construct 3

Partie 01 mise en place des éléments graphiques

Partie 02 Animer les éléments graphiques

Partie 03 Animer les éléments graphiques suite

Partie 04 Programmer les règles du jeu

Catégories
Modélisation 3D

CREALITY K2 PLUS

Vidéo démontage extrudeuse quand le filament est coincé

Remplacer la jauge de contrainte

Remplacer le câble adaptateur de la buse

Catégories
MICRO PYTHON RASPBERRY PICO W

CAPTEURS COULEURS TCS34725

RASPBERRY PICO W

Le capteur de couleur TCS34725 (Gravity)

À quoi ça sert sur notre robot ?

Le TCS34725 est un capteur de couleur.
Sur la compétition Rescue Line, il sert principalement à :

  • suivre la ligne noire
  • repérer les carrés verts pour savoir quand tourner à droite ou à gauche

Comment “voit” le capteur ?

Il éclaire le sol

Le capteur possède quatre petites LEDs blanches.

  • Elle éclaire le sol juste en dessous du robot
  • La lumière rebondit sur le sol et revient vers le capteur
  • Un sol clair renvoie beaucoup de lumière
  • Un sol foncé (ligne noire) renvoie peu de lumière

Il sépare la lumière en couleurs

À l’intérieur du capteur, il y a 4 détecteurs :

  • 🔴 Rouge (R)
  • 🟢 Vert (G)
  • 🔵 Bleu (B)
  • ⚪ Luminosité totale (Clear)

Pour chaque couleur, le capteur donne un nombre.

Ces nombres sont envoyés au microcontrôleur (ex : Raspberry Pico, mBot, etc.).

Le multiplexeur I2C

Pourquoi on en a besoin avec plusieurs capteurs de couleur ?

Rappel : c’est quoi le bus I2C ?

Le bus I2C, c’est comme une route avec quatres fils :

  • SDA : pour envoyer et recevoir les données
  • SCL : pour donner le rythme (l’horloge)

Tous les capteurs sont branchés sur la même route et parlent avec le microcontrôleur.

Avec un bus I2C ont peut dialoguer avec plusieurs dispositifs sur le même bus.

Chaque capteur a une adresse

Sur cette route, chaque capteur a une adresse, comme un numéro de maison.

Exemple :

  • Capteur température : adresse 0x48
  • Capteur distance : adresse 0x29
  • Capteur couleur TCS34725 : adresse 0x29

Quand le microcontrôleur veut parler à un capteur, il dit :

« Je parle au capteur numéro 0x29 »

Le problème avec plusieurs capteurs identiques

Dans notre robot, on utilise plusieurs capteurs de couleur identiques :

  • gauche
  • centre
  • droite

Et ils ont tous la même adresse I2C

Résultat :

  • Le microcontrôleur dit :
    « Capteur 0x29, réponds ! »
  • Tous répondent en même temps
  • Ça crée un conflit → le bus ne fonctionne plus

La solution : le multiplexeur I2C

Un multiplexeur I2C (ex : TCA9548A) est comme :

un aiguillage ou un feu de circulation pour le bus I2C

Il permet de choisir quel capteur est connecté au bus à un instant donné.

Comment fonctionne le multiplexeur ?

Le multiplexeur est lui-même un appareil I2C

  • Il a sa propre adresse
  • Le microcontrôleur peut lui parler

Il possède plusieurs “canaux” de 1 à 8 canaux

Par exemple :

  • canal 0
  • canal 1
  • canal 2
  • …
  • jusqu’à 8 canaux

Chaque canal peut avoir :

  • un capteur
  • ou même plusieurs capteurs (s’ils ont des adresses différentes)

On ouvre un canal à la fois

Le microcontrôleur dit au multiplexeur :

« Ouvre le canal 2 »

Résultat :

  • Seul le capteur branché sur le canal 2 est visible
  • Les autres sont déconnectés temporairement

Pour programmer, le capteur TCS34725 utilise la librairie class tcs34725.py à télécharger sur le microcontroleur :

Dans ton programme importe ces bibliothèques :

from machine import I2C
import time
from tcs34725 import TCS34725

Recherche les adresses sur le bus i2c :

from machine import I2C
import time
from tcs34725 import TCS34725

print("Initialisation I2C...")
i2c = I2C(0)
print("Scan I2C en cours...")
devices = i2c.scan()
print("Adresses trouvées:", [hex(d) for d in devices])
  • 0x29 : capteur de couleur
  • 0x72 : multiplexeur i2c

Exemple d’un programme de test pour lire les valeurs de deux capteurs sur les port 0 et 1 :

from machine import I2C
import time
from tcs34725 import TCS34725

print("Initialisation I2C...")
i2c = I2C(0)
print("Scan I2C en cours...")
devices = i2c.scan()
print("Adresses trouvées:", [hex(d) for d in devices])
# Initialisation du capteur
# Si vous n'utilisez PAS de multiplexeur, laissez multiplexer_addr=None
# Si vous en utilisez un, changez multiplexer_addr=0x70 (ou autre) et le port=0-7
ADDRESS_MULTIPLEXER = const(0x72)
try:
    print("Initialisation TCS34725...")
    #sensor = TCS34725(i2c)
    # Pour un multiplexeur:
    sensor01 = TCS34725(i2c, ADDRESS_MULTIPLEXER, 0)
    sensor02 = TCS34725(i2c, ADDRESS_MULTIPLEXER, 1)

    print("Capteur trouvé !")

    # Configuration optionnelle
    sensor01.integration_time(50) # 50ms (plus rapide mais moins précis que 2.4ms * n)
    sensor01.gain(4) # Gain 4x (1, 4, 16, 60)
    sensor02.integration_time(50)
    sensor02.gain(4)
    while True:
        # Lecture brute
        r, g, b, c = sensor01.read(raw=True)

        # Lecture interprétée
        temp, lux = sensor01.read(raw=False) # Note: refait une lecture

        print(f"R:{r} G:{g} B:{b} C:{c} | Temp:{temp}K Lux:{lux}")

        gray01 = sensor01.read_grayscale()
        gray02 = sensor02.read_grayscale()
        print("Read Gray : ", gray01)

        # Détection simple couleur
        if sensor01.is_red():
            print(" >> ROUGE détecté !")
        elif sensor01.is_green():
            print(" >> VERT détecté !")
        elif sensor01.is_blue():
            print(" >> BLEU détecté !")

        time.sleep(1)

except RuntimeError as e:
    print("ERREUR FATALE:", e)
except Exception as e:
    print("Erreur inattendue:", e)

Exemple initialisation capteur de couleur en direct sans le multiplexeur :

    sensor = TCS34725(i2c)

Exemple initialisation capteurs couleur via le multiplexeur :

    sensor01 = TCS34725(i2c, ADDRESS_MULTIPLEXER, 0)
    sensor02 = TCS34725(i2c, ADDRESS_MULTIPLEXER, 1)

Lecture de la nuance de gris :

        gray01 = sensor01.read_grayscale()
        print("Read Gray : ", gray01)

Détection d’une couleur :

if sensor01.is_red():
print( » >> ROUGE détecté ! »)
elif sensor01.is_green():
print( » >> VERT détecté ! »)
elif sensor01.is_blue():
print( » >> BLEU détecté ! »)

Catégories
Non classé

RASPBERRY PICO W

  • MICRO PYTHON RASPBERRY
    CARTE DE DEVELOPPEMENT RASPBERRY PICO W La carte dispose : La carte propose l’écosystème C/C++ mais également celui du Micropython. Pi Pico bénéficie des avantages de micro-python et on peut citer notamment : Sur une carte à microcontrôleur, on dispose : Le pico pi est vendu « vide », autrement dit, il ne dispose pas du Micropython… Lire la suite : MICRO PYTHON RASPBERRY
  • L’écran OLED SSD1306
    CARTE DE DEVELOPPEMENT RASPBERRY PICO W C’est quoi un écran OLED SSD1306 ? Un écran OLED SSD1306 est un petit écran que l’on branche à un microcontrôleur (comme une Raspberry Pi Pico) pour afficher du texte ou des dessins sur un port I2C. OLED, ça veut dire quoi ? Taille courante : Comment la Pico… Lire la suite : L’écran OLED SSD1306
  • Entrées et sorties numériques
    CARTE DE DEVELOPPEMENT RASPBERRY PICO W LED intégrée à la carte Sur la Raspberry Pi Pico, il y a une petite LED intégrée à la carte. Cette LED est reliée à une broche spéciale. Quand on met cette broche : Comment la Pico contrôle la LED ? La Pico utilise une sortie numérique. C’est comme… Lire la suite : Entrées et sorties numériques
  • CAPTEURS COULEURS TCS34725
    RASPBERRY PICO W Le capteur de couleur TCS34725 (Gravity) À quoi ça sert sur notre robot ? Le TCS34725 est un capteur de couleur.Sur la compétition Rescue Line, il sert principalement à : Comment “voit” le capteur ? Il éclaire le sol Le capteur possède quatre petites LEDs blanches. Il sépare la lumière en couleurs… Lire la suite : CAPTEURS COULEURS TCS34725
Catégories
MICRO PYTHON RASPBERRY PICO W Robotique

Entrées et sorties numériques

CARTE DE DEVELOPPEMENT RASPBERRY PICO W

LED intégrée à la carte

Sur la Raspberry Pi Pico, il y a une petite LED intégrée à la carte.

Cette LED est reliée à une broche spéciale.

Quand on met cette broche :

  • à 1 (ON) → la LED s’allume
  • à 0 (OFF) → la LED s’éteint

Comment la Pico contrôle la LED ?

La Pico utilise une sortie numérique.

C’est comme un interrupteur :

  • ON = courant qui passe
  • OFF = courant coupé

En MicroPython, on utilise la classe Pin.

Allumer la LED

from machine import Pin

led = Pin("LED",Pin.OUT) # LED sur la carte
led.on()                # Allumer la LED

La LED s’allume

Eteindre la LED

led.off()  # Éteindre la LED

La LED s’éteint

Faire clignoter la LED

from machine import Pin
from time import sleep

led = Pin("LED", Pin.OUT)

while True:
    led.on()      # LED allumée
    sleep(1)      # attendre 1 seconde
    led.off()     # LED éteinte
    sleep(1)      # attendre 1 seconde

Résultat :

  • la LED s’allume 1 seconde
  • puis s’éteint 1 seconde
  • et recommence en boucle

Une autre façon

from machine import Pin, Timer

# led de la carte
led=Pin("LED",Pin.OUT)

timerLed=Timer() # déclare un objet timer

def loopLed(timerLed): 
    led.toggle()

timerLed.init(freq=5, callback=loopLed)

La LED clignote toute seule, sans bloquer le programme.

C’est comme une alarme tous les x secondes :

  • tu règles l’heure
  • et il sonne tout seul
  • même si tu fais autre chose

Création du timer

  • Timer → pour créer un minuteur automatique

timerLed = Timer()

On crée un minuteur qui appellera une fonction tout seul.

Démarrage du timer

timerLed.init(freq=5, callback=loopLed)

  • freq=5 → 5 fois par seconde
  • callback=loopLed → appelle la fonction loopLed

La fonction appelée par le timer

def loopLed(timerLed):
led.toggle()

Cette fonction :

  • est appelée automatiquement par le timer
  • change l’état de la LED à chaque appel (allumée, éteinte)

Faire clignoter une LED sur le PIN GP2

Installe une LED de couleur bleue sur le port GP2 :

from machine import Pin, Timer

# led de la carte
ledBlue=Pin(2,Pin.OUT)

timerLedBlue=Timer() # déclare un objet timer

def loopLedBlue(timerLedBlue): 
    ledBlue.toggle()

timerLedBlue.init(freq=1, callback=loopLedBlue)

Faire clignoter une LED bleue avec un Timer

(sans boucle while)

  • La LED clignote toute seule,
  • une fois par seconde,
  • sans bloquer le programme.

C’est comme un réveil :

  • tu règles le rythme
  • et il déclenche la LED tout seul
  • pendant que le programme fait autre chose

La LED

ledBlue = Pin(2, Pin.OUT)

La LED est branchée sur la broche 2
C’est une sortie (ON / OFF)

Allumer / éteindre une LED avec un bouton poussoir (interruption)

Quand on appuie sur le bouton poussoir :

  • la LED change d’état
    • allumée → éteinte
    • éteinte → allumée

Installe une LED de couleur bleue sur le port GP2 et un bouton poussoir sur GP3 :

Le code complet

from machine import Pin, Timer

# led de la carte
ledBlue = Pin(2, Pin.OUT)
button1 = Pin(3, Pin.IN, Pin.PULL_UP)

ledBlue.off()

button1.irq( 
        #définition de l'interruption sur la broche
        handler = lambda btn1: ledBlue.toggle(),
        # mode de déclenchement IRQ_RISING IRQ_FALLING
        trigger = button1.IRQ_FALLING 
       )

Explication ligne par ligne

Importation

from machine import Pin, Timer

On utilise :

  • Pin → pour la LED et le bouton

La LED bleue sur GP2

ledBlue = Pin(2, Pin.OUT)

La LED est branchée sur la broche 2
C’est une sortie (ON / OFF)

Le bouton poussoir sur GP3

button1 = Pin(3, Pin.IN, Pin.PULL_UP)

Le bouton est :

  • sur la broche 3
  • configuré en entrée
  • avec une résistance pull-up interne

Pull-up, ça veut dire :

  • sans appui → niveau 1
  • bouton appuyé → niveau 0

Éteindre la LED au départ

ledBlue.off()

On commence avec la LED éteinte
État connu = pas de surprise

La partie la plus importante : l’interruption

button1.irq(
handler = lambda btn1: ledBlue.toggle(),
trigger = button1.IRQ_FALLING
)

C’est quoi une interruption ? :

  • le programme fait autre chose
  • Ding ! → bouton appuyé
  • la Pico réagit tout de suite

IRQ_FALLING

L’interruption se déclenche :

  • quand le signal passe de 1 à 0
  • donc quand on appuie sur le bouton

(parce qu’il est en pull-up)

ledBlue.toggle()

toggle() le LED inverse son état :

  • ON → OFF
  • OFF → ON

Pourquoi lambda btn1: ?

C’est une petite fonction rapide :

lambda btn1: ledBlue.toggle()

  • Elle est appelée automatiquement
  • btn1 représente le bouton (obligatoire)
  • On n’en a pas besoin ici, mais MicroPython l’exige

Pourquoi utiliser une interruption ? (le gros avantage)

Sans interruption

while True:
    if button1.value() == 0:
        ledBlue.toggle()
        sleep(0.3)

Le programme regarde le bouton tout le temps
Risque de rater un appui
Le robot est ralenti

Avec interruption

  • Le bouton est détecté instantanément
  • Le programme reste rapide

C’est quoi lambda en Python ?

lambda permet de créer une toute petite fonction,

  • en une seule ligne,
  • sans lui donner de nom.

Une fonction jetable, rapide à écrire.

Une fonction normale (classique)

def addition(a, b):
    return a + b

Cette fonction :

  • a un nom (addition)
  • fait une action
  • renvoie un résultat

La même chose avec lambda

addition = lambda a, b: a + b

C’est exactement pareil, mais :

  • en une seule ligne
  • plus court
  • sans def

Comment lire une lambda

lambda a, b: a + b

Ça se lit comme :

« Une fonction qui prend a et b et qui retourne a + b »

Tout ce qui est après : est le résultat

Catégories
MICRO PYTHON RASPBERRY PICO W

L’écran OLED SSD1306

CARTE DE DEVELOPPEMENT RASPBERRY PICO W

C’est quoi un écran OLED SSD1306 ?

Un écran OLED SSD1306 est un petit écran que l’on branche à un microcontrôleur (comme une Raspberry Pi Pico) pour afficher du texte ou des dessins sur un port I2C.

OLED, ça veut dire quoi ?

  • Chaque pixel s’allume tout seul
  • Pas besoin de rétroéclairage
  • Noir = pixel éteint → économie d’énergie

Taille courante :

  • 128 × 64 pixels
  • 128 × 32 pixels

Comment la Pico communique avec l’écran ?

La Pico communique avec l’écran grâce au bus I²C.

C’est comme une conversation :

  • La Pico = celui qui parle
  • L’écran = celui qui écoute

Les 2 fils importants du bus i2c

FilRôle
SDADonnées envoyées à l’écran
SCLCadence (rythme de communication)

L’écran a une adresse (souvent 0x3C) pour qu’on sache à qui on parle.

À quoi sert la bibliothèque micropython-ssd1306 ?

La bibliothèque sert à :

  • permettre d’écrire simplement :
    • du texte
    • des pixels
    • des formes

https://github.com/stlehmann/micropython-ssd1306

Comment fonctionne l’affichage ? (idée clé)

L’écran ne s’actualise pas tout seul.

  1. La Pico dessine dans une image invisible (le buffer)
  2. Quand tout est prêt, on dit :
oled.show()

Et l’image apparaît à l’écran

Comme dessiner sur une feuille, puis l’afficher d’un coup

Exemple simple de programme

# Création du bus I2C
i2c = I2C(0)

# Création de l'écran
oled = SSD1306_I2C(128, 64, i2c)

# Effacer l'écran
oled.fill(0)

# Écrire du texte
oled.text("Bonjour !", 0, 0)
oled.text("Initialisation", 0, 10)

# Afficher à l'écran
oled.show()

Les commandes principales (les plus utiles)

Écrire du texte

oled.text("Texte", x, y)
  • x → position horizontale
  • y → position verticale

🧹 Effacer l’écran

oled.fill(0)

Allumer tous les pixels

oled.fill(1)

Allumer un pixel

oled.pixel(x, y, 1)

Dessiner une ligne

oled.line(x1, y1, x2, y2, 1)

0 ou 1 pour éteindre ou allumer la ligne

Exemple amusant (point qui bouge)

for x in range(128):
    oled.fill(0)
    oled.pixel(x, 30, 1)
    oled.show()

Le point se déplace à l’écran

Catégories
ROBOCUP

ROBOCUP 2026 Maze

Stratégie de déplacement du robot dans le labyrinthe.

L’objectif est de permettre au robot de se déplacer tout seul dans un labyrinthe, sans se perdre, en utilisant une stratégie simple :

suivre le mur de droite et prendre en priorité les ouvertures à droite.

Principe général : suivre le mur de droite ou de gauche

Le robot imagine qu’il garde toujours sa main droite posée sur un mur.
S’il continue ainsi, il pourra explorer tout le labyrinthe sans rester bloqué.

Pour cela, le robot utilise des capteurs de distance pour savoir s’il y a un mur :

  • devant lui
  • à droite
  • à gauche

Se déplacer dans un couloir en suivant une Ligne imaginaire

Quand le robot est dans un couloir, il ne colle pas au mur :

  • il suit une ligne imaginaire parallèle au mur de droite
  • cette ligne se situe au centre du couloir

Cela permet :

  • d’éviter de toucher les murs
  • d’avancer droit

Le robot ajuste légèrement sa direction pour rester à la même distance du mur de droite et avance jusqu’à la fin du couloir

Dès que le capteur détecte un mur devant :

  • le robot s’arrête
  • cela signifie qu’il est arrivé à la fin du couloir ou à une intersection

Teste et affiche sur l’écran le niveau de batterie :

Si le niveau de batterie est trop faible le comportement du robot devient incohérent.

Quand le capteur ultrasonique n’arrive plus à mesurer, par exemple trop proche d’un mur, la valeur retournée est 300.

Télécharge et teste le robot dans le labyrinthe dans un couloir

Utilise le calcul de trajectoire PID du suivi de ligne :

Indique kp = 1 et kd = 0 pour l’instant

Télécharge et teste : Le robot va tout droit

Télécharge et teste : Le robot va à droite

Télécharge et teste : Le robot va à gauche

Modifie la valeur de kp entre 1.5 et 0.5, tu constateras que ton robot tourne plus ou moins fortement :

Suivi d’une ligne imaginaire au milieu du couloir

On imagine une ligne noire posée au milieu du couloir parallèle au mur droit du couloir. Le robot suit cette ligne en allant de droite à gauche comme pour le suivi d’une ligne noire.

  • largeur du couloir = 30 cm
  • écart de la ligne en prenant en compte la largeur du robot = 9 cm

Détail du suivi de ligne avec le capteur ultrasonique 2 sur le mur droit :

On image une ligne à 9cm (ecart_ligne) de la paroi de droite et d’une largeur de 3 cm. A droite de la ligne le robot tourne à gauche (position = -0.5à, sur la ligne il va tout droit (position = 0), à gauche de la ligne il tourne vers la droite (position = 0.5).

Télécharge et teste un couloir avec un mur à droite tout le long

Elimine les valeurs erronées :

Détail

Télécharge et teste

Essaye de suivre tout le labyrinthe, tourne en bout de couloir

En fonction des possibilités tourne à 90° en bout de couloir soit à droite, soit à gauche ou fait un demi-tour à 180°

Télécharge et teste

Le robot commence à suivre le labyrinthe avec quelques imperfection à corriger;

Problème 1 : le robot est trop proche des parois

Si le capteur ultrasonique de droite ou de gauche détecte une distance trop proche de la paroi, alors le robot recule en changeant de sens de direction pour essayer de se recentrer au milieu du couloir.

Détail pour détecter un rapprochement avec les parois de droite et de gauche :

Problème 2 : le robot reste collé à la paroi

Si le robot ne change pas de position pendant un certain temps, alors on essaye de le décoller de la paroi.

Problème 3 : le robot ne détecte pas toujours la bonne possibilité en fin de couloir

Parfois la mesure par le capteur ultrasonique est erronée. Pour éviter une erreur de direction suit à une mesure, la solution est de prendre plusieurs mesures afin valider la bonne direction à prendre :

Le robot est trop proche de la paroi en fin de couloir, on tente de reculer le robot :

On cumule les mesures pendant 3 secondes toute les 0.5 secondes

Après que le robot a effectué son quart de tour à gauche ou à droite, on vérifie de nouveau si une paroi est présente devant le robot :

Le code complet :

Problème 4 : Lorsque la paroi de droite est inexistante, le robot ne tourne pas suffisamment à droite ou tourne trop fort.

Modifie la valeur de kp :

Catégories
ROBOCUP

ROBOCUP 2026 Rescue line

Configure MBLOCK pour le suivi de ligne

Utilise le bouton extension

Rajoute ces deux éléments :

Premier essai de fonctionnement du MBOT

Premier téléchargement

Teste ton programme

Teste une programmation des moteurs

Teste ton programme

Essayons de programmer par étape le suivi de ligne

Affichons le niveau de batterie car si celle-ci est inférieure à un certain niveau, le comportement du robot devient incohérent :

Sous le lancement du MBOT CyberPi crée les variables suivantes :

  • vitesse_droite : pour gérer la vitesse du moteur EM1
  • vitesse_gauche : pour gérer la vitesse du moteur EM2
  • vitesse_maxi : vitesse maximum du robot
  • vitesse_mini : vitesse moyenne du robot
  • position : poids de la position du robot par rapport à la ligne noire
  • correction : correction à appliquer aux moteurs pour suivre la ligne noire

Gestion du bouton B pour lancer le suivi de ligne puis l’arrêter

Tester le bouton B , les leds s’allument en vert puis en rouge

Calcul la vitesse des moteurs en fonction de la position du robot par rapport à la ligne noire

Si le robot est à gauche de la ligne noire, il tourne à droite pour se recentrer sur la ligne :

Si le robot est à droite de la ligne noire, il tourne à gauche pour se recentrer sur la ligne :

Si le robot est centrer sur la ligne noire, il va tout droit :

Détail du calcul :

Ne pas oublier que les moteurs du MBOT sont inversés :

Teste pour vérifier que ton calcul est correct avec position = 0 pour aller tout droit :

Teste, le robot roule tout droit

Faire tourner le robot

Teste des valeurs de position de -2 à 2 :

Teste le robot pour qu’il tourne plus ou moins à gauche ou à droite avec des valeurs dans position entre -2 et 2

Une première version pour un Suivi de ligne

Utilise cette instruction pour la détection de la ligne noire :

Elle permet une détection par capteur L2, L1, R1, R2 :

Plus de détail de la gestion des capteurs :

Détection d’un virage par les capteurs extrêmes L2, D2 du Quad RGB du MBOT :

Capteur central ou L1 et R1 sur la ligne pour aller tout droit :

Détail du si :

Et les 2 capteurs L1 et R1 du Quad RGB du MBOT :

Teste le suivi de ligne

Tu peux rajouter plus de précision :

Plus de détail sur le rajout :

Modifie le suivi de ligne avec le calcul du PID

  • derivee : afin de suivre quand le robot passe de gauche à droite de la ligne noire
  • Kp : pour accentuer ou diminuer pour prendre le angles droits,
    • 1 ne fait rien
    • < 1 diminue l’angle des virages
    • > 1 augmente l’angle des virages
  • Kd : pour empêcher le robot de faire des zigzags
    • 0 ne fait rien
    • 0 à 3 diminuer les zigzags en ligne droite

Tu peux jouer sur ces deux valeurs pour ajuster ton suivi de ligne :

à

puis teste :

à

Cas du croisement, le robot doit aller tout droit

Si le capteur au central détecte une ligne noire en même temps que les capteurs L2 et R2, on peut déduire que le robot est sur un croisement. Le robot doit aller tout droit.

Passage d’un obstacle

Si le robot détecte un obstacle avec un dispositif placé à l’avant du robot, une stratégie de forçage est déclenchée : le robot effectue une accélération franche vers l’avant afin de franchir l’obstacle.

Puis rajouter l’appel de la fonction dans le code :

Arrêt du robot sur une ligne rouge