2

New to arduino here, sorry for asking what may be a trivial question.

I need to simulate an industrial machine at home. It operates in a cyclic motion, creating an event for every rotation / cycle. Imagine a turntable or wheel with a marker in one place.

What I would like is:

  • Have a physical wheel which I turn one rotation every 300 msec. This is the length in time of a cycle.
  • Read a marker on this wheel using a sensor, such as Sick or Omron. I have this already. Sensor can be PNP or NPN, providing a closed or open connection. I can go via an optocoupler if needed.
  • Once a signal is seen, the arduino should send a (sequential) string using RS232 to a PC. Approximately 90 characters. It is not needed to wait for response.

My question is: would be time for arduino to do this be relatively constant - ie, send out the data at approximately same point in the cycle. Example: signal read at "12" on the clock, data sent around "5".

If possible, what sort of Arduino would I be looking at ?

Or do I need something more real-time for such project, like a PLC ?

2
  • 1
    You are asking for two different things: latency of your system and the jitter
    – chrisl
    Oct 19, 2022 at 15:57
  • 1
    You’re talking about responding to a an approximately 3.33Hz signal that you can monitor with a simple edge-triggered interrupt using a microcontroller running at almost six million times that frequency. You should be perfectly fine, even factoring in the few hundred instructions to send the serial data. Oct 20, 2022 at 12:47

2 Answers 2

7

one rotation every 300 msec.

300 ms is a very long time for an Arduino, even for an AVR-based one, like an Uno.

I did a little experiment. I generated (with an Arduino...) a periodic signal consisting of a 96 µs-wide negative pulse repeating every 300 ms. I sent that signal to an Arduino Uno running the following code:

const uint8_t sensor_pin = 3;

// 90-byte message.
const char message[] = "Korem ipsum dolor sit amet, consectetur "
        "adipiscing elit sed do eiusmod tempor incididunt\r\n";

void setup() {
    pinMode(sensor_pin, INPUT_PULLUP);
    Serial.begin(9600);
}

void loop() {
    if (digitalRead(sensor_pin) == LOW) {
        Serial.write(message);

        // Wait until the signal rises again.
        while (digitalRead(sensor_pin) == LOW)
            continue;
    }
}

This is not the nicest way to do edge detection, but for this simple test it will do. You may notice that I am not using interrupts for capturing the pulse: 96 µs is long enough to be captured with this simple digitalRead(). I then captured the input and output signals with a dual-channel pocket oscilloscope. Here is a screen capture:

Oscilloscope screen capture

