CP0097 Presentation Turntable

2 Février 2019

Comme montré dans ma vidéo, ce plateau tournant offre 2 modes de fonctionnement.
Il est ausi un exemple didacticte d'utilisation d'un Arduino.


Finish.JPG

Vidéo de présentation du hardware




Vidéo de présentation du software




Voici le schéma du biniou

CP0097.GIF
 
Schéma au format SPlan

Source arduino .ino

Et voici le source :

/*
CP0097 Rotating Plate Control Copyright Cyrob 2019
Arduino pro Micro

Description

Control a Stepper motor in two modes:
- SpeedMode : The speed varie with the knob position from -max to max with a midle zero position
              Led is switched off if the motor is stopped
              Led is green if it moves
              Led is red is the maximum speed is reached

- TrackMode : The position of the motor follows the knob one
              The increment of the position change with the speed of the knob to allow precision
              Led is blue

Pushing the knob at any time stops the motor ans toggle mode.

The motor windings are desactivated when motor is Off

=====================================================================================
==========================   OPEN SOURCE LICENCE   ==================================
=====================================================================================

Copyright 2019 Philippe Demerliac Cyrob.org

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

................................................................................................................
Release history
................................................................................................................
Version Date      Author    Comment
1.0d1   02/02/19  Phildem   First blood
1.0     06/02/19  Phildem   Version OK
1.1     06/02/19  Phildem   Version OK, relative speed improvement
1.2     07/02/19  Phildem   Version OK, Code refactoring and presentation
*/

//IO Abstraction ...............................................................................................
#define kOutCpuLed  13    // Active High
#define kOutRLed    12    // Active Low
#define kOutGLed    11    // Active Low
#define kOutBLed    10    // Active Low

#define kOutDir     8    
#define kOutStep    9     // Step on Low to High transition
#define kOutEnable  5     // Active Low

#define kInKnobCk   2
#define kInKnobDir  3
#define kInKnobPush 4

// Settings ....................................................................................................
#define kMicroIdle            20          // Micro Ticker step duration in µs
#define kStepPulseWidth_us    4           // Step pulse width in µS
#define kMotorWakeUp_ms       10          // Delay in ms to let motor wake up when Enable set to low

#define kMinSpeedDelay_uT     10000       // Slower speed in delay between Step pulse in Micro idle steps
#define kMaxSpeedDelay_uT     100         // Higher speed in delay between Step pulse in Micro idle steps
#define kMaxSpeed             100         // Max Value of gSpeed
#define kSpeedInc             5           // Knob increment for Speed
#define kPosInc               2           // Knob pos Increment in TrackMode

     
// Global .....................................................................................................
static unsigned long     gLastMicro        =0;       // Micro Ticker last Time ref
static unsigned long     gLastMilli        =0;       // Milli Ticker last Time ref

static long              gSpeed            =0;       // 0 Off else -kMaxSpeed to +kMaxSpeed Sign is dir
static unsigned long     gPulseDelay       =0;       // Delay counter in Micro Ticker between pulse
static bool              gMotEnable        = false;  // True if motor enable

static bool              gLastKnobCk;                // Last knob Ck Input
static unsigned long     gLastKnobMilli    =0;       // Last milli of knob action

static bool              gModeTrack        = false;  // True if mode Track
static unsigned long     gTargetPos        =0;       // Track mode Target pos
static unsigned long     gActualPos        =0;       // Track mode Actual pos


//------------------------------------------------------------------------------------------------------------
void setup(void) {
 
  //IO Init
  pinMode(kInKnobCk, INPUT_PULLUP);
  pinMode(kInKnobDir, INPUT_PULLUP);
  pinMode(kInKnobPush, INPUT_PULLUP);

  gLastKnobCk=digitalRead(kInKnobCk);

  pinMode(kOutCpuLed, OUTPUT);
  pinMode(kOutRLed, OUTPUT);
  pinMode(kOutGLed, OUTPUT);
  pinMode(kOutBLed, OUTPUT);

  pinMode(kOutDir, OUTPUT);
  pinMode(kOutStep, OUTPUT);
  pinMode(kOutEnable, OUTPUT);

  digitalWrite(kOutDir, LOW);
  digitalWrite(kOutStep, LOW);
  DisableMotor();

  // Test Led Sequence
  digitalWrite(kOutCpuLed, HIGH);
 
  SetLedRed();
  delay(500);
  SetLedGreen();
  delay(500);
  SetLedBlue();
  delay(500);

  for (int i=0;i<5;i++){
    SetLedRed();
    delay(20);
    SetLedOff();
    delay(150);
  }

  digitalWrite(kOutCpuLed, LOW);

  SetModeSpeed();
}

