bobvanderlinden / node-machinetalk

A client-side Node API for remotely controlling/monitoring Machinekit instances through Machinetalk
GNU Lesser General Public License v3.0
2 stars 4 forks source link

Error 404 on renderjson.js three.js and OrbitControls.js #16

Closed zhivko closed 7 years ago

zhivko commented 8 years ago

I get folowing errors in web browser, after I start node-machinetalk-example with: .../node-machinetalk-example$ node index.js

GET http://localhost:3000/components/renderjson/renderjson.js localhost/:9 GET http://localhost:3000/components/threejs/build/three.js localhost/:10 GET http://localhost:3000/components/threejs/examples/js/controls/OrbitControls.js boundingbox.js:40 Uncaught ReferenceError: THREE is not defined(anonymous function) @ boundingbox.js:40context.execCb @ require.js:1678Module.check @ require.js:878Module.enable @ require.js:1165Module.init @ require.js:783callGetModule @ require.js:1192context.completeLoad @ require.js:1571context.onScriptLoad @ require.js:1699

Seems renderjson/renderjson.js is not part of repository - is this separate nodejs module?

zhivko commented 8 years ago

Also I noticed if I send machinetalk messages too fast - received message is often times null - how could that be? Is this normal? Is this a missuse from client side? Should I wait for some condition to happen or do I need to wait certain time before reading recv bytes? Maybe until is data there? I noticed ZMQ socket has .hasReceiveMore() - should I read all messages before sending new one?

zhivko commented 8 years ago

OK - executing jogging comands one after another (and not waiting for response) had some weird effects. If I make program wait 100ms between jogging commands it seems it works as it supposed to (axis number beeing 0,1,2) - exact motors now turns as indicated by .setIndex(axis) I still cannot make MDI command make work - having:

toMdiMode
Message: 088852D2010765786563757465B80305922603A00603
type: MT_EMCCMD_EXECUTED
reply_ticket: 3

executeMdi
Message: 088D52D2010765786563757465B8030692260B4A09473020583830302E30
type: MT_EMCCMD_EXECUTED
reply_ticket: 4

toManualMode
Message: 088852D2010765786563757465B80307922603A00601
type: MT_EMCCMD_EXECUTED
reply_ticket: 5
machinekoder commented 8 years ago

Have you homed the axes? It might be useful if you have another UI running to see what is actually happening. Or subscribe to the error service to get the error messages.

You do not have to wait for responses. If you dont send the ticket there will be no answer. You may also query all received messages not only one.

zhivko commented 8 years ago

No - I haven't home axes - so pobably this is the reason... Excuse me for my ignorance but I keep get looking into your code of: https://github.com/strahlex/QtQuickVcp - but still have hard time to know what details to use. Is there some reference on machinetalk services? For instance - for connecting on error service, what kind of socket type do I need (ZMQ.SUB or ZMQ.DEALER)? Also for subscribing to error service - do I need word "error" or something else?

errorSocket = con.socket(ZMQ.SUB);
errorSocket.subscribe("error".getBytes());

Can you direct me to the code line of how to use error service?

zhivko commented 8 years ago

OK, error SUB messaging works :) BUnch of errors apeared like: type: MT_EMC_OPERATOR_ERROR note: "can\'t do that (EMC_AXIS_HOME:123) in MDI mode" and type: MT_EMC_OPERATOR_ERROR note: "Can\'t issue MDI command when not homed"

So problem is: Operator error: Can't issue MDI command when not homed

I am homing axes with:

        pb.Message.Container.Builder builder = Container.newBuilder();
        pb.Status.EmcCommandParameters emcCommandParameter = pb.Status.EmcCommandParameters.newBuilder().setIndex(axis).setDebugLevel(2)
                .build();

        builder.setType(ContainerType.MT_EMC_AXIS_HOME);
        builder.setEmcCommandParams(emcCommandParameter);
        builder.setTicket(ticket++);
        Container container = builder.build();

        byte[] buff = container.toByteArray();
        String hexOutput = javax.xml.bind.DatatypeConverter.printHexBinary(buff);
        System.out.println("Message: " + hexOutput);
        getCommandSocket().send(buff);
        parseAndOutput();

