Arduino sending trigger to Nano

So i have connected Nano to the maestro from the tx of nano to the rx cable. I have given them common ground and powersupply with help of breadboard and micro usb board.

In arduino ide, I have written a code that can send the trigger of 0x55:

void setup() {
 // put your setup code here, to run once:
 Serial.begin(9600); // Use the same baud rate as set in the Maestro.
}

void loop() {
 // put your main code here, to run repeatedly:
 Serial.write(0x55); // Example trigger command (adjust as needed).
 delay(20000); // Delay between triggers.
}

In pololu c# code, I have written

public MainWindow()
        {
            InitializeComponent();
            OneDegreeInMicroSec = 11.11;

            InitializeSerialPort(); // Initialize your serial port settings
            AttachDataReceivedHandler();
        }

private void InitializeSerialPort()
        {
            mySerialPort = new SerialPort("COM8");

            mySerialPort.BaudRate = 9600;
            mySerialPort.Parity = Parity.None;
            mySerialPort.StopBits = StopBits.One;
            mySerialPort.DataBits = 8;
            mySerialPort.Handshake = Handshake.None;
            mySerialPort.RtsEnable = true;
            // Initialize the receive buffer
            receiveBuffer = new byte[1024];

            try
            {
                mySerialPort.Open();
                MessageBox.Show("Serial port opened successfully.");
            }
            catch (UnauthorizedAccessException ex)
            {
                MessageBox.Show("Unauthorized access to the serial port. Check if the port is already in use by another application.");
            }
            catch (IOException ex)
            {
                MessageBox.Show("An I/O error occurred while opening the serial port.");
            }
            catch (ArgumentException ex)
            {
                MessageBox.Show("Invalid serial port settings or name.");
            }
        }

        private void AttachDataReceivedHandler()
        {
            mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
        }

        private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
        {
            SerialPort sp = (SerialPort)sender;
            byte[] buffer = new byte[sp.BytesToRead];
            sp.Read(buffer, 0, buffer.Length);

            // Debug: Print received data as hexadecimal
            string receivedDataHex = BitConverter.ToString(buffer);
            MessageBox.Show("Received Data: " + receivedDataHex);

            // Check if the received data contains a trigger condition
            if (ContainsByte(buffer, 0x55) && mySerialPort.IsOpen)
            {
                // Raise the TriggerReceived event
                OnTriggerReceived();
                MessageBox.Show("Trigger received!");
            }
        }

        private bool ContainsByte(byte[] array, byte value)
        {
            foreach (byte b in array)
            {
                if (b == value)
                {
                    return true;
                }
            }
            return false;
        }

        

        protected virtual void OnTriggerReceived()
        {
            // Check if the event has subscribers (is not null)
            if (TriggerReceived != null)
            {
                TriggerReceived?.Invoke(this, EventArgs.Empty);
                MessageBox.Show("Trigger received!");
            }

            // Optionally, display a message regardless of whether there are subscribers
            MessageBox.Show("Trigger not received!");
        }
private void UpdateTimer_Tick(object sender, EventArgs e)
        {
            if (usc == null)
            {
                // Try connecting to a device.
                try
                {
                    TryToReconnect();
                    OnTriggerReceived();
                }
                catch (Exception e2)
                {
                    Log(e2);
                    Log("Failed connecting to #" + SerialNumberTextBox.Text + ".");
                    usc = null;
                }
            }
            else
            {
                // Update the GUI and the device.
                try
                {
                    DisplayPosition();
                    OnTriggerReceived();
                }
                catch (Exception e2)
                {
                    // If any exception occurs, log it, set usc to null, and keep trying..
                    Log(e2);
                    Log("Disconnected from #" + SerialNumberTextBox.Text + ".");
                    usc = null;
                }
            }
        }

and it keeps saying trigger not recieved. Com10 is TTL port and com 8 is command port of maestro. Please let me know how I can improve my c# code to recieve the trigger from arduino nano

Hello.

It is not entirely obvious to me what youā€™re trying to do, but from a brief look through your code, it looks like youā€™re trying to pass a special byte (0x55) through the Maestro to your computer, which can then use it as a trigger to do something.

What serial mode do you have the Maestro set to?

To help troubleshoot, you might try simplifying your code so it just prints out any bytes it receives instead of only looking for a specific one. That could help determine whether there is an issue with the connections or code/logic.

If you continue having trouble after that, could you post an updated version of your code as well as a copy of your Maestro settings file? You can save a copy of your Maestro settings file from the ā€œFileā€ drop-down menu of the Maestro Control Center while the controller is connected.

Brandon

to your question: ā€œWhat serial mode do you have the Maestro set to?ā€

I have tried it with both com 8 and com 10, so I am not sure which one I need to use to get a trigger from nano.

