user84328: I'm kind of new to Arduino and C, and I was having trouble with this sketch. I'm working on a project to control 6 servos using virtual buttons. When I hold down the button, the servo moves forward smoothly to a certain fixed point, and when I release it, it comes back to a fixed point. I initially tested this with a single servo and an actual button on my breadboard using the following sketch.
#include<Servo.h>
int switch1;
float switch1Smoothed;
float switch1Prev;
Servo myservo1;
float a=1200.0; //lower angle limit

void setup() {

  Serial.begin(115200);
  pinMode(A1,INPUT_PULLUP);
  myservo1.attach(9);
  myservo1.writeMicroseconds(a);
  switch1Prev=a;
}

void loop() {
//Motor 1
  switch1 = digitalRead(A1);// read switch | will return 1 or 0 continuously
  //Serial.println(switch1);
  switch1 = switch1 * 2400;        // multiply by angle limit

  // *** smoothing ***

  switch1Smoothed = (switch1 * 0.05) + (switch1Prev * 0.95);
  if(switch1Smoothed>=a){
  switch1Prev = switch1Smoothed;
  }
  else{
    switch1Prev = a;
  }
  // *** end of smoothing ***

//  Serial.print(switch1);                  // print to serial terminal/plotter
//  Serial.print(" , ");   
//  Serial.println(switch1Smoothed);
    myservo1.writeMicroseconds(switch1Smoothed) ;
    delay(10);                               // repeat loop 100 times per second
}

This works out just fine. Now, I'm working with NodeRed, a low code JavaScript flow creator, which is where my virtual button is, and I've set it up to send 0s or 1s as strings based on whether the button is pressed or not via serial communication. This is the config of the Serial Node on NodeRed:

And I wrote a short function on Arduino to parse the incoming string from the serial connection, convert it back to an integer, and then use that as my "button" input. However, it seems that either my logic is flawed, or my code is because my servo does not behave the same way it does with the physical button.
Here's the modified sketch:
#include <Servo.h> 
int switch1;
float switch1Smoothed;
float switch1Prev;
Servo myservo1;
float a=1200.0;
String readString, mot1, mot2;

void setup() {
  Serial.begin(9600);
  myservo1.attach(9);
  myservo1.writeMicroseconds(a);
  switch1Prev=a;
}

void captureChar(int& n1){ //using reference to pass the value

  while (Serial.available()) {
    delay(3);  //delay to allow buffer to fill 
    if (Serial.available() >0) {
      char c = Serial.read();  //gets one byte from serial buffer
      readString += c; //makes the string readString
    } 
  }

  if (readString.length() >0) {

      
    
      mot1 = readString.substring(0,1); 
      mot2 = readString.substring(1,2); 
      n1 = mot1.toInt();
      //n2 = mot2.toInt();
    readString="";
    
  } 
}

void loop(){
  captureChar(switch1);
  switch1 = switch1 * 2400;        // multiply by maximum angle limit

  // *** smoothing ***

  switch1Smoothed = (switch1 * 0.05) + (switch1Prev * 0.95);
  if(switch1Smoothed>=a){
  switch1Prev = switch1Smoothed;
  }
  else{
    switch1Prev = a;
  }
  // *** end of smoothing ***

//  Serial.print(switch1);                  // print to serial terminal/plotter
//  Serial.print(" , ");   
//  Serial.println(switch1Smoothed);
  myservo1.writeMicroseconds(switch1Smoothed);
  delay(15);
}


When I load this sketch and hold down the virtual button, i.e., send a continuous stream of string "1", the motor simply goes back and forth really fast, rather than slowly moving to the set maximum position and stopping there while the button is held.

user7508: There may be a problem with your smoothing logic, which is quite
convoluted. However, if the first code works fine, you can keep it
almost as-is, and only replace digitalRead() with a version that
reads the virtual button. It looks like that is what captureChar()
attempts to achieve. This function, however, has a couple of problems:

it has a loop and a delay, thus breaking the timing of the original
code
its interface is very different from the one of digitalRead(), and
thus cannot be used as a drop-in replacement.

Here is what I would propose as a digitalRead() replacement. It has
the same signature as the original digitalRead(), and can be used as a
drop-in replacement:
int virtual_switch_reading = LOW;

int virtualDigitalRead(uint8_t /* pin number ignored */) {
    int c = Serial.read();
    if (c == '0')
        virtual_switch_reading = LOW;
    else if (c == '1')
        virtual_switch_reading = HIGH;
    return virtual_switch_reading;
}

Note that calling Serial.available() is not useful: if no data is
available, Serial.read() returns -1, which is neither equal to '0'
nor equal to '1'.

