Arduino RS232 Serial Communication to Laser Control Board

No, the laser controller is expecting '\r'.

1 Like

So is '\n' for new line?

\r is carriage return ascii 13. \n is linefeed, ascii 10.

1 Like

thank you very much!
I just had an enlightenment moment :sweat_smile: everything just seems to be making so much sense now regarding the laser communication and what the laser control board expects to recieve ahahaha

CR is the ASCII code for Carriage Return, it's a byte with value 13(dec) or 0x0D(hex)

so if your terminal emulator was able to send the character for you, that's why it was working

in C++ some well known ASCII characters have an escape sequence and '\r' is the one for Carriage return, so doing Serial.write('\r'); is the same as doing Serial.write(13);

In Robin's tutorial you would define the end marker as '\r' to get a line

1 Like

So I have made a new code.

The laser always sends a set of initial chars that should be ignored, regardless of that I still want to read that initial communication to make sure everything is working properly.

in main.cpp setup I have this:

void setup()
{
  Serial_1.begin(baudRate_1);
  Serial_2.begin(baudRate_2);

  //setup here
  sys.initPyrometer(); //initialize Pyrometer
  sys.initLaser();     //initialize Laser
  ~
  //PID Setup
  Setpoint = 750;           //Target value (Temperature)
  myPID.SetMode(AUTOMATIC); //Turn PID ON
  myPID.SetTunings(Kp, Ki, Kd);
  myPID.SetSampleTime(10);        //Sample time = 10 [ms]
  myPID.SetOutputLimits(10, 100); //Output limits = Diode Current (10-100% of Max Laser Power)

  //Serial Communication Setup
  sys.laser_COM(); //Establish init communications to laser. check system.cpp
}

sys.laser_COM() function:

SoftwareSerial Serial_1(0, 1); //RX and TX ports
const byte numChars = 32;      //number of readable characters
char receivedChars[numChars];  //chars to print

boolean newData = false;

void System::laser_COM()
{
    //laser initial communications (to run once)
    //Check Laser YLR-200-AC User Manual for laser instructions descriprion
    Serial_1.begin(baudRate_1); //Set the data rate for the software serial port
    while (!Serial_1)
    {
        ; //wait for the serial port to connect. needed for native usb port only
    }
    recieving_data();
    show_data();
    Serial_1.println('\n');

    //Send Laser instructions now:
    Serial_1.println("DMOD"); // Disable Modulation
    Serial_1.write('\r');
    recieving_data();
    show_data();
    Serial_1.println('\n');

    Serial_1.println("DEC"); // Disable External Control
    Serial_1.write('\r');
    recieving_data();
    show_data();
    Serial_1.println('\n');

    Serial_1.println("ELE"); // Enable Hardware Emission Control
    Serial_1.write('\r');
    recieving_data();
    show_data();
    Serial_1.println('\n');
}

Serial communication functions taken from example 3 in: Serial Input Basics - updated - #2 by Robin2


void System::recieving_data() //Recieve data from laser control board
{
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char rc;

    while (Serial_1.available() > 0 && newData == false)
    {
        rc = Serial_1.read();

        if (recvInProgress == true)
        {
            if (rc != '\r')
            {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars)
                {
                    ndx = numChars - 1;
                }
            }
            else
            {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }
        else if (rc == '\n')
        {
            recvInProgress = true;
        }
    }
}

void System::show_data() //print recieved data from laser control board
{
    if (newData == true)
    {
        Serial_1.print("LASER COMMUNICATING: ");
        Serial_1.println(receivedChars);
        newData = false;
    }
}

Then everytime I send an instruction to the laser, if the laser control board understands the instruction it replies back that instruction, otherwise it gives back ERROR.
This is the code to send and recieve those instructions.
in main.cpp loop I have this:

void loop()
{
sys.tempReading(); //temperature reading
  Input = sys.tempReading();
  //PID calculation
  myPID.Compute();
  sys.laser_output(Output); //laser output intructions (Serial communication, RS232)
}

