Utiliser learndash et WordPress pour un cours en ligne ?

Utiliser learndash et WordPress pour un cours en ligne ?

Je veux créer des cours en ligne pour mes clients ou prospects. J’ai acheté l’extension learndash voici quelques temps. J’ai fait quelques essais mais je n’ai pas poursuivi. Aujourd’hui je recommence. Je vais documenter ce travail dans une série d’article ([the series]) qui contiendra les éléments suivants :

  • quelles sont les possibilités de learndash
  • installer learndash et créer un premier cours de test.
  • Etudier les différents paramètres et définir à quoi ils servent
  • Voir les possibilités de quiz et remise de devoirs en ligne
  • d’autres choses, en fonction de ce que je découvre.

Dans ce premier article, je vais voir quelles sont les possibilités de learndash.

Que peut-on mettre dans un cours en ligne ?

Pour en savoir plus sur WordPress et la formation en ligne, voir l’article ci-dessous. On peut aussi regarder les vidéos en français de cette page.

WordPress e-learning : une révolution pour la formation en ligne ?

Un cours en ligne est un ensemble de modules (pouvant être subdivisés en séquences) qui comprend des contenus pédagogiques et des évaluations. Au fur et à mesure de l’avancement de l’apprenant, il peut obtenir des certificats qui valident des apprentissages.

L’accès au cours peut être totalement ouvert ou réservé à certains. Lorsqu’il est réservé à certains, l’accès peut être gratuit ou payant.

Enfin, comme dans une formation en présentiel, il peut être nécessaire d’imposer une séquence précise ou un délai entre deux séquences.

Le créateur d’un cours en ligne doit donc au minimum pouvoir réaliser les actions suivantes :

  • créer des cours, avec modules et séquences ;
  • évaluer l’apprenant par le biais de quiz en ligne ou par des devoirs mis en ligne ;
  • Délivrer des certificats ;
  • gérer les accès aux cours, par inscription et/ou paiement en ligne ;
  • gérer le séquençage : imposer qu’une séquence soit finie avant d’en démarrer une autre ou imposer un délai pour l’accès au module suivant.

Le cours en ligne et l’expérience apprenant

Online WebinarPour l’apprenant, qui peut ne pas être très à l’aise avec l’informatique, il est essentiel que le cours en ligne lui offre une expérience agréable et motivante.

  • simplifier l’utilisation ;
  • proposer plusieurs médias. Par exemple si un cours est présenté sous forme vidéo, proposer une transcription écrite et l’éventuel diaporama en pdf séparé ;
  • rendre la formation ludique (gamification) ;
  • les évaluations ne devraient pas servir (seulement) à évaluer. Elles peuvent être très utiles à l’apprenant pour mieux comprendre, pour se positionner en tant qu’acteur de sa formation. Elles peuvent aussi servir au formateur pour identifier des points faibles de sa formation.
  • faciliter les échanges avec des humains : avec le formateur, éventuellement avec d’autres apprenants ;
  • s’adapter aux différentes façons d’apprendre

Quelles sont les fonctionnalités de learndash

Learndash est l’un des nombreux plugin LMS (Learning Management System) pour WordPress. Je l’ai choisi car c’est la seule extension créée par des spécialistes du elearning et pas par des spécialistes de WordPress. Learndash s’interface pourtant très bien avec WordPress.

compatible mobiles / tablettes

Les apprenants doivent pouvoir utiliser l’équipement de leur choix pour accéder aux cours.

vente en ligne possible

learndash s’interface avec différentes solutions de vente en ligne : Paypal ou autres avec des extensions complémentaires (gratuites ou pas).

L’achat peut se faire soit en une fois, soit par abonnement.

L’accès au cours peut être supprimé au bout d’un certain temps.

contenus fournis en « goutte à goutte »

Les contenus peuvent être mis à disposition par « drip feed » : à une date définie, x jours après l’inscription ou uniquement si un autre contenu a été validé auparavant.

gestion des « devoirs »

Lorsque l’apprenant doit rendre un « devoir », le formateur est informé de sa mise à disposition et peut le valider ou non, faire des commentaires.

Des évaluations sophistiquées

On peut utiliser des questions à choix unique ou multiple, demander une réponse en texte libre, proposer de trier des réponses ou de les mettre dans la bonne case. On peut aussi faire une enquête.