Why wwould that not work? Does it need to be in some special mode so homing could work? Currently I am homing in EMC_TASK_MODE_MANUAL mode. Do you guys see any possible flaw in my homing mesage? My homing command is:

Message: 088852D2010765786563757465B8030B922603A00601
type: MT_EMCCMD_COMPLETED
reply_ticket: 7

and after that I do not receive any message from error service... So what I am missing here?

zhivko commented 8 years ago

Is there any chance to output messages on mkwrapper side? I could then see what QtQuickVCP client posts to mkwrapper. Would this work in CRAMPS.ini:

[DISPLAY]

# Name of display program, e.g., tkemc
#DISPLAY = tkemc
#DISPLAY = gscreen
DISPLAY = mkwrapper -d
#DISPLAY = axis

note -d after mkwrapper.

machinekoder commented 8 years ago

Yes it should work.

machinekoder commented 8 years ago

@zhivko I pushed the current status of the Machinetalk documentation to https://github.com/strahlex/machinetalk-doc/blob/master/application/commandprotocol.md This might help you.

zhivko commented 8 years ago

THank you Alexander - this is very very nice documentation and it will probably help many starters to get into world of machinetalk. I immediately found command for loading gcode program: https://github.com/strahlex/machinetalk-doc/blob/master/application/commandprotocol.md#emc-task-plan-open

It will help me proceed with my project - I still need to do mechanics, but I already made a test of first stepper commanding from Java client. Also I was able to get around joint 2 following error, with increasing ferror and error variable in ini file.

emc/task/taskintf.cc 617: Error on axis 2, command number 92
NML_INTERP_LIST::append(nml_msg_ptr{size=12,type=EMC_TASK_PLAN_SYNCH}) : list_size=1, line_number=0
NML_INTERP_LIST::append(nml_msg_ptr{size=12,type=EMC_TASK_PLAN_SYNCH}) : list_size=1, line_number=0
NML_INTERP_LIST::append(nml_msg_ptr{size=12,type=EMC_TASK_PLAN_SYNCH}) : list_size=1, line_number=0
command #4 from z��� completed
zhivko commented 8 years ago

Executing MDI now works at my side after taking your suggestion into account that gcode parametere should be ascii string.

            ByteString comm = ByteString.copyFrom(Settings.parMdiCommand.getBytes("US-ASCII"));

So whole method for executing MDI command is now:

            pb.Message.Container.Builder builder = Container.newBuilder();
            ByteString comm = ByteString.copyFrom(Settings.parMdiCommand.getBytes("US-ASCII"));
            pb.Status.EmcCommandParameters emcCommandParameter = pb.Status.EmcCommandParameters.newBuilder()
                    .setCommandBytes(comm).build();
            builder.setType(ContainerType.MT_EMC_TASK_PLAN_EXECUTE);
            builder.setEmcCommandParams(emcCommandParameter);
            builder.setInterpName("execute");
            builder.setTicket(ticket++);
            container = builder.build();
zhivko commented 8 years ago

Another issue here - or better to say I am not sure how to approach error service properly Now I do this:

        Context con = ZMQ.context(1);
        errorSocket = con.socket(ZMQ.SUB);
        errorSocket.setReceiveTimeOut(3000);
        errorSocket.connect(errorUrl);
        errorSocket.subscribe("error".getBytes());
        errorSocket.subscribe("text".getBytes());
        errorSocket.subscribe("display".getBytes());
        errorSocket.setLinger(0);

and then periodically (5 sec timer):

                try {
                    contReturned = Container.parseFrom(getErrorSocket().recv());
                    System.out.println(contReturned.toString());
                    if (contReturned.getType().toString().equals("MT_EMC_OPERATOR_ERROR")) {
                        List<String> notes = contReturned.getNoteList();
                        System.out.println("Operator error:");
                        for (String note : notes) {
                            System.out.println("\t" + note);
                        }
                        System.out.println("");
                    } else if (!contReturned.getType().toString().equals("MT_PING")) {
                        System.out.println(contReturned.toString());
                    }
                } catch (InvalidProtocolBufferException e) {
                    System.out.println("Unknown message type.");
                }

