Viper Quadcopter

Hi :wave: Thank you very much for providing this bit of information (it works now, after another final piece has been dealt with - details below).

Please don’t take this the wrong way - people don’t read the documentation. Even if its as good as yours and I can tell that you’ve put a lot of effort into it. Also error messages should provide some clue about what has gone wrong, I’m not going to look up the offending Python line causing a runtime error, even if the code is open-source. Tools, code and their usage needs to be as much as possible self-evident.

That being said, even after adding the director to $PYTHONPATH I had the following error

pyuavcan publish uavcan.diagnostic.Record.1.0 '{"text": "Hello world!"}' --tr='CAN(can.media.socketcan.SocketCANMedia("vcan0",8),59)'
Error: RuntimeError: Subsystem factory 'NodeFactory' for command 'publish' has failed: No module named 'serial'

Quite annoying, because I don’t need serial at all. Fixed by

python3.8 -m pip install pyserial

EDIT: Adding documentation of success case

sudo modprobe vcan
sudo ip link add dev vcan0 type vcan
sudo ip link set up vcan0
candump -decaxta vcan0
 (1591276745.132963)  vcan0  TX - -  107D553B   [8]  00 00 00 00 00 A3 03 E0   '........'
 (1591276745.133101)  vcan0  TX - -  107FF83B   [8]  00 00 00 00 00 00 00 A0   '........'
 (1591276745.133181)  vcan0  TX - -  107FF83B   [8]  00 0C 48 65 6C 6C 6F 00   '..Hello.'
 (1591276745.133221)  vcan0  TX - -  107FF83B   [8]  20 77 6F 72 6C 64 21 20   ' world! '
 (1591276745.133292)  vcan0  TX - -  107FF83B   [3]  00 F5 40                  '..@'
 (1591276746.135043)  vcan0  TX - -  107D553B   [8]  01 00 00 00 00 A3 03 E1   '........'

Next question arises … I’m trying my hand at generating a heartbeat message:

$ pyuavcan publish 32085.Heartbeat.1.0 '{uptime: 1337}' --tr='CAN(can.media.socketcan.SocketCANMedia("vcan0",8),59)'
Error: ValueError: Malformed data spec: '32085.Heartbeat.1.0

Now I’ve got not idea from where this error is coming from, if I extent the command like that to encompass all entries of 32085.Heartbeat.1.0.uavcan it fails all the same.

$ pyuavcan publish 32085.Heartbeat.1.0 '{uptime: 1337, health: HEALTH_CAUTION, mode: MODE_MAINTAINANCE}' --tr='CAN(can.media.socketcan.SocketCANMedia("vcan0",8),59)'
Error: ValueError: Malformed data spec: '32085.Heartbeat.1.0'

:man_shrugging:

You found a bug! :tada: Congratulations, I registered it on the bug tracker. Thank you.

The correct syntax is as follows:

pyuavcan publish 32085.uavcan.node.Heartbeat.1.0 '{uptime: 1337}' --tr='CAN(can.media.socketcan.SocketCANMedia("vcan0",8),59)'

Your example didn’t work because you did not provide the full data type name. It should be 32085.uavcan.node.Heartbeat.1.0, not 32085.Heartbeat.1.0. The error message, again, could be better, I agree.

Your feedback is very important. There is a new ticket here: https://github.com/UAVCAN/pyuavcan/issues/115. I am not sure if it’s even possible to build a self-documenting command-line interface due to the limited number of interaction scenarios offered by the command line. If you have a radical idea of how to improve the usability, please share; for now, I will focus on merely improving the error messages.

Thank you very much for your prompt reply :heart: I’m not really setting out to find any bugs, it just that I really don’t like Python very much and therefore have very little on my system (lately I did sudo apt-get purge python* in a Python rage fit which left me amongst other things without a window manager - thank god such inconveniences can be recovered from by reinstalling the window manager from bash :wink: ).

Let’s get back to the subject at hand, I tried to use the “health” field too and stumbled onto the next blocker. Do I have to prefix the message type somehow?