Voir toutes les options ici (en anglais).

forums

l’apprenant peut s’inscrire à des forums spécifiques au cours. Voir l’article en anglais de learndash à ce sujet.

notifications par mail

Le formateur et l’apprenant peuvent recevoir des mails liés au cours.

rapports par utilisateur

On peut suivre chaque utilisateur : où en est-il dans le cours ? Quels sont ses résultats ?

Gestion de groupes

On peut créer des groupes d’apprenants. Par exemple un groupe de salariés d’une entreprise peut être créé pour un suivi spécifique.

Gestion de badges

Avec des extensions (gratuites), on peut générer des badges qui signifient qu’on a réussi une étape. Ca ajoute un côté ludique, utile si bien fait.

clonage des cours

Pour que le formateur puisse cloner des cours sur un autre site. C’est une extension gratuite. Voir ici.

Autres fonctionnalités

L’extension « LearnDash Toolkit » a été créée par une entreprise d’e-learning canadienne. Après avoir utilisé ces éléments pour leurs propres créations, ils l’ont mis à disposition gratuitement.

Et maintenant

Je vais créer mon premier cours en ligne dans l’article suivant de cette série .

Arduino et interruptions, la gestion des horloges internes

Arduino et interruptions, la gestion des horloges internes

Pour créer le NoRobo, j’ai dû me pencher sur la notion d’interruptions (Wikipedia). Il s’agit d’un moyen de faire faire plusieurs choses différentes par un même microprocesseur. C’est un concept essentiel dès que l’on veut faire exécuter des activités et les ajuster selon des données entrées par le biais d’une interface utilisateur (la commande bluetooth d’un robot par exemple) ou par un capteur du système.

Les ondes PWM (MLI en français)

Pwm 5stepsJ’ai commencé à m’intéresser aux PWM lorsque j’ai cherché comment contrôler la vitesse d’un moteur à courant continu. Le code dont je m’inspirais utilisait des ondes PWM. J’ai finalement décidé d’utiliser AnalogWrite(x), avec x, de 0 à 255, représentant la vitesse souhaitée.

J’ai découvert à ce moment là que AnalogWrite() envoie aussi des ondes PWM, mais dont la fréquence n’est pas contrôlée. Et par ailleurs, AnalogWrite() n’est pas exécuté si l’arduino fait autre chose. Il est donc fort probable qu’il faille que j’ai recours aux PWM lorsque je vais finaliser le NoRobo (cf la série d’article à ce sujet ici).

Mes sources principales d’information ont été « Secrets of Arduino PWM » et « Changing PWM Frequency on the Arduino« . Ca m’a permis de comprendre les réglages d’horloge que l’on peut faire sur un arduino.

Seules les broches 3,5,6, 9, 10 et 11 de l’arduino uno peuvent être configurées en sorties PWM. Elles sont repérées par un petit symbole ∼.

On notera que la fréquence d’onde PWM à utiliser est fonction des moteurs. Chacun a ses spécificités. On peut seulement dire que la fréquence est comprise entre  1 et 15 kHz.

Les Interruptions (interrupt en anglais)

Elles sont utilisées pour réaliser des activités à une fréquence régulière. Tout le monde connaît delay(), qui permet d’interrompre le sketch arduino pendant un certain temps avant de reprendre. C’est très bien pour des activités simples, mais cette fonction a un énorme problème : elle arrête tout le reste du sketch ! On la réserve donc à des sketch très simples, avec une seule activité.

L’article d’Hobbytronics (en anglais) sur les interruptions Arduino propose un sketch qui permet d’allumer et éteindre une led toutes les secondes, sans utiliser delay(). La led clignote et on peut faire faire ce qu’on veut à l’arduino en même temps. Adafruit y consacre aussi un tutoriel.

Nick Gammon donne des informations sur les interruptions dans les arduino. J’ai également lu attentivement cet article, qui m’a été très utile.