I know I already have received some error messages - but now with this code all I regullary get is exception in a style:

com.google.protobuf.InvalidProtocolBufferException: Protocol message end-group tag did not match expected tag.
or
com.google.protobuf.InvalidProtocolBufferException: Message missing required fields: type

while Container.parseFrom(getErrorSocket().recv());

So how can I correctly receive operator messages and error messages? what I am doing wrong?

zhivko commented 8 years ago

I found out I am sometimes getting error messages but usually i just get: com.google.protobuf.InvalidProtocolBufferException: Message missing required fields: type at com.google.protobuf.UninitializedMessageException.asInvalidProtocolBufferException(UninitializedMessageException.java:81) at com.google.protobuf.AbstractParser.checkMessageInitialized(AbstractParser.java:71) at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:168) at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:180) at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:185) at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:49) at pb.Message$Container.parseFrom(Message.java:6585) at com.kz.pipeCutter.BBB.BBBError$1.run(BBBError.java:73) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745)

I am using jeromeq (https://github.com/zeromq/jeromq). Isn't one of the main functionalities of zmq not to receive only partial zmq messages?

machinekoder commented 8 years ago

@zhivko You have to use recv_multipart() (or your language equivalent). The first frame of the message is the topic, the second one the actual encoded protobuf message.

machinekoder commented 8 years ago

Looks like you have to call recv() twice:

topic = getErrorSocket().recv();
contReturned = Container.parseFrom(getErrorSocket().recv());
zhivko commented 8 years ago

Ok reprogramed to use multipart messages - works much better now in a sense I do not get any errors related to unknown type. But I only get MT_PING messages back also when I should get operator and nml - mdi errors back. This is my code:

    private static Socket getErrorSocket() {
        if (BBBError.errorSocket != null)
            return errorSocket;

        String errorUrl = Settings.getInstance().getSetting(
                "machinekit_errorService_url");

        Context con = ZMQ.context(1);
        errorSocket = con.socket(ZMQ.SUB);
        errorSocket.setReceiveTimeOut(2000);
        errorSocket.setLinger(20);
        errorSocket.setHWM(0);
        errorSocket.connect(errorUrl);

        errorSocket.subscribe("error".getBytes());
        errorSocket.subscribe("text".getBytes());
        errorSocket.subscribe("display".getBytes());
        errorSocket.subscribe("status".getBytes());

        // errorSocket.setLinger(0);
        return errorSocket;
    }

        Runnable errorReporter = new Runnable() {
            @Override
            public void run() {
                try {
                    Container contReturned;

                    ZMsg receivedMessage = ZMsg.recvMsg(getErrorSocket());
                    for (ZFrame f : receivedMessage) {
                        byte[] returnedBytes = f.getData();
                        String messageType = new String(returnedBytes);
                        if (!messageType.equals("error") &&
                                !messageType.equals("text") &&
                                !messageType.equals("display") &&
                                !messageType.equals("status") ) {
                            //System.out.println(messageType);
                            contReturned = Message.Container.parseFrom(returnedBytes);
                            System.out.println(contReturned.toString());
                            System.out.println(contReturned.getOperatorError().toString());
                            List<String> notes = contReturned.getNoteList();
                            for (String note : notes) {
                                System.out.println("\t" + note);
                            }
                        }
                    }

                } catch (Exception e) {
                    if (!e.getMessage().equals("Unknown message type."))
                        e.printStackTrace();
                }
            }
        };
        scheduler.scheduleAtFixedRate(errorReporter, 0, 5, TimeUnit.SECONDS);

It is somehow strange that i am receiving MT_PING !? I do not use MT_PING anywhere in my code - so it must comming from machinekit??

zhivko commented 8 years ago

OK fixed it - it turned out that there were multiple multi-part messages. Wireshark showed there are indeed MT_PING messages comming from machinekit to my client.

zhivko commented 8 years ago

Now to the Status or Preview service - or is it Previewstatus service? From machinekit starting I see:

service: dsname = tcp://%(fqdn)s:55191 port = 55191 txtrec = ['dsn=tcp://%(fqdn)s:55191', 'uuid=a42c8c6b-4025-4f83-ba28-dad21114744a', 'instance=e1fdf80e-96f5-11e5-a5ad-544a16c5d020', 'service=status'] name = Status service on %(fqdn)s pid 10484
service: dsname = tcp://%(fqdn)s:54028 port = 54028 txtrec = ['dsn=tcp://%(fqdn)s:54028', 'uuid=a42c8c6b-4025-4f83-ba28-dad21114744a', 'instance=e2024d32-96f5-11e5-a5ad-544a16c5d020', 'service=error'] name = Error service on %(fqdn)s pid 10484
service: dsname = tcp://%(fqdn)s:50742 port = 50742 txtrec = ['dsn=tcp://%(fqdn)s:50742', 'uuid=a42c8c6b-4025-4f83-ba28-dad21114744a', 'instance=e2053088-96f5-11e5-a5ad-544a16c5d020', 'service=command'] name = Command service on %(fqdn)s pid 10484
service: dsname = tcp://%(fqdn)s:49153 port = 49153 txtrec = ['dsn=tcp://%(fqdn)s:49153', 'uuid=a42c8c6b-4025-4f83-ba28-dad21114744a', 'instance=e2090e24-96f5-11e5-a5ad-544a16c5d020', 'service=preview'] name = Preview service on %(fqdn)s pid 10484
service: dsname = tcp://%(fqdn)s:49154 port = 49154 txtrec = ['dsn=tcp://%(fqdn)s:49154', 'uuid=a42c8c6b-4025-4f83-ba28-dad21114744a', 'instance=e20994ac-96f5-11e5-a5ad-544a16c5d020', 'service=previewstatus'] name = Previewstatus service on %(fqdn)s pid 10484

So is it preview? status? or previewstatus service? I need to connect socket to to get position updates? I tried connecting on all three of them (separately) and didn't get any reply. I am using SUB similar like for an error service.

zhivko commented 8 years ago

OK correct way to get motion update is to use: machinekit_statusService_url and subscribe to "motion" channel.

zhivko commented 8 years ago

I am trying to start gcode program located in machinekit instance (location sftp://machinekit@192.168.1.99/home/machinekit/machinekit/nc_files, the gcode files was uploaded there previoulsy via ftp). I tried to find sample in: https://github.com/strahlex/QtQuickVcp/blob/master/src/applicationcontrols/ReopenAction.qml I am currently guessing how to do that in JAVA code. Currently I have this:

        pb.Message.Container.Builder builder = Container.newBuilder();
        pb.Status.EmcCommandParameters emcCommandParameter = pb.Status.EmcCommandParameters
                .newBuilder().setTaskMode(EmcTaskModeType.EMC_TASK_MODE_AUTO).build();
        builder.setType(ContainerType.MT_EMC_TASK_SET_MODE);
        builder.setEmcCommandParams(emcCommandParameter);
        builder.setInterpName("execute");
        builder.setTicket(ticket++);
        Container container = builder.build();
        byte[] buff = container.toByteArray();
        getCommandSocket().send(buff, 0);
        parseAndOutput();

        builder = Container.newBuilder();
        builder.setType(ContainerType.MT_EMC_TASK_PLAN_INIT);
        builder.setInterpName("execute");
        builder.setTicket(ticket++);
        buff = container.toByteArray();
        getCommandSocket().send(buff, 0);
        parseAndOutput();

        builder = Container.newBuilder();
        emcCommandParameter = pb.Status.EmcCommandParameters.newBuilder()
                .setPath("/home/machinekit/machinekit/nc_files/prog.gcode").build();
        builder.setType(ContainerType.MT_EMC_TASK_PLAN_OPEN);
        builder.setEmcCommandParams(emcCommandParameter);
        builder.setInterpName("execute");
        builder.setTicket(ticket++);
        container = builder.build();
        buff = container.toByteArray();
        getCommandSocket().send(buff, 0);
        parseAndOutput();

        builder = Container.newBuilder();
        builder.setType(ContainerType.MT_EMC_TASK_PLAN_RUN);
        builder.setInterpName("execute");
        builder.setTicket(ticket++);
        buff = container.toByteArray();
        getCommandSocket().send(buff, 0);
        parseAndOutput();
        return container;

I am getting this on BBB side:

Issuing EMC_TASK_PLAN_OPEN --    (+506,+268,    +6,/home/machinekit/machinekit/nc_files/prog.gcode,)
emc/task/emctask.cc 399: interp_error: A file is already open
A file is already open
Interpreter stack:   - virtual int Interp::open(const char*) 
can't open /home/machinekit/machinekit/nc_files/prog.gcode
emc/task/emctaskmain.cc 2341: error executing command 506:EMC_TASK_PLAN_OPEN
emcTaskIssueCommand() returning: -1
waiting for command #2from e�[l to complete command #0 from e�[l completed

sending motion message
process command called, id: e�[l
Issuing EMC_TASK_PLAN_OPEN --    (+506,+268,    +7,/home/machinekit/machinekit/nc_files/prog.gcode,)
emc/task/emctask.cc 399: interp_error: A file is already open
A file is already open
Interpreter stack:   - virtual int Interp::open(const char*) 
can't open /home/machinekit/machinekit/nc_files/prog.gcode
emc/task/emctaskmain.cc 2341: error executing command 506:EMC_TASK_PLAN_OPEN
emcTaskIssueCommand() returning: -1
sending motion messagecommand #2 from e�[l completed
waiting for command #2from e�[l to complete
command #2 from e�[l completed
sending motion message
command #2 from e�[l completed

If anybody have any idea what causes this error, I would appreciate it very much.

zhivko commented 8 years ago

After deepdive in: QtQuickVcp/src/application/qapplicationcommand.cpp QtQuickVcp/src/applicationcontrols/ReopenAction.qml and mkwrapper from machinekit

finally got this functionality up and running...

Running gcode works fine with this java code (still need to confirm on actual machine though):

        pb.Message.Container.Builder builder = Container.newBuilder();
        pb.Status.EmcCommandParameters emcCommandParameter = pb.Status.EmcCommandParameters
                .newBuilder().setTaskMode(EmcTaskModeType.EMC_TASK_MODE_AUTO).build();
        builder.setType(ContainerType.MT_EMC_TASK_SET_MODE);
        builder.setEmcCommandParams(emcCommandParameter);
        builder.setInterpName("execute");
        builder.setTicket(ticket++);
        Container container = builder.build();
        byte[] buff = container.toByteArray();
        getCommandSocket().send(buff, 0);
        parseAndOutput();

        builder = Container.newBuilder();
        builder.setType(ContainerType.MT_EMC_TASK_PLAN_INIT);
        builder.setInterpName("execute");
        builder.setTicket(ticket++);
        container = builder.build();
        buff = container.toByteArray();
        getCommandSocket().send(buff, 0);
        parseAndOutput();

        builder = Container.newBuilder();
        emcCommandParameter = pb.Status.EmcCommandParameters.newBuilder()
                .setPath("/home/machinekit/machinekit/nc_files/prog.gcode").build();
        builder.setType(ContainerType.MT_EMC_TASK_PLAN_OPEN);
        builder.setEmcCommandParams(emcCommandParameter);
        builder.setInterpName("execute");
        builder.setTicket(ticket++);
        container = builder.build();
        buff = container.toByteArray();
        getCommandSocket().send(buff, 0);
        parseAndOutput();

        builder = Container.newBuilder();
        builder.setType(ContainerType.MT_EMC_TASK_PLAN_RUN);
        builder.setInterpName("execute");
        builder.setTicket(ticket++);
        container = builder.build();
        buff = container.toByteArray();
        getCommandSocket().send(buff, 0);
        parseAndOutput();
zhivko commented 8 years ago

Trying to run gcode I get:

type: MT_EMC_OPERATOR_ERROR note: "E word with no G76, M66, M67 or M68 to use it"

Maybe somebody has idea what would be wrong with this gcode? Gcode available at: http://pastebin.com/R5maYT6T

bobvanderlinden commented 8 years ago

I'm not entirely sure, but could this be it? "G1 X-1.00156234E-4" notice the E.

On Mon, May 2, 2016 at 9:20 PM zhivko notifications@github.com wrote:

Trying to run gcode I get:

note: "E word with no G76, M66, M67 or M68 to use it"

Maybe somebody has idea what would be wrong with this gcode? Gcode available at: http://pastebin.com/R5maYT6T

— You are receiving this because you were mentioned.

Reply to this email directly or view it on GitHub https://github.com/bobvanderlinden/node-machinetalk/issues/16#issuecomment-216334662

zhivko commented 8 years ago

Yes that's it! Thanks!

zhivko commented 8 years ago

OK I have now: "File ended with no percent sign or program end" Is there some END needed for machinekit gcode dialect? GCode prog at pastebin: http://pastebin.com/L8Qu716R

zhivko commented 8 years ago

Adding M2 solves this error.

zhivko commented 8 years ago

OK another tricky question - I want to remote monitor for some hal pins - actually pin: motion.program-line I do not know how to add pin list to Component object

        pb.Message.Container.Builder builder = Container.newBuilder();

        // motion.program-line

        pb.Object.Component component = pb.Object.Component.newBuilder().setName("motion").setNoCreate(false).build();
        pb.Object.Pin pin = pb.Object.Pin.newBuilder().setName("motion.program-line").setType(pb.Types.ValueType.HAL_S32).setDir(pb.Types.HalPinDirection.HAL_OUT).build(); 

        //component.getParamOrBuilderList().set(0, (ParamOrBuilder)pin);

        builder.setType(ContainerType.MT_HALRCOMP_BIND);
        builder.setTicket(MachineTalkCommand.getNextTicket());

So question - how can I assign properly list of pins to component object in JAVA with machinekit protobuff for java?

I start server side haltalk with following: For this I added this line in beginning of BBB hal file CRAMPS.hal:

loadusr -W haltalk --debug 0
´´´

When enumerating for services I can see following running services

HAL Rcommand service on beaglebone tcp://beaglebone.local.:49155/ HAL Group service on beaglebone tcp://beaglebone.local.:49153/ HAL Rcomp service on beaglebone tcp://beaglebone.local.:49154/ ´´´

at log on BBB when starting machinekit with

machinekit@beaglebone:~$ machinekit ./machinekit/configs/ARM.BeagleBone.CRAMPS/CRAMPS.ini
MACHINEKIT - 0.1

I get:

machinekit@beaglebone:~$ machinekit ./machinekit/configs/ARM.BeagleBone.CRAMPS/CRAMPS.ini
MACHINEKIT - 0.1
Machine configuration directory is '/home/machinekit/./machinekit/configs/ARM.BeagleBone.CRAMPS'
Machine configuration file is 'CRAMPS.ini'
Starting Machinekit...
(time=1448831976.833003,pid=5175): Registering server on TCP port 5005.
(time=1448831976.834182,pid=5175): running server for TCP port 5005 (connection_socket = 3).
io started

I am opening hal cmd socket with this code:

        Context con = ZMQ.context(1);
        halCmdSocket = con.socket(ZMQ.DEALER);
        halCmdSocket.setReceiveTimeOut(10000);
        halCmdSocket.setLinger(0);
        halCmdSocket.setIdentity("id654645".getBytes());

        halCmdSocket.connect(halGrpUrl);
zhivko commented 7 years ago

Solve this in PipeCutter project ... closing ...