C# - Contrôle de mouvement - Gestion de la pause - Méthodes de détection de signaux de bord

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;
}

Étiquettes: C# contrôle de mouvement pause de mouvement détection de fronts automatisation industrielle

Publié le 9 juin à 02h45