laser_output() function:

void System::laser_output(float input)
{

    //     //Check Laser YLR-200-AC User Manual for laser instructions descriprion

    Serial_1.print("SDC ");  // Set Diode Current.

    Serial_1.println(input); //PID_value = Diode Current (10-100% of Max Laser Power)

    Serial_1.write('\r');

    recieving_data();

    show_data();

    Serial_1.println('\n');

    Serial_1.println("EMON"); // Emission ON

    Serial_1.write('\r');

    recieving_data();

    show_data();

    Serial_1.println('\n');

}

I have baudRate_1 set for 57600
and baudRate_2 set for 9600
I will probably change the baudRate_1 to 38400 as advised.
I am now using an arduino mega.
I am also using SoftwareSerial to have the temperature readings in monitor 2 and laser control instructions in monitor 1.

Do you think this can work?
Sorry for the amount of code I am posting, I can only test this code tomorrow morning but would like some feedback.

if you are on a MEGA use the other Hardware Serial ports !

yes, I am using ports 16 and 17 for temp readings and, at the moment, ports 0 and 1 for laser communication, but I will change that for ports 18 and 19.

OK - but don't declare SoftwareSerial on those pins, use Serial, Serial1, Serial2 and Serial3

1 Like

Thanks!!! Now I know what you mean
I was not understanding what the issue was

So I have been testing the new code just now, and I cannot receive or send any data through the arduino mega. I do not know what the issue could be.
There is no communication whatsoever. Program starts running but nothing happens

What can I do?

Arduino has very little in the way of debugging tools. Serial.print is about as good as it gets. You can add some to your code and see what it's doing.

Personally though, I'd write another sketch that just tests communication with the laser and echoes the results to the serial monitor. When that's working you'll have a better idea what's wrong with your bigger program, or at least have some clues about whereto start looking.

1 Like

OK, thanks, will do that!

Post that code

Here it goes.

main.cpp HERE:

#include <Arduino.h>
#include <PID_v1.h>
#include "system.h"

System sys;

//########################### myPID ###########################
double Setpoint; //target value
double Input;    //Temperature sensor (pyrometer)
double Output;   //ouput value of the PID controller
//PID parameters:
double Kp = 0, Ki = 10, Kd = 0;
//crate PID instance
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
//#############################################################

void setup()
{
  Serial.begin(baudRate_1);
  Serial1.begin(baudRate_1);
  Serial2.begin(baudRate_2);

  //setup here
  sys.initPyrometer(); //initialize Pyrometer
  sys.initLaser();     //initialize Laser

  //PID Setup
  Setpoint = 750;           //Target value (Temperature)
  myPID.SetMode(AUTOMATIC); //Turn PID ON
  myPID.SetTunings(Kp, Ki, Kd);
  myPID.SetSampleTime(10);        //Sample time = 10 [ms]
  myPID.SetOutputLimits(10, 100); //Output limits = Diode Current (10-100% of Max Laser Power)

  //Serial Communication Setup
  sys.laser_COM(); //Establish init communications to laser. check system.cpp
}

void loop()
{

  //main code, to run repeatedly

  //############################  PID Loop  ##########################
  //Temperature Reading in [ºC]
  sys.tempReading(); //temperature reading
  Input = sys.tempReading();
  //PID calculation
  myPID.Compute();
  sys.laser_output(Output); //laser output intructions (Serial communication, RS232)

  //sys.displayTemp(); //display temperature

  //##################### Serial Communication  ######################
  // if (Serial.available()) //checking if data is available
  // {
  //   rd = Serial.read(); //storing data in rd
  //   Serial_1.print(rd); //printing data
}


system.h HERE:

#ifndef _system_
#define _system_

#include <Arduino.h>

class System
{
private:
#define baudRate_1 57600
#define baudRate_2 9600

public:
    //pins:
    const int pyrometer_in = A0; //Pyrometer IN
    const int start_pin = 2;     //Communication from Motion (START/STOP Processing)