Enfin, la notice du microprocesseur ATMEGA 328 de l’arduino UNO contient plein de détails sur les horloges  :

  • Chapitre 15. sur les « 8-bit Timer/Counter0 with PWM » en page 93;
  • Chapitre 16. sur les « 16-bit Timer/Counter1 with PWM » en page 111;
  • Chapitre 17. sur les « Timer/Counter0 and Timer/Counter1 Prescalers » en page 138;
  • Chapitre 18. sur les « 8-bit Timer/Counter2 with PWM and Asynchronous Operation » en page 141;

Cas pratique : examen d’un morceau de code

Dans les différentes versions de sketch pour le NoRobo (par exemple celle-ci : NoRobo-Joystick-BT-commander-2016-04-12B.ino), il y a plusieurs éléments liés aux horloges. Dans les lignes ci-dessous, je n’ai laissé que les lignes qui me paraissent liées aux horloges :

uint16_t freqCounter = 0;
uint16_t oldfreqCounter = 0;
uint16_t loop_time = 0;         //how fast is the main loop running

int motorG_enable = 11; //pwm
int motorD_enable = 3; //pwm

void setup()
{

  Bl_Setup();
   
}

/****************************************************************************************************
 * LOOP
 ****************************************************************************************************/
 
void loop()
{
  //run main loop every ~4ms
  if ((freqCounter & 0x07f) == 0)
  {
    // record when loop starts
    oldfreqCounter = freqCounter;

    // every ~1s
	if ((freqCounter & 0x7FFF) == 0)
    {
      // Do something
    }

    // every ~0.13s
    if ((freqCounter & 0xFFF) == 0)
    {
      // Do something else
    }

    //calculate loop time
    if (freqCounter > oldfreqCounter)
    {
      if (loop_time < (freqCounter - oldfreqCounter)) loop_time = freqCounter - oldfreqCounter;
    }
  }
}

void Bl_Setup()
{
  cli();//stop interrupts

  //timer setup for 31.250KHZ phase correct PWM
  TCCR0A = 0;
  TCCR0B = 0;
  TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM00);
  TCCR0B = _BV(CS00);
  TCCR1A = 0;
  TCCR1B = 0;
  TCCR1A = _BV(COM1A1) | _BV(COM1B1) | _BV(WGM10);
  TCCR1B = _BV(CS10);
  TCCR2A = 0;
  TCCR2B = 0;
  TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM20);
  TCCR2B = _BV(CS20);

  // enable Timer 1 interrupt
  TIMSK1 = 0;
  TIMSK1 |= _BV(TOIE1);
  // disable arduino standard timer interrupt
  TIMSK0 &= ~_BV(TOIE1);

  sei(); // Start Interrupt

  //turn off all PWM signals
  OCR2A = 0;  //11  APIN
  OCR2B = 0;  //D3
  OCR1A = 0;  //D9  CPIN
  OCR1B = 0;  //D10 BPIN
  OCR0A = 0;  //D6
  OCR0B = 0;  //D5

  // switch off PWM Power
  motorPowerOff();
}

//--------------------------------------------------------------
// code loop timing---------------------------------------------
//--------------------------------------------------------------
// minimize interrupt code length
// is called every 31.875us (510 clock cycles)  ???????
ISR( TIMER1_OVF_vect )
{
  //every 32 count of freqCounter ~1ms
  freqCounter++;

  if ((freqCounter & 0x01) == 0)
  {
    // do another thing
  } 
}

Durant le setup, les horloges sont réglées

cli() arrête les interruptions pour procéder aux réglages.

Les trois horloges sont réglées pour fournir des fréquences de 31.25 KHz « phase correct ».

   //timer setup for 31.250KHZ phase correct PWM
  TCCR0A = 0;
  TCCR0B = 0;
  TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM00);
  TCCR0B = _BV(CS00);
  TCCR1A = 0;
  TCCR1B = 0;
  TCCR1A = _BV(COM1A1) | _BV(COM1B1) | _BV(WGM10);
  TCCR1B = _BV(CS10);
  TCCR2A = 0;
  TCCR2B = 0;
  TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM20);
  TCCR2B = _BV(CS20);

Ici on règle les trois horloges, 0, 1 et 2.

Les horloges 0 et 2 ont des compteurs 8 bits et sont très semblables. L’horloge 0 gère delay() and millis()  et tout réglage modifie ces deux fonctions.

