Interfacing 3D Printer using Arduino/ESP32

I am trying to create a device that can control 3D printers using serial communication. For this, the microcontroller I chose was the ESP32-CAM by AI Thinkers. I connected the ESP32-CAM to the WiFi and used Telegram, to communicate with the ESP. I bought a Y-Connector to split communication and power to the microcontroller. I tested that the data line in this connector is working properly using a pendrive. I connected the ESP to the PC and tested if everything is working properly. When I type and send a phrase in Telegram (example: "M115"). The serial monitor is displaying M115", and when I write "Hi" in the serial monitor, I am getting that in telegram as a response.
All these are working fine between ESP and PC, but when I connect ESP to a 3D printer, I didn't get any response back from the printer. I tried a similar thing using my PC and 3D printer. If I serially write M115, I get firmware information from the printer.

// Handle /command command
void Telebot::handleCommand(const telegramMessage& tMsg){
  sendMsg(tMsg.chat_id, USAGE_INFO_COMMAND);
  std::vector<String> endCmds = {"/end", "/exit", "/x"};
  const telegramMessage *tM {nullptr};
  String cmd {""};
  String recvTxt{"Recv: "};
  String responce {}, resTxt{};
  String prevChatId {};
  while (true) {
    tM = getNextMsg();
    if (tM) {
      prevChatId = tM->chat_id;
      cmd = tM->text;
      recvTxt = "Recv: " + toUppercase(cmd);
      sendMsg(prevChatId, recvTxt);

      if (std::find(endCmds.begin(), endCmds.end(), toLowerCase(cmd)) != endCmds.end()) break;

      if (cmd.startsWith("/")) 
        sendMsg(tM->chat_id, USAGE_INFO_COMMAD_ERROR);
      else
        Serial.println(toUppercase(cmd));

    }
    if (Serial.available()) {
      responce = Serial.readStringUntil('\n');
      resTxt = "Resp: " + responce;
      sendMsg(prevChatId, resTxt);
    }
  }
  #ifdef DEBUG
    printDebug("Exiting Command Mode.");
    Serial.println("Exiting Command Mode.");
  #endif
}

I need some help figuring out what mistake I am making. Can somebody Please help me?

Thanks in Advance

full sketch pls

if you connect printer to PC says it something?


// Telebot.hpp


#pragma once
#include "WCharacter.h"
#include <UniversalTelegramBot.h>
#include <WiFiClientSecure.h>
#include <algorithm>
#include <string>
#include <vector>
#include <cctype>

#define TRANSFER_BAUDRATE 115200


#define A_OK                    "All OK! Start the transfer."
  
#define USAGE_INFO_ALL          "Hi! \nThis is a bot to interface with you 3D printer. \n\n*Options:*\n*/print* as a caption to the GCODE file to print the file. \n*/command* to enter into command mode."
#define USAGE_INFO_PRINT        "No file uploaded.\nUpload the file and type /print as the caption.   :*"
#define USAGE_INFO_COMMAND      "Welcome to *Command Mode*. \nHere you can communicate with your printer and test your statements.\nYou will stay in this mode until you use one of the following commands:\n*/end* or */exit* or */x*"
#define USAGE_INFO_COMMAD_ERROR "You are in command mode. You will stay in this mode until you use one of the following commands:\n*/end* or */exit* or */x*"


class Telebot {
    private:
      const String          _token {"Don\'t know"};
      WiFiClientSecure      _client;
      UniversalTelegramBot  _bot;

    public:
      Telebot() = delete;
      Telebot(const String);
      const bool              initSD();
      telegramMessage* const  getNextMsg ();
      void                    handleMsgs();
      void                    handleCommand(const telegramMessage&);

      const bool   sendMsg(const String&, const String);
      const bool   sendBusyMsg(const String);
      const String get_token() const;
      const bool   is_connected();

      void sPrint_telegramMessage(const telegramMessage&) const ;

};

// Telebot.cpp


#include "Telebot.hpp"

// 
String toLowercase(String str) {
  std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) {
    return std::tolower(c);
  });
  return str;
}

String toUppercase(String str) {
  std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) {
    return std::toupper(c);
  });
  return str;
}

#ifdef DEBUG
  inline void printDebug (const String& msg){
    Serial.print("[!] => ");
    Serial.println(msg);
  }
#endif


// Constructor
Telebot::Telebot(const String token)
: _token{token}, _bot{UniversalTelegramBot(_token, _client)}, _meta{1024}
{
  // Add root certificate for api.telegram.org
  _client.setCACert(TELEGRAM_CERTIFICATE_ROOT);

  // Initialize SD card
  initSD();
}

const bool Telebot::initSD(){
  if(SD_MMC.begin()){
    #ifdef DEBUG
      printDebug("Card Mount Successful");
    #endif
    return true;
  }
  else {
    #ifdef DEBUG
      printDebug("Card Mount Failed");
    #endif
  }
  return false;
}


telegramMessage* const Telebot::getNextMsg (){
  short n = _bot.getUpdates(_bot.last_message_received + 1);

  // if no new messages do nothing
  if (!n) return nullptr;

  return &_bot.messages[0];
}

// Handle new messages sent by user
void Telebot::handleMsgs(){

  short n = _bot.getUpdates(_bot.last_message_received + 1);

  // if no new messages do nothing
  if (!n) return;

  for (short msgIdx = 0; msgIdx < n; msgIdx++){

    telegramMessage& tMsg {_bot.messages[msgIdx]}; 
    String Msg      = tMsg.text;

    #ifdef DEBUG
      printDebug(Msg);
    #endif

    if (toLowercase(Msg) == "/command"){
      handleCommand(tMsg);
    }

  }
}

