Trying to control an EPOS4 motor controller using Arduino Mega through RS232

Hello, I'm currently trying to send commands to an EPOS4 Maxon motor controller using an Arduino Mega. To explain better the system: I'm using the EPOS4 to control a motor EC-4pole 200W 48V, so connected to the motor controller are the motor cables for energy supply, hall sensor, and encoder and 48V power supply basically.
First I used the EPOS Studio to set up the motor parameters and the Baudrate that I want to use(9600). I tested if the motor was working using the EPOS studio and it works perfectly. But now I need to send control commands to the motor controller using an Arduino mega with RS232 communication. The Pinout from the EPOS4 to the Arduino is attached bellow.
The most relevant Datasheet of the EPOS4 are:

Command Library

Firmware Specifications

Communication Guide

Hardware Reference

So the problem that I'm having is that I can't communicate the Arduino to the motor controller. I'm using a code that I found online(but that I have reviewed and seems to be correct) but I always receive the same response from the Serial Monitor(Attached). What makes me believe that Arduino is not communicating with EPOS4. The code is also attached due to the long text.

I've tested wiring connections, changed the position of the wires, searched on Epos Studion for extra necessary configurations and still nothing changed. If you have any idea of what the problem is I accept any help.

Thank you,
Tuani

Epos44.ino (11.4 KB)

MAX3232-Microcontroller-Cir.png

BUT! Where is the schematic showing how YOU have all this connected?

Paul

Hi,
Welcome to the forum.

Please read the first post in any forum entitled how to use this forum.
http://forum.arduino.cc/index.php/topic,148850.0.html .
Then look down to item #7 about how to post your code.
It will be formatted in a scrolling window that makes it easier to read.

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Thanks.. Tom... :slight_smile:

I'm sorry, I thought the pinout table that I attached would be enough to understand the connections, but I made a better one now, hope this is what you asked for.
And for the code, I have tried to post is that way, but the system didn't allow me to post saying that the text was longer than the allowed amount of 9000 characters, so let me post the code by parts because the same problem is happening now.
Part1:

#include <SoftwareSerial.h>  // For Arduino uno
SoftwareSerial SerialEpcos(19, 18); // RX, TX for  arduino uno
//#define SerialEpcos  Serial1 // pro micro or leonardo 
#define ReceiveTimeOut 5000 // Maximum for waiting answer from EPOS4 in milli second
#define MaxLenFrame 10  // max number of words in frame

byte DataRead[264];
byte ReadOpcode;
byte len;
int pDataRead;
word rxCRC;
unsigned long CommErrorCode;
enum read_status {
RX_DLE,
RX_STX,
RX_OPCODE,
RX_LEN,
RX_DATA,
RX_CRC_LOW,
RX_CRC_HIGH,
RX_DONE,
ESC_OPCODE,
ESC_LEN,
ESC_DATA,
ESC_CRC_LOW,
ESC_CRC_HIGH
}read_st;


/*****************************************************************************************************/
/*  CalcFieldCRC : code from EPOS4-Communication-Guide-En.pdf                                        */
/*****************************************************************************************************/
word CalcFieldCRC(word* pDataArray, word numberOfints)
{
word shifter, c;
word carry;
word CRC = 0;
//Calculate pDataArray Word by Word
while(numberOfints--)
  {
    shifter = 0x8000;          //Initialize BitX to Bit15 
    c = *pDataArray++;         //Copy next DataWord to c
    do
    {
      carry = CRC & 0x8000;    //Check if Bit15 of CRC is set 
      CRC <<= 1;               //CRC = CRC * 2   
      if(c & shifter) CRC++;   //CRC = CRC + 1, if BitX is set in c 
      if(carry) CRC ^= 0x1021; //CRC = CRC XOR G(x), if carry is true 
      shifter >>= 1;           //Set BitX to next lower Bit, shifter = shifter/2
    } while(shifter);
  }
return CRC;

}

inline void SerialEpcosStuffing(byte BYTE)
{
if (BYTE==0x90) SerialEpcos.write(BYTE);
SerialEpcos.write(BYTE);
}

void SendFrame(byte OpCode,word* pDataArray,byte numberOfwords)
{
word CRC;
word pDataCRC[MaxLenFrame+2];
pDataCRC[0] = OpCode | (numberOfwords<<8);
for (int i=0; i<numberOfwords ; i++)
{
  pDataCRC[i+1]=pDataArray[i];
}
pDataCRC[numberOfwords+1]=0x0000;
CRC=CalcFieldCRC(pDataCRC, (word)(numberOfwords+2));
SerialEpcos.write(0x90);  // DLE=Data Link Escape 
SerialEpcos.write(0x02);  // STX=Start of Text
SerialEpcosStuffing(OpCode);
SerialEpcosStuffing(numberOfwords);
for (int i=0; i<numberOfwords ; i++)
{
  SerialEpcosStuffing(lowByte(pDataArray[i]));
  SerialEpcosStuffing(highByte(pDataArray[i]));
}
SerialEpcosStuffing(lowByte(CRC));
SerialEpcosStuffing(highByte(CRC));
}

