Skip to content

feat/led deck commands and reboot service - #866

Merged
whoenig merged 1 commit into
IMRCLab:mainfrom
dimitriasilveria:led-deck
Jun 13, 2026
Merged

feat/led deck commands and reboot service#866
whoenig merged 1 commit into
IMRCLab:mainfrom
dimitriasilveria:led-deck

Conversation

@dimitriasilveria

Copy link
Copy Markdown

Hello. Now, I crated the PR using the original main branch as the base. I added two features: the LED deck commands topic and a service to reboot the CFs.

When attaching the LEDs to the drones, I noticed that the crazyflie_server wouldn't stablish connection with them due to a highest information exchange, which would increas the latency. To fix that, I added lines 175 to 180, commented out line 550, and added lines 1009 to 1016.

@whoenig

whoenig commented Jun 9, 2026

Copy link
Copy Markdown

Thanks for cleaning up your PR!

  1. Reboot: One problem I see with adding a reboot service is that it has unexpected side effects: the drone will be reset and the "commands" written in crazyflies yaml (setting parameters, configuring logging) will be lost after the reboot. It may be possible to execute this logic after a reboot (similar to what happens when first starting the crazyflie_server), but when I experimented with that in the past that led to firmware crashes due to race conditions in the firmware.
  2. Connection fix ("To fix that, I added lines 175 to 180, commented out line 550, and added lines 1009 to 1016."). Could you describe again what happens without your changes? Especially the part regarding the radio statistics is unclear to me how that would fix any connectivity issues.
  3. The new cmd_led topic seems to be a convenience function that converts a string to a uint32, followed by setting one parameter. Perhaps this is something that should go into the crazyflie_py layer rather than the server?

@dimitriasilveria

dimitriasilveria commented Jun 9, 2026

Copy link
Copy Markdown
Author

Hi Professor,
Thank you for the quick reply.

1. Reboot: One problem I see with adding a reboot service is that it has unexpected side effects: the drone will be reset and the “commands” written in crazyflies.yaml—setting parameters and configuring logging—will be lost after the reboot. It may be possible to execute this logic after a reboot, similarly to what happens when initially starting crazyflie_server, but when I experimented with that in the past, it caused firmware crashes due to race conditions.

I have been using this reboot functionality locally for more than two years and have tested it with both the Crazyflie 2.1 and the Crazyflie Brushless.
In my current workflow, after issuing the reboot command, I restart crazyflie_server. The server then reconnects and reapplies the parameters and logging configuration from the YAML file. Therefore, I agree that the parameters are not necessarily preserved by the reboot itself; they are restored when the server is restarted.
This has still been useful in our experiments because, after landing, the drones do not accept another takeoff command until they are rebooted. Remotely rebooting them avoids having to press the power button on every drone manually.
However, I understand that automatically reconnecting and reapplying the configuration inside the existing server could introduce race conditions or other side effects, but I haven't seen any issue in my workflow. If the reboot service is outside the intended scope of the server, I can remove this part from the PR.

2. Connection fix: Could you describe again what happens without your changes? In particular, it is unclear to me how the radio-statistics changes would fix a connectivity issue.

There are two separate issues, and my original PR description did not distinguish them clearly enough.
The first issue concerns the radio-statistics warnings. After installing the LED decks, I observed messages such as:
[C24] Unexpected number of unicast packets.
Sent: 1055. Received: 48907

[C24] Unexpected number of broadcast packets.
Sent: 0. Received: 44570

The crazyflie_server would hang here and never initialize.
The following members were not explicitly initialized:

uint16_t previous_numRxBc;
uint16_t previous_numRxUc;

The first status callback then calculated:

int32_t deltaRxBc = data->numRxBc - previous_numRxBc;
int32_t deltaRxUc = data->numRxUc - previous_numRxUc;

Because the previous values were indeterminate, the first computed delta could be invalid. I therefore initialized the counters and connection-statistics objects:

, previous_numRxBc(0)
, previous_numRxUc(0)
, previous_stats_unicast_()
, previous_stats_broadcast_()
, last_latency_in_ms_(0)

I also added a first-sample flag. On the first status callback, the current cumulative counters are stored as the baseline, and no delta is calculated (this makes the lines , previous_numRxBc(0), previous_numRxUc(0) redundant, but I kept them as a good practice). From the second callback onward, the deltas are calculated between two valid samples.
This change removes the incorrect statistics warnings. However, after further testing, I do not think that this statistics issue was itself responsible for the connection hang.
The second and separate issue is that the server blocks inside:
cf_.requestMemoryToc();

The last output is:
Requesting memories...

When I skip requestMemoryToc(), the server completes its startup, and the Crazyflies can be controlled normally.
At this point, commenting out the call is only a workaround and is not an appropriate general solution for the PR, since memory functionality may be required for trajectory upload and other features. However, it was the only way I found to connect with the drones.

I am still investigating why the memory TOC request does not complete with this firmware and deck configuration, and how to properly solve that.

I also do not yet know why installing the deck made the uninitialized-counter issue visible. The variables were already uninitialized regardless of the deck. My current hypothesis is that the deck changes the firmware startup timing, the available TOCs, or the timing of the first status callback, thereby exposing an existing bug. I do not yet have evidence for a specific causal mechanism.