    //##################################  SETUP  ####################################
    //###############################################################################
    void initPyrometer();
    void initLaser();
    void laser_COM();

    //##################################  LOOP  #####################################
    //###############################################################################

    //##########################  TEMPERATURE READINGS  #############################
    //pyrometer functions (check "system.cpp"):
    double tempReading();

    //temperature variables/constants:
    int Temp_reading_V = 0;    //temperature read by Pyrometer in [Volts]
    double Temp_reading_C = 0; //temperature read by Pyrometer in [ºC]

    //################################   LASER   ####################################
    //laser functions (check "system.cpp"):
    void laser_output(float input);
    void laser_ON();
    void laser_OFF();
    void displayTemp();

    //laser variables/constants:
    float PID_value = 0; //PID control output value

    ////##################################  SERIAL  ###################################
    //#################################################################################
    void recieving_data();
    void show_data();
};

#endif

System.cpp HERE:

#include "system.h"

//############################################## SETUP FUNCTIONS ##############################################
//#############################################################################################################
void System::initLaser()
{
    pinMode(start_pin, INPUT); //Start laser pin (ON/OFF INPUT pin)
}

void System::initPyrometer()
{
    pinMode(pyrometer_in, INPUT); //pyrometer pin is INPUT
}

//########################################   SERIAL COM SETUP   ##############################################

void System::laser_COM()
{
    //laser initial communications (to run once)
    //Check Laser YLR-200-AC User Manual for laser instructions descriprion
    recieving_data();
    show_data();

    //Send Laser instructions now:
    Serial1.print("DMOD"); // Disable Modulation
    Serial1.println('\r');
    recieving_data();
    show_data();

    Serial1.print("DEC"); // Disable External Control
    Serial1.println('\r');
    recieving_data();
    show_data();

    Serial1.print("ELE"); // Enable Hardware Emission Control
    Serial1.println('\r');
    recieving_data();
    show_data();
}

//######################################################RECIEVE AND SHOW COMS

const byte numChars = 32;     //number of readable characters
char receivedChars[numChars]; //chars to print

boolean newData = false;

void System::recieving_data() //Recieve data from laser control board
{
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char rc;

    while (Serial1.available() > 0 && newData == false)
    {
        rc = Serial1.read();

        if (recvInProgress == true)
        {
            if (rc != '\r')
            {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars)
                {
                    ndx = numChars - 1;
                }
            }
            else
            {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }
        else if (rc == '\n')
        {
            recvInProgress = true;
        }
    }
}

void System::show_data() //print recieved data from laser control board
{
    if (newData == true)
    {
        Serial.print("LASER COMMUNICATING: ");
        Serial.println(receivedChars);
        newData = false;
    }
}

//############################################## LOOP FUNCTIONS ##############################################
//############################################################################################################

//###################################### TEMPERATURE READINGS FUNCTIONS ######################################
double System::tempReading()
{
    Temp_reading_V = analogRead(pyrometer_in);                  //Temperature read by pyrometer
    Temp_reading_C = map(Temp_reading_V, 205, 1023, 600, 2300); //Voltage to [ºC] conversion. Pyrometer Range = 600 to 2300 [ºC]

    return Temp_reading_C;
}

void System::displayTemp()
{
    //Temperature display (Time in [ms] / Temperature in [ºC])
    Serial2.print(millis());
    Serial2.print(" , ");
    Serial2.println(Temp_reading_C);
}

//############################################# LASER  FUNCTIONS #############################################

