Esmacat
Published © GPL3+

EASE w/ LCD & Motor Shield Using RaspberryPi Master Tutorial

Use a RaspberryPi master to communicate with 2 EtherCAT Arduino Shield by Esmacat(EASE) on Arduino to control motors using LCD shield input.

IntermediateProtip2 hours2,107

Things used in this project

Hardware components

Raspberry Pi 4 Model B
Raspberry Pi 4 Model B
EtherCAT Master
×1
Raspberry Pi Power Supply
×1
Arduino UNO
Arduino UNO
×2
EtherCAT Arduino Shield by Esmacat (EASE)
EASE Slave device
×2
Power over Ethernet Injector
×1
DC Adapter
To supply power to the Power over Ethernet Injector.
×1
Ethernet Cable, Cat6a
Ethernet Cable, Cat6a
×3
16x2 LCD Shield
×1
Adafruit Motor Shield
Adafruit Motor Shield V2 to control the motors
×1
Servo Motor
(Optional to test the code). Any Servo motor can be used. This specific motor has been used in this tutorial.
×1
DC Motor
(Optional Motor to test the code). Any dc motor can be used. This specific motor has been used in this tutorial.
×1
Stepper Motor
(Optional Motor to test the code). Any stepper motor can be used. This specific motor has been used in this tutorial.
×1
Power Source
Any power source like a lipo battery or battery eliminator to power the motors.
×1

Software apps and online services

Arduino IDE
Arduino IDE
QT creator
(Optional) IDE for building C++ Applications in Linux although any other software of your choice can be used to build the project.

Story

Read more

Schematics

Hardware Setup Schematic

Schematic of the connection used in the tutorial

Physical Hardware Connection schematic

Hardware setup after final connections

Code

Arduino with EASE and LCD Shield Code

Arduino
Code to be uploaded with the Arduino Board with EASE and LCD Shield.
/*
  Motors Control

  This sketch does the following:
  1) Gets user input for choice of motor from another Arduino connected to the EASE master.
  2) Depending on the motor chosen, it does the following
      2.1) If the motor chosen is a DC Motor, using the up and down buttons on the second Arduino
           the speed can be controlled.
           The current speed of the motor is printed on the LCD.
      2.2) If the motor chosen is a Servo Motor, using the up and down buttons on the second Arduino
           the angle can be controlled.
           The current position of the motor is printed on the LCD.
      2.3) If the motor chosen is a Stepper Motor, using the up and down buttons on the second Arduino
           the speed can be controlled.
           The current speed of the motor is printed on the LCD.            

  created 18 Dec 2019
  by Harmonic Binonics Inc. (https://www.harmonicbionics.com/).
  
*/

/*
    PIN CONFIGURATION of the LCD Shield Used
    |-----------------------------------------|
    |  LCD PIN Number  |   Arduino PIN Number |
    |-----------------------------------------|
    |       RS         |      Digital Pin 8   |
    |     ENABLE       |      Digital Pin 9   |
    |       D4         |      Digital Pin 4   |
    |       D5         |      Digital Pin 5   |
    |       D6         |      Digital Pin 6   |
    |       D7         |      Digital Pin 7   |
    |     Buttons      |      Analog Pin A0   |
    |-----------------------------------------|
    
*/

/*
    Analog Input Values for the Push Buttons
    |------------------------------------------------|
    |    Push Button     |          A0 value         |
    |------------------------------------------------|
    |       SELECT       |   val >= 500 & val <= 750 |
    |        LEFT        |   val >= 300 & val < 500  |
    |        DOWN        |   val >= 150 & val < 300  |
    |         UP         |   val >= 50  & val < 150  |
    |        RIGHT       |   val >= 0   & val < 50   |
    |------------------------------------------------|
*/

/*
    Buton Encoding Relation
    -------------------------------------------
    |    Button on LCD     |    Encoded Value  |
    -------------------------------------------
    |         Left         |          1        |
    |          Up          |          2        |
    |         Down         |          3        |
    |         Right        |          4        |
    |        Select        |          5        |
    --------------------------------------------
*/
 