pyuavcan publish 32085.uavcan.node.Heartbeat.1.0 '{uptime: 1337, health: HEALTH_CAUTION}' --tr='CAN(can.media.socketcan.SocketCANMedia("vcan0",8),59)'
Error: ValueError: invalid literal for int() with base 10: 'HEALTH_CAUTION'

Another question that came up: Which node-id is chosen for publishing this message and can I manually set it? I’ve found the folder

node-id-59

within

~/.uavcan/pyuavcan/v1.1/output-transfer-id-maps

. Does that mean that node id 59 (decimal?) was used for my last successful heartbeat transfer?

Nope, the problem is that primitive representations do not allow you to reference constants. You should just use literal 2 instead of HEALTH_CAUTION. It is, indeed, inconvenient, but I am not sure how to approach it best and this issue is so far down the list that it’s not even tracked on the bug tracker.

--transport EXPRESSION, --tr EXPRESSION
...
Observe that the node-ID for the local node is to be configured here as well,
because per the UAVCAN architecture, this is a transport-layer property.
If desired, a usable node-ID value can be automatically found using the
command "pick-node-id"; read its help for usage information (it's useful for
various automation scripts and similar tasks).
...

Don’t get me wrong – I don’t mind answering your questions; in fact, they offer extremely valuable insights about the user’s perception of what we’re building, but I am concerned that you might be spending more of your time on this than you really have to.

You set the node-ID yourself in the string CAN(can.media.socketcan.SocketCANMedia("vcan0",8),59). See 59 at the end of it? You can see the full parameter specs in the docs or you can just execute pyuavcan show-transport to read the same docs in the command line locally.

You appear to be unaware of the fact that every invocation of CLI that instantiates a non-anonymous node will be publishing the heartbeat automatically. Just letting you know because I predict that next you will be asking why is your heartbeat published twice :wink: If you want to override the fields of that auto heartbeat you can use --heartbeat-fields.

If you have any ideas about how to make the life of the user easier (aside from improving error messages), please share. The CLI toolset does seem a bit convoluted and it could be possible to make it more approachable without requiring the user to dig through the docs for hours. Maybe.

Actually I was not going to ask that question because I read in fact the whole UAVCAN v1 crash course entry where this aspect is mentioned :wink: But yes, I fully admit guilty to the trial-and-error approach when it comes to reading documentation :blush:

Actually I’ve got a couple of suggestions to make the CLI tool easier to use.

  1. As a user using the pyuavcan publish feature I’m interested first and foremost in publishing UAVCAN data on various transport layers. That’s why my focus is on setting up the message and not configuring the transportlayer which additionally is appended at the end of a already very long bash entry (alternatively it’s in front but the manipulation of the message is at the end, also undesirable). This is actually the reason why I was unable to make the connection of the 59 node id with the 59 at the end of the --tr string - it was simply lost to my eye focus because of the awful long bash line.
  2. As a typical user I’m not going to change my transport layer 3 times a day. Probably I’ll change it never. Therefore it might be worth considering to introduce “state” to the pyuavcan CLI tool which allows to permanently configure the desired transport layer. (pyuavcan config --gobal transport=CAN). It’s probably only you as the UAVCAN devs that need to change between various transport layers on a regular basis.
  3. The transport layer configuration is done via a string. I daresay that’s unusal for the typical bash user. They(we) are used to having identifiers before the parameter which give some hint as what it is that we are configuring. E.g.
--tr=[CAN|Serial|...]
--tr=CAN [can0|vcan0|can1|...] -can-mtu-=[8|64] -can-id=(0-127)

Thank you. I think 1 and 2 are sensible points and I just registered this issue here: https://github.com/UAVCAN/pyuavcan/issues/117

Not sure about the specialized options though. I implemented this approach early in the development process but it is quite messy because you have to keep these options aware and in sync with the transport implementations, it’s just too much work to maintain reliably. I think if we made the environment variables as described in the linked issue it would solve the problem ultimately because I suppose you would just stash the config away in your ~/.bashrc and never look at it again.