bool WriteObject(word Index, byte SubIndex,word* pArray)
{
word data[4];
data[0]= 0x01 | (lowByte(Index)<<8);  // NodeId=1
data[1]= highByte(Index)|(((word)SubIndex )<< 8);
data[2]=pArray[0];
data[3]=pArray[1];
SendFrame(0x68,data,(byte)4);
return ReadFrame();
}

bool ReadObject(word Index, byte SubIndex)
{
word data[2];
data[0]= 0x01 | (lowByte(Index)<<8);  // NodeId=1
data[1]= highByte(Index)|(((word)SubIndex )<< 8);
SendFrame(0x60,data,(byte)2);
return ReadFrame();
}

// For debuging:
void print_rcv_data()
{
    //todo check CRC and print data
  Serial. print("OPcode: ");
  Serial. print(ReadOpcode,HEX);
  Serial. print(" len: ");
  Serial. print(len);
  Serial. print(" Data:");
  for (int i=0; i<2*len ; i++)
  {
     Serial.print(DataRead[i],HEX);
     Serial.print(" , ");
  }
  Serial.print("CRC: ");   
  Serial.println(rxCRC, HEX); 
}

bool ReadFrame()
{
int incomingByte = 0;   // for incoming SerialEpcos data
unsigned long timer=millis();
read_st=RX_DLE;
word pDataCRC[MaxLenFrame+2];
CommErrorCode=0;
while ((read_st!=RX_DONE) and (millis()-timer < ReceiveTimeOut))
{
  if (SerialEpcos.available() > 0)
  {
    incomingByte = SerialEpcos.read();
//      Serial.print("Read: ");
//      Serial.println(incomingByte, HEX); 
//      Serial.print("read_st: ");
//      Serial.println(read_st);

Part 2:

    switch (read_st)
    {
      case RX_DLE:
         if (incomingByte==0x90) read_st=RX_STX;
         pDataRead=0;
         len=0;
         break;
      case RX_STX:
         if (incomingByte==0x02) read_st=RX_OPCODE;
         else read_st=RX_DLE;
         break;
      case RX_OPCODE:
         if ( incomingByte == 0x90)
         {
          read_st=ESC_OPCODE;
          break;
         }
         else
         {
           ReadOpcode=incomingByte;
           read_st=RX_LEN;
         }
         break;
      case RX_LEN:
         len=incomingByte;
         if ( incomingByte == 0x90)
         {
          read_st=ESC_LEN;
          break;
         }
         else read_st=RX_DATA;
         break;
      case RX_DATA:
         if ( incomingByte == 0x90)
         {
          read_st=ESC_DATA;
          break;
         }
         else
         {
           DataRead[pDataRead]=incomingByte;
           pDataRead++;
         }
         if ( pDataRead== (2*len) ) read_st=RX_CRC_LOW;
         break;
      case RX_CRC_LOW:
         rxCRC=incomingByte; 
         if ( incomingByte == 0x90) read_st=ESC_CRC_LOW;
         else read_st=RX_CRC_HIGH;
         break;
      case RX_CRC_HIGH:
         rxCRC +=incomingByte<<8;
         if ( incomingByte == 0x90) read_st=ESC_CRC_HIGH;
         else read_st=RX_DONE;
         break; 
      case ESC_OPCODE:
         if (incomingByte== 0x02)
         {
           read_st=RX_OPCODE;
           break;
         }
         else if (incomingByte== 0x90)
         {
           ReadOpcode=incomingByte;
           read_st=RX_LEN;
           break;
         }
         else Serial.println ("Protocol error: single DLE");   
         break;
      case ESC_LEN:
         if (incomingByte== 0x90)
         {
           read_st=RX_DATA;
           break;
         }
         if (incomingByte== 0x02)
         {
           read_st=RX_OPCODE;
           break;
         }
         Serial.println ("Protocol error: Escape len error");
         break;
      case ESC_DATA:
         if ( incomingByte == 0x90)
         {
           DataRead[pDataRead]=incomingByte;
           pDataRead++;
           read_st=RX_DATA;
           if ( pDataRead== (2*len) ) read_st=RX_CRC_LOW;
           break;
         }
         if (incomingByte== 0x02)
         {
           read_st=RX_OPCODE;
           break;
         }
         Serial.println ("Protocol error: Escape data error");
         break;
         
      case ESC_CRC_LOW:
         if ( incomingByte == 0x90) read_st=RX_CRC_HIGH;
         else if (incomingByte== 0x02) read_st=RX_OPCODE;
         else Serial.println ("Protocol error: Escape crc l error");
         break;
      case ESC_CRC_HIGH:
         if ( incomingByte == 0x90) read_st=RX_DONE;
         else if (incomingByte== 0x02) read_st=RX_OPCODE;
         else Serial.println ("Protocol error: Escape crc h error");
         break;
      default:
         break;
    }
  }
}
// Check Time out:
if (millis()-timer >= ReceiveTimeOut)
{
  Serial.println("Serial Time out");
  return false;
}
// check CRC:
pDataCRC[0] = ReadOpcode | ((word)len)<<8;
for (int i=0 ;  i< len ;i++ )
{
  pDataCRC[i+1]= DataRead[2*i] | (((word)DataRead[2*i+1])<<8);
}
pDataCRC[len+1]=0x0000;
if (CalcFieldCRC(pDataCRC, (word)(len+2))!= rxCRC)
{
  Serial.println("Error CRC");
  return false;
}
//  Serial.print("RCV CRC: ");Serial.println (CalcFieldCRC(pDataCRC, (word)(len+2)),HEX);
// Check communication error code
CommErrorCode= DataRead[0] | (((word)DataRead[1])<<8) | (((unsigned long)DataRead[2])<<16) | (((unsigned long)DataRead[3])<<24);
if (CommErrorCode!=0)
{
  Serial.print( "Communication Error Code:");
  Serial.println(CommErrorCode,HEX);
  return false;
}
//  print_rcv_data(); 
return true;
}


