Notes techniques sur l'implémentation de la pause de mouvement en C#.
1. Approche conceptuelle
Types de mouvement :
Mouvement relatif : Déplacement par rapport à la position actuelle. La pause est complexe car on ignore le déplacement effectué, rendant la reprise difficile.
Mouvement absolu : Déplacement par rapport à une positino d'origine. La pause est plus simple à implémenter.
Positionnement du bouton pause : Selon la documentation technique, le signal de pause doit être placé dans la séquence d'atente d'arrêt.
2. Bibliothèque de fonctions de mouvement
2.1 Déplacement absolu mono-axe
public class MotionController
{
public OperationResult PositionAbsolue(short noAxe, double position, double vitesse = 10, double acceleration = 0.0125)
{
OperationResult validation = ValiderAxe(noAxe);
if (!validation.EstSucces) return validation;
short erreur = 0;
try
{
erreur = gts.GT_ClrSts(noAxe, 1);
GererErreurs("GT_ClrSts", erreur);
erreur = gts.GT_PrfTrap(noAxe);
GererErreurs("GT_PrfTrap", erreur);
gts.TTrapPrm parametres;
erreur = gts.GT_GetTrapPrm(noAxe, out parametres);
GererErreurs("GT_GetTrapPrm", erreur);
parametres.acc = acceleration;
parametres.dec = acceleration;
parametres.smoothTime = 25;
erreur = gts.GT_SetTrapPrm(noAxe, ref parametres);
GererErreurs("GT_SetTrapPrm", erreur);
int impulsions = ConvertirPositionEnImpulsions(noAxe, position);
erreur = gts.GT_SetPos(noAxe, impulsions);
GererErreurs("GT_SetPos", erreur);
erreur = gts.GT_SetVel(noAxe, vitesse);
GererErreurs("GT_SetVel", erreur);
erreur = gts.GT_Update(1 << (noAxe - 1));
GererErreurs("GT_Update", erreur);
}
catch (Exception ex)
{
return OperationResult.CreerEchec(ex.Message);
}
return OperationResult.CreerSucces();
}
private int ConvertirPositionEnImpulsions(short noAxe, double position)
{
switch (noAxe)
{
case var n when n == parametresAvances.Axe_X:
return (int)Math.Round(position * parametresAvances.Echelle_X);
case var n when n == parametresAvances.Axe_Y:
return (int)Math.Round(position * parametresAvances.Echelle_Y);
case var n when n == parametresAvances.Axe_Z:
return (int)Math.Round(position * parametresAvances.Echelle_Z);
default:
return (int)position;
}
}
}
2.2 Déplacement absolu bi-axe
public OperationResult PositionBiAxe(short[] axes, double[] positions, double[] vitesses, double[] accelerations)
{
if (axes.Length != 2 || positions.Length != 2 || vitesses.Length != 2 || accelerations.Length != 2)
{
return OperationResult.CreerEchec("Paramètres de taille incorrecte");
}
foreach (short axe in axes)
{
OperationResult validation = ValiderAxe(axe);
if (!validation.EstSucces) return validation;
}
var configAxeX = new ConfigurationAxe
{
Numero = axes[0],
PositionCible = positions[0],
Vitesse = vitesses[0],
Acceleration = accelerations[0]
};
var configAxeY = new ConfigurationAxe
{
Numero = axes[1],
PositionCible = positions[1],
Vitesse = vitesses[1],
Acceleration = accelerations[1]
};
OperationResult resultat = PositionAbsolue(configAxeX.Numero, configAxeX.PositionCible,
configAxeX.Vitesse, configAxeX.Acceleration);
if (!resultat.EstSucces) return resultat;
resultat = PositionAbsolue(configAxeY.Numero, configAxeY.PositionCible,
configAxeY.Vitesse, configAxeY.Acceleration);
if (!resultat.EstSucces) return resultat;
return AttendreArret(new[] { configAxeX, configAxeY });
}
2.3 Attente d'arrêt avec gestion de pause
public OperationResult AttendreArret(ConfigurationAxe axe)
{
OperationResult validation = ValiderAxe(axe.Numero);
if (!validation.EstSucces) return validation;
short erreur = 0;
int statut;
do
{
if (modePauseActif)
{
ArreterAxe(axe.Numero);
AttendreReprise();
PositionAbsolue(axe.Numero, axe.PositionCible, axe.Vitesse, axe.Acceleration);
}
erreur = gts.GT_GetSts(axe.Numero, out statut, 1, out uint horloge);
GererErreurs("GT_GetSts", erreur);
} while ((statut & 0x400) != 0);
return OperationResult.CreerSucces();
}
public OperationResult AttendreArret(ConfigurationAxe[] axes)
{
if (axes.Length != 2)
{
return OperationResult.CreerEchec("Collection d'axes invalide");
}
OperationResult validation = ValiderInitialisation();
if (!validation.EstSucces) return validation;
short erreur = 0;
int statut1, statut2;
do
{
if (modePauseActif)
{
foreach (var axe in axes) ArreterAxe(axe.Numero);
AttendreReprise();
foreach (var axe in axes)
{
PositionAbsolue(axe.Numero, axe.PositionCible, axe.Vitesse, axe.Acceleration);
}
}
erreur = gts.GT_GetSts(axes[0].Numero, out statut1, 1, out uint horloge1);
erreur = gts.GT_GetSts(axes[1].Numero, out statut2, 1, out uint horloge2);
GererErreurs("GT_GetSts", erreur);
} while ((statut1 & 0x400) != 0 || (statut2 & 0x400) != 0);
return OperationResult.CreerSucces();
}
private void AttendreReprise()
{
while (modePauseActif)
{
Thread.Sleep(10);
}
}
3. Interface principale - Gestion de la pause
3.1 Vraiables d'état
private bool _etatPrecedentBoutonPause = false;
private bool _dernierFrontMontant = false;
private bool _dernierFrontDesce = true;
3.2 Boucle de surveillance du signal de pause
private void InitialiserApplication(object sender, EventArgs e)
{
ConfigurerNavigation();
OuvrirEcranParDefaut();
MettreAJourInterfaceUtilisateur();
InitialiserMateriel();
_annulationSource = new CancellationTokenSource();
Task.Run(() => ProcessusPrincipal(_annulationSource.Token));
Task.Run(() => SurveillerBoutonPause(_annulationSource.Token));
_annulationSource.Token.Register(FermerMateriel);
}
private void SurveillerBoutonPause(CancellationToken jetonAnnulation)
{
while (!jetonAnnulation.IsCancellationRequested)
{
bool etatActuel = LireBoutonPause();
if (DetecterFrontMontant(etatActuel))
{
ActiverModePause();
}
if (DetecterFrontDescendant(etatActuel))
{
DesactiverModePause();
}
}
}
3.3 Méthodes de détection de signaux de bord
private bool DetecterFrontMontant(bool etatActuel)
{
bool frontDetecte = etatActuel && !_etatPrecedentBoutonPause;
_etatPrecedentBoutonPause = etatActuel;
return frontDetecte;
}
private bool DetecterFrontDescendant(bool etatActuel)
{
bool frontDetecte = !etatActuel && _etatPrecedentBoutonPause;
_etatPrecedentBoutonPause = etatActuel;
return frontDetecte;
}