I have modified the code in a way that it recieves the bytes and displays it in the textbox, after i click the connect button and click on start trigger button.

using Pololu.Usc;
using Pololu.UsbWrapper;

using System.IO.Ports;
using System.Windows;
using System.IO;

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Windows.Forms;

namespace Pololu.Usc.MaestroEasyExample
{
    public partial class MainWindow : Form
    {
        private SerialPort serialPort;

        public MainWindow()
        {
            InitializeComponent();

            InitializeSerialPort(); // Initialize your serial port settings
           // AttachDataReceivedHandler();
        }

        #region events

 private void MainWindow_Shown(object sender, EventArgs e)
        {
            var device_list = Usc.getConnectedDevices();
            if (device_list.Count > 0)
            {
                // Clear any previous information in the SerialNumberTextBox
                SerialNumberTextBox.Text = "";

                // Iterate through the connected devices and display their serial numbers
                for (int i = 0; i < Math.Min(device_list.Count, 3); i++)
                {
                    SerialNumberTextBox.Text =  device_list[i].serialNumber;
                }


                ConnectButton.Focus();
            }
            else
            {
                SerialNumberTextBox.Focus();
            }
        }

private void ConnectButton_Click(object sender, EventArgs e)
        {
            SerialNumberTextBox.Enabled = false;
            Log("Connecting...");
            UpdateTimer.Start();
            StopConnectingButton.Enabled = true;
            ConnectButton.Enabled = false;
        }

        private void StopConnectingButton_Click(object sender, EventArgs e)
        {
            SerialNumberTextBox.Enabled = true;
            TryToDisconnect();
            UpdateTimer.Stop();
            StopConnectingButton.Enabled = false;
            ConnectButton.Enabled = true;
        }
        #endregion

        #region logging
        private void Log(Exception e)
        {
            Log(e.Message);
        }

        private void Log(string text)
        {
            if (LogTextBox.Text != "")
                LogTextBox.Text += Environment.NewLine;
            LogTextBox.Text += DateTime.Now.ToString() + "\t" + text;
            LogTextBox.SelectionStart = LogTextBox.Text.Length;
            LogTextBox.ScrollToCaret();
        }
        #endregion

#region the Maestro connection

        private Usc usc = null;

        /// <summary>
        /// Connects to the device if it is found in the device list.
        /// </summary>
        ///

        private void TryToReconnect()
        {
            foreach (DeviceListItem d in Usc.getConnectedDevices())
            {
                if (d.serialNumber == SerialNumberTextBox.Text)
                {
                    usc = new Usc(d);
                    Log("Connected to #" + SerialNumberTextBox.Text + ".");
                    return;
                }
            }
        }

        private void TryToDisconnect()
        {
            if (usc == null)
            {
                Log("Connecting stopped.");
                return;
            }

            try
            {
                Log("Disconnecting...");
                usc.Dispose();  // Disconnect
            }
            catch (Exception e)
            {
                Log(e);
                Log("Failed to disconnect cleanly.");
            }
            finally
            {
                // do this no matter what
                usc = null;
                Log("Disconnected from #" + SerialNumberTextBox.Text + ".");
            }
        }

        #endregion

private void InitializeSerialPort()
        {
            // Create a new SerialPort instance and configure it according to your Maestro's settings.
            serialPort = new SerialPort();
            serialPort.PortName = "COM8"; // Replace with your Maestro's COM port.
            serialPort.BaudRate = 9600;   // Adjust to match your Maestro's baud rate.

            try
            {
                serialPort.Open();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error opening serial port: " + ex.Message);
            }
        }



        private void ReceiveTriggerData()
        {
            try
            {
                // Check if there is data available to read from the serial port.
                if (serialPort.BytesToRead > 0)
                {
                    int bytesRead = serialPort.BytesToRead;
                    byte[] buffer = new byte[bytesRead];

                    // Read the data from the serial port into the buffer.
                    serialPort.Read(buffer, 0, bytesRead);

                    // Now you have received data in the 'buffer' array.
                    // You can process it according to your Maestro's data format.

                    // Example: Convert the received bytes to a string and display it in a TextBox.
                    string receivedData = Encoding.ASCII.GetString(buffer);
                    textBoxReceivedData.AppendText(receivedData + Environment.NewLine);

                    // Example: Parse the received data as an integer (assuming it's an integer).
                    // int triggerValue = int.Parse(receivedData);

                    // Now you can further process 'receivedData' or 'triggerValue' as needed.
                }
            }
            catch (Exception ex)
            {
                // Handle any exceptions that might occur during data reception.
                Log("Error receiving trigger data: " + ex.Message);
            }
        }

        private void Start_Click(object sender, EventArgs e)
        {
            if (usc != null)
            {
                ReceiveTriggerData();
            }
        }