word ReadStatusWord()
{
word statusWord;
ReadObject(0x6041,0);
statusWord = DataRead[4] + (((word) DataRead[5])<<8);
Serial.print("Statusword: ");
Serial.println(statusWord,HEX);
return (statusWord);
}

/* This code enable driver, run motor for 5s and stop.  
Motor configuration must be setup with EPOS studio and saved in controller*/        
void setup()
{
word data[4];
  // start serial port at 9600 bps and wait for port to open:
Serial.begin(9600);
while (!Serial) ; // wait for serial port to connect. Needed for native USB port only
SerialEpcos.begin(9600);

// send 1000 in profile acc:
//Serial.println("send 1000 in profile acc");
data[0]=1000;
data[1]=0x0000;  
WriteObject(0x6083,0,data);
// send 1000 in profile  dec:
//Serial.println("send 1000 in profile dec");
WriteObject(0x6084,0,data);
// Send 1000 in taget velocity
//Serial.println("send 1000 in taget velocity");
data[0]=1000;
WriteObject (0x60FF,0,data);
//Todo: wait for ready to switch on
// if not ready to switch on : send shutdown command
if (!(ReadStatusWord() & 0x01))
{
 Serial.println("Write 06 Controlword");
 data[0]=0x0006;
 WriteObject (0x6040,0,data);    
}
// if Ready to switch on : enable
if (ReadStatusWord() & 0x01) // or 0x20 or 0x21?
{
 Serial.println("Write 0F in  Controlword");
 data[0]=0x000F;
 WriteObject (0x6040,0,data);    
}
ReadStatusWord();
// Start operation command:
Serial.println("Write FF in Controlword");
data[0]=0x00FF;
WriteObject (0x6040,0,data);
ReadStatusWord();

delay(5000);
 //Send Halt
data[0]=0x01FF;
WriteObject (0x6040,0,data);
ReadStatusWord();

}

void loop()
{
// doc example
//ReadObject(0x30B0,0);

}

Hi,
OPs diagram.

Please read the first post in any forum entitled how to use this forum.
http://forum.arduino.cc/index.php/topic,148850.0.html .

If the comms is RS232, then you need to connect Tx of the Arduino to Rx of the controller, and Rx of the Arduino to Tx of the controller.

Thanks.. Tom.. :slight_smile:

TomGeorge:
If the comms is RS232, then you need to connect Tx of the Arduino to Rx of the controller, and Rx of the Arduino to Tx of the controller.

Hi Tom,

yes, I'm doing that. That RS232 to TTL adaptor, for some reason, on the TTL part I need to put the Rx on the Arduino Rx and the Tx on the Tx pin. But even if I exchange the wiring the result is still the same, the motor controller doesn't seem to receive and process the command sent from the Arduino.

Thank you

Tuani

How many years experience do you have in data communications programming?

Paul

Paul_KD7HB:
How many years experience do you have in data communications programming?

Paul

I'm so sorry, my replies must be really frustrating for you to be asking that. I have zero years of experience. I have started self-studying this semester because my professor asked me to control a motor system using this motor controller with RS232 communication, but since he is also not familiar with this communication he can't really help me. I've searched and checked, but I'm still quite confused about how to write the Arduino code to make the communication with the controller.

I'm now almost positive that the problem is the code because I know that the motor controller is able to receive commands through its RS232 port(I used the EPOS studio to send the commands and not Arduino). And since I've tested if Arduino is sending commands properly and that all wiring is connected and working properly, the only thing left is the code.

Again I'm sorry for my lack of knowledge in this area.

Tuani

The motor and control must be really old and have been updated over time. The reason I believe that is the message format reminds me strongly of IBM Bisync transparent communications. Then they converted to ASCII data instead of EBCDIC, but left in the escape (DLE) code from the transparent protocol.

Then you notice they NEVER EVER mention baud rate for the communications. In place they still have what IBM Bisync used to synchronize the communications electronics. So, I suspect the machine will accept any baud rate, up to some unknown maximum and will use that same baud rate when it sends a message back to you.

Before going any farther, did you read that machine will NOT reply if the CRCC is not correct. Have you been able to use the sample code to write a function to create the CRCC as they want it? That is the VERY FIRST requirement. Until that works, the rest is wasted time.

When the CRCC code is working, we can attack the next step.

Paul