The decks are relatively new, and we previously encountered a separate firmware compatibility issue involving the Crazyflie Brushless and the hardware batch we received. Bitcraze replaced those decks after identifying the issue. I mention this only as context; I cannot yet conclude that the current memory TOC problem has the same cause.

3. LED command topic: The new cmd_led topic seems to be a convenience function that converts a string to a uint32, followed by setting one parameter. Perhaps this belongs in the crazyflie_py layer rather than the server?

I added the topic to the C++ server for two reasons:
1 - Our control stack communicates directly with the C++ server rather than through crazyflie_py.
2 - The server already owns the Crazyradio connection. My understanding is that a second process should not independently open the same Crazyradio connection while crazyflie_server is running. Therefore, LED commands need to be routed through the existing server connection or through an API exposed by the server.

That said, I agree that a string containing a hexadecimal color is primarily a convenience interface. A more general solution might be to expose a typed LED message, a service, or a generic parameter-setting interface, while implementing convenience wrappers in the Python layer. I am happy to implement any of those if you could provide me with more guidance on what the best option is.

I also have a standalone Python example that connects to one Crazyflie and controls the LED deck. I can commit it if an example of that form would be useful, although it cannot run concurrently with crazyflie_server if both attempt to own the same radio connection.

Please let me know which parts you would prefer me to keep in this PR. I am happy to separate the independent fixes into smaller PRs—for example, one for initializing the statistics correctly and another for LED control.

Thank you again for your feedback. This is my first contribution an open-source project, so I am still becoming familiar with the contribution and review process. I appreciate your guidance and am excited to improve the PR accordingly.

@whoenig

whoenig commented Jun 10, 2026

Copy link
Copy Markdown

Thanks for the detailed response!

Moving forward, I suggest the following:

  1. Feel free to open a PR for the statistics fix, that's a good catch!
  2. For reboot, I'd like to discuss with @knmcguire first, as we would need to offer the same functionality in the other backends. I also have seen the need for it, but have used as "workaround" ros2 run crazyflie_tools reboot (this forces one to first kill the server, so it is clear for the user that parameters/logging will not be reconfigured).
  3. For the LED, we already have the ROS2 interface to set parameters. Essentially, all firmware parameters are available as ROS2 parameters (e.g. cf231.params.led_deck_ctrl.rgb888). If you change the value of that parameter, it will be automatically updated on the firmware via the radio. An example is in the Python layer on how the ROS2 service call would look like:
    def setParam(self, name, value):
    """
    Change the value of the given parameter.
    See :meth:`getParam()` docs for overview of the parameter system.
    Args:
    name (str): The parameter's name.
    value (Any): The parameter's value.
    """
    try:
    param_name = self.prefix[1:] + '.params.' + name
    param_type = self.paramTypeDict[name]
    if param_type == ParameterType.PARAMETER_INTEGER:
    param_value = ParameterValue(type=param_type, integer_value=int(value))
    elif param_type == ParameterType.PARAMETER_DOUBLE:
    param_value = ParameterValue(type=param_type, double_value=float(value))
    req = SetParameters.Request()
    req.parameters = [Parameter(name=param_name, value=param_value)]
    self.setParamsService.call_async(req)
    except KeyError as e:
    self.node.get_logger().warn(f'(crazyflie.py)setParam : keyError raised {e}')
    except Exception as e:
    self.node.get_logger().warn(f'(crazyflie.py)setParam : exception raised {e}')
    . It would make sense to discuss this also with @knmcguire as adding a convenience function would again force us to do so in all backends (py, cpp, sim, rs).

Com issues: Which radio and firmware are you using? I have seen this problems as well (they are caused by a longstanding bug in the firmware), but I was not able to reproduce such issues with Crazyradio2 and the latest firmware anymore.

@dimitriasilveria

Copy link
Copy Markdown
Author

Thank you again for the feedback.

  1. I'll open a new PR with the stats fix
  2. I understand that the ros2 run crazyflie_tools reboot (and I wasn't aware of this node). However, I still find the service useful because I can reboot all of them at once and add the reboot to my node instead of manually running another command.
  3. I understand that the LED color can already be updated through the ROS 2 parameter interface. For occasional changes, that interface is sufficient. My use case has a single callback running at 20 Hz that executes a dynamic task-assignment algorithm and updates the LED color according to the assigned task. Repeated parameter-service requests could introduce latency or callback jitter, particularly if requests wait for responses, accumulate, or compete with other callbacks and radio traffic. A topic would allow the application to publish the latest desired color without blocking its periodic callback, and outdated intermediate commands could be discarded. I understand, however, that the server would still ultimately transmit the value as a firmware parameter update, so the radio-side cost would remain.

Moreover, I understand that the reboot service and the LED command topic may be too specific for my application.
If you find these features to be useful to the community, I would be happy to implement it for py and sim backends as well.

Regarding the Com issue: I am using the Crazyradio2 and the latest firmware, but I only encountered the issue after attaching the LED deck and fixing the stats issue.

@dimitriasilveria dimitriasilveria mentioned this pull request Jun 10, 2026
@whoenig
whoenig merged commit e1f8e8c into IMRCLab:main Jun 13, 2026
4 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants