This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Laser

Other Parts Discussed in Thread: ENERGIA

hi there I am working on a project that involves laser control from Mach4 Darwin cnc controller.

the controller involves 3 control wires coming from the bob to a controller, 2 are Interrupts the other is a pwm.

the board has a screen 7 switches and 1 pot and a couple of leds and one wire to a laser.

I am thinking of getting a C2000 for this project would that be the correct board to use.

any advices would be accepted 

  • Hi Daniel,

    daniel lyall said:
    hi there I am working on a project that involves laser control from Mach4 Darwin cnc controller.

    What type of laser control are you looking for? Also, how is this laser interfaced?

    daniel lyall said:

    the controller involves 3 control wires coming from the bob to a controller, 2 are Interrupts the other is a pwm.

    the board has a screen 7 switches and 1 pot and a couple of leds and one wire to a laser.

    This should not be an issue. Just that you'll have to use a Serial LCD instead of parallel ones.

    If you can share more details about this laser control and its interface with controller, we can conclude on this experiment of yours.

    Regards,

    Gautam

  • #include <Bridge.h>
    #include <Console.h>
    #include <FileIO.h>
    #include <HttpClient.h>
    #include <Mailbox.h>
    #include <Process.h>
    #include <YunClient.h>
    #include <YunServer.h>
    #include <Wire.h>
    #include <LiquidCrystal.h>
    #include <PWM.h>
    
    //Setup for Diags..
    #define DIAGS   0
    #define CNCMODE 1
    #define NGRAVE  2
     
    //frequency and pins used.
    int32_t basefrequency = 5000; //5khz base freq
    int8_t  PulsePin = 9;         //Pin 9 will control the laser. 
    int8_t  BoardLED = 13;
    int8_t  FireLED  = 12;
    int8_t  PowerLED  = 5;
    int8_t  Pot  = 4;
    int8_t  Buttons  = 8;        //analogue and digital are same numbers..be carefull if you use other pins..
    int8_t  Buttons1 = 10;
    int8_t  CurButton = 0;       //currently pressed button
    int8_t  CountMode = 0;       //the mode of the up/down counter..
    bool    WaitButtonZero = false;
    int8_t  OneMicro = 16;
    int8_t  Spindle = 6; //interrupt, its on pin7
    int8_t  OpMode = 0;
    volatile unsigned short SerialIn = 0;
    volatile unsigned short LastSerial = 0;
    
    volatile unsigned long SpinOnCnt = 0;
    volatile unsigned long SpinOffCnt = 0;
    volatile bool SpindleOn = false; //remote spindle command..
    volatile bool SpindlePWM = false; //remote spindle command current state..
    
    
    
    //vars for control
    bool      PowerOn = false;
    bool      Tickle = false; // On Off Safety watchdog .. monitor the tickle for laser health
    volatile int16_t Duty = OneMicro; //this is the pulse to pulse firepower during a shot.
    volatile int32_t cnt = 0;  //this is a global interrupt counter..
    volatile bool FIRE = false;
    
    //initialize the lcd..its on a0-a6 lines in my leonardo..
    LiquidCrystal  lcd( 23,22,21,20,19,18);  // set the LCD address to 0x27 for a 20 chars and 4 line display
    
    // the main control variable for diags mode..
    int16_t   Power =  50; //0 - 100%
    unsigned long  PWMPower = 0;//0- 100% for the incoming PWM..
    int16_t   Freq = 5000; // frequency of pulses..
    int8_t    PotMode = 0;
    
    volatile int32_t   FireCount = 0;   //number of pulses to fire in diags 
    volatile int16_t   ReLoad = 1;
    
    void setup()   
    {
    
      lcd.begin(20,4); // initialize the lcd 
      lcd.setCursor(3,0);   lcd.print("Gearotic Laser");
      lcd.setCursor(0,2);   lcd.print("Waiting for Unix.");
     
    
      InitTimers();    //start up the timers.
      bool timeron = SetPinFrequency( PulsePin, basefrequency ); //set pulsepin to 5Khz
      TIMSK1 |= (1 << TOIE1);  // enable timer overflow interrupt, we'll use this one for fastpwm
       
      attachInterrupt( 0, DUMMY, RISING ); //pulse external monitor 
      attachInterrupt( 4, DUMMY, CHANGE ); //sets the routine to call..    
    
      pwmWrite( PulsePin, 8); //set for 1us for laser tickle 
      if( timeron ) //if the timercall worked..
      {
        pinMode( BoardLED, INPUT); // board led life
    	pinMode( FireLED,  OUTPUT); // fire button led
    	pinMode( PowerLED, OUTPUT); //power control led & control
    
    	pinMode( 2,   INPUT); //inputs from breakout board
    	digitalWrite( 2, LOW );
    
    	pinMode( 3,   INPUT); //inputs from breakout board
    	digitalWrite( 3, LOW );
    
    	pinMode( 11,    INPUT); //inputs from breakout board
    	digitalWrite( 11, HIGH );
    
    	pinMode( 6,    INPUT); //inputs from breakout board
    	digitalWrite( 6, HIGH );
    
    	pinMode( Spindle, INPUT); //inputs from breakout board
    
    	 
    	digitalWrite( PowerLED, PowerOn); //turn off led for power at start
    	pinMode( Pot, INPUT); //pot for variable control
        digitalWrite(4, HIGH); //set for a pullup resistor
    	pinMode( Buttons, INPUT); //Jog buttons as analogue input
        digitalWrite(Buttons, HIGH); 
    	pinMode( Buttons1, INPUT); //Rest of buttons
    	digitalWrite(Buttons1, HIGH); 
     
      } 
      SetDisplay( true ); //and draw the display mask
     
    }
    
    //main idle loop..
    
    void loop() 
    {
      HeartBeat(); //flash the board led if fire isnt flashing..
      FlashFire(); // flash the fire button if we are going to fire..
      WatchDog();  // ensure all is safe.
      DiagsOut();  //display test text if demanded..not used
      PotControl(); //use the pot for values..
      GetButton();   
      if( OpMode == CNCMODE) SpindleCalc(); //only for CNC cut/profile op's..
      if( OpMode == DIAGS )  DiagFire();
      //if( OpMode == NGRAVE)  NGraveFire();
      LaserOnOff();
      DoButtonCount();  // make freq or firecount set by button if needed.
      //set power and other vars, then display..
      SetDisplay( false );
    }
    
    
    
    void DoButtonCount()
    {
                int8_t   Accel = 1; //this is the accel of button freq, adjust as needed.
       static   int16_t  Adder = Accel;
                int16_t  Freqmax  = 200;
       static   int32_t  Bres = Freqmax;  
       if( CurButton == 0)
       {
           Adder = Accel;
           Bres = Freqmax; 
    	   return;
       }
       int16_t oldfire = FireCount;
       Bres += Adder;
       while( Bres > Freqmax ) //not very ellegant, fix later. just a timer for easier button press
       {
    	   if( CurButton == 4 ) //left arrow, switch pot to count mode..
      	                CountMode--;
    	   if( CurButton == 6 ) //left arrow, switch pot to dutycyle..
      	                CountMode++;
           if( CountMode < 0) CountMode = 2; 
           if( CountMode > 2) CountMode = 0;
    
    	   Bres -= Freqmax;
    	   if( CountMode == 0  && CurButton == 5) Freq++;
           if( CountMode == 2  && CurButton == 5) FireCount++;
           if( CountMode == 0  && CurButton == 7) Freq--;
           if( CountMode == 2  && CurButton == 7) FireCount--;
    	   if( FireCount < 0 ) FireCount = 5000;
    	   if( FireCount >  5000 ) FireCount = 0;
    	   if( Freq <= 0 ) Freq = 1;
    	   if( Freq > 5000 ) Freq = 5000;
    	   int oldop = OpMode;
    	   if( CountMode == 1 && CurButton == 5 ) OpMode++;
           if( CountMode == 1 && CurButton == 7 ) OpMode--;
    	   if( OpMode > 2 ) OpMode = 0; //these two lines just make the opMode toggle up or down..
           if( OpMode < 0 ) OpMode = 2;
    
    	   //reopen file if required.
    	   if( OpMode == NGRAVE && oldop != NGRAVE)
    	     {
               //detach the spindle interrupts.
    		   detachInterrupt(4);
    		   attachInterrupt( 1, DUMMY, RISING ); //reattach the spindle interrupt
    		   
    	     }
    		 if( OpMode != NGRAVE && oldop == NGRAVE )
    		 {
    		    attachInterrupt( 4, DUMMY, CHANGE ); //reattach the spindle interrupt
    			detachInterrupt(1);
    		 }
    	   
    
       }
       if( oldfire != FireCount ) ReLoad = FireCount;
       Adder += Accel;
       //faster..damnit..faster. :)
       if( Adder == 100 )   Adder *= 2;
       if( Adder == 400)    Adder *= 2;
        if( Adder == 1000)  Adder *= 2;
    }
    
    void DiagFire()
    {
      if( CurButton == 2 ) FireCount = ReLoad;
      //FIRE!!!!
      if( CurButton == 1 && FireCount > 0 ) FIRE = true;
      if( CurButton == 0 && FIRE && OpMode == DIAGS ) FIRE = false; //turn it off if no button is pressed in Diags mode.
    }
    
    
    void SpindleCalc()
    {
    	if( OpMode == NGRAVE )
    		return;
    	if( !SpindleOn ) return;
    
    	if( cnt - SpinOffCnt > 225 ) 
    	{
    		SpindleOn = false; //turn it off.
    		PWMPower = 0;
    		return;
    	}
    	if( SpinOffCnt < SpinOnCnt )
    	{ //probably a on/off spindle control
    		if( PWMPower == 0 ) PWMPower = Power;
      	    return;
    	}
    	int per = SpinOffCnt - SpinOnCnt;
    
        static int xc = 0;
    	static int yc = 0;
    	static int lastpwm = 0;
    	 
    	if( per > 98 ) per = 98;
    	if( per < 5 ) per = 5;
    	PWMPower = per;
    
    	//switch to base pot power
        if( (cnt - SpinOnCnt) > 130  && digitalRead(7) )
      	    PWMPower = Power; //looks like no pwm, just a spindle on command
        if( (cnt - SpinOffCnt) > 130  && !digitalRead(7) )
     	    SpindleOn = false; //looks like no pwm, just a spindle on command
    
    
    }
    
    void LaserOnOff()
    {
      //this controls Laser ON/OFF
      if( CurButton == 3 ) //power call , but only once per press
      { 
    	if( !WaitButtonZero) PowerOn = !PowerOn; 
        digitalWrite( PowerLED, PowerOn); //Set Power condition;
        WaitButtonZero = true;
      }
    
    }
    
    
    void DUMMY()
    {
      
    }
    
     
     
    int16_t FireLaser()
    {
    	int16_t ret = OneMicro; //usually we'll return 1 microsecond.
    	static int16_t Counter = basefrequency;
    	if( FIRE )
    	{   
    		if( OpMode == DIAGS )
    		  ret = Power << 5; //we'll return this power only if the counter says so..
    		else 
    		  ret =  PWMPower << 5; //in CNC modes we return the duty cycle power
    
    		if( ret > 3191 ) ret = 3191; //set a maximum pulse wdith here for your cpu speed
    		//now decide on a frequcny basis is this is a shot time..
            Counter += Freq;
    		if( Counter >= basefrequency )
    		{
    			Counter -= basefrequency;
    			if( SpindleOn && FireCount > 2000 ) FireCount = 2000;
        	    if( FireCount != 5000) FireCount--;
    		    if( FireCount <= 0 ) FIRE = false;
    		}
    		else
    			ret = OneMicro;
    	
    	}
    	if( ret < OneMicro ) ret = OneMicro; //no msaller than 1 microsecnd
    	return ret;
    }
    
    
    //display the text
    /////  Text Blockout
    
    ////////////////////////
    //        Pwr         //
    //Frq-hz  100  Pulses //
    //  5000 <--->  5000  //
    ////////////////////////
    void SetDisplay( bool clear )
    {
      if( clear ) 
      {
    	  lcd.clear(); //x,y
    	  lcd.setCursor(8, 0);    lcd.print("Pwr");
    	  lcd.setCursor(0, 1);    lcd.print("Frq-hz");
    	  lcd.setCursor(14,1);    lcd.print("Pulses");
     }
      static int8_t slw = 0;
      slw++;
      if( slw % 8 )
      if( SpindleOn && OpMode == CNCMODE ) //display of remote power setting..
      {
    	  lcd.setCursor(11, 0);    lcd.print("-Rem:");
    	  lcd.setCursor(16, 0);    lcd.print("     ");
    	  lcd.setCursor(16, 0);    lcd.print(PWMPower,10);
      }
      else
      if( OpMode == NGRAVE )
      {
          lcd.setCursor(11, 0);    lcd.print("-Rem:");
    	  lcd.setCursor(16, 0);    lcd.print("     ");
    	  lcd.setCursor(16, 0);    lcd.print(LastSerial,10);
      }
      else
      {   
    	  lcd.setCursor(11, 0);   
          lcd.print("        ");
          lcd.setCursor(16, 0);   
    	  lcd.print("     ");
      }
    
    
      //power
      lcd.setCursor(8,1);
      lcd.print( Power , 10 );
      lcd.print( "%  " );
      //frequency
      lcd.setCursor(3,3);
      lcd.print( Freq , 10 );      lcd.print("   ");
      //fire count
      lcd.setCursor(15,3);
    
      if( FireCount != 5000)
      { lcd.print( FireCount , 10 ); lcd.print("   "); }
      else
         lcd.print(" CW   ");
     
      //and count mode
      lcd.setCursor(8,3);
      switch( CountMode )
      {
      case (0) : lcd.print("<<---"); break;
      case (1) : lcd.print(" ^^^ "); break;
      case (2) : lcd.print("--->>"); break;
      }
       
      static int toggle = 0;
      static bool twinkle = true;
      toggle++;
      if( toggle > 20 )
      {
    	  toggle = 0;
    	  twinkle = !twinkle;
    	  lcd.setCursor( 0,4 ); 
    	  if( twinkle ) lcd.print("*"); else lcd.print("#");
      }
    
    //erase the mopde line..
    lcd.setCursor( 0,2 );
    lcd.print("                    ");
    
    if( SpindleOn && OpMode == DIAGS)
       OpMode = CNCMODE; //auto switch from Diags
     
      switch (OpMode)
      {
       case(0): lcd.setCursor( 8,2 );  lcd.print("Diag"); break;
       case(1): lcd.setCursor( 7,2 ); lcd.print("CNC-CW"); break;
       case(2): lcd.setCursor( 7,2 ); lcd.print("NGRAVE"); break;
      }
    }
    
    
    //helper functions
     
    void FlashFire() 
    {
      static int8_t Flashtime = 0;
      static bool   fireledstate;
      if( FireCount == 0 ) 
        fireledstate = false;
      if( Flashtime++ > 10 ) //this 10 should be change for a pleasant flash tempo..
      {
    	  digitalWrite( FireLED, fireledstate ); 
    	  fireledstate = !fireledstate;
    	  Flashtime = 0;
      }
    }
    
    //flash the board led to show we're alive
    void HeartBeat() 
    {
      static int8_t Beat = 0;
      static bool   beatstate;
      if( FireCount != 0 ) return; 
     
      if( Beat++ > 10 ) //this 10 should be change for a pleasant flash tempo..
      {
    	  //digitalWrite( BoardLED, beatstate ); 
    	  beatstate = !beatstate;
    	  Beat  = 0;
      }
    }
    
    //watchdog function, kill laser power if tickle stops..
    //or other checks all of which can be put here..
    void WatchDog()
    {
      static int lastcnt = cnt; //activity monitor
      if( lastcnt != cnt ) Tickle = true; else  Tickle = false;
      lastcnt = cnt;
    
      //set other checks here... too long a shot maybe...
    
      if( !Tickle )
      {
    	  PowerOn = false;
    	  digitalWrite( PowerLED, PowerOn); //turn off led for power at start
      }
    
    }
    //use of the pot for duty or frequency.
    void PotControl()
    {
        int32_t val = analogRead( Pot + 2 ); //the analogue for the pot pin
    	if( PotMode == 0 ) // duty cycle.. only mode at present..
    	{
           Power =  val / 10.23;
    	   if( Power < 1 ) Power = 1;
    	   if( Power > 100) Power = 100;
    	   Power = 101 - Power;
    	}
    	 
    
    }
    
    //diags text for testing and debugging..
    void DiagsOut()
    {
    	//just for testing pins..
       return; //only use if we demand it in setup..
    
      int16_t  d1 = 0, d2 = 0, d3 = 0;
      if( cnt > 2000)
      {
         cnt = 0;
         d1 = analogRead(Pot + 2);
    	 d2 = analogRead(8);
    	 d3 = analogRead(10);
    
         Console.print("pins 6,8,10 --- " );
    	 Console.print(" "); 
    	 Console.print( d1 );
    	 Console.print(" "); 
    	 Console.print( d2 );
    	 Console.print(" "); 
    	 Console.print( d3 );
    	 Console.print(" "); 
    	 Console.print( CurButton );
    	 Console.println();
    	  
      }
    
    
    }
    //figure out a button press, only one button 
    //at any time with noise rejection. This uses 2 analogue pins
    //which multiplexes many buttons on each pin.
    void GetButton()
    {
      int8_t setbounce = 4; //set a debounce here..
      static int8_t debounce = setbounce;
      static int8_t LastButton = 0;
      int8_t thisbut = 0;
    
      int16_t val = analogRead(Buttons); //fire,reload and laser
      if( val < 900 )
      {
         
    	  thisbut = 3 - (val >> 8);
      }
      val = analogRead(Buttons1); //ok, read the fire buttons then..
      if( val < 900 )
      {
          //figure out the button in the fire group
    	  thisbut = (val >> 8) + 4;
      }
    
      if( LastButton == thisbut ) debounce--;
      else   debounce = setbounce;    
      if( debounce == 0 )
      {
    	 CurButton = thisbut;
         debounce = setbounce;
      }
    
      if( WaitButtonZero && CurButton == 0)
    		 WaitButtonZero = false;
    
      LastButton = thisbut;
    
    }
    
    //make the frerq and count registers count by button.
    
    
    //this gets called at timer reset time..
    ISR(TIMER1_OVF_vect)
    {
      cnt++;
      Duty = FireLaser();   //find the next power level..    
      OCR1A = Duty;         
    }
     
    //these three interrupts are for step/dir and spindle pwm. 
    //used as direct vectors to get the speed required..
    //this interrupt is for the step pulses..any step pulses, to 
    //set a firepulse..
    
    ISR(INT0_vect) 
    {
        //step interrupt...very fast
    	if( (OpMode != DIAGS && SpindleOn)) 
    	{
    		FireCount = ReLoad;
    		FIRE = true;
    	}
     
    }
    
    //this is for recieving serial data power 
    //for 16 slice sequences.
    ISR(INT1_vect) 
    {
        //count the X steps as well for future use
    	if( PINB & ( 1 << 7))
    	     SerialIn |= 0x8000;
    	if( (SerialIn & 0xf00f ) == 0xf00f)
    	  {
           // LastSerial = SerialIn & 0x0ff0;
    	   LastSerial = (SerialIn >> 4) & 0xff;
    	   SerialIn = 0;
    	   if( LastSerial < 100 )
    	   {
    	      static unsigned short prev = 0;
    	      if( prev == LastSerial )  //must be a repeated power..
    	          PWMPower = LastSerial;
    	      prev = LastSerial;
    	   }
    	   //control the spindle
    	   if( PWMPower != 0 ) SpindleOn = true;
    	     else SpindleOn = false;  
    	   
    	  }
    	SerialIn = SerialIn >>  1; //we got a clock, so shift it..
    }
    
    //and finally a pwm spindle interrupt
    ISR(INT6_vect) 
    {
    	if( PINE & ( 1<<6))
    	{
    		SpinOnCnt = cnt;
    		SpindleOn = true;
    	}
    	else
    		SpinOffCnt = cnt;
    	return;
     
    }

    this is the code for it it was first done for arduino.

    I am correctly trying to port over for ti still got a couple of problems with it.

    I have run it though energia so I can get the libraries correct I have it in ccs now it shows the problems 

  • daniel lyall said:

    this is the code for it it was first done for arduino.

    I am correctly trying to port over for ti still got a couple of problems with it.

    I have run it though energia so I can get the libraries correct I have it in ccs now it shows the problems 

    Ok, so you'll be using energia for C2000 series. Energia is compatible with C2000 launchpad but upto certain level. Its not been fully developed and the work is still under process.

    Regards,

    Gautam

  • cool thanks for that I've got plenty of time to get this done as Mach4 wont be completely usable for another year.