Vpython 'compound' object - newbie struggling (Partially fixed but not the compound function bit)

The project I’m learning is using a BNO055 9 axis IMU sensor. As a newbie I’m teaching myself using python and vpython for the first time and took on board some your very helpful previous comments. I used the learning to successfully build 3 bouncing balls in an opaque box representing gas molecules.
I’m now trying to follow the lessons where using vpython you read the values from the sensor to visually manipulate an image representing the physical item(s).
I tried running the FULL code but got errors which I don’t understand, so I broke the program down in places to determine which part of the code generates the error.

Here is my current code:-

from vpython import *
from time import *
import numpy as np
import math

scene.range = 5
toRad = 2*np.pi/360
toDeg = 1/toRad
scene.forward = vector(-1,-1,-1)
scene.width = 600
sceneheight = 600

ArrowX = arrow(size=vector(2,0,0), axis=vector(1,0,0), shaftwidth=0.1, color=color.red)
ArrowY = arrow(size=vector(2,0,0), axis=vector(0,1,0), shaftwidth=0.1, color=color.green)
ArrowZ = arrow(size=vector(2,0,0), axis=vector(0,0,1), shaftwidth=0.1, color=color.blue)

myBoard = box(size=vector(6,0.2,2), pos=vector(0,0,0), opacity=0.5)
BNO055 = box(size=vector(2,0.15,0.6), pos=vector(-2,0.175,0), opacity=0.8, color=color.green)
nanoBoard = box(size=vector(1,0.15,0.8), pos=vector(2,0.175,0), opacity=0.8, color=color.blue)

DevBoard = compound ( [myBoard, BNO055, nanoBoard] )

When I use DevBoard = compound ( [myBoard, BNO055, nanoBoard] )

I get the following error(s) which I’m struggling to understand why after following the code example from (compound — VPython 3.2 documentation)

Task exception was never retrieved
future: <Task finished name='Task-7' coro=<WSserver.onMessage() done, defined at C:\Users\derek\AppData\Local\Programs\Python\Python312\Lib\site-packages\vpython\no_notebook.py:181> exception=TypeError("unsupported operand type(s) for *: 'float' and 'vpython.cyvector.vector'")>
Traceback (most recent call last):
  File "C:\Users\derek\AppData\Local\Programs\Python\Python312\Lib\site-packages\vpython\no_notebook.py", line 214, in onMessage
    await loop.run_in_executor(None, GW.handle_msg, msg)
  File "C:\Users\derek\AppData\Local\Programs\Python\Python312\Lib\concurrent\futures\thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\derek\AppData\Local\Programs\Python\Python312\Lib\site-packages\vpython\vpython.py", line 415, in handle_msg
    cvs.handle_event(evt)
  File "C:\Users\derek\AppData\Local\Programs\Python\Python312\Lib\site-packages\vpython\vpython.py", line 3262, in handle_event
    obj._axis.value = obj._size._x*norm(obj._axis)
                      ~~~~~~~~~~~~^~~~~~~~~~~~~~~~
TypeError: unsupported operand type(s) for *: 'float' and 'vpython.cyvector.vector'

I expected that by using the compound method it would create a single object that can be used in a while true loop to be moved in co-ordination with the sensor readings which is where the lessons are going. But I can’t get past why compound is not working as I expected?

As a newbie I’m not proficient enough yet to fully understand what the error messages mean?

Thank you in advance for any help.

Hi,

should

sceneheight = 600

instead be:
scene.height = 600 # forgot period ?

Just a preference I suppose, I wouldn’t recommend the open-ended imports of *. For example, importing:

from vpython import *

instead, import like this:

import vpython as synonymNameHere

synonymNameHere.attr = 25  # as an example

This way, you can always backtrack and reference to which package the method/attribute is being imported from. Is the scene method from time or from vpython? As you add more package imports, this will become an even more important issue. I also referenced the link, in their example, they use vec versus vector. Does this matter?

Thank you so much for having the patience here :slight_smile:
Here is my FULL code where I’m up to with this…
I’ll try your other suggestions for import…

from vpython import *
from time import *
import numpy as np
import math
 
scene.range=5
toRad=2*np.pi/360
toDeg=1/toRad
scene.forward=vec(-1,-1,-1)
 
scene.width=600
scene.height=600
 
