问:
ROS ssh launch issue
So I have a setup where I want to launch my ROS nodes via a launch file, which in turn will ssh into a udoo board and the launch the necessary files for hardware communication. The launch file works great normally when I do roslaunch, and I have set up a passwordless connection between the PC running ROS and udoo, using the ssh-rsa protocol.
I wanted to launch this on the robot upstart so used the robot-upstart package to create a service for launching. This is where my errors start, as the service does not be able to establish a ssh connection between the PC running ROS and the udoo board.
The error is as follows:

```<code> Jan 09 15:12:26 seven-robot-2 systemd[1]: Started "bringup test_ru_launch".
    Jan 09 15:12:26 seven-robot-2 root[3298]: test_ru_launch: Using workspace setup file /home/seven-robot-2/Seven_ROS/devel/setup.bash
    Jan 09 15:12:26 seven-robot-2 test_ru_launch-start[3297]: <14>Jan  9 15:12:26 root: test_ru_launch: Using workspace setup file /home/seven-robot-2/Seven_ROS/devel/setup.bash
    Jan 09 15:12:27 seven-robot-2 test_ru_launch-start[3297]: <14>Jan  9 15:12:27 root: test_ru_launch: Launching ROS_HOSTNAME=seven-robot-2, ROS_IP=, ROS_MASTER_URI=http://sevenrobot2:11311/, ROS_HOME=/root/.ros, ROS_LOG_DIR=/tmp
Jan 09 15:12:27 seven-robot-2 test_ru_launch-start[3297]: ls: cannot access '/etc/ros/melodic/test_ru_launch.d/*.xacro': No such file or directory
    Jan 09 15:12:27 seven-robot-2 test_ru_launch-start[3297]: <14>Jan  9 15:12:27 root: test_ru_launch: Generated launchfile: /tmp/test_ru_launch.launch
    Jan 09 15:12:27 seven-robot-2 root[3359]: test_ru_launch: Started roslaunch as background process, PID 3358, ROS_LOG_DIR=/tmp
    Jan 09 15:12:27 seven-robot-2 test_ru_launch-start[3297]: <14>Jan  9 15:12:27 root: test_ru_launch: Started roslaunch as background process, PID 3358, ROS_LOG_DIR=/tmp
    Jan 09 15:12:28 seven-robot-2 test_ru_launch-start[3297]: xacro: in-order processing became default in ROS Melodic. You can drop the option.
    Jan 09 15:12:29 seven-robot-2 test_ru_launch-start[3297]: remote[192.168.2.23-0]: failed to launch on udooqdl:
    Jan 09 15:12:29 seven-robot-2 test_ru_launch-start[3297]: Unable to establish ssh connection to [root@192.168.2.23:22]: Server u'192.168.2.23' not found in known_hosts
    Jan 09 15:12:29 seven-robot-2 test_ru_launch-start[3297]:
    Jan 09 15:12:29 seven-robot-2 test_ru_launch-start[3297]: RLException: unable to start remote roslaunch child: 192.168.2.23-0
    Jan 09 15:12:29 seven-robot-2 test_ru_launch-start[3297]: The traceback for the exception was written to the log file
    Jan 09 15:12:29 seven-robot-2 test_ru_launch-start[3297]: ... logging to /tmp/edd14b60-9001-11ed-8c81-7c8334b0242e/roslaunch-seven-robot-2-3358.log
    Jan 09 15:12:29 seven-robot-2 test_ru_launch-start[3297]: Checking log directory for disk usage. This may take a while.
    Jan 09 15:12:29 seven-robot-2 test_ru_launch-start[3297]: Press Ctrl-C to interrupt
    Jan 09 15:12:29 seven-robot-2 test_ru_launch-start[3297]: Done checking log file disk usage. Usage is <1GB.
    Jan 09 15:12:29 seven-robot-2 test_ru_launch-start[3297]: [31B blob data]
    Jan 09 15:12:29 seven-robot-2 test_ru_launch-start[3297]: started roslaunch server http://seven-robot-2:46315/
    Jan 09 15:12:29 seven-robot-2 test_ru_launch-start[3297]: remote[192.168.2.23-0] starting roslaunch
    Jan 09 15:12:29 seven-robot-2 test_ru_launch-start[3297]: remote[192.168.2.23-0]: creating ssh connection to 192.168.2.23:22, user[root]
    Jan 09 15:12:29 seven-robot-2 test_ru_launch-start[3297]: [192.168.2.23-0] killing on exit
    Jan 09 15:12:29 seven-robot-2 systemd[1]: test_ru_launch.service: Main process exited, code=exited, status=1/FAILURE
    Jan 09 15:12:29 seven-robot-2 systemd[1]: test_ru_launch.service: Failed with result 'exit-code'.
    Jan 09 15:12:29 seven-robot-2 systemd[1]: test_ru_launch.service: Service hold-off time over, scheduling restart.
</code>```

The service and launch file is as follows:

Service file:

```<code># THIS IS A GENERATED FILE, NOT RECOMMENDED TO EDIT.

[Unit]
Description="bringup test_ru_launch"
After=network.target
Wants=network.target
After=network-online.target
Wants=network-online.target
After=multi-user.target
Wants=multi-user.target

[Service]
Type=simple
ExecStart=/usr/sbin/test_ru_launch-start
Restart=on-failure

[Install]
WantedBy=graphical.target
</code>```

roslaunch file (part where ssh is established):

```<code><group>
        <machine name="udooqdl" address="192.168.2.23" user="root" env-loader="/home/root/Seven_ROS/env_loader_udooqdl.sh" default="true"/>
      <rosparam file="<span class="math-container">$(find seven_robot_base)/params/robotParams.yaml" command="load" ns="$</span>(arg uavcanNs)/uavcan_ros_bridge"/>
      <rosparam file="<span class="math-container">$(find seven_robot_localization)/params/diff_drive.yaml" command="load" ns="$</span>(arg uavcanNs)/uavcan_ros_bridge"/>
      <include file="<span class="math-container">$(find uavcan_ros_bridge)/launch/uavcan_ros_bridge.launch">
        <arg name="uavcanNs" value="$</span>(arg uavcanNs)"/>
        <arg name="laser_enabled" default="<span class="math-container">$(arg enable_Laser)"/>
        <arg name="publishuavcanTf" default="$</span>(arg publishcanTf)"/>
        <arg name="enableMotors" default="$(arg motors_enabled)"/>
      </include>
    </group>
</code>```

Not sure what is causing the error, any help/suggestions is appreciated. Happy to provide more information if needed. I am running ROS melodic on Ubuntu 18.04.

答:
The core error in your text is: Server u'192.168.2.23' not found in known_hosts

There are two steps to establishing an SSH connection. First you need to establish the connection and after that you present your credentials.

To avoid the risk of a man-in-the-middle attack. It is standard for ssh clients to keep track of the cryptographic fingerprint of the remote server and refuse to connect if either there's not already a fingerprint for that server or it is different on the local machine.

When doing this interactively you will typically prompt you to add a new key to the known_hosts file.

This answer has an example of what it will look like

```<code>The authenticity of host 'server-name (12.345.678.900)' can't be established.
RSA key fingerprint is XXXXXXX.
Are you sure you want to continue connecting (yes/no)?
</code>```

And the solution to your problem is to setup the known_hosts for target machine. Note that it's specific to the machine, the user, and I believe the specific protocol. (Aka roslaunch uses RSA by default which may not be the default for your command line ssh client anymore.

Make sure to test add the user of the machine. That's a common mistake when debugging.

There's also a very similar question here: A is not in your SSH known_hosts file. as a good reference.

Title: ROS ssh launch issue

Body:
The core error in your text is: Server u'192.168.2.23' not found in known_hosts

There are two steps to establishing an SSH connection. First you need to establish the connection and after that you present your credentials.

To avoid the risk of a man-in-the-middle attack. It is standard for ssh clients to keep track of the cryptographic fingerprint of the remote server and refuse to connect if either there's not already a fingerprint for that server or it is different on the local machine.

When doing this interactively you will typically prompt you to add a new key to the known_hosts file.

This answer has an example of what it will look like

The authenticity of host 'server-name (12.345.678.900)' can't be established.
RSA key fingerprint is XXXXXXX.
Are you sure you want to continue connecting (yes/no)?

And the solution to your problem is to setup the known_hosts for target machine. Note that it's specific to the machine, the user, and I believe the specific protocol. (Aka roslaunch uses RSA by default which may not be the default for your command line ssh client anymore.

Make sure to test add the user of the machine. That's a common mistake when debugging.

There's also a very similar question here: A is not in your SSH known_hosts file. as a good reference.


问:
Quadcopter Props? Wood vs Plastic vs Carbon Fiber
All the pro FPV builds and the more expensive quads don't seem to be using plastic props. Any reason for this?</p>

答:
Plastic and wood props wear and tear over the time while carbon fiber props have very less tendency to wear and tear hence are more durable ad last long. I have seen plastic props breaking in flight as it was used for long duration. So if you are making expensive setup the it is always better to use carbon fiber props as their strength is far better than plastic or wooden props.

Also carbon fiber props are more rigid than plastic props. Hence you can have better efficiency out of carbon fiber props which will result in less power consumption resulting in more flight time which is a very crucial factor while designing and build qauds or any multirotor for FPV.

ContentLicense: CC BY-SA 3.0


问:
Bump and turn toys: how do they work?
I remember that when I was a kid, in the 1980s, I had some toys made in Taiwan that basically worked like this: they moved forward uniterruptily until they bumped into an obstacle; then they moved back a few centimeters and then keep moving forward with an angle in relation to the original trajectory of 15-30º clockwise; unless they bumped something while turning back, so a forward movement was triggered, which made then move in a smaller angle.

With this routine, they could basically move everywhere in the house. I don't know very well their mechanism, all they had in common was was a wheel (or wheels?) under a metallic circle under the toy; or maybe an arc of circle where a wheel could change its direction by changing its position on the arc. My memory is fuzzy

Do you people have any idea of what was the mechanism of these toys? I am pretty sure they were quite simple as I don't remember seeing anything complicated inside them. Also, I am not a specialist in robotics, and I couldn't find anything about this type of thing by searching on google.

答:
I think I know exactly what you are talking about. I don't know the physics of it all but it's not castor wheel or microswitch.

They are called 'Bump and go' toys which uses "universal/bump and go wheel"

Here's an example (source):

Universal wheel is the driving wheels, it have two rubberized parallel wheels mounted on a rotating dish. While the toy is moving straight, the dish doesn't move. Once it hit any object, the disc rotates, toy moves backward by few millimeters and proceed to move straight again in different direction. I had cracked open a few as a kid and all the electronics inside were for lights and sounds.

I have checked cheap remote-control cars mentioned above as well and they are definitely different things.

ContentLicense: CC BY-SA 4.0

Title: Bump and turn toys: how do they work?


问:
How to bridge rclpy with Python's asyncio?
In my opinion, the correct way of running ROS2 nodes inside a larger asynchronous Python application (e.g., an application built around asyncio) is not particularly obvious. I think a good solution should (i) not busy-wait the middleware and (ii) should handle cancellation properly.

I have had go at this and found a solution (see my answer) and would like to know if anyone else has a better solution or can see any flaws in my solution.

答:
The following code creates a bridge between rclpy.spin and an application built around Python's asyncio. The guard condition is used to interrupt rmw_wait and hence return early from spin_once (to handle the case where nothing else is happening). I am using Python 3.6, but I think the same principles apply to later versions of Python with the addition of some nicer APIs being available.

import threading
import asyncio
import rclpy
from rclpy.node import Node