//============================================================================================================
// UI Led Control
//____________________________________________________________________________________________________________

//------------------------------------------------------------------------------------------------------------
// Switch State Led to Red
//------------------------------------------------------------------------------------------------------------
void SetLedRed(){
    digitalWrite(kOutRLed, LOW);
    digitalWrite(kOutGLed, HIGH);
    digitalWrite(kOutBLed, HIGH);
}

//------------------------------------------------------------------------------------------------------------
// Switch State Led to Green
//------------------------------------------------------------------------------------------------------------
void SetLedGreen(){
    digitalWrite(kOutRLed, HIGH);
    digitalWrite(kOutGLed, LOW);
    digitalWrite(kOutBLed, HIGH);
}

//------------------------------------------------------------------------------------------------------------
// Switch State Led to Blue
//------------------------------------------------------------------------------------------------------------
void SetLedBlue(){
    digitalWrite(kOutRLed, HIGH);
    digitalWrite(kOutGLed, HIGH);
    digitalWrite(kOutBLed, LOW);
}

//------------------------------------------------------------------------------------------------------------
// Switch State Led to Off
//------------------------------------------------------------------------------------------------------------
void SetLedOff(){
    digitalWrite(kOutRLed, HIGH);
    digitalWrite(kOutGLed, HIGH);
    digitalWrite(kOutBLed, HIGH);
}

//------------------------------------------------------------------------------------------------------------
//  Handle Led display must be call every ms
//------------------------------------------------------------------------------------------------------------
void LedIdle() {
 
  if (gModeTrack)
    SetLedBlue();
  else if (gSpeed==0)
    SetLedOff();
  else if (abs(gSpeed)>=kMaxSpeed)
    SetLedRed();
  else
    SetLedGreen();
}

//============================================================================================================
// Knob Handling
//____________________________________________________________________________________________________________

//------------------------------------------------------------------------------------------------------------
// Look if knob moved, return 0 if not, else -Step or +Step vs direction
//------------------------------------------------------------------------------------------------------------
long ReadKnob() {

  bool  Ck=digitalRead(kInKnobCk);

  if (Ck==gLastKnobCk)
    return 0;
   
  delayMicroseconds(400);

  gLastKnobCk=Ck;

  if (Ck==LOW)
      return 0;

  unsigned long Step;
  unsigned long Now=millis();
  if (gModeTrack){                      // Non linear in Track mode
    gLastKnobMilli=Now-gLastKnobMilli;
    Step=kPosInc;
    if (gLastKnobMilli<350)             
      Step*=8;
    else if (gLastKnobMilli<500) 
      Step*=4;
    else if (gLastKnobMilli<600)
      Step*=2;
  }
  else
    Step=kSpeedInc;
  gLastKnobMilli=Now;
 
  if (digitalRead(kInKnobDir)==LOW)   // Set Sign vs direction
    return -Step;
   
  return Step; 
}

//------------------------------------------------------------------------------------------------------------
//  Handle Knob rotation, must be call every Micro Ticker
//------------------------------------------------------------------------------------------------------------
void KnobRotIdle() {

  long k=ReadKnob();

  if (k==0)
    return;

  if (gModeTrack) {
    SetRelativeTrackPosition(k); 
  } else
    SetSpeed(gSpeed+k);
}

//------------------------------------------------------------------------------------------------------------
//  Handle Knob Push must be call every ms
//------------------------------------------------------------------------------------------------------------
void KnobPushIdle(){

  if (digitalRead(kInKnobPush)==HIGH)
    return;
 
  // Wait for button released
  while (digitalRead(kInKnobPush)==LOW)
    delay(1);

  // Toggle mode
  if (gModeTrack){      // Return to speed mode
    SetModeSpeed();
  }
  else {                // Return to Track mode
    SetModeTrack();
  }
}

//============================================================================================================
// Motor Control
//____________________________________________________________________________________________________________

//------------------------------------------------------------------------------------------------------------
// Increment motor of one step
//------------------------------------------------------------------------------------------------------------
void StepOne() {
  digitalWrite(kOutStep, HIGH);
  delayMicroseconds(kStepPulseWidth_us);
  digitalWrite(kOutStep, LOW);
}

//------------------------------------------------------------------------------------------------------------
// Enable motor power
//------------------------------------------------------------------------------------------------------------
void EnableMotor(){
  digitalWrite(kOutCpuLed, HIGH);
  digitalWrite(kOutEnable, LOW);
  if (!gMotEnable)  // To let driver wake up
    delay(kMotorWakeUp_ms);
  gMotEnable=true;
}

