What is the problem?
I'm using a vr setup to display a digital twin of a printer, using octoprint to send code to the printers and display information (all works besides this movement commands). The logs state that it receives and confirms the movement, the printer however does not move. In the web api it works perfectly fine and the GCode commands seem identical.
What did you already try to solve it?
Checked terminal for missing commands, restarted octoprint, check unity code for issues
Have you tried running in safe mode?
yes
Did running in safe mode solve the problem?
no
Systeminfo Bundle
You can download this in OctoPrint's System Information dialog ... no bundle, no support!)
octoprint-systeminfo-20240920105955.zip (123.8 KB)
Additional information about your setup
OctoPrint version, OctoPi version, printer, firmware, browser, operating system, ... as much data as possible
Lulzbot Taz Workhorse, Windows
How are you handling the splitting of the commands to two 'devices'?
How are you handling the two responses?
using System.Collections;
using System.Net.Http;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using System.Threading.Tasks;
public class SendMovementCommand : MonoBehaviour
{
public Button buttonPosX;
public Button buttonNegX;
public Button buttonPosY;
public Button buttonNegY;
public Button buttonPosZ;
public Button buttonNegZ;
public Button homeButton;
public Button cancelButton;
public TMP_Text statusText;
public TMP_Text xyProgressText;
public TMP_Text zProgressText;
public TMP_Text confirmationText;
private HttpClient client;
private string commandUrl = "http://.../api/printer/command";
private string apiKey = "...";
private float currentX = 0f;
private float currentY = 0f;
private float currentZ = 0f;
private bool canSendCommand = true;
private bool confirmCancel = false;
private Coroutine cancelCoroutine;
void Start()
{
client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Api-Key", apiKey);
buttonPosX.onClick.AddListener(() => MoveAxis("G0 X10", "X", 10));
buttonNegX.onClick.AddListener(() => MoveAxis("G0 X-10", "X", -10));
buttonPosY.onClick.AddListener(() => MoveAxis("G0 Y10", "Y", 10));
buttonNegY.onClick.AddListener(() => MoveAxis("G0 Y-10", "Y", -10));
buttonPosZ.onClick.AddListener(() => MoveAxis("G0 Z10", "Z", 10));
buttonNegZ.onClick.AddListener(() => MoveAxis("G0 Z-10", "Z", -10));
homeButton.onClick.AddListener(HomeAllAxes);
cancelButton.onClick.AddListener(CancelOrConfirm);
}
async void MoveAxis(string gCodeCommand, string axis, float moveAmount)
{
Debug.Log($"Attempting to send command: {gCodeCommand}");
Debug.Log($"Axis: {axis}, Move Amount: {moveAmount}");
if (!canSendCommand)
{
statusText.text = "Please wait for the cooldown period.";
return;
}
canSendCommand = false;
var commandPayload = new CommandPayload { command = gCodeCommand };
string jsonPayload = JsonUtility.ToJson(commandPayload);
Debug.Log($"JSON Payload: {jsonPayload}");
HttpContent content = new StringContent(jsonPayload, System.Text.Encoding.UTF8, "application/json");
HttpResponseMessage response = null;
try
{
response = await client.PostAsync(commandUrl, content);
if (response.IsSuccessStatusCode)
{
Debug.Log($"Command {gCodeCommand} sent successfully.");
if (axis == "X")
{
currentX += moveAmount;
xyProgressText.text = $"X Axis Position: {currentX}";
}
else if (axis == "Y")
{
currentY += moveAmount;
xyProgressText.text = $"Y Axis Position: {currentY}";
}
else if (axis == "Z")
{
currentZ += moveAmount;
zProgressText.text = $"Z Axis Position: {currentZ}";
}
statusText.text = $"Command {gCodeCommand} sent successfully.";
}
else
{
string errorContent = await response.Content.ReadAsStringAsync();
Debug.LogError($"Failed to send command {gCodeCommand}. Response: {response.StatusCode}, {errorContent}");
statusText.text = $"Failed to send command {gCodeCommand}. Response: {response.StatusCode}, {errorContent}";
}
}
catch (HttpRequestException e)
{
Debug.LogError($"Request error: {e.Message}");
statusText.text = $"Request error: {e.Message}";
}
await Cooldown(2);
canSendCommand = true;
statusText.text = "Ready for next command.";
}
async void HomeAllAxes()
{
if (!canSendCommand)
{
statusText.text = "Please wait for the cooldown period.";
return;
}
canSendCommand = false;
var commandPayload = new CommandPayload { command = "G28" };
string jsonPayload = JsonUtility.ToJson(commandPayload);
Debug.Log($"Sending home command: G28");
HttpContent content = new StringContent(jsonPayload, System.Text.Encoding.UTF8, "application/json");
HttpResponseMessage response = null;
try
{
response = await client.PostAsync(commandUrl, content);
if (response.IsSuccessStatusCode)
{
currentX = 0f;
currentY = 0f;
currentZ = 0f;
xyProgressText.text = "X/Y Axis Position: 0";
zProgressText.text = "Z Axis Position: 0";
statusText.text = "Home command sent successfully.";
}
else
{
string errorContent = await response.Content.ReadAsStringAsync();
Debug.LogError($"Failed to send home command. Response: {response.StatusCode}, {errorContent}");
statusText.text = $"Failed to send home command. Response: {response.StatusCode}, {errorContent}";
}
}
catch (HttpRequestException e)
{
Debug.LogError($"Request error: {e.Message}");
statusText.text = $"Request error: {e.Message}";
}
await Cooldown(2);
canSendCommand = true;
statusText.text = "Ready for next command.";
}
void CancelOrConfirm()
{
if (confirmCancel)
{
CancelObject();
confirmCancel = false;
if (cancelCoroutine != null)
{
StopCoroutine(cancelCoroutine);
confirmationText.text = ""; // Clear the confirmation text
}
}
else
{
confirmationText.text = "Are you sure you want to cancel the print? Press again to confirm.";
confirmCancel = true;
cancelCoroutine = StartCoroutine(ResetCancelConfirmation());
}
}
async void CancelObject()
{
string gCodeCommand = "M486 C"; // Assuming this command cancels the current print
var commandPayload = new CommandPayload { command = gCodeCommand };
string jsonPayload = JsonUtility.ToJson(commandPayload);
Debug.Log($"Sending cancel command: M486 C");
HttpContent content = new StringContent(jsonPayload, System.Text.Encoding.UTF8, "application/json");
HttpResponseMessage response = null;
try
{
response = await client.PostAsync(commandUrl, content);
if (response.IsSuccessStatusCode)
{
confirmationText.text = "";
statusText.text = $"Print cancelled successfully.";
}
else
{
string errorContent = await response.Content.ReadAsStringAsync();
statusText.text = $"Failed to cancel print. Response: {response.StatusCode}, {errorContent}";
}
}
catch (HttpRequestException e)
{
Debug.LogError($"Request error: {e.Message}");
statusText.text = $"Request error: {e.Message}";
}
await Cooldown(2);
statusText.text = "Ready for next command.";
}
IEnumerator ResetCancelConfirmation()
{
yield return new WaitForSeconds(5);
confirmCancel = false;
confirmationText.text = ""; // Clear the confirmation text after 5 seconds
}
async Task Cooldown(int seconds)
{
for (int i = seconds; i > 0; i--)
{
statusText.text = $"Cooldown: {i} seconds";
await Task.Delay(1000);
}
}
void OnDestroy()
{
if (client != null)
{
client.Dispose();
}
}
}
[System.Serializable]
public class CommandPayload
{
public string command;
}
I have two versions of this script for the printers (plan to merge them once fixed). This code works perfectly for the home command but others have issue (the up button for the y axis doesnt work, most buttons only respond to one press, the second press is ignored only by the actual printers movement, and the z axis will move until it hits the bed).
Maybe I am misunderstanding something. First turn on the serial logging. I want to see what you are sending to the printer and what is sends back. Next... so you are making a VR UI for OctoPrint? And not a VR printer?
serial.log (20.6 KB)
It's a digital twin of the printer (so more so a VR UI for the printer, it just displays what's happening in the VR headspace as well.)