/*
    Motor Select Options
    |--------------------------------------------------------|
    |   Motor Select Integer Value   |    Motor Controlled   |
    |--------------------------------------------------------|
    |               0                |       Servo Motor     |
    |               1                |         DC  Moror     |
    |               2                |     Stepper Motor     |
    |--------------------------------------------------------|
*/

#include <LiquidCrystal.h>      // Include LCD Arduino Library
#include <Esmacatshield.h>      //Include the Esmacat Arduino Library


// Define the Pin Numbers as Macros

# define Serial_baud_rate 9600
#define ARDUINO_UNO_SLAVE_SELECT 10      // The chip selector pin for Arduino Uno is 10 
# define RS_pin 8
# define Enable_pin 9
# define LCD_coloumns 16
# define LCD_rows 2

LiquidCrystal lcd_display(RS_pin, Enable_pin, 4, 5, 6, 7);      // Create an object for the Library class
Esmacatshield ease_with_lcd(ARDUINO_UNO_SLAVE_SELECT);      // Create a slave object and specify the Chip Selector Pin

int analog_value;      // Initialise analog input value variable
int servo_angle = 0;   // Variable to store the input angle
int stepper_speed = 0;   // Variable to store stepper motor speed
int dc_speed = 0;   // Variable to store dc motor speed
int motor_select = 0;   // Variable to choose the motor to be controlled
int prev_motor_select = 0;
int prev_servo_angle = 0;
int prev_dc_speed = 0;
int prev_stepper_speed = 0;

int ease_registers[8];      // EASE 8 registers


void setup() 
{
  lcd_display.begin(LCD_coloumns,LCD_rows);      //Initialise the number of (coloumns, rows) in the LCD
  
  lcd_display.print("Servo Motor");      // Print a message onto the LCD Display
                                         // Default is Servo Motor 
  Serial.begin(Serial_baud_rate);      // Initialise the Serial Communication with the specified Baud Rate
  
  ease_with_lcd.start_spi();      // Start SPI for EASE
}

void loop() 
{

  analog_value = analogRead(A0);
  Serial.println(analog_value);

  ease_with_lcd.write_reg_value(0,analog_value);      //Write register data (register,value, led_on)
  
  delay(50);
  
  ease_with_lcd.get_ecat_registers(ease_registers);
  servo_angle = ease_registers[1];   // Actual Servo position
  dc_speed = ease_registers[2];   // Actual dc motor speed
  stepper_speed = ease_registers[3];   // Actual Stepper Motor Speed
  motor_select = ease_registers[4];

  if(motor_select == 0)   // Servo Motor Selected
  {
    if(prev_motor_select != motor_select)
    {
      for(int i = 0; i < 16; i++)
      {
        lcd_display.setCursor(i,0);
        lcd_display.print(" ");      // Remove the previous characters (if any)
      }
    }
    lcd_display.setCursor(0,0);
    lcd_display.print("Servo Motor");
    if(prev_servo_angle != servo_angle)
    {
      for (int i = 0;i < 4;i++)
      {
        lcd_display.setCursor(i,1);
        lcd_display.print(" ");
      }
    }
    lcd_display.setCursor(0,1);
    lcd_display.print(servo_angle);
    lcd_display.setCursor(10,1);      // set the LCD cursor position (Coloumn number,Row number)
    lcd_display.print("angle"); 
  }
  
  if(motor_select == 1)   // DC Motor Selected
  {
    if(prev_motor_select != motor_select)
    {
      for(int i = 0; i < 16; i++)
      {
        lcd_display.setCursor(i,0);
        lcd_display.print(" ");      // Remove the previous characters (if any)
      }
    }
    
    lcd_display.setCursor(0,0);
    lcd_display.print("DC Motor");
    
    if(prev_dc_speed != dc_speed)
    {
      for (int i = 0;i < 4;i++)
      {
        lcd_display.setCursor(i,1);
        lcd_display.print(" ");
      }
    }
    
    lcd_display.setCursor(0,1);
    lcd_display.print(dc_speed);
    lcd_display.setCursor(10,1);      // set the LCD cursor position (Coloumn number,Row number)
    lcd_display.print("speed"); 
  }
  
  if(motor_select == 2)   // Stepper Motor Selected
  {
    if(prev_motor_select != motor_select)
    {
      for(int i = 0; i < 16; i++)
      {
        lcd_display.setCursor(i,0);
        lcd_display.print(" ");      // Remove the previous characters (if any)
      }
    }
    
    lcd_display.setCursor(0,0);
    lcd_display.print("Stepper Motor");
    
    if(prev_stepper_speed != stepper_speed)
    {
      for (int i = 0;i < 4;i++)
      {
        lcd_display.setCursor(i,1);
        lcd_display.print(" ");
      }
    }
    
    lcd_display.setCursor(0,1);
    lcd_display.print(stepper_speed);
    lcd_display.setCursor(10,1);      // set the LCD cursor position (Coloumn number,Row number)
    lcd_display.print("speed"); 
  }
  prev_motor_select = motor_select;
  prev_servo_angle = servo_angle;
  prev_dc_speed = dc_speed;
  prev_stepper_speed = stepper_speed;
}