//------------------------------------------------------------------------------------------------------------
// Disable motor power
//------------------------------------------------------------------------------------------------------------
void DisableMotor(){
  digitalWrite(kOutCpuLed, LOW);
  digitalWrite(kOutEnable, HIGH);
  gMotEnable=false;
}

//------------------------------------------------------------------------------------------------------------
// Set Global Speed, sign is direction, Speed will be clamp to max
//------------------------------------------------------------------------------------------------------------
void SetSpeed(long Speed) {

  gSpeed = constrain(Speed, -kMaxSpeed, kMaxSpeed);
}

//------------------------------------------------------------------------------------------------------------
// Handle Motor, make it turn vs gSpeed. Must be called every Micro Ticker
//------------------------------------------------------------------------------------------------------------
void MotorIdle() {
 
  if (gSpeed==0){
    DisableMotor();
    return;
  }

  if (gPulseDelay>0){
    gPulseDelay--;
    return;
  }

   EnableMotor();

  if (gSpeed>0){
    digitalWrite(kOutDir, LOW);
    gActualPos++;
  }
  else {
    digitalWrite(kOutDir, HIGH);
    gActualPos--;
  }

  StepOne();
  gPulseDelay=kMinSpeedDelay_uT/abs(gSpeed);
}

//============================================================================================================
// Mode Control
//____________________________________________________________________________________________________________

//------------------------------------------------------------------------------------------------------------
//  Indicate to switch to mode Speed
//------------------------------------------------------------------------------------------------------------
void SetModeSpeed(){
      gModeTrack=false;
      SetSpeed(0);  
}

//------------------------------------------------------------------------------------------------------------
//  Indicate to switch to mode Track
//------------------------------------------------------------------------------------------------------------
void SetModeTrack(){
      gModeTrack=true;
      gActualPos=0;
      gTargetPos=0;
      SetSpeed(0); 
}

//------------------------------------------------------------------------------------------------------------
//  Set the target position in Track Mode (Pos or neg vs Dir)
//------------------------------------------------------------------------------------------------------------
void SetRelativeTrackPosition(long Move){
   gTargetPos+=Move;
}

//------------------------------------------------------------------------------------------------------------
//  Handle Mode must be call every ms
//------------------------------------------------------------------------------------------------------------
void ModeIdle(){
 
  if (!gModeTrack)
    return;

  if (gActualPos==gTargetPos){
      gActualPos=0;
      gTargetPos=0;
      SetSpeed(0);     
  }
  else
    SetSpeed(gTargetPos-gActualPos);  
}


//============================================================================================================
//  Cooperativ multi task supervisor
//____________________________________________________________________________________________________________

//------------------------------------------------------------------------------------------------------------
//  Main Loop
//------------------------------------------------------------------------------------------------------------
void loop(void) {
 
  // µs Ticker ...................................
  unsigned long CurMicro=micros();
  if (CurMicro<gLastMicro){     // Handle µ Rollover
    gLastMicro=CurMicro;
  }

  if ((CurMicro-gLastMicro)>kMicroIdle){
    gLastMicro=CurMicro;
   
    // Fast Engine -------------
    MotorIdle();

    // Fast UI UI -------------
    KnobRotIdle();
 }
 
  // ms Ticker ................................
  unsigned long CurMilli=millis();
  if (CurMilli !=gLastMilli){
    gLastMilli=CurMilli;

    // Slow Engine -------------
    ModeIdle();

    // Slow UI -------------
    KnobPushIdle();
    LedIdle();

  } // of milli   


}

Quelques photos

J'ai monté toute l'électronique sur une veroboard


PcbTop.JPG

Les pistes en lignes facilitent les liaisons sur ce genre de montages


PcbBot.JPG

Les junpers pemettent de choisir la résolution, j'ai finalement opté pour du 1/4 de pas.


Jumpers.JPG

J'ai découpé le bouton dans une chute de plastique avec une scie cloche sans centre.
Puis fait une fixation d'axe en soudant un raccord 'Mecano" sur une plaque de cuivre.

BtTop.JPGBtBot.JPG

Le tout est monté sur un suppor pour rendre le bouton afleurant.
Toutes ces tôles de recup diverses me servent toujours....

BtFix.JPG

Le plateau, je vais le couvrir d'un tapis 'Gomme' une foit terminé.


PlateTop.JPG

J'ai usiné le support qui va bien dans une chute d'alu

PlateMeca.JPG

Ce site utilise des frames. Si vous ne voyez pas les menus à gauche, cliquez Ici