async def spin(node: Node):
    cancel = node.create_guard_condition(lambda: None)
    def _spin(node: Node,
              future: asyncio.Future,
              event_loop: asyncio.AbstractEventLoop):
        while not future.cancelled():
            rclpy.spin_once(node)
        if not future.cancelled():
            event_loop.call_soon_threadsafe(future.set_result, None)
    event_loop = asyncio.get_event_loop()
    spin_task = event_loop.create_future()
    spin_thread = threading.Thread(target=_spin, args=(node, spin_task, event_loop))
    spin_thread.start()
    try:
        await spin_task
    except asyncio.CancelledError:
        cancel.trigger()
    spin_thread.join()
    node.destroy_guard_condition(cancel)
```
<p>This code can then be used, for example, like this:</p>
<pre class="lang-py prettyprint-override"><code>async def main():
    # create a node without any work to do
    node = Node('unused')

    # create tasks for spinning and sleeping
    spin_task = asyncio.get_event_loop().create_task(spin(node))
    sleep_task = asyncio.get_event_loop().create_task(asyncio.sleep(5.0))

    # concurrently execute both tasks
    await asyncio.wait([spin_task, sleep_task], return_when=asyncio.FIRST_COMPLETED)

    # cancel tasks
    if spin_task.cancel():
        await spin_task
    if sleep_task.cancel():
        await sleep_task

# run program
rclpy.init()
asyncio.get_event_loop().run_until_complete(main())
asyncio.get_event_loop().close()
rclpy.shutdown()
</code>```

Body:
The following code creates a bridge between rclpy.spin and an application built around Python's asyncio. The guard condition is used to interrupt rmw_wait and hence return early from spin_once (to handle the case where nothing else is happening). I am using Python 3.6, but I think the same principles apply to later versions of Python with the addition of some nicer APIs being available.

import threading
import asyncio
import rclpy
from rclpy.node import Node

async def spin(node: Node):
    cancel = node.create_guard_condition(lambda: None)
    def _spin(node: Node,
              future: asyncio.Future,
              event_loop: asyncio.AbstractEventLoop):
        while not future.cancelled():
            rclpy.spin_once(node)
        if not future.cancelled():
            event_loop.call_soon_threadsafe(future.set_result, None)
    event_loop = asyncio.get_event_loop()
    spin_task = event_loop.create_future()
    spin_thread = threading.Thread(target=_spin, args=(node, spin_task, event_loop))
    spin_thread.start()
    try:
        await spin_task
    except asyncio.CancelledError:
        cancel.trigger()
    spin_thread.join()
    node.destroy_guard_condition(cancel)

This code can then be used, for example, like this:

async def main():
    # create a node without any work to do
    node = Node('unused')

    # create tasks for spinning and sleeping
    spin_task = asyncio.get_event_loop().create_task(spin(node))
    sleep_task = asyncio.get_event_loop().create_task(asyncio.sleep(5.0))

    # concurrently execute both tasks
    await asyncio.wait([spin_task, sleep_task], return_when=asyncio.FIRST_COMPLETED)

    # cancel tasks
    if spin_task.cancel():
        await spin_task
    if sleep_task.cancel():
        await sleep_task

# run program
rclpy.init()
asyncio.get_event_loop().run_until_complete(main())
asyncio.get_event_loop().close()
rclpy.shutdown()


问:
Are Artificial Intelligence and Robotics Different?
I need help in differentiating between AI and Robotics. Are AI and Robotics two different fields or is robotics a subject in AI?

I want to pursue a career in AI and Robotics. So I need your valuable suggestion. I searched the web and also some universities that I want to apply and I cannot find any such thing that I am searching for.

答:
A Basic Robot Model

Perception:

gathers input Data from Environment using Sensors(Like Laser Scanners and Cameras).

Plan:

This is the part where AI comes into play( as the robot with respect to the input coming from sensors makes intelligent decesions like: where in the world he is called Localization or where to go in order  to find a goal etc.

Action:

Action is the output means the commands given to the Actuators(like motors and servos).This comes under the field of control theory & Control Systems .Use of intensive mathematics Linear Algebra.and control systems also involve perception (both External and Internal Sensory)


问:
Parameter $r$ of Denavit-Hartenberg
By watching this video which explains how to calculate the classic Denavit–Hartenberg parameters of a kinematic chain, I was left with the impression that the parameter $r_i$ (or $a_i$) will always be positive. </p>

<p>Is this true? If not, could you give examples where it could be negative? </p>

答:
It can be negative, because these parameters are then used to describe the transformations that are needed in order to convert one reference frame to another. For example:

So if we want to go from frame $i-1$ to frame $i$  we have to do the following:

a rotation about $x_{i-1}$ for $a_{i-1}$ in order to make the $z$ axis parallel

a transport in $x_{i-1}$ axis for $r_{i-1}$ in order to go to the $z_i$ axis

a rotation about $z_i$ for $θ_{i}$ in order to make the $x$ axis parallel

a transport in $z_{i}$ axis for $d_i$ in order to reach the origin of the $i$-th frame

Because all the transformations were done in relative frames, we multiply the homogenous transformations from the right.

So the transformation matrix is:

$$ T_i^{i-1} = Rot_x(a_{i-1}) Trans(r_{i-1}) Rot_z( θ_i) Trans (d_i) $$

So the sign of the parameters are important.

Also, another way to see it is how we use them in the Transformation Matrix:

$$ T = \begin{bmatrix} R_i^{i-1} & b^{i-1} \\ 0 & 1 \end{bmatrix}$$

where $b^{i-1}$ is the vector in the $i-1$ frame that points to the origin of $i$. This vector is given (at least in the convention i use, taken from craig's book pg.83):

$$b^{i-1} = [r_{i-1} \ -sin(a_{i-1})d_i \ cos(a_{i-1})d_i]^T$$

For this vector, the sign of d_i is important. In the convention used by craig, you take the signed distance from $x_{i-1}$ to $x_i$.

Title: Parameter $r$ of Denavit-Hartenberg


问:
SLAM: global BA and IMU rate
My understanding is that in SLAM systems keyframes are recorded at a lower rate and used for loop closing and global BA vs every every image which is used for a sliding window optimization.

What I am wondering is how does the IMU rate get factored into this?

IMU data comes at a much faster rate than camera data so is all IMU data used in global BA or does it also get reduced?

答:
The structure of a SLAM algorithm is pretty variable and this has very different answers depending on the exact SLAM algorithm.

Some SLAM algorithms are discrete time approaches with IMUs acting as preintegration/prior for an estimator (e.g. the IMU is double integrated to get a position delta to act as the prior in an EKF), updating the belief (for both the system state and sensor states like estimated IMU biases, scale etc) on updates from however the SLAM method localises. Because the IMU is only used for preintegration, it's may not actually be part of the loop closure and SLAM localisation steps, it acts to give an initial guess for estimation and optimisation, and acts as a high frequency continuous odometeu output in which you can do control in.

In other SLAM algorithms, for example factor graph based methods, you might be able to add information from the IMU to the unified optimisation problem as factors at discrete times of optimisation alongside using it as an odometery source. There's also continuous time SLAM algorithms that can deal with asynchronous updates from the IMU similarly as part of the cost on an optimisation over polynomial splines to encorporate the information into the problem.

Because of the difference ways SLAM can be formulated, there's not really one approach. Its probably a good exercise to look into a few different state of the art approaches and see how they differ including but not limited to what's mentioned in Gtsam, Wildcat SLAM, etc.

Title: SLAM: global BA and IMU rate


问:
colcon build exception
I am getting this error when using the colcon build command. I don't know how this occurred and everything was working really fine.

Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2866, in get_entry_map
    ep_map = self._ep_map
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2828, in __getattr__
    raise AttributeError(attr)
AttributeError: _ep_map. Did you mean: '_dep_map'?

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/bin/colcon", line 11, in <module>
    load_entry_point('colcon-core==0.11.0', 'console_scripts', 'colcon')()
  File "/usr/lib/python3/dist-packages/colcon_core/command.py", line 118, in main
    return _main(command_name=command_name, argv=argv)
  File "/usr/lib/python3/dist-packages/colcon_core/command.py", line 143, in _main
    parser = create_parser('colcon_core.environment_variable')
  File "/usr/lib/python3/dist-packages/colcon_core/command.py", line 240, in create_parser
    get_environment_variables_epilog(
  File "/usr/lib/python3/dist-packages/colcon_core/command.py", line 289, in get_environment_variables_epilog
    entry_points = load_entry_points(group_name)
  File "/usr/lib/python3/dist-packages/colcon_core/entry_point.py", line 116, in load_entry_points
    for entry_point in get_entry_points(group_name).values():
  File "/usr/lib/python3/dist-packages/colcon_core/entry_point.py", line 94, in get_entry_points
    for entry_point in iter_entry_points(group=group_name):
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 646, in <genexpr>
    for entry in dist.get_entry_map(group).values()
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2868, in get_entry_map
    ep_map = self._ep_map = EntryPoint.parse_map(
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2557, in parse_map
    maps[group] = cls.parse_group(group, lines, dist)
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2535, in parse_group
    ep = cls.parse(line, dist)
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2513, in parse
    raise ValueError(msg, src)
ValueError: ("EntryPoint must be in 'name=module:attrs [extras]' format", '<<<<<<< HEAD')
```
<h3>Things I have tried!</h3>
<p>I haven't found any solution online, and also the auto completion for <code>colcon</code> is also not working</p>
<ul>
<li>I have tried re-installing <strong>python3-colcon-common-extensions</strong> package using</li>
</ul>
<pre class="lang-bash prettyprint-override"><code>sudo apt install python3-colcon-common-extensions
</code>```

also I have these sources in my .bashrc file

```<code># ros-humble-source
source /opt/ros/humble/setup.bash

# colcon_cd command setup
source /usr/share/colcon_cd/function/colcon_cd.sh
export _colcon_cd_root=/opt/ros/humble/

# colcon tab completion
source /usr/share/colcon_argcomplete/hook/colcon-argcomplete.bash
</code>```

答:
The error that you're getting is ValueError: ("EntryPoint must be in 'name=module:attrs [extras]' format", '<<<<<<< HEAD')

This suggests that you have a setup.py file in your Python search path which has invalid syntax. Most likely this is somewhere in your workspace and not an installed package or in the build tool like colcon.

I don't know how this occurred and everything was working really fine.

I would try to think back carefully about what changed in this period between when things were working and weren't working as that's likely the best way to find out what was wrong on your system.

Title: colcon build exception


问:
Siciliano et al. Rotation Matrix Notation
I'm reading Siciliano et al.'s Robotics: Modeling, Planning and Control, and I'm confused about the notation used in definiting rotation matrices.

On page 46, they state

If $\textbf{R}_i^j$ denotes the rotation matrix of Frame $i$ with respect to Frame $j$, it is
$$
\begin{equation}
\textbf{p}^1 = \textbf{R}_2^1\textbf{p}^2.
\end{equation}
$$

To me, this notation says, "$\textbf{R}_2^1$ 'rotates' a vector from frame 2 to frame 1." However, in the discussion of fixed frames on page 47, they state that

$$
\begin{equation}
\bar{\textbf{R}}_2^0 = \textbf{R}_1^0\textbf{R}_0^1\bar{\textbf{R}}_2^1 \textbf{R}_1^0
\end{equation} = \bar{\textbf{R}}_2^1 \textbf{R}_1^0.
$$

If I try to apply my original interpretation, it would say that $\textbf{R}_1^0$ rotates a vector from frame 1 to 0, and then $\bar{\textbf{R}}_1^2$ rotates that vector from its frame 1 to frame 2, which doesn't make sense.

If I instead interpret it as, " $\textbf{R}_1^0$ rotates a vector from frame 0 to frame 1, and then $\bar{\textbf{R}}_2^1$ rotates that vector from frame 1 to frame 2," then that make sense too.

But then the first equation from page 46 doesn't make sense, since it would say, "rotate $\textbf{p}^2$ from frame 1 to frame 2."

Any suggestions on the proper way to interpret these expressions? Thank you!

答:
There's a subtle difference involved here. It's the difference between an active and a passive transformation, whose representations are inverses of each other. $R^a_b$ is the matrix for which:

left multiplying it with $p_b$ results in the point being expressed in the $a$ frame

left multiplying it's inverse ${R^{a}_b}^{-1}=R^b_a$ with $p_b$ rotates the point in the $b$ frame such that it occupies the same relative position in the $a$ frame

(This is sort of intuitive because for the equation $y=f(x)$, $f$ transforms from point $x$ space to $y$ space and it's inverse $f^{-1}$ expresses what $x$ would need to be for $y$ to have that value)

The passage previous to the one you mentioned talks about simple composition by subsequently changing the frame that the point is expressed in. The passage you're referring to is saying that instead of first changing the frame your point is expressed in, you can transform it to an equivalent position relative to another frame, rotate it from that frame to another new frame, with the transform expressed in your initial frame.


问:
How to record all topics in a rosbag using rosbag API (rosbag::Recorder)
I am trying to create a recorder logging all topics into a rosbag using ROSBAG C++ API

The record should be eventually enabled/stopped by some external topic.

The examples show how to log specific topics, but not all of them... Has anyone some insights on how to do this without including the specific message types/headers?

Following this answer I created this first trial, which results in a segmentation fault after the bag is created (bag extension is .bag.active).

Am I using rosbag::Recorder wrongly here?

```<code>#include <rosbag/bag.h>
#include <rosbag/recorder.h>
#include <std_msgs/Bool.h>

std::unique_ptr<rosbag::Recorder> recorder;

void toggle_record(const std_msgs::Bool & msg)
{
    if(msg.data)
    {
        ROS_INFO("rosbag record -a START!");
        recorder->run();
    }
    else
    {
        ROS_INFO("rosbag record -a FINISH!");
        ros::shutdown();
    }
}

int main(int argc, char ** argv)
{
    ros::init(argc, argv, "joystick_record");
    rosbag::RecorderOptions options;
    options.record_all = true;
    options.trigger = false;
    options.regex = false;
    options.do_exclude = true;
    options.quiet = false;
    options.append_date = true;
    options.verbose = false;
    options.buffer_size = 1048576 * 512;
    options.chunk_size = 1024 * 768;
    options.limit = 0; // 0 is unlimited
    options.split = true;
    options.max_size = 1024 * 1024 * 1024;
    options.min_space = 1024 * 1024 * 1024;
    options.min_space_str = "Recording space is running out";

    recorder = std::make_unique<rosbag::Recorder>(options);

    ros::NodeHandle nh;
    ros::Subscriber record_sub = nh.subscribe("/record",10, &toggle_record);

    ROS_WARN("Waiting for /record to be true...");

    ros::spin();
}
</code>```

答:
I solved this issue temporarily by using the bag_recorder package.
It's well documented, fully featured and can be triggered externally by other nodes.

Still, looking for help on a simpler solution with rosbag::Recorder.


问:
Spdlog linker error with ROS2 packages
Good afternoon!

We are a company that has a pretty big robotic framework and we are currently working in a transition into ROS2. We are first creating the structure that all of our packages will follow. Until now, these were separate modules in the same CMake project. Now, as we are starting to test the transition we encountered an issue.

Explain the problem

As we are moving all of our framework, we have our own logger that is being used in our development. Transitioning into the ROS2 logger in all of our modules is not feasible right now. Both loggers use Spdlog under the hood (ROS2 logger and our logger). The conversion of this module is correct and everything works great downstream. However when we try to create a package that has a dependency in ROS (for the creation of a ROS node) we encounter some linker errors.

This error appears only when linking executables that depend on ROS2. If we compile executables that exclusively depend on our modules (No ROS2 dependencies) then everything works correctly

Our Spdlog installation is built from source with version v1.9.2, while I believe ROS uses the binary installation of libspdlog-dev which has version v1.5.0. I've tried to upgrade and downgrade our version with no effect and also simply installing the ROS version to no effect.

All of these linker errors refer to the fmt library which Spdlog depends on.

Linker Error

This is the linker error in question. It's repeated in the terminal quite a few times. I've changed the names of the home paths and files names but the rest is as shown.

```<code>/path/ros2_galactic/ros2-linux/include/spdlog/fmt/bundled/format.h:1051: undefined reference to `fmt::v7::detail::assert_fail(char const*, int, char const*)'
/usr/bin/ld: CMakeFiles/ProjectSample.dir/samples/ProjectSample.cpp.o: in function `spdlog::details::elapsed_formatter<spdlog::details::null_scoped_padder, std::chrono::duration<long, std::ratio<1l, 1000000l> > >::format(spdlog::details::log_msg const&, tm const&, fmt::v7::basic_memory_buffer<char, 250ul, std::allocator<char> >&)':
/usr/include/x86_64-linux-gnu/bits/string_fortified.h:34: undefined reference to `fmt::v7::detail::basic_data<void>::digits'
/usr/bin/ld: CMakeFiles/ProjectSample.dir/samples/ProjectSample.cpp.o: in function `std::make_unsigned<long>::type fmt::v7::detail::to_unsigned<long>(long)':
/path/ros2_galactic/ros2-linux/include/spdlog/fmt/bundled/core.h:326: undefined reference to `fmt::v7::detail::assert_fail(char const*, int, char const*)'
/usr/bin/ld: CMakeFiles/ProjectSample.dir/samples/ProjectSample.cpp.o: in function `fmt::v7::detail::count_digits(unsigned long)':
/path/ros2_galactic/ros2-linux/include/spdlog/fmt/bundled/format.h:924: undefined reference to `fmt::v7::detail::basic_data<void>::zero_or_powers_of_10_64_new'
/usr/bin/ld: CMakeFiles/ProjectSample.dir/samples/ProjectSample.cpp.o: in function `spdlog::details::elapsed_formatter<spdlog::details::null_scoped_padder, std::chrono::duration<long, std::ratio<1l, 1l> > >::format(spdlog::details::log_msg const&, tm const&, fmt::v7::basic_memory_buffer<char, 250ul, std::allocator<char> >&)':
/usr/include/x86_64-linux-gnu/bits/string_fortified.h:34: undefined reference to `fmt::v7::detail::basic_data<void>::digits'
/usr/bin/ld: CMakeFiles/ProjectSample.dir/samples/ProjectSample.cpp.o: in function `fmt::v7::detail::count_digits(unsigned long)':
/path/ros2_galactic/ros2-linux/include/spdlog/fmt/bundled/format.h:924: undefined reference to `fmt::v7::detail::basic_data<void>::zero_or_powers_of_10_64_new'
/usr/bin/ld: CMakeFiles/ProjectSample.dir/samples/ProjectSample.cpp.o: in function `fmt::v7::detail::format_decimal_result<char*> fmt::v7::detail::format_decimal<char, unsigned long>(char*, unsigned long, int)':
</code>```

It seems to come from "/path/ros2_galactic/ros2-linux/include/spdlog/fmt/bundled/", thus we guessed the problem comes from the Spdlog installed from ROS. I was wondering if someone has faced this issue and/or maybe knows why it's caused or has any idea on how to solve it.

Tried solutions

As I've said, we tried installing different versions of spdlog and removing ours just to have the ROS2 one but the error persists.

We've also tried making changes to the CMake but the linkage seems correct and follows the instructions of spdlog. I would prefer not to show the CMake files unless needed as they are sensitive and can't be shared as they are.

EDIT

Hello, to try to understand a bit better my structure I've added the basic CMake structure of the packages that I'm doing

```<code>cmake_minimum_required(VERSION 3.11...3.24)

project(
    moduleName
    VERSION 1.0.0
    DESCRIPTION "Add a short description of your module"
    LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)

# Declare options
option(BUILD_TESTS "Build the Tests of the module" ON)

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
    set(COMPILER_FLAGS -Wall -Wextra -Wpedantic -Wshadow -pthread)
endif()

if (NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE "Debug")
endif()

include(GNUInstallDirs)
include(${CMAKE_CURRENT_SOURCE_DIR}/cmakeutilities/CMakeFunctions.cmake)

if(<span class="math-container">${CMAKE_BUILD_TYPE} STREQUAL "Debug")
add_compile_options($</span>{COMPILER_FLAGS} -O -g)
else()
    add_compile_options(${COMPILER_FLAGS} -O2)
endif()

set(EXPORT_NAME "${PROJECT_NAME}_export")

find_package(ament_cmake REQUIRED)

################
# Dependencies #
################

find_package(dependency1 REQUIRED)
find_package(dependency2 REQUIRED)
find_package(dependency3 REQUIRED)

set(MODULE_DEPENDENCIES
    dependency1
    dependency2
    dependency3
)

#################
# Build library #
#################

add_library(<span class="math-container">${PROJECT_NAME} SHARED
./src/ModuleSource.cpp)
target_include_directories($</span>{PROJECT_NAME}
    PUBLIC
        <span class="math-container">$<BUILD_INTERFACE:$</span>{CMAKE_CURRENT_SOURCE_DIR}/include>
        <span class="math-container">$<BUILD_INTERFACE:$</span>{CMAKE_BINARY_DIR}>
        <span class="math-container">$<INSTALL_INTERFACE:$</span>{CMAKE_INSTALL_INCLUDEDIR}>
    PRIVATE
        ${CMAKE_CURRENT_LIST_DIR}
)

###################
# Install Library #
###################

# Linking
ament_target_dependencies(<span class="math-container">${PROJECT_NAME} $</span>{MODULE_DEPENDENCIES})

set_target_properties(<span class="math-container">${PROJECT_NAME}
PROPERTIES VERSION $</span>{PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR}
)

# Install Library Target
install(
    TARGETS <span class="math-container">${PROJECT_NAME}
EXPORT $</span>{EXPORT_NAME}
    LIBRARY DESTINATION <span class="math-container">${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION $</span>{CMAKE_INSTALL_LIBDIR}
    RUNTIME DESTINATION <span class="math-container">${CMAKE_INSTALL_BINDIR}
INCLUDES DESTINATION $</span>{CMAKE_INSTALL_INCLUDEDIR}
)

# Install Headers
install(
    DIRECTORY <span class="math-container">${PROJECT_SOURCE_DIR}/include/
DESTINATION $</span>{CMAKE_INSTALL_INCLUDEDIR}
)

###############
# Executables #
###############

add_executable(ModuleSample samples/ModuleSample.cpp)
target_link_libraries(ModuleSample ${PROJECT_NAME})

install(
    TARGETS ModuleSample
    DESTINATION <span class="math-container">${CMAKE_INSTALL_LIBDIR}/$</span>{PROJECT_NAME}
)

##############
# Test Suite #
##############

if((BUILD_TESTING OR BUILD_TESTS) AND LIBRARY_HAS_TESTS)
    find_package(ament_lint_auto REQUIRED)
    find_package(ament_cmake_gmock REQUIRED)
    #ament_lint_auto_find_test_dependencies()

    ament_add_gmock(ut-<span class="math-container">${PROJECT_NAME}
    ./tests/ModuleTests.cpp)
target_link_libraries(ut-$</span>{PROJECT_NAME} ${PROJECT_NAME})
endif()

##################
# Export Targets #
##################

ament_export_dependencies(<span class="math-container">${MODULE_DEPENDENCIES})
ament_export_targets($</span>{EXPORT_NAME} HAS_LIBRARY_TARGET)
ament_export_include_directories(include)

ament_package()

</code>```

Edit 2

Hello! The full structure would be something like the following. I have two packages. The first one is my own custom logger and the CMake structure is as follows:

```<code>cmake_minimum_required(VERSION 3.11...3.24)

project(
    customLogger
    VERSION 1.0.0
    DESCRIPTION "Add a short description of your module"
    LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)

# Declare options
option(BUILD_TESTS "Build the Tests of the module" ON)

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
    set(COMPILER_FLAGS -Wall -Wextra -Wpedantic -Wshadow -pthread)
endif()

if (NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE "Debug")
endif()

include(GNUInstallDirs)
include(${CMAKE_CURRENT_SOURCE_DIR}/cmakeutilities/CMakeFunctions.cmake)

if(<span class="math-container">${CMAKE_BUILD_TYPE} STREQUAL "Debug")
add_compile_options($</span>{COMPILER_FLAGS} -O -g)
else()
    add_compile_options(${COMPILER_FLAGS} -O2)
endif()

set(EXPORT_NAME "${PROJECT_NAME}_export")

find_package(ament_cmake REQUIRED)

################
# Dependencies #
################

find_package(spdlog REQUIRED)

#################
# Build library #
#################

add_library(<span class="math-container">${PROJECT_NAME} SHARED
./src/ModuleSource.cpp)
target_include_directories($</span>{PROJECT_NAME}
    PUBLIC
        <span class="math-container">$<BUILD_INTERFACE:$</span>{CMAKE_CURRENT_SOURCE_DIR}/include>
        <span class="math-container">$<BUILD_INTERFACE:$</span>{CMAKE_BINARY_DIR}>
        <span class="math-container">$<INSTALL_INTERFACE:$</span>{CMAKE_INSTALL_INCLUDEDIR}>
    PRIVATE
        ${CMAKE_CURRENT_LIST_DIR}
)

###################
# Install Library #
###################

# Linking
ament_target_dependencies(${PROJECT_NAME} spdlog)

set_target_properties(<span class="math-container">${PROJECT_NAME}
PROPERTIES VERSION $</span>{PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR}
)

# Install Library Target
install(
    TARGETS <span class="math-container">${PROJECT_NAME}
EXPORT $</span>{EXPORT_NAME}
    LIBRARY DESTINATION <span class="math-container">${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION $</span>{CMAKE_INSTALL_LIBDIR}
    RUNTIME DESTINATION <span class="math-container">${CMAKE_INSTALL_BINDIR}
INCLUDES DESTINATION $</span>{CMAKE_INSTALL_INCLUDEDIR}
)

# Install Headers
install(
    DIRECTORY <span class="math-container">${PROJECT_SOURCE_DIR}/include/
DESTINATION $</span>{CMAKE_INSTALL_INCLUDEDIR}
)

###############
# Executables #
###############

add_executable(ModuleSample samples/ModuleSample.cpp)
target_link_libraries(ModuleSample ${PROJECT_NAME})

install(
    TARGETS ModuleSample
    DESTINATION <span class="math-container">${CMAKE_INSTALL_LIBDIR}/$</span>{PROJECT_NAME}
)

##############
# Test Suite #
##############

if((BUILD_TESTING OR BUILD_TESTS) AND LIBRARY_HAS_TESTS)
    find_package(ament_lint_auto REQUIRED)
    find_package(ament_cmake_gmock REQUIRED)
    #ament_lint_auto_find_test_dependencies()

    ament_add_gmock(ut-<span class="math-container">${PROJECT_NAME}
    ./tests/ModuleTests.cpp)
target_link_libraries(ut-$</span>{PROJECT_NAME} ${PROJECT_NAME})
endif()

##################
# Export Targets #
##################

ament_export_dependencies(<span class="math-container">${MODULE_DEPENDENCIES})
ament_export_targets($</span>{EXPORT_NAME} HAS_LIBRARY_TARGET)
ament_export_include_directories(include)

ament_package()

</code>```

The CMake from the second package is identical to the first one except that it depends on the custom logger:

```<code>find_package(customLogger REQUIRE)

ament_target_dependencies(${PROJECT_NAME} customLogger)
</code>```

If, instead of:

```<code>ament_target_dependencies(${PROJECT_NAME} spdlog)
</code>```

We write:

```<code>target_link_libraries(${PROJECT_NAME} spdlog::spdlog)
</code>```

Then we get a different linker error:

```<code>/ros2_galactic/ros2-linux/include/spdlog/logger.h:168: undefined reference to `spdlog::details::log_msg::log_msg(spdlog::source_loc, fmt::v7::basic_string_view<char>, spdlog::level::level_enum, fmt::v7::basic_string_view<char>)'
/usr/bin/ld: /path/ros2_galactic/ros2-linux/include/spdlog/logger.h:168: undefined reference to `spdlog::details::log_msg::log_msg(spdlog::source_loc, fmt::v7::basic_string_view<char>, spdlog::level::level_enum, fmt::v7::basic_string_view<char>)'
/usr/bin/ld: /path/ros2_galactic/ros2-linux/include/spdlog/logger.h:168: undefined reference to `spdlog::details::log_msg::log_msg(spdlog::source_loc, fmt::v7::basic_string_view<char>, spdlog::level::level_enum, fmt::v7::basic_string_view<char>)'
</code>```

Still, it seems to be finding the spdlog installation of ROS2 instead of the one we use.

Changing the find package into:

```<code>find_package(spdlog 1.9.2 REQUIRED)
</code>```

makes it so that it finally finds our installation instead of the ROS2 one but downstream it does not seem to find it anymore and it keeps throwing the same linker errors.

答:
After some trial an error and going through the suggestions that people made, I managed to at least make it work. It seems that when I try to link to my own spdlog installation (not the ros version), it finds it but links to it incorrectly. If I link to both, spdlog and rclcpp, then it find both installations and links correctly to the one I need.

I'm not sure why this happens or what could be the solution but in the end I wrote something like:

```<code>find_package(spdlog 1.9.2 REQUIRED)
find_package(rclcpp REQUIRED)

ament_target_dependencies(my_project rclcpp spdlog)
</code>```

Using this, the program compiles and links correctly.

Thank you all for the help, and if someone knows why this could be happening please feel free to comment and give your insight.

Title: Spdlog linker error with ROS2 packages

Body:
After some trial an error and going through the suggestions that people made, I managed to at least make it work. It seems that when I try to link to my own spdlog installation (not the ros version), it finds it but links to it incorrectly. If I link to both, spdlog and rclcpp, then it find both installations and links correctly to the one I need.

I'm not sure why this happens or what could be the solution but in the end I wrote something like:

find_package(spdlog 1.9.2 REQUIRED)
find_package(rclcpp REQUIRED)

ament_target_dependencies(my_project rclcpp spdlog)

Using this, the program compiles and links correctly.

Thank you all for the help, and if someone knows why this could be happening please feel free to comment and give your insight.


答: Another option could be to start the rosbag via rosmon rosservice call. Then your C++ Node would only need to make the service call to start or stop it.

Title: How to record all topics in a rosbag using rosbag API (rosbag::Recorder)

Body:
I am trying to create a recorder logging all topics into a rosbag using ROSBAG C++ API

The record should be eventually enabled/stopped by some external topic.

The examples show how to log specific topics, but not all of them... Has anyone some insights on how to do this without including the specific message types/headers?

Following this answer I created this first trial, which results in a segmentation fault after the bag is created (bag extension is .bag.active).

Am I using rosbag::Recorder wrongly here?

```<code>#include <rosbag/bag.h>
#include <rosbag/recorder.h>
#include <std_msgs/Bool.h>

std::unique_ptr<rosbag::Recorder> recorder;

void toggle_record(const std_msgs::Bool & msg)
{
    if(msg.data)
    {
        ROS_INFO("rosbag record -a START!");
        recorder->run();
    }
    else
    {
        ROS_INFO("rosbag record -a FINISH!");
        ros::shutdown();
    }
}

int main(int argc, char ** argv)
{
    ros::init(argc, argv, "joystick_record");
    rosbag::RecorderOptions options;
    options.record_all = true;
    options.trigger = false;
    options.regex = false;
    options.do_exclude = true;
    options.quiet = false;
    options.append_date = true;
    options.verbose = false;
    options.buffer_size = 1048576 * 512;
    options.chunk_size = 1024 * 768;
    options.limit = 0; // 0 is unlimited
    options.split = true;
    options.max_size = 1024 * 1024 * 1024;
    options.min_space = 1024 * 1024 * 1024;
    options.min_space_str = "Recording space is running out";

    recorder = std::make_unique<rosbag::Recorder>(options);

    ros::NodeHandle nh;
    ros::Subscriber record_sub = nh.subscribe("/record",10, &toggle_record);

    ROS_WARN("Waiting for /record to be true...");

    ros::spin();
}
</code>```


问:
Zoom/scale image combined with rectify/undistort and publish modified CameraInfo in a ros nodelet?
I'm running the rectify nodelet on a factory calibrated oak-d-w camera and I don't like how much of the original distorted image gets chopped off as a result.  I think I saw there was an alternate rectification node or nodelet that can apply a scale factor and do the right modifications to the camera info and publishes it out, but now I'm not finding it.

Curved black border areas are fine as consequence for scaling the image too much (though it would be nice if it could optionally automatically calculate the right scale factor to be right on the edge of having undefined black pixels in the output image, or make sure every input pixel contributes to the output image- using getOptimalNewCameraMatrix()?).

答:
So far I'm able to get most of what I want by adding blank borders to the distorted input image and offsetting cx & cy in the corresponding camera info (and making the camera info width and height match the larger image size).

I added a Pad nodelet to image_manip that does this https://github.com/lucasw/image_manip/blob/master/image_manip/src/pad.cpp#L69-L88 (the pad parameters need to be made dynamic reconfigure variables, or at least rosparams).  Maybe the rectification nodelet could take padding parameters and would be much more efficient without having to modify the input distorted image?

Really wide angle cameras (like the oak-d-w) need a lot of padding to get more of the edges of the image, it's diminishing returns and increasingly odd looking.

(I'll add some helpful images here when I have a good example to share)


答:
I'm building on Raghav's helpful answer to get to my original confusion. In short, I believe reading these matrix compositions comes down to how you interpret the transformations.

A current frame rotation like

$$
\begin{equation}
R_2^0 = R_1^0R_2^1
\end{equation}
$$

Can be understood two ways.

Way 1:

we rotate frame 0 $(F_0)$ to $F_2$ by rotating $F_0$ to $F_1$ and then $F_1$ to $F_2$. In this interpretation, we read the numbers on the matrices top-to-bottom.

Way 2:

we can express a vector currently in $F_2$ in terms of $F_0$ by rotating it from $F_2$ to $F_1$ and then from $F_1$ to $F_0$. In this interpretation, we read the numbers in the matrices from bottom to top.

Rotation Matrix Composition

At least with Siciliano's notation, we interpret compositions of current frame rotations with Way 1 because the focus is on how frames are being shifted at each step with post-multiplication.

Title: Siciliano et al. Rotation Matrix Notation

Body:
I'm reading Siciliano et al.'s Robotics: Modeling, Planning and Control, and I'm confused about the notation used in definiting rotation matrices.

On page 46, they state

If $\textbf{R}_i^j$ denotes the rotation matrix of Frame $i$ with respect to Frame $j$, it is
$$
\begin{equation}
\textbf{p}^1 = \textbf{R}_2^1\textbf{p}^2.
\end{equation}
$$

To me, this notation says, "$\textbf{R}_2^1$ 'rotates' a vector from frame 2 to frame 1." However, in the discussion of fixed frames on page 47, they state that

$$
\begin{equation}
\bar{\textbf{R}}_2^0 = \textbf{R}_1^0\textbf{R}_0^1\bar{\textbf{R}}_2^1 \textbf{R}_1^0
\end{equation} = \bar{\textbf{R}}_2^1 \textbf{R}_1^0.
$$

If I try to apply my original interpretation, it would say that $\textbf{R}_1^0$ rotates a vector from frame 1 to 0, and then $\bar{\textbf{R}}_1^2$ rotates that vector from its frame 1 to frame 2, which doesn't make sense.

If I instead interpret it as, " $\textbf{R}_1^0$ rotates a vector from frame 0 to frame 1, and then $\bar{\textbf{R}}_2^1$ rotates that vector from frame 1 to frame 2," then that make sense too.

But then the first equation from page 46 doesn't make sense, since it would say, "rotate $\textbf{p}^2$ from frame 1 to frame 2."

Any suggestions on the proper way to interpret these expressions? Thank you!


问:
VS Code C/C++ extension Issue with ros program header file
Recently, when I was trying to compile a ROS programm written in C++ (with C/C++ extension installed in VSCode) I ran in to a problem with the header files included in the program (rclcpp, etc.) and the error was that those header files couldn't be resolved. When I tried disabling the extension the problem got solved. Is there any other way around to solve this issue?

How to recreate the error

Install the C/C++ extension in VSCode from here.

Make sure that the extension is enabled.

Create a simple ROS package with --build-type as ament_cmake and list some of the dependencies using --dependencies as rclcpp etc. or simply create ROS package with C++ code in it. For example :

ros2 pkg create SamplePackage --build-type ament_cmake --dependencies rclcpp

Now add some sample code to the src folder and try to include the rclcpp library using #include "rclcpp/rclcpp.hpp" header and you will get the error and the header cannot be resolved.

Below is the screen sample ROS package that I have created with the extension enabled

When the extension is disabled the error goes out. Below is the screenshot of the same package with the extension disabled.

How I tried to solve the issue

I edited the file c_cpp_properties.json (file used to set the C/C++ extension configuration in VSCode) as per given below.

{
  "configurations": [
    {
      "name": "Linux",
      "includePath": ["/opt/ros/humble/include/**/**/", "${workspaceFolder}/**"],
      "defines": [],
      "compilerPath": "/usr/bin/clang",
      "cStandard": "c17",
      "cppStandard": "c++14",
      "intelliSenseMode": "linux-clang-x64"
    }
  ],
  "version": 4
}
```

I tried using multiple variations in the path, and all of it didn't worked for me. I am attaching the screenshot for the folder that contains the header file for ROS 2 down below,

The error prevails even after updating the path in the C/C++ extension settings, please refer the screenshot below.

答:
I've run your commands from above inside a Docker container that is used within VS Code via the Dev Containers extension. (This is just my favourite method - it's exactly the same as running the commands on a normal Linux bash.)

My devcontainer.json file inside the .devcontainer folder contains following lines:

```<code>{
    "name": "ROS 2 C++ extension issue",

    // Sets the run context to one level up instead of the .devcontainer folder.
    "context": "..",

    // docker image to be used for development process
    "image": "ros:humble-ros-base-jammy",

    // Set *default* container specific settings.json values on container create.
    "settings": {},

    // Add the IDs of extensions you want installed when the container is created.
    "extensions": [
        "ms-vscode.cpptools"
    ],

    // Uncomment the next line to run commands after the container is created - for example installing curl.
    "postCreateCommand": "apt-get update && apt-get install -y clang"
}
</code>```

Once the container is created and started in VS Code I ran source /opt/ros/humble/setup.bash, then ros2 pkg create SamplePackage --build-type ament_cmake --dependencies rclcpp and created a ros_timer.cpp inside the src folder with following content:

```<code>// Copyright 2016 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <chrono>
#include <memory>

#include "rclcpp/rclcpp.hpp"

using namespace std::chrono_literals;

/* This example creates a subclass of Node and uses a fancy C++11 lambda
 * function to shorten the timer syntax, at the expense of making the
 * code somewhat more difficult to understand at first glance if you are
 * unaccustomed to C++11 lambda expressions. */

class MinimalTimer : public rclcpp::Node
{
public:
  MinimalTimer()
  : Node("minimal_timer")
  {
    auto timer_callback = [this]() -> void {RCLCPP_INFO(this->get_logger(), "Hello, world!");};
    timer_ = create_wall_timer(500ms, timer_callback);
  }

private:
  rclcpp::TimerBase::SharedPtr timer_;
};

int main(int argc, char * argv[])
{
  rclcpp::init(argc, argv);
  rclcpp::spin(std::make_shared<MinimalTimer>());
  rclcpp::shutdown();
  return 0;
}
</code>```

Now if I open the file I see red squiggles because it cannot find the include file. We've to tell IntelliSense where to search for it, so create a c_cpp_properties.json inside the .vscode folder (example configurations for gcc and clang, note that ROS 2 Humble targets C++17 (not relevant for this example but could lead to problems later on)):

```<code>{
    "configurations": [
        {
            "name": "ROS 2 clang",
            "includePath": [
                "${workspaceFolder}/**",
                "/opt/ros/humble/include/**"
                "/usr/include/**"
            ],
            "defines": [],
            "compilerPath": "/usr/bin/clang",
            "cStandard": "c17",
            "cppStandard": "c++17",
            "intelliSenseMode": "linux-clang-x64"
        }
    ],
    "version": 4
}

/*
{
    "configurations": [
        {
            "name": "ROS 2 gcc",
            "includePath": [
                "${workspaceFolder}/**",
                "/opt/ros/humble/include/**",
                "/usr/include/**"
            ],
            "defines": [],
            "compilerPath": "/usr/bin/gcc",
            "cStandard": "c11",
            "cppStandard": "c++17",
            "intelliSenseMode": "linux-gcc-x64"
        }
    ],
    "version": 4
}
*/
</code>```

After configuring IntelliSense the red squiggles are gone and I can do a right click on #include "rclcpp/rclcpp.hpp" and go to the definition. I can also right click a function or definition inside the code and e.g. peek its definition.

But if I disable the C/C++ extension (and restart VS Code as this seems to be required) the red squiggles are gone as you noticed but I also lost all the C/C++ extension functionality (right click doesn't show much).

Body:
I've run your commands from above inside a Docker container that is used within VS Code via the Dev Containers extension. (This is just my favourite method - it's exactly the same as running the commands on a normal Linux bash.)

My devcontainer.json file inside the .devcontainer folder contains following lines:

{
    "name": "ROS 2 C++ extension issue",

    // Sets the run context to one level up instead of the .devcontainer folder.
    "context": "..",

    // docker image to be used for development process
    "image": "ros:humble-ros-base-jammy",

    // Set *default* container specific settings.json values on container create.
    "settings": {},

    // Add the IDs of extensions you want installed when the container is created.
    "extensions": [
        "ms-vscode.cpptools"
    ],

    // Uncomment the next line to run commands after the container is created - for example installing curl.
    "postCreateCommand": "apt-get update && apt-get install -y clang"
}

Once the container is created and started in VS Code I ran source /opt/ros/humble/setup.bash, then ros2 pkg create SamplePackage --build-type ament_cmake --dependencies rclcpp and created a ros_timer.cpp inside the src folder with following content:

// Copyright 2016 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <chrono>
#include <memory>

#include "rclcpp/rclcpp.hpp"

using namespace std::chrono_literals;

/* This example creates a subclass of Node and uses a fancy C++11 lambda
 * function to shorten the timer syntax, at the expense of making the
 * code somewhat more difficult to understand at first glance if you are
 * unaccustomed to C++11 lambda expressions. */

class MinimalTimer : public rclcpp::Node
{
public:
  MinimalTimer()
  : Node("minimal_timer")
  {
    auto timer_callback = [this]() -> void {RCLCPP_INFO(this->get_logger(), "Hello, world!");};
    timer_ = create_wall_timer(500ms, timer_callback);
  }

private:
  rclcpp::TimerBase::SharedPtr timer_;
};

int main(int argc, char * argv[])
{
  rclcpp::init(argc, argv);
  rclcpp::spin(std::make_shared<MinimalTimer>());
  rclcpp::shutdown();
  return 0;
}

Now if I open the file I see red squiggles because it cannot find the include file. We've to tell IntelliSense where to search for it, so create a c_cpp_properties.json inside the .vscode folder (example configurations for gcc and clang, note that ROS 2 Humble targets C++17 (not relevant for this example but could lead to problems later on)):

{
    "configurations": [
        {
            "name": "ROS 2 clang",
            "includePath": [
                "${workspaceFolder}/**",
                "/opt/ros/humble/include/**"
                "/usr/include/**"
            ],
            "defines": [],
            "compilerPath": "/usr/bin/clang",
            "cStandard": "c17",
            "cppStandard": "c++17",
            "intelliSenseMode": "linux-clang-x64"
        }
    ],
    "version": 4
}

/*
{
    "configurations": [
        {
            "name": "ROS 2 gcc",
            "includePath": [
                "${workspaceFolder}/**",
                "/opt/ros/humble/include/**",
                "/usr/include/**"
            ],
            "defines": [],
            "compilerPath": "/usr/bin/gcc",
            "cStandard": "c11",
            "cppStandard": "c++17",
            "intelliSenseMode": "linux-gcc-x64"
        }
    ],
    "version": 4
}
*/

After configuring IntelliSense the red squiggles are gone and I can do a right click on #include "rclcpp/rclcpp.hpp" and go to the definition. I can also right click a function or definition inside the code and e.g. peek its definition.

But if I disable the C/C++ extension (and restart VS Code as this seems to be required) the red squiggles are gone as you noticed but I also lost all the C/C++ extension functionality (right click doesn't show much).


问:
Network Issues: ROS2 Topic visibility dependency to Network Interfaces
My colleagues and I had the issue that sometime ros2 topics were not shown in “ros2 topic list” or that we could not “ros2 topic echo” the data. After further investigation, we concluded that the problem occurred when we connected/disconnected new devices to the network ports after the ROS2 nodes were already running. We are able to reproduce two cases:

Setup:

Ubuntu 22.04

ROS2 humble

Direct connection to network port, no switch in between.

The problem is shown with any DDS vendor. The only thing that solves these problems is a restart of the ros2 daemon and a restart of the ROS2 nodes. (ros2 daemon restart alone is not sufficient)

My first conclusion in case 1 is that the DDS is not performing a new discovery into the new active network interface. For case 2, I am still unsure what the problem is, but it seems that the DDS creates a dependency on the network interface connected at start.

Is anyone else able to reproduce these issues?

答:
Apparently this is a well known issue:
https://github.com/ros2/rmw/pull/344#issuecomment-1398852633

In their own words:

The use-case is the following: all the existing DDS implementations currently scan for available network interfaces only once, i.e. when a DDS participant is created. This usually happens when you call rclcpp::init().
If a network interface is not available at that time it will be ignored.
For example: you start a ROS application, then you bring up WiFi -> the ROS application will not use WiFi.


问:
How to make specific link static?
I want to simulate a RR robot in gazebo and I want to place the first link over a box. This box shouldn't be a part of the simulation, and is there only for visual effect.

How can I make a specific link/object static?

I created a fixed joint with a link named "world". Also, I tried adding a static tag.

However, it still included in the physics calculations, resulting in a weird behaviour. It spins on its own and it tilts, like this:

Relevant parts of the urdf:

```<code><link name="world"/>

<joint name="world_joint" type="fixed">
  <parent link="world"/>
  <child link="base_link"/>
  <origin rpy="0 0 0" xyz="0 0 ${base_height}"/>
</joint>

<link name="base_link">
  <visual>
    ...
  </visual>
  <collision>
    ...
  </collision>
  <inertial>
    <mass value="100" />
    <inertia ixx="0.1" ixy="0.0" ixz="0.0"
              iyy="0.1" iyz="0.0"
              izz="0.1" />
    <origin rpy="0 0 0" xyz="0 0 ${-base_height/2}"/>
  </inertial>
</link>

<gazebo reference="base_link" >
  <material> Gazebo/Blue </material>
  <static>true</static>
</gazebo>
</code>```

I made the inertia of the base_link greater

```<code><inertia ixx="100" ixy="0.0" ixz="0.0" iyy="100" iyz="0.0" izz="100" />
</code>```

and now the base doesn't tilt and the link doesn't rotate on its own. However, as I specified it as a static link, I anticipated that it shouldn't have that behaviour no matter its inertia.

Edit
After some more searching, i found out that you cannot specify a link as static (sdf documentation). However, i still expect that the fixed joint with the world frame would keep the box in place.

I also changed some parameters of the physics engine, namely erp and cfm (you can find them here), but the weird behaviour continued.

答:
To add a static link, you add the the kinematic property to your urdf:

```<code><gazebo reference="base_link" >
  <!-- other properties you want to define for the base link -->
  <kinematic> true </kinematic>
</gazebo>
</code>```

Here is a list of the properties of links. There isn't a static property. There is a kinematic property. I found this source that said the following:

A kinematic link (as opposed to a dynamic link) is not affected by external forces. It can influence other bodies in its vicinity, but it's not influenced by them.

And i tested it and it worked perfectly.

Title: How to make specific link static?

Body:
To add a static link, you add the the kinematic property to your urdf:

<gazebo reference="base_link" >
  <!-- other properties you want to define for the base link -->
  <kinematic> true </kinematic>
</gazebo>

Here is a list of the properties of links. There isn't a static property. There is a kinematic property. I found this source that said the following:

A kinematic link (as opposed to a dynamic link) is not affected by external forces. It can influence other bodies in its vicinity, but it's not influenced by them.

And i tested it and it worked perfectly.


问:
How to deal with asynchronous samples in a kalman filter framework multi-sensor fusion?
I have setup a sensor fusion problem to estimate a classical 2d position + orientation of a wheeled mobile robot in an embedded environment.

Sensor measurements include:

IMU (6axis accl+gyro) @ 40Hz

GPS (2d position) @1Hz

Wheel odometry (linear v_x, angular omega_z) @ 10Hz

I do not know what is the best way to setup an EKF estimate loop when such samples are not updating synchronously.

These are the possibilities that come to my mind:

Consider the filter (and thus model dynamics) timestep constant (arbitrarily fixed, let's say the fastest sensor's sampling rate, i.e. IMU @ 40Hz) and each loop do 1 predict + 3 model measurement updates with the current sensor sample stored (1 update for each sensor sample). This considers constant sensor samples between subsequent loops, effectively assuming constant ans synchronous sampling.

Consider the filter (and thus model dynamics) timestep variable (maybe adding such timestep as control variable) and do 1 prediction + 1 update for each sensor sample update. Such timestep should be computed from subsequent sample timestamp difference from a sample measurement queue.

The second approach sounds more complex as it requires a prediction step for each incoming sample (besides dealing with all the timestamps computation witchcraft) but may be the most accurate as the filter updates only when we are triggered by sensor updates.

Thanks you so much for your support :)

答:
The correct way of integrating multi-rate observations in a Kalman framework when the measurements are unavailable is to let the system evolve resorting merely to the prediction steps.

Therefore, set up the overall system rate to be equal to the fastest one and then manipulate the $\mathbf{H}$ matrix as described in https://dsp.stackexchange.com/a/60513.


问:
catkin_make not creating a catkin workspace for ROS through Robostack (Conda) environment
I've recently been encountering an issue when trying to create a working catkin workspace for ROS through RoboStack.

Robostack is utilized to create a working ROS environment installed in Conda.

When activating the environment in Conda, I have been able to successfully very that ROS is working when I run the set ros command through the miniconda command prompt:

```<code>(robostackenv) C:\.....>set ros

ROS_DISTRO=noetic
ROS_ETC_DIR=C:\Users\user\miniconda3\envs\robostackenv\Library\etc\ros
ROS_IP=127.0.0.1
ROS_MASTER_URI=http://127.0.0.1:11311
ROS_OS_OVERRIDE=conda:win64
ROS_PACKAGE_PATH=C:\Users\user\miniconda3\envs\robostackenv\Library\share
ROS_PYTHON_VERSION=3
ROS_ROOT=C:/Users/user/miniconda3/envs/robostackenv/Library/share/ros
ROS_VERSION=1
</code>```

I've also installed various extensions to succesfully utilize ROS within VSCode (NOT the full IDE Visual Studio one). These extensions include:

ROS

C/C++ (VsCode is configured with a GCC compiler, which allows it to run C//C++ files already

CMake

However, for some reason I can't create a workspace for ROS. I've already created a catkin_workspace and src folder by:

```<code>(robostackenv) C:\.....>robostackenv\mkdir catkin_workspace
(robostackenv) C:\.....>robostackenv\catkin_workspace\mkdir src
</code>```

But every time I try to utilize catkin_make within the main workspace directory, it ends up failing:

```<code>(robostackenv) C:\Users\user\ProgrammingProjects\robostackenv\catkin_workspace>catkin_make
Base path: C:\Users\user\ProgrammingProjects\robostackenv\catkin_workspace
Source space: C:\Users\user\ProgrammingProjects\robostackenv\catkin_workspace\src
Build space: C:\Users\user\ProgrammingProjects\robostackenv\catkin_workspace\build
Devel space: C:\Users\user\ProgrammingProjects\robostackenv\catkin_workspace\devel
Install space: C:\Users\user\ProgrammingProjects\robostackenv\catkin_workspace\install
Copying file from "C:\Users\user\miniconda3\envs\robostackenv\Library\share\catkin\cmake\toplevel.cmake" to "C:\Users\user\ProgrammingProjects\robostackenv\catkin_workspace\src\CMakeLists.txt"
####
#### Running command: "cmake C:\Users\user\ProgrammingProjects\robostackenv\catkin_workspace\src -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCATKIN_DEVEL_PREFIX=C:\Users\user\ProgrammingProjects\robostackenv\catkin_workspace\devel -DCMAKE_INSTALL_PREFIX=C:\Users\user\ProgrammingProjects\robostackenv\catkin_workspace\install -G NMake Makefiles" in "C:\Users\user\ProgrammingProjects\robostackenv\catkin_workspace\build"
####
CMake Error at CMakeLists.txt:6 (project):
  Running

   'nmake' '-?'

  failed with:

   The system cannot find the file specified

CMake Error: CMAKE_C_COMPILER not set, after EnableLanguage
CMake Error: CMAKE_CXX_COMPILER not set, after EnableLanguage
-- Configuring incomplete, errors occurred!
See also "C:/Users/user/ProgrammingProjects/robostackenv/catkin_workspace/build/CMakeFiles/CMakeOutput.log".
Invoking "cmake" failed
</code>```

What am I doing that's wrong? ROS is installed properly with RoboStack, set ros shows that it works, my files are named corrently, what gives?

If I run, catkin_init_workspace, it'll generate a CMakeLists.txt file, but that is it.

答:
Did you install a C/C++ compiler, make and CMake? Not the VS Code extensions, the programs themselves.

Be sure also to add them into the Windows path environment variable.


问:
Gazebo Garden plugin and nested models
I have a problem that I'm not able to solve with Gazebo Garden.

I wrote a System plugin that handles a stereo camera, I need a plugin to interface the simulator with our SDK.

Differently from Gazebo Classic in Gazebo there is not a Multi Camera sensor, so I must associate the plugin to a model containing the two sensors instead of associating it to a single sensor.

This works correctly, but I have not found a way to add multiple simulated stereo cameras to the same robot model because I do not know how to associate each plugin to the correct sensors pair.

In SDF I could create nested models and I guess this can solve my issue, but how can I achieve the same when describing the robot with URDF in ROS2?

I'm going crazy trying to find a working solution :(

答:
You have three possible paths you can choose:

Make your plugin handle two stereo cameras -- you can configure your plugin as to which components are stereo cameras, or hard wire it (see the DiffDrive.cpp on how to configure your plugin based on sdf tags)

Abstract your plugin into a custom sensor, then attach the sensor element into the correct places (two places), then write a world-level plugin that manages all of the sensors.  This will be the harder road, but it will scale to an arbitrary number of sensors.

Add the plugin twice, but pass in configuration information to each plugin xml tag so that you publish on different topics, and you are looking at different attached cameras, or if you are attaching the camera in the plugin, enough info in the xml tag so that you can configure where the plugin places the camera, etc.

OwnerDisplayName: Myzhar

Title: Gazebo Garden plugin and nested models


问:
SetuptoolsDeprecationWarning in ros2 Humble
I was trying to follow this tutorial in the official documentation of ros2 Humble for Integrating launch files into ROS 2 packages and ran in to the below given error after doing trying to perform a build on the package using

colcon build --packages-select py_launch_example
```
<p>The package build compilation given me the following error.</p>
```Starting >>> py_launch_example
[3.759s] WARNING:colcon.colcon_ros.task.ament_python.build:Package 'py_launch_example' doesn't explicitly install a marker in the package index (colcon-ros currently does it implicitly but that fallback will be removed in the future)
[3.793s] WARNING:colcon.colcon_ros.task.ament_python.build:Package 'py_launch_example' doesn't explicitly install the 'package.xml' file (colcon-ros currently does it implicitly but that fallback will be removed in the future)
--- stderr: py_launch_example
/usr/lib/python3/dist-packages/setuptools/command/install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.
  warnings.warn(
---
Finished <<< py_launch_example [1.23s]

Summary: 1 package finished [4.38s]
  1 package had stderr output: py_launch_example
```

I have found a similar issue in this thread in ROS Answers. Please help! Thank you

Additional Informations

operating system : Ubuntu 22.04 LTS

ROS Distro : Humble

Python version : 3.10.6

Solutions I have tried :

Downgrading the setuptools to older version 58.2.0, this actually worked for me and the warning was no longer shown.

removing the line install_requires=['setuptools'] from the setup.py file and use --allow-overriding tag while rebuilding. This solution didn't work for me.

答:
I'm pretty familiar with this issue, and we're not quite ready to move to the new APIs that the setuptools folks are deprecating the current workflows in favor of. This post has a robust, if somewhat outdated, summary of some of the hurdles: https://github.com/colcon/colcon-core/issues/454#issuecomment-1262592774

As an alternative to downgrading setuptools, you could use the PYTHONWARNINGS environment variable to suppress that particular warning. I added this to my .bashrc and it works well:

PYTHONWARNINGS="ignore:setup.py install is deprecated::setuptools.command.install"; export PYTHONWARNINGS
```


问:
Gazebo Plugin not found
I am trying to simulate wind on gazebo garden on ubuntu 22.04. So, I found this plugin libgz-sim-wind-effects-system.so in my plugins path and included it as follows:

```<code><plugin name="gz::sim::v7::systems::WindEffects" filename="libgz-sim-wind-effects-system.so">
                <direction>0</direction>
                <speed>100000</speed>
                <turbulence>0.5</turbulence>
            </plugin>
</code>```

However, I keep getting this error

```<code>`Failed to load plugin [libgz-sim-wind-effects-system.so] : couldn't find shared library.`
</code>```

But the file exists in the same path as other plugins I'm using in the same file and I added the path of the file to the environment variable as such

```<code>export GAZEBO_PLUGIN_PATH=/usr/lib/x86_64-linux-gnu/
</code>```

So, any idea what is the problem here? Also, is this the correct plugin and should I be another plugin to simulate wind.

答:
The correct syntax is

    <plugin
      filename="gz-sim-wind-effects-system"
      name="gz::sim::systems::WindEffects">
```

So you'd need to remove lib from the filename. Also, it's not necessary to include the anonymous namespace v7.

You can also run the wind.sdf example and see if that works for you:
https://github.com/gazebosim/gz-sim/blob/af73ebe7c8c693fd54e391f79c11bf9f24df2640/examples/worlds/wind.sdf

Title: Gazebo Plugin not found

Body:
The correct syntax is

    <plugin
      filename="gz-sim-wind-effects-system"
      name="gz::sim::systems::WindEffects">

So you'd need to remove lib from the filename. Also, it's not necessary to include the anonymous namespace v7.

You can also run the wind.sdf example and see if that works for you:
https://github.com/gazebosim/gz-sim/blob/af73ebe7c8c693fd54e391f79c11bf9f24df2640/examples/worlds/wind.sdf


问:
Error while building using colon - colcon build --symlink-install --cmake-args
```<code>shahmeet18@shahmeet18-Precision-5510:~/autoware$ colcon build --symlink-install --cmake-args -DCMAKE_BUILD_TYPE=Release
Starting >>> autoware_lint_common
Starting >>> autoware_auto_geometry_msgs
Starting >>> autoware_auto_mapping_msgs
Starting >>> tier4_debug_msgs
Starting >>> autoware_common_msgs
Starting >>> autoware_auto_system_msgs
Starting >>> autoware_adapi_v1_msgs
Starting >>> tier4_planning_msgs
Finished <<< autoware_lint_common [1.28s]
Starting >>> autoware_cmake
--- stderr: autoware_auto_geometry_msgs
Traceback (most recent call last):
  File "/opt/ros/humble/share/rosidl_generator_py/cmake/../../../lib/rosidl_generator_py/rosidl_generator_py", line 8, in <module>
    from rosidl_generator_py import generate_py
ImportError: cannot import name 'generate_py' from 'rosidl_generator_py' (/opt/ros/humble/local/lib/python3.10/dist-packages/rosidl_generator_py/__init__.py)
gmake[2]: *** [autoware_auto_geometry_msgs__py/CMakeFiles/autoware_auto_geometry_msgs__py.dir/build.make:158: rosidl_generator_py/autoware_auto_geometry_msgs/_autoware_auto_geometry_msgs_s.ep.rosidl_typesupport_fastrtps_c.c] Error 1
gmake[1]: *** [CMakeFiles/Makefile2:590: autoware_auto_geometry_msgs__py/CMakeFiles/autoware_auto_geometry_msgs__py.dir/all] Error 2
gmake[1]: *** Waiting for unfinished jobs....
gmake: *** [Makefile:146: all] Error 2`
---
Failed   <<< autoware_auto_geometry_msgs [1.33s, exited with code 2]
Aborted  <<< tier4_debug_msgs [1.33s]
Aborted  <<< autoware_common_msgs [1.34s]
Aborted  <<< autoware_cmake [0.08s]
Aborted  <<< autoware_auto_mapping_msgs [1.40s]
Aborted  <<< autoware_auto_system_msgs [1.42s]
Aborted  <<< autoware_adapi_v1_msgs [1.73s]
Aborted  <<< tier4_planning_msgs [1.94s]

Summary: 1 package finished [3.00s]
  1 package failed: autoware_auto_geometry_msgs
  7 packages aborted: autoware_adapi_v1_msgs autoware_auto_mapping_msgs autoware_auto_system_msgs autoware_cmake autoware_common_msgs tier4_debug_msgs tier4_planning_msgs
  7 packages had stderr output: autoware_adapi_v1_msgs autoware_auto_geometry_msgs autoware_auto_mapping_msgs autoware_auto_system_msgs autoware_common_msgs tier4_debug_msgs tier4_planning_msgs
  226 packages not processed
</code>```

How can I rectify this?

答:
I believe this can happen when there are multiple Python interpreters on a system. I've seen this before with Anaconda users.

Here's an issue filed previously with this exact error: https://github.com/ros2/rosidl_python/issues/168

Note that the rosidl_generator_py package is present and installed in /opt/ros/humble, but the script is having trouble finding the Python module in the same package.

The debian packages for ROS 2 are built to use the system's default Python 3 interpreter. If you have another interpreter installed on your system (take a look at which python3), you should disable it when using ROS 2 debian packages. If you wish to re-build ROS 2 using a different interpreter, please try uninstalling the debians and building all of ROS 2 from source.


问:
How to design shafts and select bearings
I am trying to design robotic joints for a SCARA arm, I am mainly missing information about the shaft and bearings components.

Design would be similar to MakerArm / Dobot M1 kickstarter projects.

So Z translation would be built using a ball screw, the others joint would be more "classic" (I want to avoid belt/pulley).

And so here are the multiple questions pending in my head:

Why do we have motors with cylindrical shaft and others with a D shaped one? Are there other shapes? How do you chose the appropriate one?

Can you confirm that I should avoid mounting parts directly on the motor shaft, and instead use a 2nd shaft? For the Z-axis, I believe the ball screw can be considered as the 2nd shaft.

Concerning that 2nd shaft (if needed) which formula or abacus can I use to determine shape/diameter and whether it is hollow (how much?) or not.

Looking at universal robots joints in this video, Inside a Universal Robots Axis, it seems they use a hollow shaft while it seems harder/longer and more expensive to manufacture, so there may be a reason? Is it related to inertia?

Should I use a coupler between the two shaft that will act as a fuse?

Because in the video linked before I don't see any couplers.
Gearbox (harmonic drive in their case seems) to be the only part between motor and output shaft. If needed which coupler would you recommend (keeping backlash low), oldham or another ?

Finally about bearings

For the Z joint (ball screw based) am I right, when saying that mounting methods have been "standardized" by CNC industry and available choices are between the following 4 "patterns", with standard "supporting" parts that includes the bearing?

For the motor part of these linear actuator they seem to often use "basic" DC brushed (or brushless?) motors and I saw 2 different mounting designs, one where the motor is in line with the ball screw

The 2nd one where the motor is parallel with pulley/belt or gears to transmit torque

Is it only a matter of space available or is one design more efficient than the other?

For the other joints, how do I know how many bearings, their size/type (depends on load type?), how to mount them and where (I already guessed it goes between the motor shaft and the part to rotate).

Thanks for reading/answering (even hints would be appreciated).

答:
1/ Why do we have motors with cylindrical shaft and others with a D shaped one ? Are there other shapes ? How do you chose the appropriate one ?

I find shafts with D profile are better to transfer the force and it greatly helps reduce slipping since matting a D shaft (on the motor side) with a D bore (on a pulley or wheel hub) creates a geometric lock between the matting components.

All high-torque motors come with such profiles in general. Of course, there are exceptions to everything. There are other profiles too, like a shaft with keyways and tapper wedge inserts as keys. Criteria to select the profile varies based on the application under consideration.

D-shaft is the most simplest one to manufacture and easy to assemble and disassemble with its counterparts.

2/ Can you confirm that I should avoid mounting parts directly on the motor shaft, and instead use a 2nd shaft ? For the Z-axis, I believe the ball screw can be considered as the 2nd shaft.

Mounting directly or indirectly depends on the load-bearing capacity of the motor shaft. So, once you figure out the limitations of your motor shaft that should narrow down your query. The type of coupling can also be a deciding factor. Eg: A shaft coupling using a sleeve and grub screw may be adequate if it is a low torque application. If the shaft material is weaker than the coupling material, say you are using a grub screw to lock the shaft and its counterparts, under high torque the screw can eat the shaft away resulting in a lot of backlashes or total failure of shaft-to-shaft coupling.

Is it only a matter of space available or is one design more efficient than the other ?

Both are two very different motors used for two very different applications, the first one is a stepper motor which has better-holding torque & precise control, and the second one is a high-speed in-runner brushed motor (hence all the step-down/ low gear setup to convert that high speed to high torque). For your use case, I believe you need decent torque and good precision so a servo motor or stepper should be adequate.

Hope this helps :)


问:
How can such a small motor produce so much torque?
I have only recently gotten into robotics - so I'm not that familiar - please excuse me if this is a silly question.

I was looking at servo and stepper motors. I can see that a lot of servo motors basically look like this one:

This servo can produce 1.1Nm of force. I have seen it. It's very small, light and cute. It doesn't look as "professional" as the types below.

There are also much larger (stepper) motors that look like these:

This is significantly larger, heavier, yet produces only 0.4Nm of torque.

It's very shocking to me that such a small motor outperforms this larger one. Ignoring the differences between stepper and servo motors, is there any advantage to using this larger one?

Will it have better speed or reliability perhaps?

答:
It's very shocking to me that such a small motor outperforms this larger one. Ignoring the differences between stepper and servo motors, is there any advantage to using this larger one?

The Stepper motor (the second one) has higher holding torque by its design and operates in an open loop, hence a less complex control system, whereas Servo achieves higher torque at high speed and has poor holding torque, and operates in a closed feedback loop using an encoder setup for positional feedback. Hence, servos use complex control systems. Stepper motors because of their simplicity are priced cheaper compared to servo motors.

Eg: Cheaper 3D printers have stepper motors, whereas high-precision (and expensive) ones use servo motors.

Said that the smaller servo achieves its high torque capability at the cost of its high speed and limited range in its movement by utilizing a compound gearing setup.

The stepper is bare bone with no gears in it hence lower output torque than the servo in comparison.

@jsotola I doubted it too. So are you saying if we compared the naked motors, the servo one would have a lower torque? And if we had applied the same gearbox to each, would the stepper have a larger torque?

Yes, it's safe to say that given the same gearing ratio, the stepper will produce way more torque than the servo. The 1.1NM value on the servo motor is achieved only at the end of the gearbox, but the 0.4NM value on the Stepper motor is its own torque rating.

So your application determines which one is suited best based on their ability and capability. There is form-factor to take into account as well.

Hope this helps :)


问:
transform Pose - undefined reference to std::chrono::time_point, tf2::doTransform
I'm trying to transform frames using tf2 using ros2 rolling but I'm getting this error:

```<code>/usr/bin/ld: CMakeFiles/reading_laser.dir/src/reading_laser.cpp.o: in function `geometry_msgs::msg::PoseStamped_<std::allocator<void> >& tf2_ros::BufferInterface::transform<geometry_msgs::msg::PoseStamped_<std::allocator<void> > >(geometry_msgs::msg::PoseStamped_<std::allocator<void> > const&, geometry_msgs::msg::PoseStamped_<std::allocator<void> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::chrono::duration<long, std::ratio<1l, 1000000000l> >) const':
reading_laser.cpp:(.text._ZNK7tf2_ros15BufferInterface9transformIN13geometry_msgs3msg12PoseStamped_ISaIvEEEEERT_RKS7_S8_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEENSt6chrono8durationIlSt5ratioILl1ELl1000000000EEEE[_ZNK7tf2_ros15BufferInterface9transformIN13geometry_msgs3msg12PoseStamped_ISaIvEEEEERT_RKS7_S8_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEENSt6chrono8durationIlSt5ratioILl1ELl1000000000EEEE]+0x5a): undefined reference to `std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long, std::ratio<1l, 1000000000l> > > tf2::getTimestamp<geometry_msgs::msg::PoseStamped_<std::allocator<void> > >(geometry_msgs::msg::PoseStamped_<std::allocator<void> > const&)'
/usr/bin/ld: reading_laser.cpp:(.text._ZNK7tf2_ros15BufferInterface9transformIN13geometry_msgs3msg12PoseStamped_ISaIvEEEEERT_RKS7_S8_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEENSt6chrono8durationIlSt5ratioILl1ELl1000000000EEEE[_ZNK7tf2_ros15BufferInterface9transformIN13geometry_msgs3msg12PoseStamped_ISaIvEEEEERT_RKS7_S8_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEENSt6chrono8durationIlSt5ratioILl1ELl1000000000EEEE]+0x7a): undefined reference to `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > tf2::getFrameId<geometry_msgs::msg::PoseStamped_<std::allocator<void> > >(geometry_msgs::msg::PoseStamped_<std::allocator<void> > const&)'
/usr/bin/ld: reading_laser.cpp:(.text._ZNK7tf2_ros15BufferInterface9transformIN13geometry_msgs3msg12PoseStamped_ISaIvEEEEERT_RKS7_S8_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEENSt6chrono8durationIlSt5ratioILl1ELl1000000000EEEE[_ZNK7tf2_ros15BufferInterface9transformIN13geometry_msgs3msg12PoseStamped_ISaIvEEEEERT_RKS7_S8_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEENSt6chrono8durationIlSt5ratioILl1ELl1000000000EEEE]+0xcf): undefined reference to `void tf2::doTransform<geometry_msgs::msg::PoseStamped_<std::allocator<void> > >(geometry_msgs::msg::PoseStamped_<std::allocator<void> > const&, geometry_msgs::msg::PoseStamped_<std::allocator<void> >&, geometry_msgs::msg::TransformStamped_<std::allocator<void> > const&)'
</code>```

Here's my callback function

```<code> void transform() {

        std::vector<Eigen::Vector2d> temp_pose;
        for (const auto & input_pose : poses_) {
            // transform vector poses into PoseStamped to be compatible with transform function
            geometry_msgs::msg::PoseStamped input_pose_;
            input_pose_.header.frame_id = "robot_frame";
            input_pose_.pose.position.x = input_pose(0);
            input_pose_.pose.position.y = input_pose(1);
            geometry_msgs::msg::PoseStamped output_pose;
            try {
            tf_buffer_->transform(input_pose_, output_pose, "world");
            } catch (tf2::TransformException &ex) {
            RCLCPP_ERROR(this->get_logger(), "%s",ex.what());
            }
            //transform output poses back into vector
            temp_pose.push_back({output_pose.pose.position.x, output_pose.pose.position.y});
        }
        poses_ = temp_pose;
}
</code>```

The error happens in this line

```<code>tf_buffer_->transform(input_pose_, output_pose, "world");
</code>```

Here's how it's defined in the node

```<code>tf_buffer_ = std::make_unique<tf2_ros::Buffer>(this->get_clock());
subscription2_ = std::make_shared<tf2_ros::TransformListener>(*tf_buffer_);
</code>```

This is how the file is configured in my CMakeLists.txt

```<code>find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(sensor_msgs REQUIRED)
find_package(std_msgs REQUIRED)
find_package(grid_map_core REQUIRED)
find_package(tf2 REQUIRED)
find_package(tf2_ros REQUIRED)
find_package(grid_map_cv REQUIRED)
find_package(OpenCV REQUIRED)
find_package(geometry_msgs REQUIRED)

add_executable(reading_laser src/reading_laser.cpp
src/ShaftGrid.cpp)
    ament_target_dependencies(reading_laser rclcpp std_msgs sensor_msgs grid_map_core tf2 tf2_ros geometry_msgs grid_map_cv OpenCV)
set(targets_list
  reading_laser)

install(
  TARGETS <span class="math-container">${targets_list}
  ARCHIVE DESTINATION lib
  LIBRARY DESTINATION lib
  RUNTIME DESTINATION lib/$</span>{PROJECT_NAME}
)
</code>```

Any idea why this is happening? It doesn't happen when I use other functions such as

```<code> tf_buffer_->lookupTransform("world", "robot_frame", rclcpp::Time(0));
</code>```

答:
To use type transforms you need to include the appropriate packages + link against them. When you call doTransform against a geometry_msgs, you have to include the tf2_geometry_msgs package headers and link against them to get the implementation. This allows users to create their own toTransform functions for various custom types. There's an analog as well for eigen and sensor_msgs types you should also be aware of.

https://github.com/ros2/geometry2/blob/49d4be4e8dd08282fc3bf5238459ce41d6befe6f/tf2_geometry_msgs/include/tf2_geometry_msgs/tf2_geometry_msgs.hpp


问:
Is it possible to make DIY clone of MakerBeam
Is it possible to make clone of http://www.makerbeam.eu/ of some easy accessible material like:

wood

plywood

OSB

MDF

HDF

others

Using any type of CNC machine to mill some holes and rails in those materials may give sufficient results e.g. to make a prototype of 3D printer of such "beams".

Of course it won't be as rigid and durable but for making prototypes it may be good idea.

Just for reference: when reading this http://www.lowtechmagazine.com/2012/12/how-to-make-everything-ourselves-open-modular-hardware.html I've found this http://bitbeam.org/, this https://www.google.com/search?q=grid+beam&client=ubuntu&hs=zAr&channel=fs&source=lnms&tbm=isch&sa=X&ved=0CAcQ_AUoAWoVChMIiLHdqf2MyQIVQZoUCh1cHwV1&biw=1215&bih=927 and this http://www.gridbeam.com/, and this https://www.tetrixrobotics.com/.

答:
The main problem you will have with this idea is that the MakerBeam / MicroRax / 80/20 rails are extruded aluminum, not milled.  It might be difficult to replicate the design in wood.

Beyond that, the wood will have roughly 1/10 the tensile strength of the aluminum and 1/20th the compression strength.


问:
Why do we need to know the translation between Camera and IMU?
In Visual Inertial Odometry, assuming the camera and the IMU are attached to the same rigid body, why isn't it enough to know just the relative rotation between the camera and the IMU? Why do we need to know the relative translation too?

Imagine a situation where we know the exact relative rotation ${^I_C}R$ from camera's frame of reference to IMU's frame of reference, but we don't know the relative translation ${^I_C}t$ between them. Where in a VIO pipeline would the relative translation ${^I_C}t$ be used and why VIO cannot work without it?

Isn't the point of camera-IMU extrinsics to transform the angular velocity and acceleration measurements from the IMU frame of reference to the camera frame of reference? Velocity and acceleration aren't points, but vectors, so adding an arbitrary offset ${^I_C}t$ to them doesn't make sense to me.

To simplify the situation, let's assume ${^I_C}R$ to be identity so the axes of camera's and IMU's frame of references are aligned, but assume there is a shift ${^I_C}t$ between the camera and the IMU.

My understanding so far is that the rotational component of the motion experienced by the IMU and the camera is the same, regardless of the pivot point of the rotation. I can only imagine ${^I_C}t$ being of use when somehow correlating gyro and accelerometer readings to identify the pivot point of the rotation experienced by the IMU.

By knowing the location of the pivot point of the rotation relative to the IMU and knowing camera-IMU extrinsics, it would be possible to get a better inter-frame translation estimate, but separating acceleration caused by rotation from other sources of acceleration seems difficult to me.

答:
You answered yourself.
Your underlying model of point moving through space usually assumes the center of gravity to match the camera frame.
If  your inertial sensor have a translational offset from the camera attached to a rotating rigid body, you would measure extra tangential and radiant acceleration components that your camera should not experience.

You can remove them by using the gyroscope angular rates $\omega$ and knowing the offset $r$. This should be the relationship between the accelerations measured in the imu frame and camera frame:

$$a^{\text{cam}} = a^{\text{imu}} - \dot{\omega} \times r - \omega \times \omega \times r$$


答:
It's important to know the offset between the camera and the IMU because the IMU's information is only useful when it can be correleated with the camera data.

In a lot of the trivial cases this difference could be negligible. However depending on your requirements for accuracy you will need to compensate.

Lets use a thought experiment of a baseball batter. And simplify it down to a 1m bat mounted on a motor. With the IMU mounted at the pivot point (aka by the hands) and the camera at the tip of the bat. And you want to be tracking the incoming baseball visually. And for simplicity lets put the ball on a tee just out of reach of the bat so it's not moving.

When the camera observes the ball it will be experiencing translational movement as well as rotational movement. The ball will appear to be approaching the camera on an arc. But by the construction of the experiment we know that the IMU is only reporting rotational motion. Such that if you ignore the offset between the camera and the IMU at any give point as you will miss estimate the velocity of the ball. This is most obvious when the bat is passing very close to the ball. The camera will believe that the ball is moving at approximately $v = \omega \times r$ because the only estimated motion of the camera is the rotation $w$ and I'm assuming the ball in negligably far away from the camera $ \epsilon $, implying that $\epsilon \times \omega \sim 0$ Thus the velocity of the stationary ball would be computed to be approximately the velocity of the camera because the camera's motion is not being properly compensated for. And if you're trying to track this ball or anything else in the scene, integrating these incorrect velocities over time will cause your whole understanding of the environment to diverge.

Now this is showing the worst case of the ratios of $r$ and $\epsilon$ but this is the math that is required to maintain high accuracy. In some cases you can make arguments that ignoring these components won't be a problem. But unless you've fully made that case and know that it will never be invalid in the future, it's generally considered best to do the full computation as it can be done relatively quickly in closed form and you don't have to put caveats into your system about the ratio of the distance from the IMU to the camera to the objects in the view.

Title: Why do we need to know the translation between Camera and IMU?

Body:
In Visual Inertial Odometry, assuming the camera and the IMU are attached to the same rigid body, why isn't it enough to know just the relative rotation between the camera and the IMU? Why do we need to know the relative translation too?

Imagine a situation where we know the exact relative rotation ${^I_C}R$ from camera's frame of reference to IMU's frame of reference, but we don't know the relative translation ${^I_C}t$ between them. Where in a VIO pipeline would the relative translation ${^I_C}t$ be used and why VIO cannot work without it?

Isn't the point of camera-IMU extrinsics to transform the angular velocity and acceleration measurements from the IMU frame of reference to the camera frame of reference? Velocity and acceleration aren't points, but vectors, so adding an arbitrary offset ${^I_C}t$ to them doesn't make sense to me.

To simplify the situation, let's assume ${^I_C}R$ to be identity so the axes of camera's and IMU's frame of references are aligned, but assume there is a shift ${^I_C}t$ between the camera and the IMU.

My understanding so far is that the rotational component of the motion experienced by the IMU and the camera is the same, regardless of the pivot point of the rotation. I can only imagine ${^I_C}t$ being of use when somehow correlating gyro and accelerometer readings to identify the pivot point of the rotation experienced by the IMU.

By knowing the location of the pivot point of the rotation relative to the IMU and knowing camera-IMU extrinsics, it would be possible to get a better inter-frame translation estimate, but separating acceleration caused by rotation from other sources of acceleration seems difficult to me.