Edit: addressing the requirement to have six virtual switches.
As stated in a comment, I suggest you encode the states of all the
switches, within NodeRed, as a single byte, with one bit per switch. You
would then send this byte to the Arduino, either periodically or
whenever any switch changes state.
On the Arduino, in order to simulate digitalRead() on a virtual
switch, you first have to map the pin numbers to the virtual switches:
// Map a pin number to a virtual switch.
const uint8_t virtual_switch_masks[NUM_DIGITAL_PINS] = {
    0,     // pin 0: not virtual
    0,     // pin 1: not virtual
    1<<0,  // pin 2: virtual switch 0
    1<<1,  // pin 3: virtual switch 1
    // etc...
};

Note that this table doesn't store switch numbers. It instead stores
bit masks. For example, virtual switch 1 is stored as 1<<1 =
0b00000010, i.e. all bits are clear except for bit number 1 (rightmost
being zero), which is set.
You can then simulate digitalRead() by extracting the relevant bit
from the byte you last received from NodeRed, which is done by a
bitwise and with the relevant mask:
// States of all virtual switches, one bit per switch.
uint8_t virtual_switch_states = 0;

int virtualDigitalRead(uint8_t pin) {
    uint8_t mask = virtual_switch_masks[pin];

    // If this is not a virtual switch, do a regular digitalRead().
    if (!mask)
        return digitalRead(pin);

    // For a virtual switch, extract the relevant bit
    // from virtual_switch_states.
    if (virtual_switch_states & mask)
        return HIGH;
    else
        return LOW;
}

In order to update the states of the virtual switches from the data
received, you just have to add this somewhere within loop():
if (Serial.available())
    virtual_switch_states = Serial.read();


84328: <p>I'm kind of new to Arduino and C, and I was having trouble with this sketch. I'm working on a project to control 6 servos using virtual buttons. When I hold down the button, the servo moves forward smoothly to a certain fixed point, and when I release it, it comes back to a fixed point. I initially tested this with a single servo and an actual button on my breadboard using the following sketch.</p>
<pre><code>#include&lt;Servo.h&gt;
int switch1;
float switch1Smoothed;
float switch1Prev;
Servo myservo1;
float a=1200.0; //lower angle limit

void setup() {

  Serial.begin(115200);
  pinMode(A1,INPUT_PULLUP);
  myservo1.attach(9);
  myservo1.writeMicroseconds(a);
  switch1Prev=a;
}

void loop() {
//Motor 1
  switch1 = digitalRead(A1);// read switch | will return 1 or 0 continuously
  //Serial.println(switch1);
  switch1 = switch1 * 2400;        // multiply by angle limit

  // *** smoothing ***

  switch1Smoothed = (switch1 * 0.05) + (switch1Prev * 0.95);
  if(switch1Smoothed&gt;=a){
  switch1Prev = switch1Smoothed;
  }
  else{
    switch1Prev = a;
  }
  // *** end of smoothing ***

//  Serial.print(switch1);                  // print to serial terminal/plotter
//  Serial.print(&quot; , &quot;);   
//  Serial.println(switch1Smoothed);
    myservo1.writeMicroseconds(switch1Smoothed) ;
    delay(10);                               // repeat loop 100 times per second
}
</code></pre>
<p>This works out just fine. Now, I'm working with NodeRed, a low code JavaScript flow creator, which is where my virtual button is, and I've set it up to send 0s or 1s as strings based on whether the button is pressed or not via serial communication. This is the config of the Serial Node on NodeRed:</p>
<p><a href="https://i.stack.imgur.com/L51g1.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/L51g1.png" alt="Serial Port Config on NodeRed" /></a></p>
<p>And I wrote a short function on Arduino to parse the incoming string from the serial connection, convert it back to an integer, and then use that as my &quot;button&quot; input. However, it seems that either my logic is flawed, or my code is because my servo does not behave the same way it does with the physical button.</p>
<p>Here's the modified sketch:</p>
<pre><code>#include &lt;Servo.h&gt; 
int switch1;
float switch1Smoothed;
float switch1Prev;
Servo myservo1;
float a=1200.0;
String readString, mot1, mot2;

void setup() {
  Serial.begin(9600);
  myservo1.attach(9);
  myservo1.writeMicroseconds(a);
  switch1Prev=a;
}

void captureChar(int&amp; n1){ //using reference to pass the value

  while (Serial.available()) {
    delay(3);  //delay to allow buffer to fill 
    if (Serial.available() &gt;0) {
      char c = Serial.read();  //gets one byte from serial buffer
      readString += c; //makes the string readString
    } 
  }

  if (readString.length() &gt;0) {

      
    
      mot1 = readString.substring(0,1); 
      mot2 = readString.substring(1,2); 
      n1 = mot1.toInt();
      //n2 = mot2.toInt();
    readString=&quot;&quot;;
    
  } 
}