        #region updating

        /// <summary>
        /// This function will be called once every 100 ms to do an update.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void UpdateTimer_Tick(object sender, EventArgs e)
        {
            if (usc == null)
            {

                // Try connecting to a device.
                try
                {
                    TryToReconnect();
                   // SendTrigger();
                }
                catch (Exception e2)
                {
                    Log(e2);
                    Log("Failed connecting to #" + SerialNumberTextBox.Text + ".");
                    usc = null;
                }
            }
            else
            {
                // Update the GUI and the device.
                try
                {
                    ReceiveTriggerData();
                }
                catch (Exception e2)
                {
                    // If any exception occurs, log it, set usc to null, and keep trying..
                    Log(e2);
                    Log("Disconnected from #" + SerialNumberTextBox.Text + ".");
                    usc = null;
                }
            }
        }

        #endregion

    }
}

but somehow I am not sure if this is the right way of programming to recieve a trigger. Or maybe the trigger is not being recieved. This is how my hardware set up is:

Hello.

To clarify, Iā€™m not asking which COM port you are connecting to; Iā€™m asking what serial mode you have the Maestro configured in. You can configure the serial mode from the ā€œSerial Settingsā€ tab of the Maestro Control Center, and you can find a description of the available serial modes in the ā€œSerial Settingsā€ section of the Maestro userā€™s guide. From your description of your setup, I suspect you want to use the USB Dual Port mode and use COM10 (the serial port).

Brandon

I tried a few iterations having USB Dual Port, with com 8 and com 10 and UART fixed baud rate 9600 with both com 8 and com 10. But it did not seem to detect the trigger.

I agree with you, I want to use tx-rx pins to recieve the trigger in maestro, hence using com 10(TTL port) is better.

Just to double check my understanding, it sounds like you are basically just using the Maestro as a USB-to-serial adapter right now; is that correct? If so, is there a particular reason you want to do that instead of using the Arduino Nano Everyā€™s built-in USB functionality?

If you do want to continue using it as a USB-to-serial adapter, any of the Maestroā€™s serial modes should work. You will just need to make sure to use the TTL port if youā€™re using USB Dual Port mode or the Command port if it is in any of the other serial modes. However, Serial on the Arduino Nano Every seems to refer to its USB Serial port, so I suspect you should be using Serial1 to use the UART in your Arduino program. You can use a scope to confirm that you see the signal on the Arduinoā€™s TX connection to the Maestroā€™s RX pin.

For confirming that the Maestro is properly passing on the data, you can try connecting to the appropriate COM port with a serial terminal program, such as the Arduino IDEā€™s Serial Monitor, Tera Term, or PuTTY. (Please note that 0x55 is ā€˜Uā€™ in ASCII so you should probably see a slow sequence of ā€˜Uā€™ if itā€™s working.)

There are some parts of your C# program that look suspect, but unfortunately the engineer most familiar with C# and the Pololu USB SDK is out right now and wonā€™t be back until next week. However, checking that everything else is working separately is a good start.

Brandon

Yes Iā€™d like to it use Maestro as a USB to serial adapter. Iā€™d like to program the maestro to perform certain actions every time it receives a trigger. First I am checking with Arduino nanoto recieve trigger, after it works successfully, Iā€™d replace nano with another controller used my institute.

Great news, I recieved the trigger. You were right about using Serial1 instead of Serial to use the UART in my arduino program. Thanks a lot for resolving my issue.

1 Like

Another question: When I am sending an external trigger to the Mini Maestro 12, does it detect this trigger at its rising/falling-edge/level?

It is still not entirely clear to me what you are doing. The Maestro does not have an automated trigger feature. There are a few different ways you could set it up to start a sequence of movements from an external signal. For example, you could write a script that monitors the input channel and waits for it to go low or high before moving on. Alternatively, you could set up your script with subroutines and use the ā€œRestart Script at Subroutineā€ command to run them.

If you still arenā€™t sure how to proceed, please tell me more about what you are trying to do, and I might be able to offer some more specific advice.

Brandon

Yes I am performing certain actions to the motors, whenever an external signal (which acts as a trigger from nano in this case) arrives. My question was, when the external signal arrives through TTL, does it act on the rising edge of this external trigger signal?

The Maestro uses a non-inverted TTL serial line, which has a default (non-active) state of high and is registered as active when itā€™s low. The data format is 8 data bits, one stop bit, with no parity (often expressed as 8-N-1). You can find more information in the ā€œTTL Serialā€ section of the Maestro userā€™s guide.

Brandon

Got it, the TTL serial line is registered as active when itā€™s low, which implies it responds to a low voltage level. Therefore, the Maestro responds to the falling level, by default setting.