The cyan trace at the top is the received pulse. The yellow trace below is the output of the serial port. The negative pulse on this trace that is almost coincident with the received pulse is the start bit. Then the signal rises to transmit the first data bit, which is a 1 (that's why I chose “K” rather than “L” as the first letter).

What you can see in this capture is that the latency of the Arduino is tiny at this scale: a small fraction of the duration of the start bit. What you cannot see is the jitter, which is quite large in relative terms, but still small compared to the time scales relevant to you. In short, the delay between the falling edge on the input and the falling edge of the serial port start bit fluctuates roughly between 10 and 20 µs. Yes, those are microseconds. This delay is roughly 20,000 times shorter than the rotation period. If the signal is read at “12” on the clock, the start bit fires at 12 hours with 0 minutes and 2 seconds.

Note that, on the other hand, the time needed to send the message at 9600 b/s is 93.6 ms, a significant fraction of the rotation period. And I didn't look at the behavior of the USB-to-serial converter chip, which is another can of worms...

11
  • There's no reason why the serial port speed can't be increased. I'm always using 115200 as baud rate, and never had any problems.
    – PMF
    Oct 20, 2022 at 9:26
  • 2
    @PMF: The OP has a very good reason to not increase the serial port speed: he wants to simulate an industrial device that speaks at 9600 b/s. Oct 20, 2022 at 9:36
  • 1
    @MarkMorganLloyd: The output buffer of the chip in question is one byte deep. Two bytes if you count the shift register holding the remaining bits of the byte being transmitted. And yet, the code I posted has no issues reliably sending the whole message: Serial.write() is smarter than you think. There is no risk of overrun as long as the input pulses are spaced more than 93.6 ms apart, and they only come every 300 ms. Oct 20, 2022 at 12:48
  • 1
    @MarkMorganLloyd: My point is, even with this 64-byte internal buffer, Serial.write() reliably sends a 90-byte string if asked to. Oct 20, 2022 at 18:02
  • 1
    @MarkMorganLloyd: Re “Not in all cases in my experience”: If Serial.write() does not send reliably 90 bytes when asked to, you have a bug in your code. Probably one that is corrupting memory. Re “if the ISR is still clearing the buffer..”: In this case, a new message is due while the previous one has not been sent completely. Of course there will be extra jitter! There is no way around this. Fortunately for the OP, the messages take 93.6 ms to send and are sent every 300 ms. Oct 20, 2022 at 18:44
2

TLDR: any Arduino is probably sufficient for your purpose when done properly.

I'll assume a proper HIGH/LOW binary signal from the sensor, HIGH when it "sees" the marker, LOW when it doesn't.

What could go wrong?

  1. You use digitalRead() to get the state of the digital input. Depending on the pulse width, you might not catch the high state. Use interrupts instead.
  2. Sending the data over Serial port takes longer than a turn of the machine. 90 bytes at 9600 bit/s needs (90 bytes * 10 bits/byte / (9600 kbit/s) = 93ms. In 300ms, there's enough time to send the 90 bytes. And 9600 bit/s is quite slow: you can probably use 115200 bit/s on short or shielded wires.
  3. "Approximately 90 characters": calculate everything for the maximum data that will eventually be sent
  4. Getting the data on Arduino side takes too long. You didn't give details on where those 90 bytes come from. Asking 90 devices to each give you a byte of data might not be possible in 300ms.
  5. Receiving the data on the PC side (or whatever) might be delayed, because it is buffered. Especially USB to Serial adapters have no guaranteed timing. Doing the math for USB devices is hard.
  6. Threading on the PC side: due to the OS Thread scheduling, the application that shall receive the data might not get CPU time for several milliseconds, 16ms (1/64s) is quite common. Doing the math is impossible (try running 8 real time threads that do something else and your PC is basically frozen)
  7. Processing on the PC side: unknown
  8. Displaying: after processing until a signal is displayed on the screen, that may take another 16 ms (at 60 Hz refresh rate).

would be time for Arduino to do this be relatively constant

Relatively: yes. It certainly depends on the implementation (the Arduino C++ code).

If the data to send is hard coded 90 characters, I would expect the complete signal has been sent at before the 4 o'clock mark (94ms /300ms * 12 hours ~ 3 hours) . I see the problem more on the receiving side (see points 5., 6., 7. and 8.).

what sort of Arduino would I be looking at ?

I don't know all of them, but an Uno will certainly work. If you only have that one digital input, even smaller ones are probably ok. Just start with an Uno or what you have available and see how it goes.

do I need something more real-time for such project, like a PLC?

I don't see a need for a PLC in your project.

6
  • Your answer is also useful, but I had to accept the other once for providing exact measurements. As this would just be a simulation the 90 characters would be just fixed text and an increasing counter, so no delay getting input from anywhere. The receiving end is well capable of handling the input. Unfortunately switching to 115k is not possible due to the actual machine being simulated.
    – MyICQ
    Oct 20, 2022 at 7:00
  • @MyICQ: accepting the other answer is ok. I am not overly happy with the digitalRead() decision of that answer - probably because I had too many issues with digitalRead() not working reliably enough in my projects. Anyway, if the suggested code is roughly what you need, that's a fine answer. Oct 20, 2022 at 7:23
  • What would be the alternative to digitalRead() ? I am new to Arduino, and somehow the event of sending serial string should be triggered ?
    – MyICQ
    Oct 20, 2022 at 7:32
  • @MyICQ: note that I accidentally calculated with kbits/s instead of bit/s, so I was off by a factor of 1000. OMG! See the new calculation. The whole data is sent at around the 3 o'clock mark Oct 20, 2022 at 7:33
  • 2
    1. I am not a huge fan of digitalRead() either, but it has the benefit of simplicity, and it is newbie-friendly. If the stuff was really time-critical, I would use interrupts. With care, because printing to Serial from interrupt context has its issues. 2. 90 bytes at 9600/8N1 should take 93.75 ms (do not forget the start and stop bits). At the Arduino-rounded “9600 bps” speed it takes 93.6 ms. Oct 20, 2022 at 7:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.