void loop(){
  captureChar(switch1);
  switch1 = switch1 * 2400;        // multiply by maximum angle limit

  // *** smoothing ***

  switch1Smoothed = (switch1 * 0.05) + (switch1Prev * 0.95);
  if(switch1Smoothed&gt;=a){
  switch1Prev = switch1Smoothed;
  }
  else{
    switch1Prev = a;
  }
  // *** end of smoothing ***

//  Serial.print(switch1);                  // print to serial terminal/plotter
//  Serial.print(&quot; , &quot;);   
//  Serial.println(switch1Smoothed);
  myservo1.writeMicroseconds(switch1Smoothed);
  delay(15);
}

</code></pre>
<p>When I load this sketch and hold down the virtual button, i.e., send a continuous stream of string &quot;1&quot;, the motor simply goes back and forth really fast, rather than slowly moving to the set maximum position and stopping there while the button is held.</p>
 7508: <p>There may be a problem with your smoothing logic, which is quite
convoluted. However, if the first code works fine, you can keep it
<em>almost</em> as-is, and only replace <code>digitalRead()</code> with a version that
reads the virtual button. It looks like that is what <code>captureChar()</code>
attempts to achieve. This function, however, has a couple of problems:</p>
<ul>
<li>it has a loop and a delay, thus breaking the timing of the original
code</li>
<li>its interface is very different from the one of <code>digitalRead()</code>, and
thus cannot be used as a drop-in replacement.</li>
</ul>
<p>Here is what I would propose as a <code>digitalRead()</code> replacement. It has
the same signature as the original <code>digitalRead()</code>, and can be used as a
drop-in replacement:</p>
<pre class="lang-cpp prettyprint-override"><code>int virtual_switch_reading = LOW;

int virtualDigitalRead(uint8_t /* pin number ignored */) {
    int c = Serial.read();
    if (c == '0')
        virtual_switch_reading = LOW;
    else if (c == '1')
        virtual_switch_reading = HIGH;
    return virtual_switch_reading;
}
</code></pre>
<p>Note that calling <code>Serial.available()</code> is not useful: if no data is
available, <code>Serial.read()</code> returns <code>-1</code>, which is neither equal to <code>'0'</code>
nor equal to <code>'1'</code>.</p>
<hr />
<p><strong>Edit</strong>: addressing the requirement to have six virtual switches.</p>
<p>As stated in a comment, I suggest you encode the states of all the
switches, within NodeRed, as a single byte, with one bit per switch. You
would then send this byte to the Arduino, either periodically or
whenever any switch changes state.</p>
<p>On the Arduino, in order to simulate <code>digitalRead()</code> on a virtual
switch, you first have to map the pin numbers to the virtual switches:</p>
<pre class="lang-cpp prettyprint-override"><code>// Map a pin number to a virtual switch.
const uint8_t virtual_switch_masks[NUM_DIGITAL_PINS] = {
    0,     // pin 0: not virtual
    0,     // pin 1: not virtual
    1&lt;&lt;0,  // pin 2: virtual switch 0
    1&lt;&lt;1,  // pin 3: virtual switch 1
    // etc...
};
</code></pre>
<p>Note that this table doesn't store switch numbers. It instead stores
<em>bit masks</em>. For example, virtual switch 1 is stored as <code>1&lt;&lt;1</code> =
<code>0b00000010</code>, i.e. all bits are clear except for bit number 1 (rightmost
being zero), which is set.</p>
<p>You can then simulate <code>digitalRead()</code> by extracting the relevant bit
from the byte you last received from NodeRed, which is done by a
<em>bitwise and</em> with the relevant mask:</p>
<pre class="lang-cpp prettyprint-override"><code>// States of all virtual switches, one bit per switch.
uint8_t virtual_switch_states = 0;

int virtualDigitalRead(uint8_t pin) {
    uint8_t mask = virtual_switch_masks[pin];

    // If this is not a virtual switch, do a regular digitalRead().
    if (!mask)
        return digitalRead(pin);

    // For a virtual switch, extract the relevant bit
    // from virtual_switch_states.
    if (virtual_switch_states &amp; mask)
        return HIGH;
    else
        return LOW;
}
</code></pre>
<p>In order to update the states of the virtual switches from the data
received, you just have to add this somewhere within <code>loop()</code>:</p>
<pre class="lang-cpp prettyprint-override"><code>if (Serial.available())
    virtual_switch_states = Serial.read();
</code></pre>