void System::laser_output(float input)
{
    // if (digitalRead(start_pin) == HIGH)
    // {
    //     //sys.PID();
    //     //Check Laser YLR-200-AC User Manual for laser instructions descriprion

    Serial1.print("SDC "); // Set Diode Current.
    Serial1.print(input);  //PID_value = Diode Current (10-100% of Max Laser Power)
    Serial1.println('\r');
    recieving_data();
    show_data();

    Serial1.print("EMON"); // Emission ON
    Serial1.println('\r');
    recieving_data();
    show_data();
    // }

    // if (digitalRead(start_pin) == LOW)
    // {
    //     //Check Laser YLR-200-AC User Manual for laser instructions descriprion

    //     Serial.println("EMOFF"); // Emission OFF
    // }
}

I think you have mixed up your serial ports. It looks like you're using Serial1 to talk to the laser, but in your showData function which is presumably where you're hoping to see the laser's response, you also print to Serial1.

I'd expect anything you want to see on the monitor to be printed to Serial unless you've wired things specifically to avoid the.

1 Like

I uploaded my code (Arduino Uno RS232 Serial Communication to Laser Control Board - #35 by rodrigo_m_l_vieira) which is already edited with the changes @wildbill advised. The code in the comment above is also updated with your advices.

I connect to my Arduino Mega and start the serial monitor.
Once I start my serial monitor I can send data and the RX led lights up, but nothing, and I mean absolutely nothing, shows up on the serial monitor. It stays always blank.

I do not think it is even running the laser_COM function, in the void setup.

What could be happening?

You have way too much code for something that doesn't work and now you're looking at big bang testing. I'd write a minimal program and get that working and splice the stuff you have written into it a small piece at a time and test each of them.

If you would rather debug what you have, put some more serial prints in to see where execution goes. To start with, one right after the serial begins just to see something on the monitor.

1 Like

You need to get the laser communication to work seamlessly first. let's focus on that.

  • You need to have the Laser connected to Serial1 (so Rx to Tx, Tx to Rx, GND to GND) and having the laser configured at factory settings, so 57600 bauds.
  • Don't connect anything else to your Arduino.
  • Connect the USB cable to your PC
  • Open the Serial Monitor in the IDE. Set the baud rate to 115200. Set the Line ending to CR
  • upload this code on your Arduino Mega
#define laserSerial Serial1

const size_t messageMaxSize = 50;
char incomingMessage[messageMaxSize + 1]; // +1 for trailing '\0'

boolean getAnswer(const char endMarker = '\r')
{
  static size_t index = 0;
  boolean messageComplete = false;
  int incomingByte = laserSerial.read();
  if (incomingByte != -1) {
    if (incomingByte == endMarker) { // do not store the end marker
      incomingMessage[index] = '\0';
      messageComplete = true;
      index = 0;
    } else {
      incomingMessage[index++] = (char) incomingByte;
      incomingMessage[index] = '\0';
      if (index >= messageMaxSize) index = messageMaxSize - 1; // don't overflow
    }
  }
  return messageComplete;
}

void setup() {
  Serial.begin(115200);
  laserSerial.begin(57600);
  Serial.println(F("Ensure Serial monitor's line ending is set to CR"));
  Serial.println(F("Ready to send commands"));
}

void loop() {
  // send what we type in
  if (Serial.available()) laserSerial.write(Serial.read());

  // listen for an answer
  if (getAnswer()) {
    Serial.print(F("Laser answered ["));
    Serial.print(incomingMessage);
    Serial.println(("]"));
  }
}

You'll probably see some garbage first coming with the first answer as the doc states

After power on the laser sends some service bytes to RS-232 interface. These bytes should be ignored

type RFV and validate with Enter in the Serial Monitor
--> do you see an answer? (the command to Read current software revision)

type RSN and validate with Enter in the Serial Monitor
--> do you see an answer? (the command to Read Serial Number)

if that works then you've successfully communicated with your Laser.

1 Like

Have you thought about how you will test this? Commanding a 200W laser with code that isn't fully debugged doesn't sound like a good idea.

It would be nice if you could attach a much lower powered laser until you have your system running to your satisfaction. I don't know that that's plausible though.

I would be tempted to write a simulator on another Arduino for the testing piece. Then its "laser" can be a simple LED.

1 Like