L’horloge 1 dispose d’un compteur 16 bits (valeurs de 0 à 65535). La librairie servo.h s’en sert et il vaut mieux ne pas l’utiliser lorsqu’on a des servomoteurs.

Pour configurer une horloge, on doit modifier les registres de réglage correspondants. Ces registres, au nombre de 2 par horloge s’appellent des « Timer/Counter Control Registers ». On les appelle donc TCCRxA et TCCRxB, où x est le numéro de l’horloge. Chaque registre fait 8 bits et stocke une valeur de configuration.

Pour l’horloge 1, les bits les plus importants sont les trois derniers de TCCR1B (CS12, CS11 et CS10). En les modifiant, on peut changer la vitesse d’horloge.

PAr défaut, lorsque CS10, 11 et 12 sont à 0, l’horloge 1 tourne à 16 MHZ. C’est la même vitesse lorsque seul CS10 est à 1. On fera donc un cycle d’horloge toutes les (1/16*10ˆ6) seconde, soit 6.25*10-8 s. Notre compteur passera donc de 0 à 65535 en (65535 * 6.25*10-8s), soit toutes les 0.0041 seconds.

_BV(bit) est une macro qui convertit un numéro de bit en un octet. En écrivant TCCR1B = _BV(CS10); , on dit de régler CS10 à 1, CS11 et CS12 restant à 0. On a donc un « prescaler » fixé à 1, selon le tableau ci-dessous :

CS12 CS11 CS10 Description
0 0 0 No clock source (Timer/Counter stopped)
0 0 1 clki/o/1 (No prescaling)
0 1 0 clki/o/8 (From Prescaler)
0 1 1 clki/o/64 (From Prescaler)
1 0 0 clki/o/256 (From Prescaler)
1 0 1 clki/o/1024 (From Prescaler)
1 1 0 External clock source on T1 pin. Clock on falling edge
1 1 1 External clock source on T1 pin. Clock on rising edge

Ce prescaler permet de ralentir le compteur. Si le prescaler est à 1, le compteur fera un overflow tous les 0.004 secondes (4 millisecondes) comme vu précédemment.

Si le prescaler est à 256 par exemple (  TCCR1B = _BV(CS12); ), la vitesse d’horloge passe à 1/(16*10⁶/256), ou 0.000016 secondes (62500 Hz). L’horloge aura un overflow toutes les (65535 *0.000016=) 1.04856 secondes.

Si on ecrivait TCCR1B = _BV(CS10) | _BV(CS12), le prescaler serait 1024. On aurait donc une vitesse d’horloge de 1/(16*10⁶ / 1024), soit 0.000064 seconds (15625 Hz). Maintenant on aura un overflow toutes les (65535 * 6.4*10-5s), or 4.194s

 Dans notre cas, on aura un overflow toutes les 4 millisecondes. C’est donc toutes les 4 millisecondes que se déclenchera l’ISR liée au timer 1. 

Pour tout savoir sur les réglages du timer 0, voir l’arduino timer cheat sheet.

Enfin, la ligne suivante règle le timer 1 en mode

TCCR1A = _BV(COM1A1) | _BV(COM1B1) | _BV(WGM10);

TCCR1A est réglé en Phase-correct PWM.

Les deux moteurs sont connectés aux broches du timer 2

Les broches 11 et 3 correspondent au timer 2. Les 9 et 10 au timer 1 et les 5 et 6 au timer 0.

Une interruption est réalisée grâce au timer 1

  // enable Timer 1 interrupt
  TIMSK1 = 0;
  TIMSK1 |= _BV(TOIE1);
  // disable arduino standard timer interrupt
  TIMSK0 &= ~_BV(TOIE1);

  sei(); // Start Interrupt

TIMSK1 |= _BV(TOIE1);  définit que lors de l’overflow, il faut déclencher une interruption. Et comme on a mis à 1 le bit CS10, ce sera le vecteur  (TIMER1_OVF_vect) qui sera déclenché à chaque overflow.

Les horloges fonctionnent en incrémentant un compteur. Il compte de 0 à 255 (si le registre fait 8 bits, 0 à 65535 s’il fait 16 bits). Lorsque le compteur atteint sa valeur maximale, il fait un « overflow » et se remet à 0. Lorsqu’un overflow se produit, on peut déclencher une interruption grâce à une routine de service d’interruption (ISR). c’est ce qui se passe dans l’ISR ci-dessous.

