Notifications
Clear all

Returning and unpacking multiple values from a function

16 Posts
4 Users
0 Likes
446 Views
(@dubbadan)
Member
Joined: 2 years ago
Posts: 24
Topic starter  

Hi. This is a tad embarrassing, but I'm having trouble with this apparently basic task. It seems that I'm missing something obvious in regards to returning and unpacking multiple values from a function.

There may be other issues with the below code, but for now I'm addressing this particular issue.

from machine import PWM, ADC, Pin
import utime
import math

xAxisJoyPin = ADC(27)
yAxisJoyPin = ADC(26)

# Outputs to 2 IBT-2 h-bridge motor controllers
RFpwmPin = PWM(Pin(6)) #RF = Right Forward
RBpwmPin = PWM(Pin(8)) #RB = Right Backward
LFpwmPin = PWM(Pin(7))
LBpwmPin = PWM(Pin(9))

# Set PWM frequency high in order to limit motor noise
RFpwmPin.freq(10000)
RBpwmPin.freq(10000)
LFpwmPin.freq(10000)
LBpwmPin.freq(10000)

# Global variables
joyMin = 0
joyMax = 65535
speedMin = 0
speedMax = int(65535 * 0.75)
joyCentre = int(joyMax / 2)
joyDeadZone = 4500 # (0-65535)
joyCentrePlusDZ = joyCentre + joyDeadZone
joyCentreMinusDZ = joyCentre - joyDeadZone
RFmotorSpeed = 0
RBmotorSpeed = 0
LFmotorSpeed = 0
LBmotorSpeed = 0

# Below function code mostly copied from  https://www.instructables.com/Joystick-to-Differential-Drive-Python/ 

def joystickToDiff(x, y, joyMin, joyMax, speedMin, speedMax):

z = math.sqrt(x * x + y * y)

rad = math.acos(math.fabs(x) / z)

angle = rad * 180 / math.pi

tcoeff = -1 + (angle / 90) * 2
turn = tcoeff * math.fabs(math.fabs(y) - math.fabs(x))
turn = round(turn * 100, 0) / 100
mov = max(math.fabs(y), math.fabs(x))

if (y > joyCentre):
functOutLeft = mov
functOutRight = turn
elif (y < joyCentre):
functOutRight = mov
functOutLeft = turn


return rightOut, leftOut


while True:
x = xAxisJoyPin.read_u16()
y = yAxisJoyPin.read_u16()
utime.sleep(0.01)

# Zero point of joystick tends to jump around. Perhaps some electronic solution might be better?
if x < 1000:
x = 0
if y < 1000:
y = 0

# Print for analysis
print ("xAxis:", x, "yAxis:", y, end=' ')
print ("RF:", RFmotorSpeed, "LF:", LFmotorSpeed, end=' ')
print ("RB:", RBmotorSpeed, "LB:", LBmotorSpeed)

# If joystick is in centre dead zone, motors off, return to top of loop
# if ((x > joyCentreMinusDZ or x < joyCentrePlusDZ) and (y > joyCentreMinusDZ or y < joyCentrePlusDZ)):
# RFmotorSpeed = 0
# RBmotorSpeed = 0
# LFmotorSpeed = 0
# LBmotorSpeed = 0
# continue

# Send inputs to joystickToDiff function for processing
joystickToDiff(x, y, joyMin, joyMax, speedMin, speedMax)

# Save outputs from joystickToDiff function
leftOut, rightOut = joystickToDiff()

# Divide the 2 processed variables into 4 (relative to joystick position)
# to send to motor controller inputs
if y < joyCentreMinusDZ:
if x < joyCentreMinusDZ:
LBmotorSpeed = leftOut
if x > joyCentrePlusDZ:
LFmotorSpeed = leftOut
if y > joyCentrePlusDZ:
if x < joyCentreMinusDZ:
RBmotorSpeed = rightOut
if x > joyCentrePlusDZ:
RFmotorSpeed = rightOut

# Send PWM signals to motor controllers
RFpwmPin.duty_u16(RFmotorSpeed)
RBpwmPin.duty_u16(RBmotorSpeed)
LFpwmPin.duty_u16(LFmotorSpeed)
LBpwmPin.duty_u16(LBmotorSpeed)

 

I'm getting the message "TypeError: function takes 6 positional arguments but 0 were given" regarding the line

leftOut, rightOut = joystickToDiff()

which confuses me because I believe I've already sent the input arguments to the function with the line

joystickToDiff(x, y, joyMin, joyMax, speedMin, speedMax)

 


   
Quote
Ron
 Ron
(@zander)
Father of a miniature Wookie
Joined: 3 years ago
Posts: 6530
 

@dubbadan   The eror message is right, I don't know how to explain it better, the function needs 6 inputs, you gave it 0.

I'm getting the message "TypeError: function takes 6 positional arguments but 0 were given" regarding the line

leftOut, rightOut = joystickToDiff()

The second line where you have 6 parameters is correct, but you can only return a single value. It can be a pointer to a structure, but in modern programming conventions that is a sure sign of a poor design.

At a 15 second glance, there are dozens of errors, a lot of the code is of unknown syntax.

 

 

 

First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
Sure you can learn to be a programmer, it will take the same amount of time for me to learn to be a Doctor.


   
ReplyQuote
(@davee)
Member
Joined: 3 years ago
Posts: 1547
 

Hi @dubbadan,

   In general, the 'full set' of arguments must be passed to a function on every call ... it does not 'remember' you sent them earlier.

Admittedly, some languages allow the programmer to make functions with default values that get substituted if a call is made to the function with less than the full set of arguments.

And also some languages allow the same function name to be defined more than once, each time with a different set of parameter types, and the compiler figures out which one is being called by matching the calling argument types to the parameter types.

Both of these cases imply the function definition is either more 'complex' or there is more than function definition with the same function name. I can't see either applying to the listed code.

So, I think you will need the full set of arguments every time.

Best wishes, Dave


   
ReplyQuote
(@dubbadan)
Member
Joined: 2 years ago
Posts: 24
Topic starter  

Thanks for the patient replies.

Posted by: @davee

So, I think you will need the full set of arguments every time.

Posted by: @zander

The eror message is right, I don't know how to explain it better, the function needs 6 inputs, you gave it 0.

 

Forgive my noobiness, but what I thought I was doing with this line

leftOut, rightOut = joystickToDiff()

was retrieving the function outputs, not sending it input arguments. What I'm trying to work out is how I go about retrieving and unpacking the function outputs.

 


   
ReplyQuote
Ron
 Ron
(@zander)
Father of a miniature Wookie
Joined: 3 years ago
Posts: 6530
 

@dubbadan It happens in a single line, but there will only be one returned value.

From the reference manual, see pic.

 

EDIT: I just noticed its Python. I don't know python, so ignore what I said.

Screenshot 2023 12 08 at 19.21.23

 

First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
Sure you can learn to be a programmer, it will take the same amount of time for me to learn to be a Doctor.


   
ReplyQuote
(@dubbadan)
Member
Joined: 2 years ago
Posts: 24
Topic starter  

Thanks for that reference, I have read that but also have read that it is possible to return more than one value from a function, eg via a tuple, list or dict.


   
ReplyQuote
(@davee)
Member
Joined: 3 years ago
Posts: 1547
 

Hi @dubbadan,

  Python is not my forte either, but you can return more than one value ... however, you need to do it 'at the same time' as when you call it with the full set of arguments.

1st Google response I got is https://note.nkmk.me/en/python-function-return-multiple-values/ which kind of shows the answer  .. if you don't like that one, there are plenty more for you to find yourself.

Best wishes, Dave


   
ReplyQuote
Ron
 Ron
(@zander)
Father of a miniature Wookie
Joined: 3 years ago
Posts: 6530
 

@dubbadan First learn to use the reply link so you cause an email to be sent to them to let them know a reply was posted.

That may be in Python, I don't know Python. In my decades of professional experience, we avoided things like that as they were proven to raise more bug reports than simple bool or integer return values. If you are using python, don't tag me any more as I can't help you.

First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
Sure you can learn to be a programmer, it will take the same amount of time for me to learn to be a Doctor.


   
ReplyQuote
byron
(@byron)
No Title
Joined: 5 years ago
Posts: 1111
 

@dubbadan

Your code does not show any indentation which makes it hard to guess the intent and of course would not actually run as presented as the indentation is critical in python coding blocks.  

I expect the particular line of code you mention giving you the error is really meant to get the return values from your function call on the previous line - e.g.

leftOut, rightOut = joystickToDiff(x, y, joyMin, joyMax, speedMin, speedMax)

But also you cannot put 

if y < joyCentreMinusDZ:
if x < joyCentreMinusDZ:
LBmotorSpeed = leftOut

The first if has now 'if' statements to perform and the second if fails, as all the rest of your code to indent e.g.

if x < joyCentreMinusDZ:
    LBmotorSpeed = leftOut

Where you meaning to join the if y and if x with an 'and' or an 'or' ?

Maybe the lack of indentation is how the new coding works in this forum since its update the other day, lets see.  I'll post a small snippet of your code with indents

def joystickToDiff(x, y, joyMin, joyMax, speedMin, speedMax):
    z = math.sqrt(x * x + y * y)
    rad = math.acos(math.fabs(x) / z)
    angle = rad * 180 / math.pi
    tcoeff = -1 + (angle / 90) * 2
    turn = tcoeff * math.fabs(math.fabs(y) - math.fabs(x))
    turn = round(turn * 100, 0) / 100
    mov = max(math.fabs(y), math.fabs(x))

    if (y > joyCentre):
        functOutLeft = mov
        functOutRight = turn
    elif (y < joyCentre):
        functOutRight = mov
        functOutLeft = turn

    return rightOut, leftOut


while True:
    x = xAxisJoyPin.read_u16()
    y = yAxisJoyPin.read_u16()
    utime.sleep(0.01)
    # Zero point of joystick tends to jump around. Perhaps some electronic solution might be better?
    if x < 1000:
        x = 0
    if y < 1000:
        y = 0
    # Print for analysis
    print ("xAxis:", x, "yAxis:", y, end=' ')
    print ("RF:", RFmotorSpeed, "LF:", LFmotorSpeed, end=' ')
    print ("RB:", RBmotorSpeed, "LB:", LBmotorSpeed)

    # Send inputs to joystickToDiff function for processing
    # and
    # Save outputs from joystickToDiff function
    leftOut, rightOut = joystickToDiff(x, y, joyMin, joyMax, speedMin, speedMax)

That looks better 😀 

This post was modified 3 months ago by byron

   
ReplyQuote
byron
(@byron)
No Title
Joined: 5 years ago
Posts: 1111
 

Posted by: @byron

But also you cannot put 

if y < joyCentreMinusDZ:
if x < joyCentreMinusDZ:
LBmotorSpeed = leftOut

And another follow up comment, Of course the following is OK, and shows that unless you present properly formatted code its hard to follow.

if y < joyCentreMinusDZ:
    if x < joyCentreMinusDZ:
        LBmotorSpeed = leftOut

 

 


   
ReplyQuote
(@dubbadan)
Member
Joined: 2 years ago
Posts: 24
Topic starter  

Apologies to all.


   
ReplyQuote
(@dubbadan)
Member
Joined: 2 years ago
Posts: 24
Topic starter  

Posted by: @davee

you can return more than one value ... however, you need to do it 'at the same time' as when you call it with the full set of arguments.

Thanks!


   
ReplyQuote
(@dubbadan)
Member
Joined: 2 years ago
Posts: 24
Topic starter  

Posted by: @byron

I'll post a small snippet of your code with indents

Did you add the indents manually after copy and pasting? I read the page https://forum.dronebotworkshop.com/add-code/ but it doesn't mention indents so I left it, presuming that was how it should happen.

I also made the error of pasting my whole sketch, I'll cut smaller sections in the future.


   
ReplyQuote
byron
(@byron)
No Title
Joined: 5 years ago
Posts: 1111
 

Posted by: @dubbadan

Did you add the indents manually after copy and pasting?

No, I just pasted the code into the code window.  Of course to put some indents into your code I had to copy your text into the Thonny IDE and adjust it in that editor.  But then to unload my code from Thonny I just cut and pasted it into the forum code window and the indentation was preserved OK. 

This post was modified 3 months ago by byron

   
ReplyQuote
(@dubbadan)
Member
Joined: 2 years ago
Posts: 24
Topic starter  

This worked! Unpack the outputs and call the function with the input arguments ON THE SAME LINE! Who would've thought?

leftOut, rightOut = joystickToDiff(x, y, joyMin, joyMax, speedMin, speedMax)

   
ReplyQuote
Page 1 / 2