Function not working when hardcoding instead of using input()

Question:

I’m working with Python on my PC, sending serial commands to an arduino which controls a certain number of stepper motors.
However, in this function:

# takes array of commands to send to motors (in order) and sends commmand arcodinlgy
# each element of commands is an absolute angle (rad) to give to one motor
def send_command(commands):
    if not len(commands) > 0:
        return

    # make command string to send serial
    # (with command separator and line termination)
    command_string = "";
    for i in range(len(commands) - 1):
        command_string += f"{commands[i]:.4f}{COMMAND_SEPARATOR}"
    command_string += f"{commands[-1]:.4f}{LINE_TERMINATOR}"
    # make command string into bytes UTF-8
    # print(command_string)
    command_string = bytes(command_string, "utf-8")

    # send command string serial
    print(f"Sending command: " + str(command_string))
    port.write(command_string)
    # wait for arduino's return_code on serial
    while True:
        if port.inWaiting() > 0:
            return_code = int(port.readline())
            return return_code

# driving code
while True:
    commands = [0, 0]
    commands[0] = float(input("command 1: "))
    commands[1] = float(input("command 2: "))
    return_code = send_command(commands)
    print(f"return code: {return_code}")

This code works correctly, but if I don’t want user input for the commands :

while True:
    commands = [float(random.random()*pi), float(random.random()*pi)]
    # or even the following doesn't work for exemple:
    # commands = [3.1415, 0.5555]
    return_code = send_command(commands)
    print(f"return code: {return_code}")
    sleep(1)

This code doesn’t.
I don’t get why because in the first case, the line print(f"Sending command: " + str(command_string)) prints exactly the same as in the second case :

Sending command: b'3.1415:0.5555n'

(when input those angles)
But in the second case, no return code is received, and the function doesn’t work.

I tried totally hardcoding the values given.
I implemented that the commands are always formated the same way, and always converted with float() (before the print("Serial command... line.
So I expected the same behavior for the two codes, and I don’t see what changes between the two (since the print("Serial command ... line gives the same and is the last line before the command is sent over serial

Thanks !

Asked By: Stijn B

||

Answers:

Try to add logging to receiving part.

Replace this:

while True:
    if port.inWaiting() > 0:
        return_code = int(port.readline())
        return return_code

With this:

import time
while True:
    if port.inWaiting() > 0:
        print(f"Received {port.inWaiting()} bytes.")
        return_code = int(port.readline())
        return return_code
    print("Nothing received yet.")
    time.sleep(0.1)

Maybe your Arduino does not response for request, and you just waiting for the response in infinite loop.

You can also add timeout for response, so after some time if there was no response method send_command(commands) will just return None.

Answered By: Ivan Perehiniak

Found the problem :

After every new serial connection, the Arduino resets.
When it resets, it need a little time to start the loop() function !

So when I was entering my commands manually, I gave it a little time without noticing, but when the commands were generated inside my Python code, the first command was sent so quickly that it wasn’t interpreted by the Arduino, and the function didn’t get a return code from the Arduino !

2 ways to solve the problem:

1. Adding a timeout

TIMEOUT = 2
TIMEOUT_ACTIVE = True

def send_command(commands):

    ### same code as above ### 

    port.write(command_string)
    # wait for arduino's return_code on serial WITH TIMEOUT
    init_time = time()
    while (not TIMEOUT_ACTIVE) or (time() - init_time) <= TIMEOUT:
        if port.inWaiting() > 0:
            return_code = int(port.readline())
            return return_code

2. Waiting before sending the first command

waiting 2 seconds (tested 1 seconds, was not enough) before begining to send commands

sleep(2)
while True:
    commands = [float(random.random()*pi), float(random.random()*pi)]
    return_code = send_command(commands)
    print(f"return code: {return_code}")
    # don't need the sleep(0.1) anymore
Answered By: Stijn B
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.