Arduino with EASE and Motor Shield Code

Arduino
Code to be uploaded to the Arduino board with EASE and Motor Shield
/*
  Motors Control

  This sketch does the following:
  1) Gets update for the speed from another Arduino connected to the EASE master.
  2) Depending on the motor chosen, it does the following
      2.1) If the motor chosen is a DC Motor, the motor is set to run at the set speed.
           The current speed of the motor is printed on the LCD.
      2.2) If the motor chosen is a Servo Motor, the motor is set at the desired position.
           The current position of the motor is printed on the LCD.
      2.3) If the motor chosen is a Stepper Motor, the motor is set to run at the set speed.          

  created 18 Dec 2019
  by Harmonic Binonics Inc. (https://www.harmonicbionics.com/). 
  
*/

/*
    Buton Encoding Relation
    -------------------------------------------
    |    Button on LCD     |    Encoded Value  |
    -------------------------------------------
    |         Left         |          1        |
    |          Up          |          2        |
    |         Down         |          3        |
    |         Right        |          4        |
    |        Select        |          5        |
    --------------------------------------------
*/
 
/*
    Motor Select Options
    |--------------------------------------------------------|
    |   Motor Select Integer Value   |    Motor Controlled   |
    |--------------------------------------------------------|
    |               0                |       Servo Motor     |
    |               1                |         DC  Motor     |
    |               2                |     Stepper Motor     |
    |--------------------------------------------------------|
*/

#include <Wire.h>
#include <Adafruit_MotorShield.h>   // Include the Adafruit Motor Shield Library

#include <Servo.h>   // Include the Arduino Servo Library
#include <Esmacatshield.h>      //Include the Esmacat Arduino Library

// Define the Pin Numbers as Macros
# define servo_control_pin 9   // Servo is connected to Servo port #1 on the Motor Shield
# define Serial_baud_rate 9600
# define ARDUINO_UNO_SLAVE_SELECT 10      // The chip selector pin for Arduino Uno is 10 

// Create objects for various motor classes and EASE
Esmacatshield ease_with_motor(ARDUINO_UNO_SLAVE_SELECT);      // Create a slave object and specify the Chip Selector Pin

// Create the motor shield object with the default I2C address
Adafruit_MotorShield AFMS = Adafruit_MotorShield(); 

// Create an object for Stepper Motor
Adafruit_StepperMotor *stepper_motor = AFMS.getStepper(200, 2);   // Connect a stepper motor with 200 steps per revolution
                                                                  // (1.8 degree) to motor port #2 (M3 and M4)
// Create an object for DC Motor
Adafruit_DCMotor *dc_motor = AFMS.getMotor(2);   // Connect a DC motor to motor port #2 (M2)

// Create an object for the Servo Motor Class
Servo servo_2;   // Servo is connected to Servo port #2 on the Motor Shield so the name servo_2 is used

// Required variables Initialization
int motor_select = 0;   // Variable to choose which motor to control
int servo_angle = 0;   // Variable to store the input angle
int stepper_speed = 0;   // Variable to store stepper motor speed
int dc_speed = 0;   // Variable to store dc motor speed
int ease_registers[8];      // EASE 8 registers

