MRLcomm WriteMicroseconds fails

I just programmed MRLcomm version 35 into my Arduino Mega 2560 and am trying to communicate with it from a Windows C++ program I wrote. I can find the Mega, open the COM port, and get the MRLcomm version and acknowledgement successfully. I can also attach a servo to a pin, after which the servo centers.

 

However, if I try to use the writeMicroseconds() function via MRLcomm the servo pulse always goes to the minimum (544uS). In the MRLcomm code only a single byte (ioCmd[2]) is being passed to the Arduino Servo Library function. Since a byte cannot represent the necessary 1000 to 2000 uS range it appears the Arduino library defaults to the minimum value. It seems MRLcomm needs to build an integer from 2 bytes and pass that. Of course, this brings up the Big-endian vs. Little-endian question, but either should be fine as long as it is documented.

 

GroG's picture

Hello Dak ! Wow ..

Hello Dak !

Wow .. impressive, nice work ... and ...  You are absolutely correct.

Its a bug and its been around forever, I suspect because not as many people use writeMicroseconds.
And your solution is correct.

I've fixed this in the latest commit. https://github.com/MyRobotLab/myrobotlab/commit/4270b3eeb71bd5db8a03698d8276e47e1ca2e2c0  

on the develop branch....

The Endian-ness is handled in a consistent way (BigEndian) in MrlMsg.cpp

Since you obviously have programming skills, I would recommend you use the latest on develop (Version 37 of MrlComm)

If you do (which I highly recommend) - you will need to keep your function map up to date.  The function map is completely generated and represents the integer value between a method call to MrlComm

The name of the generated msg map is ArduinoMsgCodec.h

currently SERVO_WRITE_MICROSECONDS is mapped to 59 - but it changes whenever we have to regenerate it.

So I would :

I'm very curious with your project, and your windows c++ program.

Cheers

 

dak's picture

Thanks for the Quick Update!

Hi GroG!

Thanks for the quick turnaround and suggestions. I'm hoping to have a litte time this evening to try your recommendations. I'll include the ArduinoMsgCodec.h file in my code and use the #defines to stay in sync.

My project is InMoov. However, I wanted to understand the details and work from the ground up, so decided to write the Windows program. I use Embarcadero (formerly Borland) C++ Builder, so it is very easy to write and build a GUI app for me. I've written a ton of C/C++, but have almost no Python experience (yet?).

I chose writeMilliseconds() because I could check the signal with an oscilloscope without having to do math to convert rotation angle to pulse width. This also avoided the possibility of grinding the servo at one end or the other if something wasn't right.

Doug

dak's picture

Not as easy as it sounds...

Ok, so I downloaded the latest MRLcomm (Version 37), compiled it (after commenting out a "heartbeatEnable = true" in MRLcomm.cpp because it was out of scope), and programmed my Mega. There has been a TON of work since version 35! 

It appears that to attach a servo now I must first attach a device of type servo, get the device ID out of the response, and then attach the servo using that ID. Is that correct? I'm guessing this is to be able to dynamically allocate devices rather than statically allocating them at build time and simultaneously allow devices to be named?

If so, this won't work because Device::deviceAttach() is empty and always returns false, resulting in the DEVICE_ATTACH (or is it ATTACH_DEVICE -  I think I saw both) returning a "DEVICE not attached" message. Without the ID I can't do the actual SERVO_ATTACH to connect a servo device to a pin.

Am I even close?

Thanks!

Doug

calamity's picture

Hi DougYes it have been a

Hi Doug

Yes it have been a ton of change.

Let me try to explain how it work now

Every object, be sensor or servo or anything, in MRLComm are derived from the Device class. It make it easier to make it work with the polymorphism of the classes.

you are seeing Device::deviceAttach() as empty because it's a virtual function, so it's the class that inherit from Device that implement the method.

 

The first step you need to do is to create the device

 

MSG STRUCTURE

 *                    |<-- ioCmd starts here                                        |<-- config starts here
 * MAGIC_NUMBER|LENGTH|ATTACH_DEVICE|DEVICE_TYPE|NAME_SIZE|NAME .... (N)|CONFIG_SIZE|DATA0|DATA1 ...|DATA(N)
 *
 * ATTACH_DEVICE - this method id
 * DEVICE_TYPE - the mrlcomm device type we are attaching
 * NAME_SIZE - the size of the name of the service of the device we are attaching
 * NAME .... (N) - the name data
 * CONFIG_SIZE - the size of the folloing config
 * DATA0|DATA1 ...|DATA(N) - config data
 
After creating the Device, the Arduino will send the message : PUBLISH_ATTACHED_DEVICE | ID | NAME_SIZE | NAME
 
this is the ID you need to send command to the device
 
 
         
dak's picture

Missed the Virtual

Calamity-

 

Thanks! Initially I missed the virtual function in the device class, and had not had a chance to re-post here after I figured out my error. Thanks for confirming it! I'm in the process now of writing code to do what you said.

Doug

 

GroG's picture

To add slightly to Calamity's

To add slightly to Calamity's excellent description...

You add devices just as he said, but MrlComm.cpp "sort of" represents the Arduino state.

Which is to say, when you want pins turned on or off, or if you want to read them, or change pin modes - you don't "attach a device" .. instead these functions can be done without a device - and the commands are sent directly.

dak's picture

Mostly Working Now

I have it mostly working - I can attach a servo with config data that sets the angle and that works. I still need to reset or something at the beginning - it turns out I can attach multiple times to the same pin and the output signal to the servo is a mess if I do that.

I see a lot of 4 byte responses that are "0xaa 0x02 0x01 0x01". I think these are PUBLISH_MRLCOMM_ERRORs. I get 2 after reset following the version and board info, (which could be from garbage at initial serial link connect), but then I get them after doing some of the other commands. I suspect I'm sending extra bytes, but haven't found it in my code yet. 

Ok - found it! Turns out I'm not very good at counting bytes...

GroG's picture

That's what computers are for

That's what computers are for ;)