Sorry for the longer break but I was caught up in quite a lot of things. There’s one thing that has been on my mind lately - Is there a RPM message in the new UAVCAN V1? I’ve been wondering since I’m putting quite some effort in a UAVCAN V1 Arduino Library which I mainly intend to use to drive 4 Zubax Orel 20 ESCs (which aren’t even ported to UAVCAN V1 yet). If there’s no RPM message I imagine the porting to be a bit more ressource consuming and I’m starting to wonder whether or not to drop the whole UAVCAN V1 thing and go back to the legacy protocol.

We are working with Dronecode to develop the Drone Profile for UAVCAN which will include the ESC status data.

I don’t think staying with v0 is sensible at all because it is inferior to v1 in many aspects.

Thank you very much for getting back to me on that one. Do you have an estimation when said Drone Profile will be available? I’m also reluctant to throw away all the work done for supporting the V1 version but it has started to look like an uphill battle.

Here you’ve mentioned that you might get to upgrade the Orel 20 to V1 in June, given that June has passed I’m wondering at what time-horizon we are looking at?

I will prioritize ESC messages but I can’t give you a timeline at the moment, not yet. It depends on the coordination of many involved parties here.

We don’t know yet. Are you available to help us here?

Once the drone profile is available and if’s similar enough with the messages used in V0 then it should be relatively easy to port the Orel 20 to UAVCAN V1, I can do that.

1 Like

Finally the Viper Quadcopter effort got a logo …

Viper Logo

… what do you think about it? :wink:

That’s not a bad logo (even the fact that the direction of the propellers is incorrect cannot spoil it).

:sweat_smile: Great catch :sweat_smile: Obviously the designer hasn’t ever owned a quadcopter and I myself didn’t think of it. Since I rolled out the logo already across all repositories I won’t change that aspect, but being made aware now it will be a constant tickle in the background of my mind :stuck_out_tongue:

Today (after a 2.5 month wait time) my Zubax Orel 20 order from Titan Elite/USA finally arrived (Corona delivery times are horrible!). Got them mounted on a Armattan Frame. Not looking forward to the wiring part. Also wondering if there could be motors with more power for those tiny 3" rotors?

1 Like

Good morning :wave:
I’m in the process of adding the handling of Service exchanges to the Arduino UAVCAN library. I’m wondering about how I can stimulate pyuavcan so that I can create the response part of the message which I need for feeding into my test code (see this line)?

pyuavcan call only shows me the request, in absence of a answering node, how would I get to the correct response for feeding into my test setup?

$ pyuavcan call 27 435.uavcan.node.ExecuteCommand.1.0 '{command: 0xCAFE, parameter: "I want a double espresso with cream"}' --tr='CAN(can.media.socketcan.SocketCANMedia("vcan0",8),13)'
The request has timed out after 1.0 seconds

You can’t do that from CLI, it’s by design. Write a script instead or use Python prompt as shown here: Proposed change to variable-length arrays. When dealing with service types, add .Request or .Response after the type name.

So I’ve written myself a little script to create a ExecuteCommand.1.0 Response …

#!/usr/bin/python3.8

import pyuavcan
import uavcan
import uavcan.node

serialized = pyuavcan.dsdl.serialize(uavcan.node.ExecuteCommand_1_0.Response(status=1))
print (bytes(next(serialized)))

… which produces …

$ ./create-response.py 
b'\x01\x00\x00\x00\x00\x00\x00'

… which I interpret as a 7-byte long payload with the 1st byte containing the status and the rest being … UAVCAN “overhead”? Is this a suitable response to the request? Also I’d need to generate the right node ID for the response, the remote node id of that particular request is 27.

The definition of the response is as follows, if we remove everything but the fields:

uint8 status
void48

So the size is 7 bytes, which agrees with your observations.

This is a suitable serialized response data structure. This is a presentation-layer entity.

Now you’re talking about the transport layer. To get at this level, you need to make a service server and send a request to it. An example is shown in the PyUAVCAN Basic Demo.