void setup() 
{
  Serial.begin(9600);           // set up Serial library at 9600 bps

  AFMS.begin();  // create with the default frequency 1.6KHz
  
  stepper_motor->setSpeed(10);  // 10 rpm 
  
  dc_motor->setSpeed(0);   // Set the initial Speed of DC Motor to 0
  // dc_motor->run(FORWARD);  

  servo_2.attach(servo_control_pin);   // Servo 1 on Adafruit Motor Shield is connected
                                       // to Pin 10 of the Arduino board
  ease_with_motor.start_spi();      // Start SPI for EASE
}

void loop() 
{
  ease_with_motor.get_ecat_registers(ease_registers);

  motor_select = ease_registers[0];   // Motor to control
  servo_angle = ease_registers[1];   // Actual Servo position
  dc_speed = ease_registers[2];   // Actual dc motor speed
  stepper_speed = ease_registers[3];   // Actual Stepper Motor Speed
  Serial.println(motor_select);
  if(motor_select == 0)
  {
    servo_2.write(servo_angle);
    Serial.print("Servo Angle ");
    Serial.println(servo_angle);
  }
  
  if(motor_select == 1)
  {
    if(dc_speed > 0)
    {
      dc_motor->setSpeed(dc_speed);
      dc_motor->run(FORWARD);
    }
    else
    {
      dc_motor->setSpeed(dc_speed);
      dc_motor->run(BACKWARD);
    }
    Serial.print("DC Speed");
    Serial.println(dc_speed);
  }

  if(motor_select == 2)
  {
    if(stepper_speed > 0)
    {
      stepper_motor->step(stepper_speed,FORWARD,SINGLE);
    }

    else
    {
      stepper_motor->step(stepper_speed,BACKWARD,SINGLE);
    }
    Serial.print("Stepper Speed");
    Serial.println(stepper_speed);
   }
}

ease_lcd_motor_control/main.cpp

C/C++
Software to be run on the EtheCAT master, main.cpp file
/** @file
 *  @brief This file contains the template for the main program for the Esmacat slave
 *  project */
/*****************************************************************************************
 * INCLUDES
 ****************************************************************************************/
#include <iostream>
#include "my_app.h"

/*****************************************************************************************
 * FUNCTIONS
 ****************************************************************************************/
/**
 * @brief Initializes the execution of the Ethercat communication and
 *        primary real-time loop for your application for the desired
 *        slave
 * @return
 */

int main()
{
    //this is defined in my_app.cpp and my_app.h
    my_app app;

    // if you already know the ethernet adapter name for EtherCAT, uncomment and use the line below
    //    app.set_ethercat_adapter_name(" WRITE YOUR ETHERNET ADAPTER NAME");

    // If the name is not known, select through the terminal an ethernet adapter (the slave)
    // you'd like to communicate with over EtherCAT
    app.set_ethercat_adapter_name_through_terminal();

    // start the esmacat application customized for your slave
    app.start();

    //the application runs as long as the esmacat master and slave are in communication
    while (app.is_esmacat_master_closed() == FALSE );
    return 0;
}

ease_lcd_motor_control/my_app.cpp

C/C++
Source code of the application class
/** @file
 * @brief This file contains the definition of the functions associated with the user-defined
 * application for the Esmacat slave project */
 /*****************************************************************************************
 * INCLUDES
 ****************************************************************************************/
#include "my_app.h"

/*****************************************************************************************
 * FUNCTIONS
 ****************************************************************************************/
/**
 * @brief Identifies the actual Esmacat slave sequence in the EtherCAT communication chain.
 */
void my_app::assign_slave_sequence(){
    // tell the master what type of slave is at which point in the chain
    assign_esmacat_slave_index(&ease_motor_shield, 1);  //<-- The Motor Shield is connected in number 0
    assign_esmacat_slave_index(&ease_lcd_shield, 0);   //<-- The LCD Shield is connected in number 1
}

/**
 * @brief Configure your Esmacat slave.
 * Link Esmacat slave object with the actual Esmacat slave in the EtherCAT communication chain.
 * Functions beginning with 'configure_slave' must only be executed in this function
 */
