Related
I have seen quite a few questions regarding this issue, and I have not been able to wrap my head around it.
So here is a concrete example.
I create a cube and in edit mode I add loopcuts. No sweat!
I copy the code from the info window and I try it out in a script and I get the ominous RuntimeError: Operator bpy.ops.mesh.loopcut_slide.poll() expected a view3d region & editmesh error message.
I understand now that it is about first giving python the right context by overriding. And alas, I do not know how to do it!
Here is the code:
import bpy
import os
os.system("cls")
# remove the default cube...
objs = bpy.data.objects
for obj in objs:
if obj.name.find("Cube") == 0:
bpy.data.objects.remove(obj, do_unlink=True)
# add a cube!
bpy.ops.mesh.primitive_cube_add(size=2, enter_editmode=True, align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
# do something to it to be sure that we have it...
bpy.data.objects['Cube'].scale[0] = 10
# THE CODE BELOW GIVES THE RuntimeError: Operator bpy.ops.mesh.loopcut_slide.poll() expected a view3d region & editmesh error message.
# What is the override code I have to use to fix it????????
bpy.ops.mesh.loopcut_slide(MESH_OT_loopcut={"number_cuts":16, "smoothness":0, "falloff":'INVERSE_SQUARE', "object_index":0, "edge_index":4, "mesh_select_mode_init":(True, False, False)}, TRANSFORM_OT_edge_slide={"value":0, "single_side":False, "use_even":False, "flipped":False, "use_clamp":True, "mirror":True, "snap":False, "snap_target":'CLOSEST', "snap_point":(0, 0, 0), "snap_align":False, "snap_normal":(0, 0, 0), "correct_uv":True, "release_confirm":False, "use_accurate":False})
import bpy
import os
os.system("cls")
objs = bpy.data.objects
for obj in objs:
if obj.name.find("Cube") == 0:
bpy.data.objects.remove(obj, do_unlink=True)
# add a cube!
bpy.ops.mesh.primitive_cube_add(size=2, enter_editmode=True, align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
# do something to it to be sure that we have it...
bpy.data.objects['Cube'].scale[0] = 10
for area in bpy.context.screen.areas:
if area.type == 'VIEW_3D':
for region in area.regions:
if region.type == 'WINDOW':
override = {'area': area, 'region': region, 'edit_object':bpy.context.edit_object}
bpy.ops.mesh.loopcut_slide(override,MESH_OT_loopcut={"number_cuts":16, "smoothness":0, "falloff":'INVERSE_SQUARE', "object_index":0, "edge_index":4, "mesh_select_mode_init":(True, False, False)}, TRANSFORM_OT_edge_slide={"value":0, "single_side":False, "use_even":False, "flipped":False, "use_clamp":True, "mirror":True, "snap":False, "snap_target":'CLOSEST', "snap_point":(0, 0, 0), "snap_align":False, "snap_normal":(0, 0, 0), "correct_uv":True, "release_confirm":False, "use_accurate":False})
This question already has answers here:
Need to Install PyOpenGL (Windows)
(1 answer)
PyOpenGL glutInit NullFunctionError
(14 answers)
Attempt to call an undefined function glutInit
(2 answers)
Closed 2 years ago.
I have a project when I need to do boolean operations with 3D models (CGS mainly), and I was trying to implement the example given on the library for python but it is not working. Seems like the code runs on OpenGL and the error comes from it instead of the example.
Anybody has an idea of how to make it work?
What am I missing?
Here is the error I get and the library link is below.
OpenGL.error.NullFunctionError: Attempt to call an undefined function
glutInit, check for bool(glutInit) before calling
Library link: https://github.com/timknip/pycsg
Example code
import sys
import os
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
sys.path.insert(0, os.getcwd())
from csg.core import CSG
from csg.geom import Vertex, Vector
from optparse import OptionParser
light_ambient = [0.3, 0.3, 0.3, 1.0]
light_diffuse = [0.7, 0.7, 0.7, 1.0] # Red diffuse light
light_position = [100.0, 100.0, 100.0, 0.0] # Infinite light location.
rot = 0.0
class TestRenderable(object):
def __init__(self, operation):
self.faces = []
self.normals = []
self.vertices = []
self.colors = []
self.vnormals = []
self.list = -1
a = CSG.cube()
b = CSG.cylinder(radius=0.5, start=[0., -2., 0.], end=[0., 2., 0.])
for p in a.polygons:
p.shared = [1.0, 0.0, 0.0, 1.0]
for p in b.polygons:
p.shared = [0.0, 1.0, 0.0, 1.0]
recursionlimit = sys.getrecursionlimit()
sys.setrecursionlimit(10000)
try:
if operation == 'subtract':
polygons = a.subtract(b).toPolygons()
elif operation == 'union':
polygons = a.union(b).toPolygons()
elif operation == 'intersect':
polygons = a.intersect(b).toPolygons()
else:
raise Exception('Unknown operation: \'%s\'' % operation)
except RuntimeError as e:
raise RuntimeError(e)
sys.setrecursionlimit(recursionlimit)
for polygon in polygons:
n = polygon.plane.normal
indices = []
for v in polygon.vertices:
pos = [v.pos.x, v.pos.y, v.pos.z]
if not pos in self.vertices:
self.vertices.append(pos)
self.vnormals.append([])
index = self.vertices.index(pos)
indices.append(index)
self.vnormals[index].append(v.normal)
self.faces.append(indices)
self.normals.append([n.x, n.y, n.z])
self.colors.append(polygon.shared)
# setup vertex-normals
ns = []
for vns in self.vnormals:
n = Vector(0.0, 0.0, 0.0)
for vn in vns:
n = n.plus(vn)
n = n.dividedBy(len(vns))
ns.append([a for a in n])
self.vnormals = ns
def render(self):
if self.list < 0:
self.list = glGenLists(1)
glNewList(self.list, GL_COMPILE)
for n, f in enumerate(self.faces):
glMaterialfv(GL_FRONT, GL_DIFFUSE, self.colors[n])
glMaterialfv(GL_FRONT, GL_SPECULAR, self.colors[n])
glMaterialf(GL_FRONT, GL_SHININESS, 50.0)
glColor4fv(self.colors[n])
glBegin(GL_POLYGON)
if self.colors[n][0] > 0:
glNormal3fv(self.normals[n])
for i in f:
if self.colors[n][1] > 0:
glNormal3fv(self.vnormals[i])
glVertex3fv(self.vertices[i])
glEnd()
glEndList()
glCallList(self.list)
renderable = None
def init():
# Enable a single OpenGL light.
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient)
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse)
glLightfv(GL_LIGHT0, GL_POSITION, light_position)
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
# Use depth buffering for hidden surface elimination.
glEnable(GL_DEPTH_TEST);
# Setup the view of the cube.
glMatrixMode(GL_PROJECTION);
gluPerspective(40.0, 640./480., 1.0, 10.0);
glMatrixMode(GL_MODELVIEW);
gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.)
def display():
global rot
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glPushMatrix()
glTranslatef(0.0, 0.0, -1.0);
glRotatef(rot, 1.0, 0.0, 0.0);
glRotatef(rot, 0.0, 0.0, 1.0);
rot += 0.1
renderable.render()
glPopMatrix()
glFlush()
glutSwapBuffers()
glutPostRedisplay()
if __name__ == '__main__':
parser = OptionParser()
parser.add_option('-o', '--operation', dest='operation',
type='str', default='subtract')
(options, args) = parser.parse_args()
renderable = TestRenderable(options.operation)
glutInit()
glutInitWindowSize(640,480)
glutCreateWindow("CSG Test")
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA)
glutDisplayFunc(display)
init()
glutMainLoop()
There is a issue when installing pyopengl with pip install pyopengl on Windows systems.
Go to Unofficial Windows Binaries for Python Extension Packages
Download a 32 bit or 64 bit package for PyOpenGL provides bindings to OpenGL, GLUT, and GLE
(e.g.
PyOpenGL‑3.1.5‑cp39‑cp39‑win_amd64.whl and
PyOpenGL_accelerate‑3.1.5‑cp39‑cp39‑win_amd64.whl)
Open Command Prompt (cmd.exe) as administrator. Change to the download directory and install the packages by pip install packagename.whl.
e.g:
pip install PyOpenGL‑3.1.5‑cp39‑cp39‑win_amd64.whl
and
pip install PyOpenGL_accelerate‑3.1.5‑cp39‑cp39‑win_amd64.whl
If the package is already installed, but doesn't work, then you have to ignore the currently installed package, by the option --ignore-installed:
pip install --ignore-installed PyOpenGL‑3.1.5‑cp39‑cp39‑win_amd64.whl
pip install --ignore-installed PyOpenGL_accelerate‑3.1.5‑cp39‑cp39‑win_amd64.whl
I am writing a PyQt5 application that uses OpenGL to slice an STL into images and displays them as it goes. The application works fine when invoked from the command line (Windows 10, Python 3.7.1, PyInstaller 3.5), but when I try packaging it with pyinstaller it crashes with an error:
Traceback (most recent call last):
File "app_qt.py", line 45, in initializeGL
self.gl = self.context().versionFunctions()
ModuleNotFoundError: No module named 'PyQt5._QOpenGLFunctions_4_1_Core'`
The call comes from a QtGui.QOpenGLWindow object. I have followed the suggestions in this answer to no avail. I have tried importing PyQt5 directly, and adding it to the hidden imports in the .spec file as well for pyinstaller.
Since the application runs fine when invoked normally (i.e. python slicer_gui.py) I am inclined to believe pyinstaller is neglecting to add an import to the package somewhere.
Here is the full code. The GUI is simple (pun intended):
import PySimpleGUI as sg
import app_pyopengl
# define GUI layout
layout = [
[sg.Text('STL to Slice', size=(16, 1)), sg.Input(), sg.FileBrowse()],
[sg.Text('Layer Thickness (um) ', size=(16, 1)), sg.InputText('10')],
[sg.Submit(button_text="Slice"), sg.Cancel(button_text='Quit')]
]
# name the window
window = sg.Window('PyQT STL Slicer').Layout(layout)
# loop until user quits
while True:
button, values = window.Read() # read all values in the window
if button == "Quit":
exit()
if button == "Slice":
thickness = float(values[1]) / 1000 # convert um to mm
filename = values[0]
app_pyopengl.main(filename, thickness)
Here is the slicing application:
import sys
import os
import shutil
from ctypes import c_float, c_uint, sizeof
from PyQt5 import QtGui, QtCore, QtWidgets
from stl import mesh
import numpy as np
from printer import printer
GLfloat = c_float
GLuint = c_uint
EPSILON = 0.00001
SCR_WIDTH = 640
SCR_HEIGHT = int(SCR_WIDTH * printer.height / printer.width)
class Window(QtGui.QOpenGLWindow):
def __init__(self,
stlFilename,
layerThickness,
sliceSavePath,
*args,
**kwargs):
super().__init__(*args, **kwargs)
self.setTitle('STL Slicer')
self.vertVAO, self.vertVBO = 0, 0
self.maskVAO, self.maskVBO = 0, 0
self.numOfVerts = 0
self.bounds = dict()
self.totalThickness = 0.
self.currentLayer = 0
self.height = 0
self.stlFilename = stlFilename
self.layerThickness = layerThickness
self.sliceSavePath = sliceSavePath
def initializeGL(self):
self.gl = self.context().versionFunctions()
self.shaderProg = QtGui.QOpenGLShaderProgram()
self.shaderProg.create()
self.shaderProg.addShaderFromSourceFile(
QtGui.QOpenGLShader.Vertex, 'shaders/slice.vert')
self.shaderProg.addShaderFromSourceFile(
QtGui.QOpenGLShader.Fragment, 'shaders/slice.frag')
self.shaderProg.link()
self.loadMesh()
self.proj = QtGui.QMatrix4x4()
self.proj.setToIdentity()
self.proj.ortho(0, printer.width*printer.pixel,
0, printer.height*printer.pixel,
-self.totalThickness, self.totalThickness)
self.model = QtGui.QMatrix4x4()
self.model.setToIdentity()
self.model.translate(0, 0, self.totalThickness+EPSILON)
self.sliceFbo = QtGui.QOpenGLFramebufferObject(
printer.width,
printer.height
)
self.sliceFbo.setAttachment(
QtGui.QOpenGLFramebufferObject.CombinedDepthStencil
)
def loadMesh(self):
# Get information about our mesh
ourMesh = mesh.Mesh.from_file(self.stlFilename)
self.numOfVerts = ourMesh.vectors.shape[0] * 3
self.bounds = {
'xmin': np.min(ourMesh.vectors[:,:,0]),
'xmax': np.max(ourMesh.vectors[:,:,0]),
'ymin': np.min(ourMesh.vectors[:,:,1]),
'ymax': np.max(ourMesh.vectors[:,:,1]),
'zmin': np.min(ourMesh.vectors[:,:,2]),
'zmax': np.max(ourMesh.vectors[:,:,2])
}
self.totalThickness = self.bounds['zmax'] - self.bounds['zmin']
#######################################
# make VAO for drawing our mesh
self.vertVAO = QtGui.QOpenGLVertexArrayObject()
self.vertVAO.create()
self.vertVAO.bind()
self.vertVBO = QtGui.QOpenGLBuffer(QtGui.QOpenGLBuffer.VertexBuffer)
self.vertVBO.create()
self.vertVBO.bind()
self.vertVBO.setUsagePattern(QtGui.QOpenGLBuffer.StaticDraw)
data = ourMesh.vectors.astype(GLfloat).tostring()
self.vertVBO.allocate(data, len(data))
self.gl.glVertexAttribPointer(0, 3, self.gl.GL_FLOAT,
self.gl.GL_FALSE, 3*sizeof(GLfloat), 0)
self.gl.glEnableVertexAttribArray(0)
self.vertVBO.release()
self.vertVAO.release()
#######################################
# a mask vertex array for stencil buffer to subtract
maskVert = np.array(
[[0, 0, 0],
[printer.width*printer.pixel, 0, 0],
[printer.width*printer.pixel, printer.height*printer.pixel, 0],
[0, 0, 0],
[printer.width*printer.pixel, printer.height*printer.pixel, 0],
[0, printer.height*printer.pixel, 0]], dtype=GLfloat
)
#######################################
# make VAO for drawing mask
self.maskVAO = QtGui.QOpenGLVertexArrayObject()
self.maskVAO.create()
self.maskVAO.bind()
self.maskVBO = QtGui.QOpenGLBuffer(QtGui.QOpenGLBuffer.VertexBuffer)
self.maskVBO.create()
self.maskVBO.bind()
self.maskVBO.setUsagePattern(QtGui.QOpenGLBuffer.StaticDraw)
data = maskVert.tostring()
self.maskVBO.allocate(data, len(data))
self.gl.glVertexAttribPointer(0, 3, self.gl.GL_FLOAT,
self.gl.GL_FALSE, 3*sizeof(GLfloat), 0)
self.gl.glEnableVertexAttribArray(0)
self.maskVBO.release()
self.maskVAO.release()
#######################################
def paintGL(self):
if self.height >= self.totalThickness-EPSILON:
sys.exit()
else:
self.height += self.layerThickness
self.currentLayer += 1
self.draw()
self.renderSlice()
self.update()
def draw(self):
self.gl.glViewport(0, 0, self.size().width(), self.size().height())
self.gl.glEnable(self.gl.GL_STENCIL_TEST)
self.gl.glClearColor(0., 0., 0., 1.)
self.gl.glClear(self.gl.GL_COLOR_BUFFER_BIT | self.gl.GL_STENCIL_BUFFER_BIT)
self.vertVAO.bind()
self.shaderProg.bind()
self.model.translate(0, 0, -self.layerThickness)
self.shaderProg.setUniformValue('proj', self.proj)
self.shaderProg.setUniformValue('model', self.model)
self.gl.glEnable(self.gl.GL_CULL_FACE)
self.gl.glCullFace(self.gl.GL_FRONT)
self.gl.glStencilFunc(self.gl.GL_ALWAYS, 0, 0xFF)
self.gl.glStencilOp(self.gl.GL_KEEP, self.gl.GL_KEEP, self.gl.GL_INCR)
self.gl.glDrawArrays(self.gl.GL_TRIANGLES, 0, self.numOfVerts)
self.gl.glCullFace(self.gl.GL_BACK)
self.gl.glStencilOp(self.gl.GL_KEEP, self.gl.GL_KEEP, self.gl.GL_DECR)
self.gl.glDrawArrays(self.gl.GL_TRIANGLES, 0, self.numOfVerts)
self.gl.glDisable(self.gl.GL_CULL_FACE)
self.gl.glClear(self.gl.GL_COLOR_BUFFER_BIT)
self.maskVAO.bind()
self.gl.glStencilFunc(self.gl.GL_NOTEQUAL, 0, 0xFF)
self.gl.glStencilOp(self.gl.GL_KEEP, self.gl.GL_KEEP, self.gl.GL_KEEP)
self.gl.glDrawArrays(self.gl.GL_TRIANGLES, 0, 6)
self.gl.glDisable(self.gl.GL_STENCIL_TEST)
self.shaderProg.release()
def renderSlice(self):
self.sliceFbo.bind()
self.gl.glViewport(0, 0, printer.width, printer.height)
self.gl.glEnable(self.gl.GL_STENCIL_TEST)
self.gl.glClearColor(0., 0., 0., 1.)
self.gl.glClear(self.gl.GL_COLOR_BUFFER_BIT | self.gl.GL_STENCIL_BUFFER_BIT)
self.vertVAO.bind()
self.shaderProg.bind()
self.shaderProg.setUniformValue('proj', self.proj)
self.shaderProg.setUniformValue('model', self.model)
self.gl.glEnable(self.gl.GL_CULL_FACE)
self.gl.glCullFace(self.gl.GL_FRONT)
self.gl.glStencilFunc(self.gl.GL_ALWAYS, 0, 0xFF)
self.gl.glStencilOp(self.gl.GL_KEEP, self.gl.GL_KEEP, self.gl.GL_INCR)
self.gl.glDrawArrays(self.gl.GL_TRIANGLES, 0, self.numOfVerts)
self.gl.glCullFace(self.gl.GL_BACK)
self.gl.glStencilOp(self.gl.GL_KEEP, self.gl.GL_KEEP, self.gl.GL_DECR)
self.gl.glDrawArrays(self.gl.GL_TRIANGLES, 0, self.numOfVerts)
self.gl.glDisable(self.gl.GL_CULL_FACE)
self.gl.glClear(self.gl.GL_COLOR_BUFFER_BIT)
self.maskVAO.bind()
self.gl.glStencilFunc(self.gl.GL_NOTEQUAL, 0, 0xFF)
self.gl.glStencilOp(self.gl.GL_KEEP, self.gl.GL_KEEP, self.gl.GL_KEEP)
self.gl.glDrawArrays(self.gl.GL_TRIANGLES, 0, 6)
self.gl.glDisable(self.gl.GL_STENCIL_TEST)
image = self.sliceFbo.toImage()
# makes a QComboBox for different Image Format,
# namely Format_Mono, Format_MonoLSB, and Format_Grayscale8
image = image.convertToFormat(QtGui.QImage.Format_Grayscale8)
image.save(os.path.join(self.sliceSavePath,
'out{:04d}.png'.format(self.currentLayer)))
self.sliceFbo.release()
def keyPressEvent(self, event):
if event.key() == QtCore.Qt.Key_Escape:
sys.exit()
event.accept()
def main(stlFilename, layerThickness):
temp = os.path.dirname(stlFilename)
sliceSavePath = os.path.join(temp, 'slices')
# remove old slices folder if there is one, and make a new empty one
if os.path.exists(sliceSavePath):
shutil.rmtree(sliceSavePath) # using shutil here avoids permissions errors
if not os.path.exists(sliceSavePath):
os.mkdir(sliceSavePath)
# Set format here, otherwise it throws error
# `QCocoaGLContext: Falling back to unshared context.`
# on Mac when use QOpenGLWidgets
# https://doc.qt.io/qt-5/qopenglwidget.html#details last paragraph
format = QtGui.QSurfaceFormat()
format.setRenderableType(QtGui.QSurfaceFormat.OpenGL)
format.setProfile(QtGui.QSurfaceFormat.CoreProfile)
format.setVersion(4, 1)
format.setStencilBufferSize(8)
QtGui.QSurfaceFormat.setDefaultFormat(format)
app = QtWidgets.QApplication(sys.argv)
window = Window(stlFilename, layerThickness, sliceSavePath)
window.resize(SCR_WIDTH, SCR_HEIGHT)
window.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main(sys.argv[1], float(sys.argv[2]))
I heard and read that, defining large number of information is easy using class structure, which is defined in C language (see C Code below).
I want to defined similar way using Python. I need little favor on code, and I am in new learner group of Python.
Any suggestion about which way make it easy to define? Going dict is fine, but class is best.
Example in C code below (and I have additional similar structures and information):
typedef struct
{
U16 ID;
S8 Name[32];
S8 Description[96];
S8 Units[16];
enum eType Type;
F32 Scaling;
F32 Offset;
BOOL Writeable;
} sDataInfo;
/* ID, Name, Description, Unit, Type, Scaling, Offset, Writable */
sDataInfo data_items[] =
{
0x0202, "dtc_num_of_faults_", "Number of DTCs", "", u8, 1, 0, FALSE,
0x2007, "FlBodyVertLocSel_A_Meas_", "FL Vertical Acceleration", "m/s^2", s16, 0.05, 0, FALSE,
0x2008, "FrBodyVertLocSel_A_Meas_", "FR Vertical Acceleration", "m/s^2", s16, 0.05, 0, FALSE,
0x2022, "RlBodyVertLocSel_A_Meas_", "RL Vertical Acceleration", "m/s^2", s16, 0.05, 0, FALSE
}
It is important to know every one the above code can be changed in Python. None of question answered for above in any online chain.
And expecting some examples as well.
As I said in a comment, I'm not sure exactly what you want...but here's one guess:
from pprint import pprint
import sys
def sprintf(format, *args):
return format % args
def _attributes_from_dict(d):
self = d.pop('self')
for n, v in d.items():
setattr(self, n, v)
class DataInfo(object):
fieldnames = 'id, name, description, units, type, scaling, offset, writeable'.split(', ')
def __init__(self, id, name, description, units, type, scaling, offset, writeable):
_attributes_from_dict(locals())
def __repr__(self): # optional
values = tuple(getattr(self, fieldname) for fieldname in self.fieldnames)
id = values[0]
remainder = ', '.join(map(repr, values[1:]))
return sprintf('%s(0x%04x, %s)', self.__class__.__name__, id, remainder)
u8, s16 = 0, 1 # enum eType names and values
data_items = [
DataInfo(*args) for args in [
(0x0202, "dtc_num_of_faults_", "Number of DTCs", "", u8, 1, 0, False),
(0x2007, "FlBodyVertLocSel_A_Meas_", "FL Vertical Acceleration", "m/s^2", s16, 0.05, 0, False),
(0x2008, "FrBodyVertLocSel_A_Meas_", "FR Vertical Acceleration", "m/s^2", s16, 0.05, 0, False),
(0x2022, "RlBodyVertLocSel_A_Meas_", "RL Vertical Acceleration", "m/s^2", s16, 0.05, 0, False),
]
]
pprint(data_items)
Output:
[DataInfo(0x0202, 'dtc_num_of_faults_', 'Number of DTCs', '', 0, 1, 0, False),
DataInfo(0x2007, 'FlBodyVertLocSel_A_Meas_', 'FL Vertical Acceleration', 'm/s^2', 1, 0.05, 0, False),
DataInfo(0x2008, 'FrBodyVertLocSel_A_Meas_', 'FR Vertical Acceleration', 'm/s^2', 1, 0.05, 0, False),
DataInfo(0x2022, 'RlBodyVertLocSel_A_Meas_', 'RL Vertical Acceleration', 'm/s^2', 1, 0.05, 0, False)]
I'm using a BCF2000 Behringer fader as input to control a robot using ROS. Everything was working fine, but suddenly it stopped working. By suddenly I mean after I got to word after a week off. I need to know if it's a hardware or software problem (maybe somebody drop it off while I was gone? I don't think so but I cannot find a bug). I'm running only a python module that reads the data from the fader and publishes it in ROS to find the problem, which is that I cannot make the sliders of the fader move.
Basically, the python module reads two integers from the argument list. If a third one is given, all values of the fader should be put to 0 (sliders and buttons). The first integer is the input device id, and the second is the output device id. This is:
if len(sys.argv) > 1:
input_dev = int(sys.argv[1])
else:
input_dev = pygame.midi.get_default_input_id()
print "Using DEFAULT input device %d" % input_dev
if input_dev == -1:
print "No default MIDI input device"
exit(-1)
print "Using input device %d" % input_dev
if len(sys.argv) > 2:
output_dev = int(sys.argv[2])
else:
output_dev = pygame.midi.get_default_output_id()
print "Using DEFAULT output device %d" % input_dev
if output_dev == -1:
print "No default MIDI output device"
exit(-1)
print "Using output device %d" % output_dev
controller = pygame.midi.Input(input_dev)
controller_input = pygame.midi.Output(output_dev)
The thing is that I don't know how to find the correct input device number. For the last month I was calling it using '3' and '2', meaning:
me#mycpu:ros$ rosrun bcf2000 bcf2000_driver.py 3 2
if I make an echo of the published data, I get all the data published when I move any slider or press a button. For example:
me#mycpu:ros$ rostopic echo /bcf2000/joy
header:
seq: 1
stamp:
secs: 1441969279
nsecs: 677656888
frame_id: ''
axes: [21.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 69.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
buttons: [127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
but if I write to the fader, the sliders won't move. Again, this code was working a few days ago. I'm 100% sure is the same code according to the GIT repository log. For example, putting everything to 0:
for i in range(1,93):
controller_input.write([[[176, i, 0, 0], 0]])
where the fader has 93 channels.
It may be that I'm using the wrong output device number. I've changed the number between 0 and 10 and nothing. How do I find out what is the correct device number? How do I debug that is actually a software issue (maybe a OS issue, I don't know) or a hardware issue? The last is very unlikely, since it would be a very selective hardware issue. But I may be mistake.
UPDATE: This only happens on my computer, so it's not a hardware issue.
UPDATE 2: This is the output of aseqdump -l
me#mycpu:ros$ aseqdump -l
Port Client name Port name
0:0 System Timer
0:1 System Announce
14:0 Midi Through Midi Through Port-0
24:0 BCF2000 BCF2000 MIDI 1
24:1 BCF2000 BCF2000 MIDI 2
I can listen to the input using aseqdump -p 24:0.
Listing the info from all devices using get_device_info gives:
('ALSA', 'Midi Through Port-0', 0, 1, 0)
('ALSA', 'Midi Through Port-0', 1, 0, 0)
('ALSA', 'BCF2000 MIDI 1', 0, 1, 0)
('ALSA', 'BCF2000 MIDI 1', 1, 0, 0)
('ALSA', 'BCF2000 MIDI 2', 0, 1, 0)
('ALSA', 'BCF2000 MIDI 2', 1, 0, 0)
('ALSA', 'BCF2000 MIDI 3', 0, 1, 0)
('ALSA', 'aseqdump', 0, 1, 0)
For devices 2, 4 and 6 I cannot write to the device. I'm trying to write to each output device using:
#!/usr/bin/env python
import pygame
import pygame.midi
import sys
import time
def main():
pygame.midi.init()
devices = pygame.midi.get_count()
if devices < 1:
print "No MIDI devices detected"
exit(-1)
print "Found %d MIDI devices" % devices
print("id -- interface -- name -- input -- ouput -- opened")
for ii in range(devices):
ll = pygame.midi.get_device_info(ii)
bool1 = bool(ll[2])
bool2 = bool(ll[3])
bool3 = bool(ll[4])
print(str(ii) + " -- " + str(ll[0]) + " -- " + str(ll[1]) + " -- " + str(bool1) + " -- " + str(bool2) + " -- " + str(bool3))
if (bool2):
value = 0
if ii%2 == 0:
value = 127
controller = pygame.midi.Output(ii)
controller.write([[[176, 48, 0, 0], value]])
time.sleep(2)
which should print the device info for each device, and if its an output device, it should move the first slider. It doesn't move for any device.