myArrowX = arrow(axis=vec(1,0,0), size=vec(2,0,0), shaftwidth=0.1, color=color.red)
myArrowY = arrow(axis=vec(0,1,0), size=vec(2,0,0), shaftwidth=0.1, color=color.green)
myArrowZ = arrow(axis=vec(0,0,1), size=vec(2,0,0), shaftwidth=0.1, color=color.blue)

#size = vec(length, height, width)
myBoard = box (size=vec(6,0.2,2), pos=vec(0,0,0), opacity = 0.5)
BNO055 = box (size=vec(1,0.15,0.8), pos=vec(2,0.175,0), opacity = 0.8, color=color.blue)
nanoBoard = box (size=vec(2,0.15,0.6), pos=vec(-2,0.175,0), opacity = 0.8, color=color.green)

frontArrow=arrow(axis=vec(1,0,0), size=vec(4,0,0), shaftwidth=0.1, color=color.white, round=True)
upArrow=arrow(axis=vec(0,1,0), size=vec(4,0,0), shaftwidth=0.1, color=color.magenta, round=True) 
sideArrow=arrow(axis=vec(0,0,1), size=vec(4,0,0), shaftwidth=0.1, color=color.orange, round=True)

myObj = compound([myBoard,BNO055,nanoBoard]) #This is what I understand from the glowscript example for a compound function
while (True):
    pitch=15*toRad
    for yaw in np.arange(0, 2*np.pi, .01):
        rate(40)
        y=vec(0,1,0)

        # x=cos(psi)cos(theta) y=1sin(theta) z=sin(psi)cos(theta)
        #yaw is angle psi, pitch is angle theta
        k=vec(cos(yaw)*cos(pitch), sin(pitch), sin(yaw)*cos(pitch))
        
        s=cross(k,y) #cross product k vec with y vec
        v=cross(s,k) #cross product s vec with k vec
 
        frontArrow.axis=k
        sideArrow.axis=s
        upArrow.axis=v

        #Took me a while to work this out from the lesson example on changing the arrow length
        #the lesson example simply uses frontArrow.length=4
        frontArrow.size=vec(4,0,0)
        sideArrow.size=vec(2,0,0)
        upArrow.size=vec(2,0,0)

        #This is the part of the lesson code I'm struggling with to understand why it fails and whaat the errors mean when I execute the program
        myObj.axis=k
        myObj.up=v

        #These are my attempts to fix the issue!!!
        #myObj.axis=vec(1,1,1)
        #myObj.up=cross(s,k)

        

Here is my non elegant solution with pitch at 0degs but you can see what happens to the myBoard, BNO055 and nanoBoard objects all rotating around vector(k).
However, whenever I implement myObj = compound([myBoard,BNO055,nanoBoard]) it breaks the program with the same error list?

from vpython import *
from time import *
import numpy as np
import math
 
scene.range=5
toRad=2*np.pi/360
toDeg=1/toRad
scene.forward=vec(-1,-1,-1)
 
scene.width=600
scene.height=600
 
myArrowX = arrow(axis=vec(1,0,0), size=vec(2,0,0), shaftwidth=0.1, color=color.red)
myArrowY = arrow(axis=vec(0,1,0), size=vec(2,0,0), shaftwidth=0.1, color=color.green)
myArrowZ = arrow(axis=vec(0,0,1), size=vec(2,0,0), shaftwidth=0.1, color=color.blue)

#size = vec(length, height, width)
myBoard = box (size=vec(6,0.2,2), pos=vec(0,0,0), opacity = 0.5)
BNO055 = box (size=vec(1,0.15,0.8), pos=vec(2,0.175,0), opacity = 0.8, color=color.blue)
nanoBoard = box (size=vec(2,0.15,0.6), pos=vec(-2,0.175,0), opacity = 0.8, color=color.green)

frontArrow=arrow(axis=vec(1,0,0), size=vec(4,0,0), shaftwidth=0.1, color=color.white, round=True)
upArrow=arrow(axis=vec(0,1,0), size=vec(4,0,0), shaftwidth=0.1, color=color.magenta, round=True) 
sideArrow=arrow(axis=vec(0,0,1), size=vec(4,0,0), shaftwidth=0.1, color=color.orange, round=True)