// Handle /command command
void Telebot::handleCommand(const telegramMessage& tMsg){
  sendMsg(tMsg.chat_id, USAGE_INFO_COMMAND);
  std::vector<String> endCmds = {"/end", "/exit", "/x"};
  const telegramMessage *tM {nullptr};
  String cmd {""};
  String recvTxt{"Recv: "};
  String responce {}, resTxt{};
  String prevChatId {};
  while (true) {
    tM = getNextMsg();
    if (tM) {
      prevChatId = tM->chat_id;
      cmd = tM->text;
      recvTxt = "Recv: " + toUppercase(cmd);
      sendMsg(prevChatId, recvTxt);

      if (std::find(endCmds.begin(), endCmds.end(), toLowerCase(cmd)) != endCmds.end()) break;

      if (cmd.startsWith("/")) 
        sendMsg(tM->chat_id, USAGE_INFO_COMMAD_ERROR);
      else
        Serial.println(toUppercase(cmd));

    }
    if (Serial.available()) {
      responce = Serial.readStringUntil('\n');
      resTxt = "Resp: " + responce;
      sendMsg(prevChatId, resTxt);
    }
  }
  #ifdef DEBUG
    printDebug("Exiting Command Mode.");
    Serial.println("Exiting Command Mode.");
  #endif
}

// Helper function to send simple message
const bool Telebot::sendMsg(const String& chatId, const String Msg){
  #ifdef DEBUG
    printDebug("Sending the info: \n" + Msg);
  #endif
  return _bot.sendMessage(chatId, Msg, "markdown");
}

const String Telebot::get_token() const{
  return _token;
}

#include "DEBUG.h"

// initialising Telebot
#include "Telebot.hpp"
Telebot* telebot{nullptr};

void setup(){
  Serial.begin(115200);

void loop(){

  if(telebot -> is_connected())
    telebot -> handleMsgs();

}

When I connect printer to PC and serial print "M115", the printer response is the current firmware info. This I tested using a python code that I wrote. I want the same with ESP32-CAM.

for example Marlin FW says on connection:

start
echo: External Reset
Marlin 1.1.9.1

echo: Last Updated: 2020-06-20 | Author: (none, default config)
echo:Compiled: Aug  1 2023
echo: Free Memory: 5602  PlannerBufferBytes: 1232
echo:Hardcoded Default Settings Loaded
echo:  G21    ; (mm)

echo:Filament settings: Disabled
echo:  M200 D3.00
echo:  M200 D0
echo:Steps per unit:
echo:  M92 X80.00 Y80.00 Z4000.00 E500.00
echo:Maximum feedrates (units/s):
echo:  M203 X300.00 Y300.00 Z5.00 E25.00
echo:Maximum Acceleration (units/s2):
echo:  M201 X3000 Y3000 Z100 E10000
echo:Acceleration (units/s2): P<print_accel> R<retract_accel> T<travel_accel>
echo:  M204 P3000.00 R3000.00 T3000.00
echo:Advanced: Q<min_segment_time_us> S<min_feedrate> T<min_travel_feedrate> X<max_x_jerk> Y<max_y_jerk> Z<max_z_jerk> E<max_e_jerk>
echo:  M205 Q20000 S0.00 T0.00 X10.00 Y10.00 Z0.30 E5.00
echo:Home offset:
echo:  M206 X0.00 Y0.00 Z0.00
echo:PID settings:
echo:  M301 P22.20 I1.08 D114.00

is your printer silent? no "OK" to each command?

I was expecting the same. but I don't get anything. No response.
(I am getting all these when I connect my PC to the Printer.)

maybe you wired TX/RX/GND wrong or ESP32 is not 5V tolerant

The ESP32-CAM does not have a USB port built-in to program it. For that, I have an FTDI Programmer board attached to the ESP32-CAM, and I have a Y-splitter attached to this board to power the board and communicate with the board. The Y-splitter is not required when it is connected to a PC.
(FYI: I checked the communication line of the Y-splitter with a pen drive and phone. It is working fine in data transfer.)

I think if the board works with PC it should work with the printer because both work on the same 5V TTL level

My doubt is with the Y-splitter. Do you think we can use this Y-splitter like this?

no idea what you talking about. you using same usb-uart converter for usb port on PC or for usb port on Printer, right?

or you using for comunication uart cable?

So, This ESP32-CAM-MB board comes with an ESP32-CAM development board. It is meant for connecting the board to a PC and programming the board.

Please check out these two links for more clarification:

My question is:
If we are connecting the dev board to the printer through the CAM-MB board, the dev board doesn't get power since the printer is an output device. So the dev board has to be externally powered. For this, the solution I came up with is to use a Y-splitter from Amazon. It has a Micro-USB male on one end to connect to the MB board and a USB female for the Printer connection, and a Micro-USB female for powering the board.

FYI: I checked for this, The Micro-USB power line on the Y-splitter only supplies power, not data.

Is this setup OKAY, or are there any problems, Are we not supposed to do power and Serial through the same USB port (Micro USB port of the MB board)?

изображение
here USB-UART converter. it is "slave" USB device, the 3d printer is slave too. only PC is the USB host.
communication between two slaves is not possible.
for powering ESP32 board from printer you may want such cable (only power, no data lines):

you should connect free UART pins of ESP32 to UART pins of 3d printer. of course it is possible that USB-UART converters on both devices may cause interfering when you use its UART pins.

Is there a way to do this using USB but not UART?
Can I use any other board?

RaspberryPi

To my knowlage i think you cant do that with your specific board, but there is one that may be able to do that its ESP32-s3- wroom freenove. Its got two usb-c ports one uart and one otg. But im not sure so do your research.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.