Mujoco KDL Wrapper  0.3.18
MuJoCo + KDL bridge for robot kinematics and dynamics
Loading...
Searching...
No Matches
camera_ros.hpp
Go to the documentation of this file.
1/* SPDX-License-Identifier: MIT
2 * Copyright (c) 2026 Vamsi Kalagaturu
3 * See LICENSE for details. */
4
5#pragma once
6
7#include <mujoco/mujoco.h>
8#include <rclcpp/rclcpp.hpp>
9#include <sensor_msgs/msg/camera_info.hpp>
10#include <sensor_msgs/msg/image.hpp>
11
12#include <cstdint>
13#include <string>
14
15namespace mj_kdl {
16
17/**
18 * @ingroup grp_recorder
19 * What a simulated camera is called on the ROS graph, and how often it is published.
20 */
22{
23 std::string camera; // camera name in the compiled model (a scene prefixes robot cameras)
24 std::string frame_id; // must name a ROS-optical frame: +Z forward, +X right, +Y down
25 std::string topic_ns; // -> <topic_ns>/color, <topic_ns>/camera_info
26 int width = 0;
27 int height = 0;
28 double rate_hz = 30.0;
29};
30
31/**
32 * @ingroup grp_recorder
33 * Publishes an already-rendered RGB frame as sensor_msgs/Image plus its CameraInfo.
34 *
35 * A frame sink, not a renderer: it creates no node, no executor and no thread, and never
36 * touches mjModel or mjData after construction. Call it from the thread that rendered the
37 * frame - render once, hand the same buffer to whatever else consumes it.
38 *
39 * Intrinsics are read from the model's cam_fovy at construction, so the published K is the one
40 * MuJoCo rendered with. Pixels are published exactly as rendered: a MuJoCo camera looks along
41 * its -Z with +Y up, so `frame_id` must name a frame already rotated into the ROS optical
42 * convention, or every pose a consumer estimates comes out rotated.
43 *
44 * CameraRosPublisher pub(*node, model, conf);
45 * if (pub.wants_frame(t) && render_rgb(&vr, model, data, rgb.data())) pub.publish(rgb.data(), t);
46 */
48{
49 public:
50 CameraRosPublisher(rclcpp::Node &node, const mjModel *model, CameraConf conf);
51
52 /** Due by rate, and somebody is subscribed to the image topic. No frame is touched. */
53 bool wants_frame(double sim_t) const;
54
55 /** One top-down RGB frame, width * height * 3 bytes, stamped with the sim time it shows. */
56 void publish(const std::uint8_t *rgb, double sim_t);
57
58 /** The CameraInfo published alongside every frame; built once, only its stamp changes. */
59 const sensor_msgs::msg::CameraInfo &camera_info() const { return info_; }
60
61 private:
62 CameraConf conf_;
63 rclcpp::Publisher<sensor_msgs::msg::Image>::SharedPtr image_pub_;
64 rclcpp::Publisher<sensor_msgs::msg::CameraInfo>::SharedPtr info_pub_;
65 sensor_msgs::msg::Image image_;
66 sensor_msgs::msg::CameraInfo info_;
67 double period_s_ = 0.0;
68 double next_due_s_ = 0.0;
69};
70
71} // namespace mj_kdl
bool wants_frame(double sim_t) const
void publish(const std::uint8_t *rgb, double sim_t)
const sensor_msgs::msg::CameraInfo & camera_info() const
CameraRosPublisher(rclcpp::Node &node, const mjModel *model, CameraConf conf)
std::string frame_id
std::string topic_ns
std::string camera