Pour voir la liste des interruptions, voir le chapitre « 12.4 Interrupt Vectors in ATmega328 and ATmega328P », en page 65 de la « datasheet » du ATmega328 (de l’arduino Uno).

Une ISR, Interruption Service Routine

//--------------------------------------------------------------
// code loop timing---------------------------------------------
//--------------------------------------------------------------
// minimize interrupt code length
// is called every 31.875us (510 clock cycles)  ???????
ISR( TIMER1_OVF_vect )
{
  //every 32 count of freqCounter ~1ms
  freqCounter++;

  if ((freqCounter & 0x01) == 0)
  {
    // do another thing
  }
}

ISR( TIMER1_OVF_vect )  est une « interrupt service routine », qui s’éxécute lorsque TIMER1_OVF_vect  se déclenche.

La boucle suit le temps

void loop()
{
  //run main loop every ~4ms
  if ((freqCounter & 0x07f) == 0)
  {
    // record when loop starts
    oldfreqCounter = freqCounter;

    // every ~1s
	if ((freqCounter & 0x7FFF) == 0)
    {
      // Do something
    }

    // every ~0.13s
    if ((freqCounter & 0xFFF) == 0)
    {
      // Do something else
    }

    //calculate loop time
    if (freqCounter > oldfreqCounter)
    {
      if (loop_time < (freqCounter - oldfreqCounter)) loop_time = freqCounter - oldfreqCounter;
    }

  }
}

Les broches 2 et 3 pour des external interrupts…

voir le chapitre 13 « External Interrupts », en page 70 de la « datasheet » du ATmega328 (de l’arduino Uno).

Les broches « INT0 » et « INT1 » (respectivement 2 et 3 sur l’arduino Uno) servent à déclencher des interruptions externes.

Exemple suivant issu de cet article en français de Michael Bouvy.

par exemple sur le pin INT0 (soit D2) nous attachons une interruption, qui appellera la fonction « myInterrupt » lors d’un passage du pin à l’état haut :

attachInterrupt(0, myInterrupt(), RISING);

Bien que le pin Arduino soit « D2 », nous indiquons ici « 0 » qui est le n° de pin d’interruption (0 pour INT0 / D2, 1 pour INT1 / D3).

Ensuite, une fonction exécutera ce qui doit être fait lorsque la broche passe à l’état haut :

void myInterrupt() {
  // do something ...
}

Noter que dans le programme du balancing robot, les moteurs utilisent les broches 3,5,6,9,10 et 11, donc toutes les broches connectées aux horloges de l’arduino.  INT du gyroscope ne peut donc pas être relié à ces horloges…

Communication I2C

Dans la documentation du ATmega328 (de l’arduino Uno), le chapitre 22, en page 206 est intitulé « 2-wire Serial Interface » (TWI). C’est la partie qui correspond à I2C.

C’est la librairie wire.h qui gère le protocole I2C sur l’arduino.

http://www.robot-electronics.co.uk/i2c-tutorial

La ligne writeTo(MPU6050, PWR_MGMT_1, 0);  de la fonction angle_setup() dit au gyroscope de se « réveiller » et d’utiliser l’horloge interne à 8MHz. D’après ce que je comprends, c’est l’horloge interne du gyroscope, pas une des horloges de l’arduino.

Mais si INT du gyroscope est connecté à une broche de l’arduino, que se passe-t-il ?

Et maintenant ?

Je suis loin d’avoir tout compris, mais le brouillard s’éclaircit. Je retourne donc à mon NoRobo, avec un article dans la série « un robot arduino ».

NoRobo : mesurer l’angle en avant ou en arrière, pas facile…

NoRobo : mesurer l’angle en avant ou en arrière, pas facile…

Dans l’article précédent de cette série, « « , j’ai vu comment lire les données d’un gyroscope avec un arduino. Aujourd’hui, cinquième article, je place ce gyroscope sur le NoRobo et je prépare le code pour connaitre l’inclinaison du robot vers l’avant ou vers l’arrière. Il a toujours 3 roues et cette fonction est inutile pour l’instant. Mais c’est le préalable pour que le robot tienne « debout » sur deux roues !  (suite…)