#This is what I understand from the glowscript example for a compound function
#myObj = compound([myBoard,BNO055,nanoBoard])
while (True):
    pitch=0*toRad
    for yaw in np.arange(0, 2*np.pi, .01):
        rate(40)
        y=vec(0,1,0)

        # x=cos(psi)cos(theta) y=1sin(theta) z=sin(psi)cos(theta)
        #yaw is angle psi, pitch is angle theta
        k=vec(cos(yaw)*cos(pitch), sin(pitch), sin(yaw)*cos(pitch))
        
        s=cross(k,y) #cross product k vec with y vec
        v=cross(s,k) #cross product s vec with k vec
 
        frontArrow.axis=k
        sideArrow.axis=s
        upArrow.axis=v

        #Took me a while to work this out from the lesson example on changing the arrow length
        #the lesson example simply uses frontArrow.length=4
        frontArrow.size=vec(4,0,0)
        sideArrow.size=vec(2,0,0)
        upArrow.size=vec(2,0,0)

        #This is the part of the lesson code I'm struggling with to understand why it fails and whaat the errors mean when I execute the program
        #myObj.axis=k
        #myObj.up=v

        
        #These are my attempts to fix the issue!!!
        
        myBoard.axis= vec(k)
        BNO055.axis= vec(k)
        nanoBoard.axis= vec(k)
                
        #myObj.up=cross(s,k)

What does this function do? This function is not defined anywhere. What does the value 40 represent? It performs this exact same calcuation 629 times, why?

len(np.arange(0, 2*np.pi, 0.01))
>>> 629

It would make sense if the argument was a variable but it is not. Its a constant.

I also notice that you are not using the following variable. It appears that you don’t need it.

toDeg=1/toRad

My understanding of this function in vpython is that it sets the ‘refresh’ screen rate of the objects in it. The lower the rate(value) the slower the image moves, the higher the rate(value) the faster the screen update (I’ve tried it with higher and lower values).
I’m really out of my depth at the moment trying to establish why
myObj = compound ([myBoard, BNO055,nonoBoard])
kills the program and doesn’t enter into the while loop?

Ok. Well, unfortunately, I can’t help you further. I tried downloading the vpython package library to recreate your issue but I am unable to since according to the error that I received, you need Microsoft Visual C++ 14.0 or greater which I don’t have.

If you are just learning Python, I recommend learning the core language first.

Thank you for taking the time to have a go, I’ve recently changed from using python idle to using python in Visual Studio Code, and I get the same errors there.

I’ll keep plugging away :+1:

I think we’re using the same code from Paul McWhorter. Have you been able to make any progress?

Hi,
Yes we are probably using the same code from Paul McWhorter. I have learned that I have to make slight code changes to his original code because of the Python version I use and I also use Platformio as my IDE.
For the issue I had with Vpython ‘compound’ object, I made no progress with it. I was trying to ‘compound’ as one object the Arduino nano board and the BNO055 board together with the development board. My solution was to uncouple the nano board and BNO055 board from the development board (just use one box) and it works fine then.
So I will continue with the course now using just the one box ‘visual’ and the associated arrows representing the 3 Vector directions for X, Y and Z.
The other changes I made were also using ‘vector’ BEFORE writing numerical values for length, height and width for example. I also noticed this way vpython changes the order of length, height and width.
Happy to share my code examples.

I see. I have a little bit of a different application for my code. Essentially, I just need the visualization, however I’m using a 6 axis IMU (LSM6DS3) and I’m having issues where the visual output is 2x the actual rotation. For example, if I pitch 90 degrees, the visual will pitch 180. Additionally, I know that I can’t estimate yaw since I’m missing the degrees of freedom a magnetometer would provide, but it’s not critical. I was pretty interested in what you were doing because

A: It’s helpful to see what others are doing with the same code
B: Your thread was relatively new

What version of python are you using? I’m on 3.10.11 and the compound object correctly for me. I don’t think it matters what IDE you use for your boards as long as you have the same libraries as Paul.

My version of Python is 3.12.1
If your visualisation is twice the actual reading value, then probably you have an error in the maths.

toRad=2*np.pi/360

toDeg=1/toRad

pitch=30*toRad

I will be progressing to Lesson 19 next as I realised I had to change the vectors to the below in order to get my vector arrows and box aligned correctly:

        k=vec(cos(yaw)*cos(pitch), sin(pitch), sin(yaw)*cos(pitch))     
        s=cross(k,y) #cross product k vec with y vec
        v=cross(s,k) #cross product s vec with k vec
        myBoard.axis= s
        myBoard.up= v

I still think it’s my version of vpython V7. that has the problem with ‘compound’.

I now have everything working, a vpython graphic for visualsaition and an Arduino NANO with a BNO055 giving out all the correct values over the serial port. So obviously the next part is how to tie the two together.