void my_app::configure_slaves(){
    // add initialization code here
    // Functions starting with "configure_slave" work only in configure_slaves() function
}

/** @brief Initialization that needs to happen on the first iteration of the loop
 */
void my_app::init()
{ 
    // LCD Shield Initialization
    ease_lcd_shield.set_output_variable_0_OUT_GEN_INT0(0);
    ease_lcd_shield.set_output_variable_1_OUT_GEN_INT1(0);
    ease_lcd_shield.set_output_variable_2_OUT_GEN_INT2(0);
    ease_lcd_shield.set_output_variable_3_OUT_GEN_INT3(0);
    ease_lcd_shield.set_output_variable_4_OUT_GEN_INT4(0);

    // Motor Shield Initialization
    ease_motor_shield.set_output_variable_0_OUT_GEN_INT0(0);
    ease_motor_shield.set_output_variable_1_OUT_GEN_INT1(0);
    ease_motor_shield.set_output_variable_2_OUT_GEN_INT2(0);
    ease_motor_shield.set_output_variable_3_OUT_GEN_INT3(0);

    cout << "Servo Motor Selected \n";

    // Intialisation of the variables
    motor_select = 0;
    servo_postion = 0;
    dc_speed = 0;
    stepper_speed = 0;
    prev_analog_value = 0;
    lcd_analog_input_value = 1023;   // Random value initialization
    button_pressed_flag = FALSE;
}
/*
   EASE LCD Shield Register Mapping
   |--------------------------------------------------|
   |   Register Number   |           Mapping          |
   |--------------------------------------------------|
   |         0           |   LCD analog input value   |
   |         1           |         Servo Angle        |
   |         2           |       DC Motor Speed       |
   |         3           |     Stepper motor Speed    |
   |         4           |         Motor Select       |
   |--------------------------------------------------|
*/

/*
   EASE Motor Shield Register Mapping
   |--------------------------------------------------|
   |   Register Number   |           Mapping          |
   |--------------------------------------------------|
   |         0           |         Motor Select       |
   |         1           |         Servo Angle        |
   |         2           |       DC Motor Speed       |
   |         3           |     Stepper motor Speed    |
   |--------------------------------------------------|
/**

 * @brief Executes functions at the defined loop rate
 */
void my_app::loop(){
    // add functions below that are to be executed at the loop rate
    lcd_analog_input_value = ease_lcd_shield.get_input_variable_0_IN_GEN_INT0();

    // cout << lcd_analog_input_value << " ";
    // <----------------------------------------------------------------------->
    //                            LCD Shield  Code 
    // <----------------------------------------------------------------------->


    if (lcd_analog_input_value >= 50 && lcd_analog_input_value <= 150)   // Up Button Increase Speed
    {
        // cout << lcd_analog_input_value << "\t";
        if (motor_select == 0)
        {
            servo_postion += 1;
            ease_lcd_shield.set_output_variable_1_OUT_GEN_INT1(servo_postion % 180);
            cout << "Servo position Increased \n";
        }

        else if (motor_select == 1)
        {
            dc_speed += 1;
            ease_lcd_shield.set_output_variable_2_OUT_GEN_INT2(dc_speed);
            cout << "DC Motor Speed Increased \n";
        }

        else
        {
            stepper_speed += 1;
            ease_lcd_shield.set_output_variable_3_OUT_GEN_INT3(stepper_speed);
            cout << "Stepper Motor Speed Increased \n";
        }

    }

    if (lcd_analog_input_value >= 150 && lcd_analog_input_value <= 300)   // Down Button Decrease Speed
    {
        // cout << lcd_analog_input_value << "\t";
        if (motor_select == 0)
        {
            servo_postion -= 1;
            ease_lcd_shield.set_output_variable_1_OUT_GEN_INT1(servo_postion % 180);
            cout << "Servo position decreased \n";
        }

        else if (motor_select == 1)
        {
            dc_speed -= 1;
            ease_lcd_shield.set_output_variable_2_OUT_GEN_INT2(dc_speed);
            cout << "DC Motor Speed decreased \n";
        }

        else
        {
            stepper_speed -= 1;
            ease_lcd_shield.set_output_variable_3_OUT_GEN_INT3(stepper_speed);
            cout << "Stepper Motor Speed decreeased \n";
        }
    }


    if (lcd_analog_input_value >= 500 && lcd_analog_input_value <= 750)
    {
        cout << lcd_analog_input_value << "\t";
        motor_select = (motor_select + 1) % 3;
        ease_lcd_shield.set_output_variable_4_OUT_GEN_INT4(motor_select);
        if (motor_select == 0)   cout << "Servo Motor Selected" << endl;
        if (motor_select == 1)   cout << "DC Motor Selected" << endl;
        if (motor_select == 2)   cout << "Stepper Motor Selected" << endl;
    }

    // <----------------------------------------------------------------------->
    //                            Motor Shield  Code 
    // <----------------------------------------------------------------------->
    ease_motor_shield.set_output_variable_0_OUT_GEN_INT0(motor_select);
    ease_motor_shield.set_output_variable_1_OUT_GEN_INT1(servo_postion);
    ease_motor_shield.set_output_variable_2_OUT_GEN_INT2(dc_speed);
    ease_motor_shield.set_output_variable_3_OUT_GEN_INT3(stepper_speed);
    prev_analog_value = lcd_analog_input_value;  
}

ease_lcd_motor_control/my_app.h

C/C++
Header files for the application class
/** @file
 * @brief This file contains the declaration of the class associated with the user-defined
 * application for the Esmacat slave project */

#ifndef MY_APP_H
#define MY_APP_H

/*****************************************************************************************
 * INCLUDES
 ****************************************************************************************/
#include <iostream>
#include "application.h"
//Include the header file for the Esmacat slave you plan to use for e.g. Analog Input slave
//#include "esmacat_analog_input.h"
#include "ethercat_arduino_shield_by_esmacat.h"
using namespace std;

/*****************************************************************************************
 * CLASSES
 ****************************************************************************************/
/**
 * @brief Description of your custom application class
 *
 * Your custom application class my_app inherits the class 'esmacat_application'
 * Write functions to override the parent functions of 'esmacat_application'
 * Declare an object of your slave class (e.g. ecat_ai)
 * Declare any other variables you might want to add
 * Define the constructor for initialization
 */
class my_app : public esmacat_application
{
private:
    void assign_slave_sequence(); /** identify sequence of slaves and their types*/
    void configure_slaves(); /** setup the slave*/
    void init(); /** code to be executed in the first iteration of the loop */
    void loop(); /** control loop*/

    // Creating objects for the slave class
    esmacat_ethercat_arduino_shield_by_esmacat ease_lcd_shield;  /** < create a Esmacat slave object for the EASE with LCD shield */
    esmacat_ethercat_arduino_shield_by_esmacat ease_motor_shield;   /** < create a Esmacat slave object for the EASE with Motor shield */
    
    // Declaring the required variables
    uint32_t lcd_analog_input_value;
    uint32_t servo_postion;
    uint32_t dc_speed;
    uint32_t stepper_speed;
    uint32_t motor_select;
    uint32_t prev_analog_value;
    bool button_pressed_flag;

public:
    /** A constructor- sets initial values for class members */
    my_app()
    {
    }
};

#endif // MY_APP_H

ease_lcd_motor_control/CMakeLists.txt

Plain text
CMake Lists file of the project
file(GLOB MY_PROJECT_HEADERS *.h)
file(GLOB MY_PROJECT_SOURCES *.cpp *.c)

add_executable(ease_lcd_motor_control ${MY_PROJECT_SOURCES} ${MY_PROJECT_HEADERS})

target_link_libraries(ease_lcd_motor_control ethercat_driver esmacat)

install(TARGETS ease_lcd_motor_control DESTINATION ./bin)

Esmacat EtherCAT Master Software

EtherCAT Arduino Shield by Esmacat (EASE) Arduino Library

Library file to be included in the Arduino IDE.

Credits

Esmacat

Esmacat

11 projects • 16 followers
Esmacat is an easy yet powerful EtherCAT solution for robotics. Our EtherCAT tech allow users to run EtherCAT applications in minutes!

Comments