问:
Getting A Head Start With iRobot Create3 (ROS2)
With the announcement of the iRobot Create3 "with ROS2 support", and to get a head start playing with it, iRobot has some create3 GitHub repos:

https://github.com/iRobotEducation/create3_sim

https://github.com/iRobotEducation/create3_examples
and apparently a dependency on:

https://github.com/iRobotEducation/irobot_create_msgs

I have started a "Create3 ROS2 Controller" with a RaspberryPi3B running ROS2 Galactic over 64-bit Ubuntu 20.04 Server.

Since this is a headless, no desktop install, I have not installed the create3_sim repo.

Where should I put irobot_create_msgs and how do I build it?

My tree:

```<code>$ tree -L 2
├── create3ros
│   ├── create3_examples_ws
│   ├── create3_ws
</code>```

This is the error:

```<code>ubuntu@CREATE3:~/create3ros/create3_examples_ws$ colcon build
Starting >>> create3_examples_msgs
Starting >>> create3_examples_py
Finished <<< create3_examples_py [5.42s]
[Processing: create3_examples_msgs]
Finished <<< create3_examples_msgs [49.4s]
Starting >>> create3_coverage
--- stderr: create3_coverage
CMake Error at CMakeLists.txt:22 (find_package):
  By not providing "Findirobot_create_msgs.cmake" in CMAKE_MODULE_PATH this
  project has asked CMake to find a package configuration file provided by
  "irobot_create_msgs", but CMake did not find one.

  Could not find a package configuration file provided by
  "irobot_create_msgs" with any of the following names:

    irobot_create_msgsConfig.cmake
    irobot_create_msgs-config.cmake

  Add the installation prefix of "irobot_create_msgs" to CMAKE_PREFIX_PATH or
  set "irobot_create_msgs_DIR" to a directory containing one of the above
  files.  If "irobot_create_msgs" provides a separate development package or
  SDK, be sure it has been installed.

---
Failed   <<< create3_coverage [7.51s, exited with code 1]

Summary: 2 packages finished [58.1s]
  1 package failed: create3_coverage
  1 package had stderr output: create3_coverage
<span class="math-container">```
```

答:
Got it:  Needed to clone the msgs into the same src dir as the examples:

```<code>$ tree -L 4
.
├── create3ros
│   ├── create3_examples_ws
│   │   └── src
│   │       ├── create3_examples
│   │       └── irobot_create_msgs

</code>```

and the build proceeds and succeeds after 16min 31s.

Body:
Got it:  Needed to clone the msgs into the same src dir as the examples:

$ tree -L 4
.
├── create3ros
│   ├── create3_examples_ws
│   │   └── src
│   │       ├── create3_examples
│   │       └── irobot_create_msgs

and the build proceeds and succeeds after 16min 31s.


问:
Confusion about Gimbal lock
I am trying to understand exactly what is happening when Gimbal lock occurs. I have read many explanations now which provide the high-level idea, in that Gimbal lock occurs when two axes are aligned during the sequence of three rotations. But I am struggling to understand what this really means in terms of the calculations that are going on.

Here's my understanding of the setup. We have an initial 3D rotation of a body, and a target 3D rotation of that body, and we want to move the body from the initial to the target rotation. To do this, we calculate the Euler angles representing this rotation. (I don't know the maths behind this, but I will assume that this is just an algorithm that takes in an initial and target rotation, and returns a third rotation).

So, we now have a rotation expressed as Euler angles, which we want the body to move over. And now I will explain my confusion. From what I have been reading, there are two ideas:

Gimbal lock occurs when two of the axes become aligned, during the sequence of three rotations, which means that there is one axis about which rotation cannot occur.

Due to Gimbal lock, the path which the rotation occurs over will not be "straight", and there will be a curve.

This to me is very confusing. 1) is saying that Gimbal lock means that we cannot rotate the body along a certain axis. 2) is saying that Gimbal lock means that we can rotate the body, but that the path will not be "straight".

Please can somebody explain which one is correct, and help me to overcome this confusion? Thanks!

答:
First of all, don't use Euler angles. That's a real nasty thing.

I don't understand 2 without the context but 1 means the following.

If the following is your rotation matrix,

Rotation Matrix = Rotx(x)*Roty(y)*Rotz(z),

Gimbalock means two different rotation matrices R1 and R2 could be the same.

R1 = Rotx(x+10deg)*Rotz(y)*Rotx(z)

R2 = Rotx(x)*Rotz(y+10deg)*Rotx(z)

The following shows a visualization of this problem.
https://en.wikipedia.org/wiki/File:Gimbal_Lock_Plane.gif

Obviously, either you change x or y the result is the same and once it happens your control system will go bad.

You don't even need to understand this. Just stay away from Euler angles and use rotation vector representation.

ContentLicense: CC BY-SA 4.0

Title: Confusion about Gimbal lock


问:
Which type of actuator will be suitable for a very strong robot arm?
I wish to build a robotic arm that can lift a useful amount of weight (such as 3-6 kg on an arm that can extend to approx 1.25 meters). What actuators are available to accomplish this? The main factors and design points are:

Not Expensive

5 to 6 DOF

to be mounted on a yet to be designed mobile platform

battery powered

stronger than hobby servos (at least for the 'shoulder' and 'elbow' joints)

not slow to actuate

答:
There are two more factors to consider: Complexity and cost.

Industrial robotic arm like that

industrial robotic arm http://halcyondrives.com/images/robotic_arm.png

Image from http://halcyondrives.com

normally use torque from the gearbox to direct drive the joint, now think about the torque the gear reduction should support and the size/weight it will be? It simple huge and expensive, their materials need to support a huge torque.

Let's take your example with the arm fully horizontally extended.
Lets consider just the load of 6Kg at 1m, you have $ 600Kgf/cm $. This is not including the robot arm own weight (easily more 4Kg), and considering just 1m.

Some solutions industry uses

Strain Wave Gearing or Harmonic drive

Image from http://commons.wikipedia.org

To get lighter gear reduction, with high reduction ratios, most uses Strain Wave Gearing or Harmonic drive. Its low-weight, robust, and according to wikipedia can have a reduction of $ 200:1 $ (wikipedia says more) where a planetary gear can archive $ ~ 10:1 $.

But this type of gearing is very expensive and complex.

Springs and counter-weights

Image from http://www.globalrobots.ae

Other even simple solution is adding counter-weights like you see in the image. This has a linkage to act both on the forearm (I forget the name) and in the arm. Springs will help too, and if mounted on the same axis of the joint but a bit offset, it will put more force as the arm gets more extended.

Low-cost and less complex solutions for the mechanical drive system

Now for less cost and less complex solutions, what I should think is removing the high torque at the gear drive, so you can use less expensive materials. For a pure electronic drive, this would be a linear actuator.

There is a variety of linear actuators. But the idea is that it will take less force (depending on what points of the arm it is attached).

"Nut" and leadscrew type

This type of actuator has many sub-types, and that affects efficiency, wear, force, and much more. But in general, they have a high force and a relative slow-to-medium speed (this will again depend on the type, it can be vary fast, like the ones used on some motion platform simulators).

6 dof motion platform with electric linear actuators http://cfile29.uf.tistory.com/T250x250/195BAD4B4FDB0AF104C30F.

Electric linear actuators are substituting hydraulic linear actuators at this application, and they need to be fast and strong, some simulators easily weight more than 2 tons.

Belt or chain drive

For more speed and other simple method are the belt or chain drive like that

Image from http://images.pacific-bearing.com

This is of course an industrial made one, this is a DIY one, and it has more for the
application: (yes it has space for much improvement, but is a good form to show how fast and strong it can be even in this design).
http://bffsimulation.com/linear-act.php

This allows you to use less gearing, if a motor could output $ 50Kgf/cm $ and you use a 2 cm diameter pulley, you would get $ 50Kgf $ (not considering losses) on the full stroke.

Also the bearings at this actuator will need to support most radial forces, where in a "leadscrew and nut" the bearing will take most axial force. So depending on the force you need to use a thrust ball bearing.


问:
Forward Kinematics for articulated manipulator not giving right answer
I calculated the forward kinematics for an articulated manipulator robot in ROS, but I am not getting the right answer. Here is the diagram for the robot configuration I used-

When Q1,Q2,and Q3 are zero this calculation is supposed to give the dx,dy and dz as 2,0,1 if I consider all the link lengths as 1.But after I substitute these values of Q1=0,Q2=0, and Q3=0 I get dx,dy, and dz as 2,0,0. I double checked the DH parameters and calculations in Matlab, but the values are still 2,0,0. I am not sure why I am not getting the right answer. Maybe I am getting the right answer, but I don't understand it.

My Matlab calculation after substituting Q1, Q2,and Q3 as 0,0,0-

```<code>>> a1

a1 =

     1     0     0     0
     0     0    -1     0
     0     1     0     0
     0     0     0     1

>> a2

a2 =

     1     0     0     1
     0     1     0     0
     0     0     1     0
     0     0     0     1

>> a3

a3 =

     1     0     0     1
     0     1     0     0
     0     0     1     0
     0     0     0     1

>> t06=a1*a2*a3

t03 =

     1     0     0     2
     0     0    -1     0
     0     1     0     0
     0     0     0     1

>>
</code>```

In my inverse kinematics code when I enter the coordinates of end effector as 2,0,1, I get correct Q values i.e 0,0,0 or 0,0,2Pi.
Where am I going wrong?

答:
You have drawing that shows some vertical distance $d_1$ between your first and second frames:

but on your table you don't have any values for $d_1$:

You didn't show how you built up your matrices, so I can't tell you how/where exactly you went wrong, but I strongly suspect you've dropped your $d_1$ distance. This is what's setting your elevation, so it makes sense to me that you're getting $z=0$ when $d_1=0$.


问:
Tried to advertise a service that is already advertised in this node [/leo/controller_manager/list_controllers]
I'm trying to do a multi agent simulation using leo_rover which is open source. I'm comfortable with single system, but when I add a second robot using namespaces i get the second robot spawned in the gazebo exactly where i want, but the controllers for the two agents try to get published at the same node location. In the end neither of the controller spawns and I'm left with rovers without controllers.

This is the rover.launch file.

```<code><launch>
   <arg name="init_pose"/>
   <arg name="robot_name"/>
   <param name="robot_description" command="<span class="math-container">$(find xacro)/xacro $</span>(find leo_description)/urdf/new.urdf.xacro" />

   <!-- push robot_description to factory and spawn robot in gazebo -->
   <node name="urdf_spawner" pkg="gazebo_ros" type="spawn_model"
    args="<span class="math-container">$(arg init_pose) -unpause -urdf -model $</span>(arg robot_name) -param /robot_description" respawn="false" output="screen"/>

  <node pkg="robot_state_publisher" type="robot_state_publisher"  name="robot_state_publisher" ns="leo">
      <param name="publish_frequency" type="double" value="30.0" />
  </node>

  <include file="$(find leo_control)/launch/control.launch">
   <!-- TODO: add possible arguments for depth camera, etc.-->
  </include>

</launch>
</code>```

This is the control.launch used in the rover.launch

```<code><launch>

  <arg name="use_tf_static" default="false"/>
  <arg name="model" default="$(find leo_description)/urdf/new.urdf.xacro"/>

  <!-- Load controller configuration />-->
  <rosparam command="load" file="$(find leo_control)/config/control.yaml" />

  <node name="controller_spawner" pkg="controller_manager" type="spawner"
    respawn="false" args="leo_velocity_controller leo_joint_publisher" output="screen" ns="leo"/>

</launch>
</code>```

Below launch file tries to add 2rovers into the simulation using namespaces.

```<code><launch>
  <!-- No namespace here as we will share this description.
      Access with slash at the beginning -->
  <param name="robot_description" command="<span class="math-container">$(find xacro)/xacro $</span>(find leo_description)/urdf/new.urdf.xacro" />

  <!-- BEGIN ROBOT 1-->
  <group ns="rover1">
    <param name="tf_prefix" value="rover1_tf" />
    <include file="$(find btp)/launch/rover.launch" >
      <arg name="init_pose" value="-x 0 -y 0 -z 0" />
      <arg name="robot_name"  value="Robot1" />
    </include>
  </group>

  <!-- BEGIN ROBOT 2-->
  <group ns="rover2">
    <param name="tf_prefix" value="rover2_tf" />
    <include file="$(find btp)/launch/rover.launch" >
      <arg name="init_pose" value="-x -2 -y 0 -z 0" />
      <arg name="robot_name"  value="Robot2" />
    </include>
  </group>
</launch>
</code>```

Below multisim.launch file combines all these launches.

```<code><launch>
   <arg name="world_name" default="worlds/empty.world"/>

   <include file="<span class="math-container">$(find gazebo_ros)/launch/empty_world.launch">
     <arg name="world_name" value="$</span>(arg world_name)"/> <!-- world_name is wrt GAZEBO_RESOURCE_PATH environment variable -->
     <arg name="paused" value="false"/>
     <arg name="use_sim_time" value="true"/>
     <arg name="gui" value="true"/>
     <arg name="headless" value="false"/>
     <arg name="debug" value="true"/>
     <arg name="verbose" value="true"/>
   </include>
   <!-- start gui -->
   <!-- <node name="gazebo_gui" pkg="gazebo" type="gui" respawn="false" output="screen"/> -->

   <!-- include our robots -->
   <include file="$(find btp)/launch/multi_rover.launch"/>
</launch>
</code>```

Now the error why I launch this multisim.launch file.

```<code>[ERROR] [1611075925.200755903, 0.394000000]: Tried to advertise a service that is already advertised in this node [/leo/controller_manager/list_controllers]
[ERROR] [1611075925.200778314, 0.394000000]: Tried to advertise a service that is already advertised in this node [/leo/controller_manager/list_controller_types]
[ERROR] [1611075925.200811448, 0.394000000]: Tried to advertise a service that is already advertised in this node [/leo/controller_manager/load_controller]
[ERROR] [1611075925.200824730, 0.394000000]: Tried to advertise a service that is already advertised in this node [/leo/controller_manager/unload_controller]
[ERROR] [1611075925.200841861, 0.394000000]: Tried to advertise a service that is already advertised in this node [/leo/controller_manager/switch_controller]
[ERROR] [1611075925.200859178, 0.394000000]: Tried to advertise a service that is already advertised in this node [/leo/controller_manager/reload_controller_libraries
</code>```

答:
I am trying to do similar thing but with ridgeback robot provided by clearpath robotics and implemented your answer. But still facing the same issue. I attaching the launch file of one_robot.launch. Please help.

respawn="false" output="screen" />

```<code><node pkg="robot_state_publisher" type="state_publisher"
      name="robot_state_publisher" output="screen"/>

<!-- The odometry estimator, throttling, fake laser etc. go here -->
<!-- All the stuff as from usual robot launch file -->
</code>```

    front_left_wheel:
      p: 1
      i: 0.1
      d: 0
    front_right_wheel:
      p: 1
      i: 0.1
      d: 0
    rear_left_wheel:
      p: 1
      i: 0.1
      d: 0
    rear_right_wheel:
      p: 1
      i: 0.1
      d: 0

Body:
I am trying to do similar thing but with ridgeback robot provided by clearpath robotics and implemented your answer. But still facing the same issue. I attaching the launch file of one_robot.launch. Please help.

respawn="false" output="screen" />

<node pkg="robot_state_publisher" type="state_publisher"
      name="robot_state_publisher" output="screen"/>

<!-- The odometry estimator, throttling, fake laser etc. go here -->
<!-- All the stuff as from usual robot launch file -->

    front_left_wheel:
      p: 1
      i: 0.1
      d: 0
    front_right_wheel:
      p: 1
      i: 0.1
      d: 0
    rear_left_wheel:
      p: 1
      i: 0.1
      d: 0
    rear_right_wheel:
      p: 1
      i: 0.1
      d: 0


问:
Solving a grid maze with blocked paths
I have to build two robots (virtual) that will solve a grid maze that has blocked paths colored in red. The robots cannot go on these red paths in any case. There are several white patches in some random places on the grid and they consist of coins of two colors (yellow, blue). Positions of these small white patches can differ from positions in below grid.

The robots have to pick these coins, take blue coins to the Right side big white starting square, and yellow coins to the Left side big white starting square. There are 6 coins altogether. (3- Yellow, 3- Blue) Robots can only carry one coin at once. Communication between robots is optional. (But I think it's better to have communication between the two robots)

The robots do not know the grid map ahead. Are there any specific algorithms that can be used for this mapping purpose?

Are there any algorithms that can be used for solving this kind of problem? I did some searching but I was unable to find any algorithms that can be used for such a problem. Could you please guide me on how to solve this?

Time the robot takes to complete the task is the key performance factor here.

Any help is much appreciated. Thank you!

答:
You didn't specify any performance requirement. That admits the simple algorithm:

```<code>do forever:
    move at random
    if in a destination square
        if carrying coin that matches destination
            drop coin
    else if at a coin and not carrying one
        pick up coin
</code>```

Also you didn't specify

whether the robots know the grid map ahead of time, or if they have to discover it for themselves

whether the robots know how many coins there are

whether the robots move in discrete steps from one intersection to the next

whether the two robots supposed to cooperate

If the map is known (or becomes known through sufficient exploration) I would start with Dijkstra's shortest path algorithm. That would help a robot get from where it is, to where a coin is. Then get from there to the destination square. Then repeat that process until all the coins get to their destination. If the number of coins is unknown, then the robots will keep track of what paths they have covered--if all paths have been covered without finding any coins, they're done.

Edited to add response to comments

By "move in discrete steps" I mean the considerably simpler case where you could consider the grid to be a graph. That is to be distinguished from a somewhat more physical simulation where the robot moved at X meters/second along a path Y meters long and needed to recognize when it had a choice of paths to take. That gets into localization and SLAM and all that, which is complicated enough that I infer that's not what you meant!

A discrete graph would have nodes (grid intersections, plus the two special destination squares) and edges (paths connecting the nodes). Blocked paths don't even need to be represented. A discrete move would be a single instantaneous operation, taking the robot from one node, along an edge, to another node.

You could assume (or specify) that each robot knows:

where it is

what edges (paths) and nodes (intersections) it has visited

Then it would be good to read about graph traversal algorithms. That would provide an efficient way to explore the graph (grid). Once all the coins are discovered (if not transported), you could even stop it early, without mapping the entire graph.

That should result in "sufficient exploration" to get into shortest path planning.

I suspect that a more able algorithmicist than I am might find ways to bias the exploration vs transport to take early advantage of information as it is discovered. But that's a brainstorm for another day.

Title: Solving a grid maze with blocked paths

Body:
You didn't specify any performance requirement. That admits the simple algorithm:

do forever:
    move at random
    if in a destination square
        if carrying coin that matches destination
            drop coin
    else if at a coin and not carrying one
        pick up coin

Also you didn't specify

whether the robots know the grid map ahead of time, or if they have to discover it for themselves

whether the robots know how many coins there are

whether the robots move in discrete steps from one intersection to the next

whether the two robots supposed to cooperate

If the map is known (or becomes known through sufficient exploration) I would start with Dijkstra's shortest path algorithm. That would help a robot get from where it is, to where a coin is. Then get from there to the destination square. Then repeat that process until all the coins get to their destination. If the number of coins is unknown, then the robots will keep track of what paths they have covered--if all paths have been covered without finding any coins, they're done.

Edited to add response to comments

By "move in discrete steps" I mean the considerably simpler case where you could consider the grid to be a graph. That is to be distinguished from a somewhat more physical simulation where the robot moved at X meters/second along a path Y meters long and needed to recognize when it had a choice of paths to take. That gets into localization and SLAM and all that, which is complicated enough that I infer that's not what you meant!

A discrete graph would have nodes (grid intersections, plus the two special destination squares) and edges (paths connecting the nodes). Blocked paths don't even need to be represented. A discrete move would be a single instantaneous operation, taking the robot from one node, along an edge, to another node.

You could assume (or specify) that each robot knows:

where it is

what edges (paths) and nodes (intersections) it has visited

Then it would be good to read about graph traversal algorithms. That would provide an efficient way to explore the graph (grid). Once all the coins are discovered (if not transported), you could even stop it early, without mapping the entire graph.

That should result in "sufficient exploration" to get into shortest path planning.

I suspect that a more able algorithmicist than I am might find ways to bias the exploration vs transport to take early advantage of information as it is discovered. But that's a brainstorm for another day.


问:
How to republish odometry in different frame?
I have navigation Odometry, but its some how not in the robot body frame. The odometry is being published in world frame, so its not correct. So i need to transform in the robot body frame as that how should be in the correct way. So I tried to republish the linear velocity in the x axis in the robot body frame but the code is not working. Here is the ros node

```<code>#include <ros/ros.h>
#include <tf/transform_broadcaster.h>
#include <nav_msgs/Odometry.h>

float linear_x;
ros::Publisher odom_pub;

void poseCallback(const nav_msgs::OdometryConstPtr& msg){

    linear_x = (msg->twist.twist.linear.x );
    nav_msgs::Odometry pose_gt_frame;

        pose_gt_frame.header.frame_id = "world";

    //set the velocity
    pose_gt_frame.child_frame_id = "rexrov2/base_link";
    pose_gt_frame.twist.twist.linear.x = linear_x;

    //publish the message
    odom_pub.publish(pose_gt_frame);

}

int main(int argc, char** argv){
  ros::init(argc, argv, "my_tf_broadcaster");

  ros::NodeHandle node;
  ros::Subscriber sub = node.subscribe("/rexrov2/pose_gt", 10, &poseCallback);
  ros::spin();
  return 0;
};
</code>```

When run the code I got error

```<code>[FATAL] [1635340917.678039503, 15.652000000]: ASSERTION FAILED
    file = /opt/ros/melodic/include/ros/publisher.h
    line = 106
    cond = false
    message =
[FATAL] [1635340917.680256176, 15.654000000]: Call to publish() on an invalid Publisher
[FATAL] [1635340917.680299807, 15.654000000]:
</code>```

What can be wrong? Any help? Thanks

答:
It sounds like you need a static frame transform node.
I suggest you look up how to launch a static frame transform in a launch file.
Static frame transforms allow you to connect 2 separate frames with a constant frame in between them. Usually, odometry is with respect to the robot base_link, not the world frame. The static transform automates the frame linking such that you don't have to write any C++ or python to connect frames.

EDIT:

I see what you did: you forgot to initialize the ROS topic that the publisher publishes too.
In other words, you never called the constructor of the publisher. I suggest you look the documentation for how to do that.


问:
How do I build a world for a line follower bot in gazebo?
I am just starting off in robotics with my own little pet project: a line follower using openCV. However, I have no idea how to create a world in Gazebo for the bot. I went through the official Gazebo tutorials, however there doesn't seem to be stuff that can help me with this.

I intend to build a plane which will be the floor of the room and "paint" a line on it for the bot to follow. I know many pre-made models exist, but I would like to try it out on my own. How can I achieve this? Can Blender be used to create such a room?

答:
At the high level you're going to add a texture to the ground plane for the simplest approach. There's a gazebo tutorial on adding color and textures. The coloring of the line is a texture. There's also a section on Textures in the model Appearance Tutorial Gazebo Tutorial

There are many different tools that you can use to create the textures and models with textures. Blender is a commonly used tool, but you can use any 3D drawing tool.

However I'd suggest looking for projects who have already done this that you can play with. A good way to learn how to work with things is to start with an existing model and modify it instead of trying to start from scratch at first.

A quick search finds several projects with line follower worlds already implemented.

https://github.com/sudrag/line_follower_turtlebot

http://edu.gaitech.hk/turtlebot/line-follower.html

https://upcommons.upc.edu/bitstream/handle/2117/111138/tot.pdf


问:
Generate robot model for openrave
Is there another way to generate a collada model to work with openrave other than converting an URDF file with ROS' collada_urdf software?

The problem I'm encountering is with the setup needed to use ROS' program (setting up the ros distro and catkin, ecc..).

Since I've drawn the robot in SolidWorks is there a simpler way to generate the needed collada model?

答: Blender can create COLLADA files for use in robot simulation. The native blend file format can be exported to COLLADA through the built-in export tool. There is also a stack exchange website for Blender.

Title: Generate robot model for openrave


答:
If you've drawn the robot in Solidworks, you can just export to URDF directly. There's a tutorial on how to do it on the ROS wiki. There are more details there, but briefly, from the site:

Open your assembly in SolidWorks.

Set the position of your joints as you would like them exported

Click "Tools>Export to URDF". If using 1.5.1 or older will be under "File>Export to URDF" (sometimes its "Extras>File>Export to URDF")

Title: Generate robot model for openrave

Body:
Is there another way to generate a collada model to work with openrave other than converting an URDF file with ROS' collada_urdf software?

The problem I'm encountering is with the setup needed to use ROS' program (setting up the ros distro and catkin, ecc..).

Since I've drawn the robot in SolidWorks is there a simpler way to generate the needed collada model?


问:
Does full motor current pass through 'switches' on children's driving vehicles?
I plan to hijack a powerwheels-like toy to control it with the jetson nano.  Here is the toy:

https://www.wayfair.com/outdoor/pdp/konbeca-ride-on-bumper-car-kids-toy-electric-funny-ride-on-car-for-360-spin-powered-knbe1220.html?piid=59995891

I want to keep it ultra simple so my idea is to just take off the 'handles'(levers) and hook the wires to two relays controlled by the Jetson.

What I do not understand is if the full 30amp current goes through these wires, so that I would need heavy duty relays, or if some little relays than just take like up to 10amps are fine since it's just a 'switch'.

答:
So the answer is that indeed, the motor current wires are exactly the same wires wired into the switches:

This is apparently the univerally most common way these things are wired, and it would be good for people on this robotics site to be aware of that.

I hope this future robotics prototypers hooking up computers to these toys.  My 10-amp relays have not burned out yet, though I have no  idea how much current they get when eg the toy is pushing against a wall.


问:
What are the usual results for pedestrian posture detection?
When talking about lane detection in a road, usually robotic computer vision system give lines in an image.

For detecting obstacles, those system give Bounding Boxes.

My question is, for pedestrian (human) pose detection, in which format are the results given usually?

答: Typically any detected object would be reported with a bounding box. Then you have information for those objects, like heading, speed, etc., and you can project the bounding box's location into the future given its size and the path information.


问:
How to perform decoupling between decision making and action execution in ROS2?
Hi I'm making a robot using:

ros2 foxy

OS Ubuntu Linux 20.04.2 LTS (Focal Fossa).

Linux 5.8.0-59-generic

I built an Action based on the tutorial Building an Action Server and Client. Then expanded it using Serial and successfully managed to send messages to the serial port as seen in this thread.

The structure of my project is the following:

```<code>- workspace
    - src
        - arduino_comm #Represents the controller for the motor
             - serial_server.py
             - serial_client.py
        - motor_interface
        - other_interface
</code>```

The Server and Client use the following action, which is based on the tutorial

```<code>##################################################
#Action that sends robot towards a specific spatial position.
##################################################
#Goal of achieving a specific position.
int32 botgoalposition
---
#Resulting position that we're aiming to attain.
int32[] botendposition
---
#Feedback message about current position.
int32[] botcurrposition
</code>```

So far it works well, now I want to create a main node that will take care of the decision making and indicate where the robot will move. So far I think I'll start with something simple like pressing the keyboard's arrowkeys to turn them into commands to the action server that represent a change in coordinates and make arduino_comm translate them to commands for the Arduino to move a pair of motors.

I thought about it and to me it makes the most sense to build a service to send the coordinates only once to the action and then wait for a response from the action server called arduino_comm. Nonetheless I read that services are/used to? be blocking so if I want the main controller to perform other actions (such as receiving input from a joystick or a keyboard, or process from a camera) the robot wouldn't be able to do those decisions, right?

On the other hand in the documentation here about publishers and subscribers it mentions that they're non-blocking and convenient for calling from a given topic to all the available nodes subscribed to that topic. But I'm not sure if sending a stream of data may impact my actions and cause them to reset.

So I'd like to know what are the suggested options for the architecture of a robot like that.

When to use publisher vs service as main control logic of a robot that will send data to all the other nodes?

If I create a logic node that will send commands to all the others, do I need to send the commands to action clients (meaning I need to codify an action client for every node or just one client that is the logic node and holds the topics for all servers) or can I send them directly to the action server?

What are some tutorials I can use for ROS2 on how to send and receive commands from one node to another? And does it matter if they're publishers/action/services?

答:
As a general rule of thumb, publications and topics are good for streaming data and commands where they're flowing continuously. Services are better for handling singular events that are not repeating such that you care about validating that every specific request has gone through and possibly want feedback.

The action clients are just convenient mechanisms designed to facilitate interacting with the action server interface. You can instansiate multiple of them programmatically as classes inside your node for convenience or you can choose to do it manually and directly send commands to the server. I'd recommend at least leveraging the client classes as a base class so they take care of a lot of the logic for you.

For tutorials on sending and receiving data in ROS 2 between nodes the Client Libraries Tutorials cover that well. (Make sure to select the right version you're working with). The different communication mechanisms are quite different and are designed such that you can take advantage of the different characteristics depending on your specific use cases. You may find this summary of pattern useful for how to differentiate topics services and actions.

In the future please try to separate your questions in to separate more specific questions. Asking multiple questions at the same time is likely to get a good answer for one but not necessarily all of them together unless you can get someone who has expertise in all the areas.


问:
2D path following robot, converting XY axis path to input on wheels
at the moment I am creating an android program, that will steer my simple, 3 wheel (2 motors, 1 for balance) robot to move online following the path drawn by user on his screen. The robot is operated through WiFi and has 2 motors that will react on any input signals.

Imagine user drawing a path for this robot on smartphone screen. It has aquired all the points on XY axis, every time beginning with (0,0). Still I have no idea, how to somehow "convert" just points, into voltage input to both motors. Signals will be sent in approx. 60Hz connection, so quite fast. Maybe not every single axis point will be taken into consideration, there will be surely some skips, but that is irrelevant, since this path does not have to be done perfectly by the robot, just in reasonable error scale.

Do you have any idea on how to make the robot follow defined axis points that overall create a path?

Edit 10.01:

The voltage will be computed by the robot, so input on both is between -255 and 255 and the velocity should increase or decrease lineary in those borders.
Additionaly, I would like to solve it as if there were perfect conditions, I don't need any feedback crazy models. Let's assume that all the data is true, no sensors and additional devices. Just XY axis path and required input (ommit wheel slide too).

答:
There are two ways you can approach this problem, open-loop and closed-loop. Open-loop approach should be easier although it will be highly inaccurate. The closed-loop is more complex but it should improve the accuracy. The decision depends on your application and how much time you can spend.

The robot has to follow a requested path drawn by the user. To do that, you first need to track the position and orientation (state) of the robot. In the open-loop approach this is done by blindly predicting the state of the robot based on the input. So for example if you know that the robot is positioned at (0,0) facing at 0 degrees, and the input in the wheels is the same (i.e. drives "straight") at 1 meter per second, you would expect that after a second, the state of the robot will be (1,0) and still facing at 0 degrees (in reality this wont be the case because of uncertainties but it is just a rough estimation). This is usually done based on a mathematical model of the robot.  For the close-loop approach you also use feedback from the robot. One way to do this is with odometry, i.e. measuring the distance traveled by each wheel and therefore estimating its state using a model, for example the Kinematic Model. State estimation is improved, since you have the model (as in the open-loop) to "predict" the state and then you have the feedback to correct that prediction. For later reference lets define the state estimation as $\hat{x}$.

The closed-loop approach is certainly more accurate but it mainly depends on what sensors you use. An odometry based estimation will be acceptable for short periods but after that it will diverge and be useless. As always, this depends on your application and tolerance for accuracy.

The second step is to decide what input is required to send to the motor. This decision is made based on where the robot is i.e. $\hat{x}$ and where it needs to go $x_r$. For this you need a controller that constantly tries to minimize the error $e=\hat{x}-x_r$. So for your example, $x_r$ holds the coordinates of the next point that has to be visited by the robot. A simple controller would be one that:

Rotates the robot until it faces the point $x_r$

Moves the robot in a straight line until it reaches the point

Load the next point in $x_r$ and go to the first step

There are of course more sophisticated controllers which have certain properties but the above should work for your application.

ContentLicense: CC BY-SA 3.0


问:
How do I find the transfer function for my quadcopter altitude system?
This is not so much of a how but if I am right so far. I am looking at the z-axis now only. The linearized equation of motion for the thrust in the z-direction is:

$$
T=m\cdot \ddot{z}+mg,
$$

where $m$ is the mass, $\ddot{z}$ is the acceleration in the z-direction and $g$ is gravity acceleration and $T$ is the thrust. I will now Laplace transform it so it can be put in the frequency domain. I will first solve for the acceleration.

$$
\ddot{z} = T/m - mg
$$

I will now Laplace transform and this gives:

$$
T(s)/m - 1/(mg) = Z(s)s^2
$$

After some computations, I end with:

$$
Z=T(s)/(ms^2) -1/(mgs^2)
$$

I have ignored the last term because I have seen that usually plants in the control system it should "multipy-able" i.e one term. I am not sure if that is an error. What should I put in the drone plant then? See below for the figure.

This is put into my control system. I have made a PD controller and the control law (I made this myself, I have seen other papers using other inputs but I did not see the intuition) is sent which is:

$$
T = T_d + K_p \cdot e + K_d \cdot \dot{e}
$$

Where $T$ is the total thrust sent and $T_d$ is the desired thrust and $K_p$ and $K_d$ are the gains for derivative and position error.

All this is put into this control system. (the green part is technicality but it is to be ignored).

Will I be able to find the transfer function (by simplifying the blocks using block diagram reduction) and then send a step response to it so I can check what $K_p$ and $K_d$ values I need?

答:
You cannot simply neglect the weight.

The total thrust $T$ is normally provided by a combination of a feed-forward term $T_{FF}$ and a feedback term $T_{FB}$:

$$
T = T_{FF} + T_{FB}.
$$

Ideally, the feed-forward contribution should be designed such that it delivers the effort required to drive the plant toward the target:

$$
T_{FF} = mg + m\ddot{z_d}.
$$

If we replace the expression of $T$ into the dynamical equation of the system, we get:

$$
T_{FB} + m\ddot{z_d} = m\ddot{z}.
$$

The weight is canceled out from the equation (not really, as there is an offset – read below) and if $T_{FB} = 0$, we obtain $\ddot{z}=\ddot{z_d}$ and therefore $z=z_d$.

In reality, we don't know exactly the weight $mg$, thus the feedback $T_{FB}$ needs to compensate for these uncertainties and all the unmodelled quantities. For example, we generally don't have a perfect calibration of the thrust system; hence, the equation that states how to generate $T_{FF}$ from the forces at stake is certainly affected by errors.

The term $T_{FB}$ can be thus chosen to be a PID over the position error. You need the D part for stability reasons because the plant is actually a double integrator, but you need also the I part as there exists a fixed offset between the real weight and its estimate. The integral part I serves right to account for this offset.

Also, notice how $z_d$ cannot be made independent from $\ddot{z_d}$ as it is shown in your control architecture. To make things work properly, we need to enforce that $z_d$ is the output of a double integrator acting on $\ddot{z_d}$. In essence, $z_d$ shouldn't undergo stepwise transitions but rather needs to be shaped correctly.

Finally, you cannot neglect the drag force, which can be usually modeled as a term that depends linearly on the velocity $\dot{z}$.

A somewhat related resource is https://robotics.stackexchange.com/a/19658/6941.

To elaborate more on the part of the gravity, let's refer to the following equation that highlights all the contributions:

$$
m\ddot{z} =  -mg + \hat{m}\hat{g} + \hat{m}\ddot{z_d} + T_{FB},
$$

where the terms under hat are estimates.

It's visible how the dynamics is fully decoupled between the double integrator and the remaining terms (there's no drag), namely (1) the weight $-mg$, (2) the counter-weight $\hat{m}\hat{g}$, (3) the desired effort $\hat{m}\ddot{z_d}$, and (3) the feedback $T_{FB}$, which in turn can be considered all as independent inputs.

The system is linear, thus you can leverage the superposition principle to compute the whole response as a summation of the responses to the single inputs.

Thereby, you'll end up considering for your study the mere equation:

$$
m\ddot{z} = u,
$$

where $u$ accounts for a generic input.

The corresponding Laplace transform is:

$$
\frac{z}{u} = \frac{1}{m s^2}
$$

At this point, you ought to study all the dynamic properties of this system and come up with a controller responsible for delivering $T_{FB}$. To this end, you may want to read up this nice review: Naive Control of Double Integrator. The PD approach is one of the proposed solutions that works quite well, actually.

Once you know everything about it, you're simply done as the system will respond equally to your thrust and to the effect of gravity.

Now, if you want to add up feed-forward terms, the effect of gravity will be compensated (not canceled out exactly) beforehand thanks to your estimates $\hat{m}$ and $\hat{g}$. Since estimates cannot be perfect, you need to introduce an integral part as well and transform the PD into a PID.


答:
You're attempting to move a robot along a predefined path without the aid of sensors, so really we just need to convert the list of points into a list of pre-scripted actions.

Convert input points to $({\Delta}x, {\Delta}y)$ pairs

Convert $({\Delta}x, {\Delta}y)$ pairs to $(\Delta\theta, d)$ pairs

Convert $(\Delta\theta, d)$ pairs to $(V_{left}, V_{right}, {\Delta}t)$ tuples

The first step is easy -- simple subtraction.

The second step is also fairly straightforward: using the pythagorean theorem for the distance and the atan2 function for the angle:

(Then just keep track of the last $\theta$ so you can calculate $\Delta\theta$).

The last step is a little tricky.  You want to convert that set of angles and distances to the left and right wheel voltages, and the time to run them.  This will actually give you two $(V_{left}, V_{right}, {\Delta}t)$ tuples for every $(\Delta\theta, d)$ pair: one to change the angle, and one to travel the distance.

For a given width $w$ between the wheels, the change in the angle (radians) will be based on the movements of the right and left wheel:
$$
\Delta \theta = \frac{1}{w} \left( {\Delta}d_{left} - {\Delta}d_{right}\right)
$$
You'll have to decide what voltages and $\Delta t$ will produce that change in distance for your robot.

Next, you'll do the same calculation for $d$.  Both motors will use the same voltage to (hopefully) travel the same distance.

That should produce a list of times and voltages that approximate the line you drew.

Title: 2D path following robot, converting XY axis path to input on wheels

Body:
at the moment I am creating an android program, that will steer my simple, 3 wheel (2 motors, 1 for balance) robot to move online following the path drawn by user on his screen. The robot is operated through WiFi and has 2 motors that will react on any input signals.

Imagine user drawing a path for this robot on smartphone screen. It has aquired all the points on XY axis, every time beginning with (0,0). Still I have no idea, how to somehow "convert" just points, into voltage input to both motors. Signals will be sent in approx. 60Hz connection, so quite fast. Maybe not every single axis point will be taken into consideration, there will be surely some skips, but that is irrelevant, since this path does not have to be done perfectly by the robot, just in reasonable error scale.

Do you have any idea on how to make the robot follow defined axis points that overall create a path?

Edit 10.01:

The voltage will be computed by the robot, so input on both is between -255 and 255 and the velocity should increase or decrease lineary in those borders.
Additionaly, I would like to solve it as if there were perfect conditions, I don't need any feedback crazy models. Let's assume that all the data is true, no sensors and additional devices. Just XY axis path and required input (ommit wheel slide too).


答:
That weight is indeed a problem for you to get the transfer function, since it will prevent you from separating the input and output.

For the controller design part, one method that is usable is to consider the weight of the vehicle as a constant  disturbance, and using a feed-forward element to compensate for this disturbance.

You neglect the weight at first, that way you have a Laplace domain representation which you can use to get the transfer function of the system. When you have the transfer function, you can use a method of your choice to design your controller. As it is apparent from the transfer function, it is not possible for a P Controller to stabilise the system, therefore you need a derivative action to stabilise it. After you designed the controller, you can send a step signal to see how it performs, when the weight is neglected.

However, your real system has the weight term, which effects the behaviour. Therefore, for your system's real performance (when the weight is considered) to be close to what you got when you had sent the step signal, you need to eliminate the effect of the weight with a structure apart from the PD Controller itself. If you just use the PD Controller you designed, on your system model (which includes the weight), you will notice that the system performance will deviate from what you had calculated during the design process of the PD Controller. The reason for that is you will not be compensating the disturbance efficiently enough.

We considered the weight as a constant disturbance, and feed-forward control is a commonly used method to eliminate the effects of identifiable disturbances on the system. By introducing this feed-forward term, we aim to make the response of the system, as close as the results we got from the PD Controller design process.

So, to sum it up:

Ignore the weight at first. Then you will be able to have your transfer function.

By using this transfer function, design your PD Controller by considering your design criteria.

To compensate the effect of the ignored weight, use a Feed-forward term. You can search the internet on how you can find the feed-forward coefficient.

For the simulation part, you use the equation that includes the weight as your plant. Because all the assumptions we make while designing the controller is to  ease up the design process for ourselves. If it is needed, we simplify the system equations and design our controller(s) based on those equations. However to see how they perform, we use the actual plant models. That way we are able to see if our assumptions hold true, and the real performance is close to what we had assumed/predicted.

Title: How do I find the transfer function for my quadcopter altitude system?

Body:
This is not so much of a how but if I am right so far. I am looking at the z-axis now only. The linearized equation of motion for the thrust in the z-direction is:

$$
T=m\cdot \ddot{z}+mg,
$$

where $m$ is the mass, $\ddot{z}$ is the acceleration in the z-direction and $g$ is gravity acceleration and $T$ is the thrust. I will now Laplace transform it so it can be put in the frequency domain. I will first solve for the acceleration.

$$
\ddot{z} = T/m - mg
$$

I will now Laplace transform and this gives:

$$
T(s)/m - 1/(mg) = Z(s)s^2
$$

After some computations, I end with:

$$
Z=T(s)/(ms^2) -1/(mgs^2)
$$

I have ignored the last term because I have seen that usually plants in the control system it should "multipy-able" i.e one term. I am not sure if that is an error. What should I put in the drone plant then? See below for the figure.

This is put into my control system. I have made a PD controller and the control law (I made this myself, I have seen other papers using other inputs but I did not see the intuition) is sent which is:

$$
T = T_d + K_p \cdot e + K_d \cdot \dot{e}
$$

Where $T$ is the total thrust sent and $T_d$ is the desired thrust and $K_p$ and $K_d$ are the gains for derivative and position error.

All this is put into this control system. (the green part is technicality but it is to be ignored).

Will I be able to find the transfer function (by simplifying the blocks using block diagram reduction) and then send a step response to it so I can check what $K_p$ and $K_d$ values I need?


问:
Invoking "make cmake_check_build_system" failed in ROS melodic
I try to install the tum_ardrone_sim package in my machine, so I get clone in my workspace this link https://bitbucket.org/theconstructcore/tum_ardrone_sim.git.

Finally I try to make it using this command: catkin_make
However I get this error:

```<code>-- Using these message generators: gencpp;geneus;genlisp;gennodejs;genpy
-- Generating .msg files for action action_controller/MultiDofFollowJointTrajectory /home/sekmani/catkin_ws/src/tum_ardrone_sim/tum-simulator-indigo/action_controller/action/MultiDofFollowJointTrajectory.action
-- action_controller: 7 messages, 0 services
-- +++ processing catkin package: 'voxel_grid'
-- ==> add_subdirectory(navigation/voxel_grid)
-- +++ processing catkin package: 'costmap_2d'
-- ==> add_subdirectory(navigation/costmap_2d)
-- Using these message generators: gencpp;geneus;genlisp;gennodejs;genpy
-- Boost version: 1.65.1
-- Found the following Boost libraries:
--   system
--   thread
--   chrono
--   date_time
--   atomic
-- costmap_2d: 1 messages, 0 services
-- +++ processing catkin package: 'nav_core'
-- ==> add_subdirectory(navigation/nav_core)
-- Using these message generators: gencpp;geneus;genlisp;gennodejs;genpy
-- +++ processing catkin package: 'base_local_planner'
-- ==> add_subdirectory(navigation/base_local_planner)
-- Using these message generators: gencpp;geneus;genlisp;gennodejs;genpy
-- Boost version: 1.65.1
-- Found the following Boost libraries:
--   thread
--   chrono
--   system
--   date_time
--   atomic
-- base_local_planner: 1 messages, 0 services
-- +++ processing catkin package: 'carrot_planner'
-- ==> add_subdirectory(navigation/carrot_planner)
-- Using these message generators: gencpp;geneus;genlisp;gennodejs;genpy
-- +++ processing catkin package: 'clear_costmap_recovery'
-- ==> add_subdirectory(navigation/clear_costmap_recovery)
-- Using these message generators: gencpp;geneus;genlisp;gennodejs;genpy
-- +++ processing catkin package: 'dwa_local_planner'
-- ==> add_subdirectory(navigation/dwa_local_planner)
-- Using these message generators: gencpp;geneus;genlisp;gennodejs;genpy
-- +++ processing catkin package: 'move_slow_and_clear'
-- ==> add_subdirectory(navigation/move_slow_and_clear)
-- Using these message generators: gencpp;geneus;genlisp;gennodejs;genpy
-- Boost version: 1.65.1
-- Found the following Boost libraries:
--   thread
--   chrono
--   system
--   date_time
--   atomic
-- +++ processing catkin package: 'navfn'
-- ==> add_subdirectory(navigation/navfn)
-- Using these message generators: gencpp;geneus;genlisp;gennodejs;genpy
-- navfn: 0 messages, 2 services
-- NAVFN_HAVE_FLTK: 1, NETPBM:
-- FLTK orf NETPBM not found: cannot build navtest
-- +++ processing catkin package: 'global_planner'
-- ==> add_subdirectory(navigation/global_planner)
-- Using these message generators: gencpp;geneus;genlisp;gennodejs;genpy
-- +++ processing catkin package: 'rotate_recovery'
-- ==> add_subdirectory(navigation/rotate_recovery)
-- Using these message generators: gencpp;geneus;genlisp;gennodejs;genpy
-- +++ processing catkin package: 'move_base'
-- ==> add_subdirectory(navigation/move_base)
-- Using these message generators: gencpp;geneus;genlisp;gennodejs;genpy
-- +++ processing catkin package: 'turtlebot3_description'
-- ==> add_subdirectory(turtlebot3/turtlebot3_description)
-- Configuring incomplete, errors occurred!
See also "/home/sekmani/catkin_ws/build/CMakeFiles/CMakeOutput.log".
See also "/home/sekmani/catkin_ws/build/CMakeFiles/CMakeError.log".
Makefile:7194: recipe for target 'cmake_check_build_system' failed
make: *** [cmake_check_build_system] Error 1
Invoking "make cmake_check_build_system" failed
</code>```

I try to solve it, so I run this command:
rosdep install --from-paths /home/sekmani/catkin_ws/src --ignore-src.

But also I get this error:

```<code>ERROR: the following packages/stacks could not have their rosdep keys resolved
to system dependencies:
amcl: [python3-pykdl] defined as "not available" for OS version [bionic]
</code>```

I am using ROS melodic and Ubuntu 18.

答:
Your instinct to install the rosdeps due to a missing dependency in the compile is good.

The rosdep failure is that you're missing the package definition. And the Ubuntu package python3-pykdl is not available in Bionic. It's only in Focal and newer and is explicitly stated as not available. As such I have to guess that you're using a newer version of a package on an older system.

Your build error snippet does not appear to be enough to capture the initial error. You're only showing the error handling. For more help please edit your question to include instructions how to install a minimal workspace and provide the commands you're running so we can reproduce the problem to get more help. It's likely that you're using something like a noetic branch with python3 by default but trying to build on bionic+melodic with python2.


问:
Pose of the end-effector
I am trying to get the pose of the end-effector. I have attached the picture. I am stuck. I wrote the transformation matrices - I am not sure how to move forward next. How do I find the end-effector pose?.

答:
Looks like a 4-bar slider-crank system with a linear output. Generally, with these closed-chain kinematics, you need to compute the end-effector pose (point P) from two open chains with one open chain starting at link 1 to link 2 and the other open chain starting at link 3 to link 2. Then you need to solve for the generalized coordinates, which from your diagram appear to be $\phi_1$,  $\phi_2$, $\phi_3$. $\phi_4$. Personally, I think this selection of generalized coordinates is redundant and incomplete. Redundant because $\phi_4$ can be derived from $\phi_1 + \phi_2 = \phi_3 + \phi_4$. Incomplete because you need one at least one more to describe the linear offset from the end of link 1 to the end of link 3, let's call this $a_L$. So, I think the generalized coordinates of the system should instead be $\phi_1, \phi_2, \phi_3$, and $a_L$,

For the sake of your diagram (and explanation), lets proceed with the fact that the following are unknown: $\phi_1, \phi_2, \phi_3, \phi_4$, and $a_L$.

If $\phi_1$ and $\phi_2$ are known, then the position $P$ from the first open loop chain is:
$P_x = a_1 \cos(\phi_1) + a_2 \cos (\phi_2)$

$P_y = a_1 \sin(\phi_1) + a_2 \sin (\phi_2)$

If instead only $a_L, \phi_3,$ and $\phi_4$ are known, then the position $P$ from the second open loop chain is:

$P_x = a_3 \cos(\phi_3) + L \cos (\phi_4) + a_4$, where we add $a_4$ to express point $P$ in the same origin.

$P_y = a_3 \sin(\phi_3) + L \sin (\phi_4)$, where $L = a_2 - a_L $.

Finally, remember that $\phi_4$ has the following property:

$\phi_1 + \phi_2 = \phi_3 + \phi_4$

You have 5 equations (after substituting L) and 5 unknowns ($\phi_1, \phi_2, \phi_3, \phi_4$, and $a_L$.). An analytical solution exists for finding these values in closed-form.

As a final note, the equations I wrote above can be extracted from the transformation matrices, but I think it's clearer to present it this way.

Good luck!

Title: Pose of the end-effector


问:
Unintentional point cloud duplication during depth image conversion
I have a quite challenging question. I use ROS Melodic on Ubuntu18.04. My goal is to transform a ROS depth image to pointcloud2 format and show it in rviz. The theory seems ok, but I do not now where I fail. My problem can be seen on the image: it looks like that the pointcloud is somehow duplicated and shifted each other, although there is only one corridor in front of the camera.

I uploaded my code as a gist where I transform the depth image.

What I now see in rviz is this:

There is a corridoor in front of my camera, but somehow twice. I thought about the camera calibration and parameters, but I use the data from CameraInfo messages. Although I played with the fx,fy,cx,cy parameters, I cannot align to overleap the two corridor.

Where am I wrong?

答:
At first I thought there was some sort of systematic raw format or resolution error, sort of like ROS + kinect depth data duplication .

Then I noticed that each corridor appears in a different perspective, as if the sensor turned to point a different way between two captured frames. You didn't say what sensor you're using, but I assume it's not two cams that happen to point 45 degrees apart!

One might surmise that there are actually two or more frames piled up or appended in the same buffer -- sort of like a double exposure -- and the sensor actually did turn between the shots. Maybe some frame buffer or index needs to be cleared or reinitialized, or something, between frames?


问:
Emulation of an Orrery
Orrery is a clockwork model of the solar system. I am trying to emulate one in 2D. Now, to emulate, I need to know what goes on inside. Can someone please explain the basic principle behind the clockwork? Or direct me to a resource that will explain all the machinery inside a simple Orrery.</p>

答:
An orrery just represents the different speeds at which planets orbit the sun by careful selection of gear ratios.

Here is a set of plans that define the gears themselves, but you could calculate the necessary ratios from the orbital period of each planet.

In code, it would be something like:

```<code>timestep = 0
while True:
    timestep = timestep + 1
    for each planet:
        theta = (timestep / orbital_period(planet)) % 360
        draw(planet, theta)
</code>```

Title: Emulation of an Orrery

Body:
An orrery just represents the different speeds at which planets orbit the sun by careful selection of gear ratios.

Here is a set of plans that define the gears themselves, but you could calculate the necessary ratios from the orbital period of each planet.

In code, it would be something like:

timestep = 0
while True:
    timestep = timestep + 1
    for each planet:
        theta = (timestep / orbital_period(planet)) % 360
        draw(planet, theta)


答:
I agree with r-bryan that you're likely missinterpreting some of the metadata. It could be the frame width or alternatively the stride width or something else in the depth image.

There's a good reference implementation that you can compare yours to the one in depth_image_proc The main part of the implementation is in this header where you can see that there's several more parameters from the metadata being processed.

As an exercise learning to do this is valuable. However for actual usage on a system, I'd highly recommend just using the nodelet already in the open source implementation in this package which has already been used heavily in many applications. If there's additional features or speedups you're looking for contributing them back there would be great too.

Title: Unintentional point cloud duplication during depth image conversion

Body:
I have a quite challenging question. I use ROS Melodic on Ubuntu18.04. My goal is to transform a ROS depth image to pointcloud2 format and show it in rviz. The theory seems ok, but I do not now where I fail. My problem can be seen on the image: it looks like that the pointcloud is somehow duplicated and shifted each other, although there is only one corridor in front of the camera.

I uploaded my code as a gist where I transform the depth image.

What I now see in rviz is this:

There is a corridoor in front of my camera, but somehow twice. I thought about the camera calibration and parameters, but I use the data from CameraInfo messages. Although I played with the fx,fy,cx,cy parameters, I cannot align to overleap the two corridor.

Where am I wrong?


问:
Connecting iRobot Create 2 with Arduino; Unable to interface with iRobot using Arduino
Over the past month since I bought iRobot Create 2, I have failed to establish communication between the Arduino and iRobot Create 2. I will describe my hardware setup and my Arduino code, then ask several questions that would help future projects as well.

Hardware Setup: The iRobot Create 2 is connected with the Arduino based on the connection provided in pdf document at this link - https://edu.irobot.com/learning-library/controlling-create-2-with-arduino-and-android.

Software Setup: Following is a very basic code that I am using in my Arduino.

```<code>
#include <SoftwareSerial.h>

int rxPin = 10; //connected to pin 4 (TXD) of iRobot based on above document
int txPin = 11; //connected to pin 3 (RXD) of iRobot based on above document
int ddPin = 5;  //connected to pin 5 (BRC) of iRobot

//Set up a new Software Serial Port
SoftwareSerial softSerial = SoftwareSerial(rxPin, txPin);

void setup() {

// Defining PinModes
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
  pinMode(ddPin, OUTPUT);
  softSerial.begin(19200);

// Change the BAUD Rate/Waking up
  digitalWrite(ddPin, HIGH);
  delay(100);
  digitalWrite(ddPin, LOW);
  delay(500);
  digitalWrite(ddPin, HIGH);
  delay(2000);

// Start Command
  softSerial.write(128); //Starts the OI

// Mode Command - Passive, Safe, Full
  softSerial.write(131); //Set mode to Safe
}

void loop() {
  // put your main code here, to run repeatedly:
  Serial.write(145);  //Serial.print(137, BYTE);
  Serial.write(0x00);
  Serial.write(0xc8);
  Serial.write(0x00);
  Serial.write(0x01);
}
</code>```

How I am deploying it ?
I burn the above code into my Arduino using my laptop (Mac Pro). It compiles and burns fine without any issue. Then I disconnect the Arduino from my laptop and connect the Arduino using Jumper Wires to iRobot Mini DIN as following -
Pin 10 of Arduino -> Pin 4 of iRobot;
Pin 11 of Arduino -> Pin 3 of iRobot;
Pin 5 of Arduino  -> Pin 5 of iRobot;

GND of Arduino    -> Pin 6 of iRobot;
Vin of Arduino    -> Pin 1 of iRobot

Observations

When I connect the GND of Arduino to iRobot Pin 6, iRobot gets active - Green light

Create 2 doesn't move at all OR No Reaction.

Questions

I am unsure if the bot is communicating at 19200 Baud Rate ? In the above code, I believe that the code is wrong and maybe that's the problem.

What could possibly be any other problems ?

What is the correct way to set up the Baud Rate ? I do not clearly understand the documentation for Baud Rate for the Method 2 ? How do you execute Method 2 on Arduino ?

答:
There are a few things wrong with this code that are stopping it from working.

Setting the baud rate. From the Create 2 Open Interface Spec, page 4, the way to set the baud rate is to "wait 2 seconds after turning on Roomba and then pulse the baud rate change low three times." Your code only pulses the pin low once, so the robot wakes up but is not having its baud rate changed. You can fix this by changing your first wake up and baud rate change block as follows:

```<code>    // Wake up
      digitalWrite(ddPin, HIGH);
      delay(100);
      digitalWrite(ddPin, LOW);
      delay(500);
      digitalWrite(ddPin, HIGH);
      delay(2000);

    // Baud rate change
      for (int i = 0; i < 3; i++) {
        digitalWrite(ddPin, LOW);
        delay(200);
        digitalWrite(ddPin, HIGH);
        delay(200);
      }
</code>```

Serial port confusion. It seems like you're using software serial for some things (in setup()) but also hardware serial for others (in loop()). Stick to one or the other; for this, let's use the software serial port for the Create 2 as you've wired it, and the hardware serial port for debugging. Add Serial.begin(9600); to your setup() function, and then you can use the USB to serial UART through the "serial monitor" in the Arduino IDE for debugging.

Confusion about how to use loop(). The loop() function runs over and over and over again. Had you been communicating over the correct serial port, you would just be slamming that drive command into the robot over and over and over again. Once is enough. You could either put it at the very end of your setup() function, or else put it in loop() and then go do something else, or wait, or delay forever. In my rewrite of your code, I've chosen to just busy-wait forever in a while(1).

Missing cast of 0x00 literal in (soft)Serial.write(). Arduino has Serial.write overloaded, so if you just want to send a null character, you have to cast it as byte.

Signal timings. You noted that you are "burning" the code onto your Arduino and then plugging the Arduino into the robot using jumper wires. Depending on the order you plug things in, various pulses or serial commands might happen before the robot is fully connected. You might consider adding a very long delay at the beginning of your code or (even better) adding a physical button to a GPIO on the Arduino that the code waits to be pressed before trying to talk to the robot.

Power concerns. You note that you are plugging VBAT directly into the Arduino's VIN. Depending on the Arduino, this might be a problem. On the dock, VBAT can rise all the way to 21 V, but the Arduino Uno has a recommended operating maximum input voltage of 12 V, and absolute maximum of 20 V. You might consider adding another voltage regulator (or else being really careful not to plug the Arduino into your Create 2 while it's on the dock; it won't violate the absolute max of the Arduino when it's not charging).

Incorporating all these changes, here is the correct, working version of your code, tested on my Create 2 with an Arduino Uno:

```<code>#include <SoftwareSerial.h>

int rxPin = 10; //connected to pin 4 (TXD) of iRobot Create 2
int txPin = 11; //connected to pin 3 (RXD) of iRobot Create 2
int ddPin = 5;  //connected to pin 5 (BRC) of iRobot Create 2

//Set up a new Software Serial Port
SoftwareSerial softSerial = SoftwareSerial(rxPin, txPin);

void setup() {

  Serial.begin(9600);

// Defining PinModes
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
  pinMode(ddPin, OUTPUT);
  softSerial.begin(19200);

  Serial.println("Wake up!");
  digitalWrite(ddPin, HIGH);
  delay(100);
  digitalWrite(ddPin, LOW);
  delay(500);
  digitalWrite(ddPin, HIGH);
  delay(2000);

  Serial.println("Set baud rate.");
  for (int i = 0; i < 3; i++) {
    digitalWrite(ddPin, LOW);
    delay(200);
    digitalWrite(ddPin, HIGH);
    delay(200);
  }

  Serial.println("Start OI in Safe Mode.");
  softSerial.write(128); //Starts the OI
  softSerial.write(131); //Set mode to Safe
}

void loop() {
  Serial.print("Arc left... ");
  softSerial.write(145);
  softSerial.write((byte)0x00);
  softSerial.write(0xc8);
  softSerial.write((byte)0x00);
  softSerial.write(0x01);

  Serial.println("and do nothing else.");
  while(1);
}
</code>```

I hope this helps. Sorry it's so late; I must have missed the question during the chaos of 2020.

Please note that I am an iRobot employee, but the postings on this site are my own and don't necessarily represent iRobot's positions, strategies, or opinions.

Body:
There are a few things wrong with this code that are stopping it from working.

Setting the baud rate. From the Create 2 Open Interface Spec, page 4, the way to set the baud rate is to "wait 2 seconds after turning on Roomba and then pulse the baud rate change low three times." Your code only pulses the pin low once, so the robot wakes up but is not having its baud rate changed. You can fix this by changing your first wake up and baud rate change block as follows:

    // Wake up
      digitalWrite(ddPin, HIGH);
      delay(100);
      digitalWrite(ddPin, LOW);
      delay(500);
      digitalWrite(ddPin, HIGH);
      delay(2000);

    // Baud rate change
      for (int i = 0; i < 3; i++) {
        digitalWrite(ddPin, LOW);
        delay(200);
        digitalWrite(ddPin, HIGH);
        delay(200);
      }

Serial port confusion. It seems like you're using software serial for some things (in setup()) but also hardware serial for others (in loop()). Stick to one or the other; for this, let's use the software serial port for the Create 2 as you've wired it, and the hardware serial port for debugging. Add Serial.begin(9600); to your setup() function, and then you can use the USB to serial UART through the "serial monitor" in the Arduino IDE for debugging.

Confusion about how to use loop(). The loop() function runs over and over and over again. Had you been communicating over the correct serial port, you would just be slamming that drive command into the robot over and over and over again. Once is enough. You could either put it at the very end of your setup() function, or else put it in loop() and then go do something else, or wait, or delay forever. In my rewrite of your code, I've chosen to just busy-wait forever in a while(1).

Missing cast of 0x00 literal in (soft)Serial.write(). Arduino has Serial.write overloaded, so if you just want to send a null character, you have to cast it as byte.

Signal timings. You noted that you are "burning" the code onto your Arduino and then plugging the Arduino into the robot using jumper wires. Depending on the order you plug things in, various pulses or serial commands might happen before the robot is fully connected. You might consider adding a very long delay at the beginning of your code or (even better) adding a physical button to a GPIO on the Arduino that the code waits to be pressed before trying to talk to the robot.

Power concerns. You note that you are plugging VBAT directly into the Arduino's VIN. Depending on the Arduino, this might be a problem. On the dock, VBAT can rise all the way to 21 V, but the Arduino Uno has a recommended operating maximum input voltage of 12 V, and absolute maximum of 20 V. You might consider adding another voltage regulator (or else being really careful not to plug the Arduino into your Create 2 while it's on the dock; it won't violate the absolute max of the Arduino when it's not charging).

Incorporating all these changes, here is the correct, working version of your code, tested on my Create 2 with an Arduino Uno:

#include <SoftwareSerial.h>

int rxPin = 10; //connected to pin 4 (TXD) of iRobot Create 2
int txPin = 11; //connected to pin 3 (RXD) of iRobot Create 2
int ddPin = 5;  //connected to pin 5 (BRC) of iRobot Create 2

//Set up a new Software Serial Port
SoftwareSerial softSerial = SoftwareSerial(rxPin, txPin);

void setup() {

  Serial.begin(9600);

// Defining PinModes
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
  pinMode(ddPin, OUTPUT);
  softSerial.begin(19200);

  Serial.println("Wake up!");
  digitalWrite(ddPin, HIGH);
  delay(100);
  digitalWrite(ddPin, LOW);
  delay(500);
  digitalWrite(ddPin, HIGH);
  delay(2000);

  Serial.println("Set baud rate.");
  for (int i = 0; i < 3; i++) {
    digitalWrite(ddPin, LOW);
    delay(200);
    digitalWrite(ddPin, HIGH);
    delay(200);
  }

  Serial.println("Start OI in Safe Mode.");
  softSerial.write(128); //Starts the OI
  softSerial.write(131); //Set mode to Safe
}

void loop() {
  Serial.print("Arc left... ");
  softSerial.write(145);
  softSerial.write((byte)0x00);
  softSerial.write(0xc8);
  softSerial.write((byte)0x00);
  softSerial.write(0x01);

  Serial.println("and do nothing else.");
  while(1);
}

I hope this helps. Sorry it's so late; I must have missed the question during the chaos of 2020.

Please note that I am an iRobot employee, but the postings on this site are my own and don't necessarily represent iRobot's positions, strategies, or opinions.


问:
Relative rotation and a new reference frame as the rotation of the first object
this is my first post on this forum

I have $n$ IMUs which outputs its rotation their matrices in the $XYZ$ world coordinate system $w$. I would like to use multiple IMUs $n$, such as $n_{1}, n_{2}, n_{3} ...$. IMUs are connected by spherical joints with a fixed arm length $d$ such as $d_{1}, d_{2}, d_{3} ...$.

The relative rotation represented in $w$ between two IMUs $n_{1}$ and $n_{2}$ is:

$R_{n_{1}\leftarrow n_{2}} = (R_{n_{1}\leftarrow w})(R_{n_{2}\leftarrow w})^{T}$

but instead of the $w$ coordinate system, I would like to read the relative rotation of the $R_{n_{1}\leftarrow n_{2}}$ in the $n_{1}$ coordinate system as $X'Y'Z'$.

How do I calculate it?

答:
I've found the solution.

Instead of using intrinsic matrix to angle conversions such as:

$yaw = atan2(R_{n_{1}\leftarrow n_{2}}(2,1),R_{n_{1}\leftarrow n_{2}}(1,1))$

$pitch = asin(−R_{n_{1}\leftarrow n_{2}}(3,1))$

$roll = atan2(R_{n_{1}\leftarrow n_{2}}(3,2),R_{n_{1}\leftarrow n_{2}}(3,3))$

I should use extrinsic matrix to angle conversions such as:

$yaw = atan2(−R_{n_{1}\leftarrow n_{2}}(1,2),R_{n_{1}\leftarrow n_{2}}(1,1))$

$pitch = asin(R_{n_{1}\leftarrow n_{2}}(1,3))$

$roll = atan2(−R_{n_{1}\leftarrow n_{2}}(2,3),R_{n_{1}\leftarrow n_{2}}(3,3))$


问:
Estimating distance between joint positions
I was wondering if there is any good way to estimate the difference between two joint states of a robotic arm.

Currently I am using something like this: $\sqrt{\sum_i^N{(JStateA[i]-JStateB[i])^2}}$. Where $JStateA$ and $JStateB$ are the two joint states.

However, this formula gives the same weight to all joints. Ideally, I would  like the formula to reflect that moving the first joint (that moves the whole arm) is a much more significant change than moving the last joint (which only moves the hand).

答:
I'm guessing you're wanting to change the weighting to modify some joint optimization code? But if you want to change the weighting then you need to decide how those weights change.

The best advice I think I could provide, given the wording of your question, would be to consider the Jacobian for your robot arm. The naive approach would be to consider just distance between the joint and end effector, but that doesn't consider the configuration of your robot arm.

The Jacobian puts all of your partial derivatives together in one place for you, and that gives you how much your end effector changes given a change in a particular joint value - $\partial f/\partial q$.


问:
Mobile robotic arm camera position
I'm working on my graduation project which is a mobile robotic arm that performs pick and place tasks.

I wanted to know the possible ways to mount the camera where i can reach the desired destination and for the robot arm to be able to perform the pick and place task.

Based on what I've seen, most people mount the camera on a fixed platform pointing down, but I prefer it to be mounted to the robot. Do I have to mount it looking down? Because i figured this way i can only use it for the picking and placing part, not the robot reaching the destination too.

答:
It really depends on your idea.
I also did a similar project, and I was satisfied with the camera mounted to the end effector. Thus I could see wether the gripper is really gripping an object ot not, and also the area where it will place it.

Another advantage of mounting the camera to a robot is that you can also explore your surroundings with it e.g. creating a point cloud map, or just update it...
This is really depends on you.

Search for similar projects and compare it with your options.

Title: Mobile robotic arm camera position


答:
Let's consider four points $A, B, C$ and $D$ and let us consider the parameter $d$, as shown in the figures below. And let us consider $p_e=\begin{Bmatrix}0\\0\\0\\1\end{Bmatrix}$ to be the end-effector location in end-effector's coordinate system.

Now, there are two ways of connecting the origin and the end-effector position, namely $O-A-P$ and $O-C-B-P$.

For the connection $O-A-P$, we can see from the figure that $\overline{OA}$ makes $\psi_1$ with positive x-axis in anticlockwise direction, and $\overline{AP}$ makes $\psi_2$ with $\overline{OA}$ in anticlockwise direction. Therefore the end-effector location in origin's coordinate system $p_o$ is given by

$p_o=R_z(\psi_1) \cdot T_x(a_1) \cdot R_z(\psi_2) \cdot T_x(a_2) \cdot p_e$

$\Rightarrow p_o = \begin{bmatrix}1 & 0 & 0 & 0 \\ 0 & \cos{\psi_1} & -\sin{\psi_1} & 0\\ 0 & \sin{\psi_1} & \cos{\psi_1} & 0\\ 0 & 0 & 0 & 1\end{bmatrix} \begin{bmatrix}1 & 0 & 0 & a_1 \\ 0 & 1 & 0 & 0\\ 0 & 0 & 1 & 0\\ 0 & 0 & 0 & 1\end{bmatrix} \begin{bmatrix}1 & 0 & 0 & 0 \\ 0 & \cos{\psi_2} & -\sin{\psi_2} & 0\\ 0 & \sin{\psi_2} & \cos{\psi_2} & 0\\ 0 & 0 & 0 & 1\end{bmatrix} \begin{bmatrix}1 & 0 & 0 & a_2 \\ 0 & 1 & 0 & 0\\ 0 & 0 & 1 & 0\\ 0 & 0 & 0 & 1\end{bmatrix} \begin{Bmatrix}0\\0\\0\\1\end{Bmatrix} $

$\Rightarrow p_o = \begin{Bmatrix}a_{1} \cos{\left(\psi_{1} \right)} + a_{2} \cos{\left(\psi_{1} + \psi_{2} \right)}\\a_{1} \sin{\left(\psi_{1} \right)} + a_{2} \sin{\left(\psi_{1} + \psi_{2} \right)}\\0\\1\end{Bmatrix}$

For the connection $O-C-B-P$, we can see from the figure that $\overline{OC}$ makes $0^c$ angle with positive x-axis in anticlockwise direction, $\overline{CB}$ makes $\psi_3$ with $\overline{OC}$ in anticlockwise direction and $\overline{BP}$ makes $\psi_4$ with $\overline{CB}$ in clockwise direction. Therefore the end-effector location in origin's coordinate system $p_o$ is given by

$p_o=R_z(0) \cdot T_x(a_4) \cdot R_z(\psi_3) \cdot T_x(a_3) \cdot R_z(-\psi_4) \cdot T_x(d) \cdot p_e$

$\Rightarrow p_o = \begin{bmatrix}1 & 0 & 0 & a_{4}\\0 & 1 & 0 & 0\\0 & 0 & 1 & 0\\0 & 0 & 0 & 1\end{bmatrix}
\begin{bmatrix}\cos{\left(\psi_{3} \right)} & - \sin{\left(\psi_{3} \right)} & 0 & 0\\\sin{\left(\psi_{3} \right)} & \cos{\left(\psi_{3} \right)} & 0 & 0\\0 & 0 & 1 & 0\\0 & 0 & 0 & 1\end{bmatrix}
\begin{bmatrix}1 & 0 & 0 & a_{3}\\0 & 1 & 0 & 0\\0 & 0 & 1 & 0\\0 & 0 & 0 & 1\end{bmatrix}
\begin{bmatrix}\cos{\left(-\psi_{4} \right)} & - \sin{\left(-\psi_{4} \right)} & 0 & 0\\\sin{\left(-\psi_{4} \right)} & \cos{\left(-\psi_{4} \right)} & 0 & 0\\0 & 0 & 1 & 0\\0 & 0 & 0 & 1\end{bmatrix}
\begin{bmatrix}1 & 0 & 0 & d\\0 & 1 & 0 & 0\\0 & 0 & 1 & 0\\0 & 0 & 0 & 1\end{bmatrix}
\begin{Bmatrix}0\\0\\0\\1\end{Bmatrix} $

$\Rightarrow p_o = \begin{Bmatrix}a_{3} \cos{\left(\psi_{3} \right)} + a_{4} + d \cos{\left(\psi_{3} - \psi_{4} \right)}\\a_{3} \sin{\left(\psi_{3} \right)} + d \sin{\left(\psi_{3} - \psi_{4} \right)}\\0\\1\end{Bmatrix}$

We have two expressions for $p_o$. Let's equate them.

$\begin{Bmatrix}a_{1} \cos{\left(\psi_{1} \right)} + a_{2} \cos{\left(\psi_{1} + \psi_{2} \right)}\\a_{1} \sin{\left(\psi_{1} \right)} + a_{2} \sin{\left(\psi_{1} + \psi_{2} \right)}\\0\\1\end{Bmatrix}=\begin{Bmatrix}a_{3} \cos{\left(\psi_{3} \right)} + a_{4} + d \cos{\left(\psi_{3} - \psi_{4} \right)}\\a_{3} \sin{\left(\psi_{3} \right)} + d \sin{\left(\psi_{3} - \psi_{4} \right)}\\0\\1\end{Bmatrix}$

From this, we can have two equations:

$a_{1} \cos{\left(\psi_{1} \right)} + a_{2} \cos{\left(\psi_{1} + \psi_{2} \right)}=a_{3} \cos{\left(\psi_{3} \right)} + a_{4} + d \cos{\left(\psi_{3} - \psi_{4} \right)}$

and

$a_{1} \sin{\left(\psi_{1} \right)} + a_{2} \sin{\left(\psi_{1} + \psi_{2} \right)}=a_{3} \sin{\left(\psi_{3} \right)} + d \sin{\left(\psi_{3} - \psi_{4} \right)}$

Given $\psi_1$ and $\psi_3$, there are still three unknowns here, namely $\psi_2$, $\psi_4$ and $d$. But we have only two equations. We need at least one more independent equation in order to solve for the three unknowns for particular values of $\psi_1$ and $\psi_3$.

Let's consider the loop $O-C-B-A-O$. Since it is a loop, the transformation matrices, when multiplied, should produce identity matrix.

We can see from the figure that $\overline{OC}$ makes $0^c$ angle with positive x-axis in anticlockwise direction, $\overline{CB}$ makes $\psi_3$ with $\overline{OC}$ in anticlockwise direction, $\overline{BA}$ makes $\pi-\psi_4$ with $\overline{CB}$ in anticlockwise direction, $\overline{AO}$ makes $\psi_2$ with $\overline{BA}$ in clockwise direction, and $\overline{OC}$ makes $\pi-\psi_1$ with $\overline{AO}$ in anticlockwise direction. Therefore the relation is given by

$T_x(a_4)\cdot R_z(\psi_3)\cdot T_x(a_3)\cdot R_z(\pi-\psi_4)\cdot T_x(d)\cdot R_z(-\psi_2)\cdot T_x(a_1)\cdot R_z(\pi-\psi_1)=I_4$

$\Rightarrow \begin{bmatrix}1 & 0 & 0 & a_{4}\\0 & 1 & 0 & 0\\0 & 0 & 1 & 0\\0 & 0 & 0 & 1\end{bmatrix}\begin{bmatrix}\cos{\left(\psi_{3} \right)} & - \sin{\left(\psi_{3} \right)} & 0 & 0\\\sin{\left(\psi_{3} \right)} & \cos{\left(\psi_{3} \right)} & 0 & 0\\0 & 0 & 1 & 0\\0 & 0 & 0 & 1\end{bmatrix}\begin{bmatrix}1 & 0 & 0 & a_{3}\\0 & 1 & 0 & 0\\0 & 0 & 1 & 0\\0 & 0 & 0 & 1\end{bmatrix}\begin{bmatrix} \cos{\left(\pi - \psi_{4} \right)} & - \sin{\left(\pi - \psi_{4} \right)} & 0 & 0\\\sin{\left(\pi - \psi_{4} \right)} & \cos{\left(\pi - \psi_{4} \right)} & 0 & 0\\0 & 0 & 1 & 0\\0 & 0 & 0 & 1\end{bmatrix}\begin{bmatrix}1 & 0 & 0 & d \\0 & 1 & 0 & 0\\0 & 0 & 1 & 0\\0 & 0 & 0 & 1\end{bmatrix}\begin{bmatrix}\cos{\left(-\psi_{2} \right)} & - \sin{\left(-\psi_{2} \right)} & 0 & 0\\\sin{\left(-\psi_{2} \right)} & \cos{\left(-\psi_{2} \right)} & 0 & 0\\0 & 0 & 1 & 0\\0 & 0 & 0 & 1\end{bmatrix}\begin{bmatrix}1 & 0 & 0 & a_{1}\\0 & 1 & 0 & 0\\0 & 0 & 1 & 0\\0 & 0 & 0 & 1\end{bmatrix}\begin{bmatrix}\cos{\left(\pi-\psi_{1} \right)} & - \sin{\left(\pi-\psi_{1} \right)} & 0 & 0\\\sin{\left(\pi-\psi_{1} \right)} & \cos{\left(\pi-\psi_{1} \right)} & 0 & 0\\0 & 0 & 1 & 0\\0 & 0 & 0 & 1\end{bmatrix}=\begin{bmatrix}1 & 0 & 0 & 0\\0 & 1 & 0 & 0\\0 & 0 & 1 & 0\\0 & 0 & 0 & 1\end{bmatrix}$

$\Rightarrow \begin{bmatrix}\cos{\left(\psi_{1} + \psi_{2} - \psi_{3} + \psi_{4} \right)} & \sin{\left(\psi_{1} + \psi_{2} - \psi_{3} + \psi_{4} \right)} & 0 & - a_{1} \cos{\left(\psi_{2} - \psi_{3} + \psi_{4} \right)} + a_{3} \cos{\left(\psi_{3} \right)} + a_{4} - d \cos{\left(\psi_{3} - \psi_{4} \right)}\\- \sin{\left(\psi_{1} + \psi_{2} - \psi_{3} + \psi_{4} \right)} & \cos{\left(\psi_{1} + \psi_{2} - \psi_{3} + \psi_{4} \right)} & 0 & a_{1} \sin{\left(\psi_{2} - \psi_{3} + \psi_{4} \right)} + a_{3} \sin{\left(\psi_{3} \right)} - d \sin{\left(\psi_{3} - \psi_{4} \right)}\\0 & 0 & 1 & 0\\0 & 0 & 0 & 1\end{bmatrix}=\begin{bmatrix}1 & 0 & 0 & 0\\0 & 1 & 0 & 0\\0 & 0 & 1 & 0\\0 & 0 & 0 & 1\end{bmatrix}$

We can derive many equations from this, but they must be redundant. Let's equate the first row and the first column of LHS and RHS. We get

$\cos{\left(\psi_{1} + \psi_{2} - \psi_{3} + \psi_{4}\right)}=1$

$\Rightarrow \psi_{1} + \psi_{2} - \psi_{3} + \psi_{4}=0$

$\Rightarrow \psi_{3} - \psi_{4} = \psi_{1} + \psi_{2}$

Putting this in the earlier two equations gives

$a_{1} \cos{\left(\psi_{1} \right)} + a_{2} \cos{\left(\psi_{1} + \psi_{2} \right)}=a_{3} \cos{\left(\psi_{3} \right)} + a_{4} + d \cos{\left(\psi_{1} + \psi_{2} \right)}$

$\Rightarrow \left(a_2-d\right)\cos{\left(\psi_1+\psi_2\right)}=a_3 \cos{\left(\psi_3\right)}-a_1\cos{\left(\psi_1\right)}+a_4$

and

$a_{1} \sin{\left(\psi_{1} \right)} + a_{2} \sin{\left(\psi_{1} + \psi_{2} \right)}=a_{3} \sin{\left(\psi_{3} \right)} + d \sin{\left(\psi_{1} + \psi_{2} \right)}$

$\Rightarrow \left(a_2-d\right)\sin{\left(\psi_1+\psi_2\right)}=a_3 \sin{\left(\psi_3\right)}-a_1\sin{\left(\psi_1\right)}$

Squaring and adding the equations gives

$\left[\left(a_2-d\right)\cos{\left(\psi_1+\psi_2\right)}\right]^2+\left[\left(a_2-d\right)\sin{\left(\psi_1+\psi_2\right)}\right]^2=\left[a_3 \cos{\left(\psi_3\right)}-a_1\cos{\left(\psi_1\right)}+a_4\right]^2+\left[a_3 \sin{\left(\psi_3\right)}-a_1\sin{\left(\psi_1\right)}\right]^2$

$\Rightarrow d=a_2\pm \sqrt{a_1^2 +a_3^2 + a_4^2 -2a_1a_3\cos{\left(\psi_1-\psi_3\right)}+a_4\left(a_1\cos{\left(\psi_1\right)}-a_3\cos{\left(\psi_3\right)}\right)}$

And dividing one equation with the other equation gives

$\frac{\left(a_2-d\right)\sin{\left(\psi_1+\psi_2\right)}}{\left(a_2-d\right)\cos{\left(\psi_1+\psi_2\right)}}=\frac{a_3 \sin{\left(\psi_3\right)}-a_1\sin{\left(\psi_1\right)}}{a_3 \cos{\left(\psi_3\right)}-a_1\cos{\left(\psi_1\right)}+a_4}$

$\Rightarrow \psi_2=-\psi_1+\tan^{-1}{\left(\frac{a_3 \sin{\left(\psi_3\right)}-a_1\sin{\left(\psi_1\right)}}{a_3 \cos{\left(\psi_3\right)}-a_1\cos{\left(\psi_1\right)}+a_4}\right)}$

Therefore, we have $\psi_2$ and $d$ in terms of $\psi_1$ and $\psi_3$. And so, we can write all the other unknown variables in terms of $\psi_1$ and $\psi_3$.

Hence, for the position of the end-effector, we have

$p_o = \begin{Bmatrix}a_{1} \cos{\left(\psi_{1} \right)} + a_{2} \cos{\left(\psi_{1} + \psi_{2} \right)}\\a_{1} \sin{\left(\psi_{1} \right)} + a_{2} \sin{\left(\psi_{1} + \psi_{2} \right)}\\0\\1\end{Bmatrix}$

$\Rightarrow p_o = \begin{Bmatrix}a_{1} \cos{\left(\psi_{1} \right)} + a_{2} \cos{\left(\tan^{-1}{\left(\frac{a_3 \sin{\left(\psi_3\right)}-a_1\sin{\left(\psi_1\right)}}{a_3 \cos{\left(\psi_3\right)}-a_1\cos{\left(\psi_1\right)}+a_4}\right)} \right)}\\a_{1} \sin{\left(\psi_{1} \right)} + a_{2} \sin{\left(\tan^{-1}{\left(\frac{a_3 \sin{\left(\psi_3\right)}-a_1\sin{\left(\psi_1\right)}}{a_3 \cos{\left(\psi_3\right)}-a_1\cos{\left(\psi_1\right)}+a_4}\right)} \right)}\\0\\1\end{Bmatrix}$

And for the orientation of the end-effector link, from the figure we can have

$\psi = \psi_1+\psi_2$

$\Rightarrow \psi = \tan^{-1}{\left(\frac{a_3 \sin{\left(\psi_3\right)}-a_1\sin{\left(\psi_1\right)}}{a_3 \cos{\left(\psi_3\right)}-a_1\cos{\left(\psi_1\right)}+a_4}\right)}$

Title: Pose of the end-effector

Body: I am trying to get the pose of the end-effector. I have attached the picture. I am stuck. I wrote the transformation matrices - I am not sure how to move forward next. How do I find the end-effector pose?.


问:
4-Wheeled Mobile Robot, Motor-Torque, RPM Calculation
I want the torque, rpm of every motor to be used considering certain factors, in a 4 wheeled robot as you see in the picture below.

Here are the factors affecting motor specifications that I Had taken into account::::

Load = 22 KG

Wheel Mass = 0.25KG

Wheel outer Diameter = 0.1 m

Number of Wheels = 4

Friction Coefficient = 0.4 (hard plastic on dry plywood)

Drive system efficiency = 70%   (this is actually from brushed dc motor averages)

Transmission = Direct coupling

Floor maximum slope = 10 degrees

Load holding while the motor is stopped = Yes

Required robot velocity = 24 m/s

Required robot Acceleration = 8.8 m/s^(2)

Number of motors = 4

Type of wheel = Omni wheel/Normal wheel (not sure how you calculate for omni wheels as they have rollers on them)

Type of Motor = Brushed DC motor

From online motor sizing tools, I am getting a total torque requirement of 6 nM for the entire system. However, this answer varies from other online resources and my own personal math that I had done.
I also tried to take into the type of wheel to be used as a factor but the I am unsure of the math involving Omni wheels and their load.

Can someone shed some light on Getting the torque and rpm for motors in this system, on normal wheels and on Omni wheels if possible?

If anyone has any papers or did similar math for getting these values, kindly share your workings if possible, it will be of great help.
Also I apologize if this is a wrong stack exchange to post as it can be considered a borderline Physics question.

答:
Hope this still helps you, you can try here:

https://www.societyofrobots.com/RMF_calculator.shtml

https://www.orientalmotor.com/motor-sizing/index.html

https://www.maxongroup.de/medias/sys_master/8819062800414.pdf?attachment=true

(Page 23, Sorry it is in german but it has everything for estimations.)

Load holding when the motor stops: I think without brakes you will need self-locking gears.

You should use rolling resistance instead of friction. https://www.engineeringtoolbox.com/rolling-friction-resistance-d_1303.html


问:
A* as a planning algorithm
Researchers refer to A* as the planning method but: how does A* work as a path planning algorithm, instead of a graph search method?
And how does it compare to RRT?</p>

答: You discretize your continuous workspace and that becomes the graph. The simplest way to do this is to put an evenly spaced grid on top of your workspace. The search graph is now a graph where grid positions are nodes and adjacent grid positions share an edge. Any graph search algorithm should work for this setting. There are various problems with this approach which is why roboticists tend to use RRT or sampling-based algorithms for path/motion planning.</p>

Title: A* as a planning algorithm


问:
Once you understand motors, what's the next step?
I've gone through tutorials on how to build circuits and control dc, stepper, and servo motors.  I may not understand everything about them internally, but i have a good basic foundation.

Now i'm at a loss for where to go from here.  I'm more interested in learning how to make mechanical devices with them than just the electronics behind the devices.  While i know that they go hand in hand, i want to learn more about the mechanical aspects of using motors.

I have in mind several ultimate goal projects that i want to work toward, like home automation, model rc vehicles, autonomous robots, etc...  But i'm sure that there is more to mechanics that i need to learn before i can jump into a project like that.  He who will learn to fly one day must first learn to stand and walk.

Are there hobbyist mechanical starter kits or starter projects to learn how to make effective use of electric motors?  I don't necessarily need a specific product endorsement, but rather a general idea of what important concepts to learn and materials / projects to help me learn them.

My apologies if this question is too broad.  I can refine it if deemed necessary.

答:
so now you have a good foundation of motors and the similar electro-mechanical actuators.
You have to learn or you have to build up a concepts of all kinds of mechanical parts needed to do a project on a mechanical robotics.
see there are so many things nto thr domain of robotics but first you have to go step by step.
as you have a good knowledge about the motors then go through there ratings and emf and all the ratings stuffs and after that try to know which motors are used for which purposes.
see for robotics the purpose of using the components should be known to do a project in robotics domain.so after gathering the practical knowledge you may tend to the different parts onto them.Try to design a system especially a mechanical system that may be a simple one (like a robotic mechanical arm) and then try to implement some gear related and pully related mechanical system that will do a specific job for you.or you can interface these kinds of motors like a system of steering system of a car etc or you may try something innovative generator system by using motors you have or you can interface it to a analog circuit to make a low cost mechanical system for a specific requirement.you cann try a different one like you can make an autonomous system using a microcontroller or microprocessor system and interface it with some sensors and after sensing the environment you can control the actuators to get your requirement done!
hope the suggestions may help you.


问:
Implementing Dynamic Balancing on Robot Dog
I made a robot dog using Lewansoul LX-16a Smart Serial bus motors and a 3D printed body. I am using an Arduino Mega 2560 to control everything. I already have the inverse kinematics working. But for some reason, I can't get the robot to balance on 3 legs. I have tried to balance the weight, and tried to hard code other legs to move down to shift the CG. But that trick doesn't work when I am trying to make the gaits. I want the dog to balance dynamically as it walks. I want to use a gyroscope to do that, but I don't know where to start.

Details:

3D model - https://www.thingiverse.com/thing:4445119

Github repo with my code - https://github.com/Project-Zeta-v2/

答:
Consider the triangle formed by the three feet that touch the ground. For static balance, the center of gravity's projection needs to be within that triangle. Crouching will lower the CG but won't necessarily move it into the triangle. If the feet were to stay put but the legs lean to one side, that would shift the CG. For dynamic balance, as the CG and the triangle move relative to each other, the static inside-the-triangle condition can be momentarily violated.  That's sort of a brief controlled fall, but things are ok as long as a foot moves (the triangle moves) to counter it in time. Gait is a complicated thing. Good thing others have studied it, so you don't have to discover it all.

Cool project.  Good luck!


问:
How to calibrate a magnetometer on a heavy robot
I am wondering how to calibrate a magnetometer on an IMU that is installed on a heavy robot. Normally, hard and soft iron calibration is done by spinning the IMU in all axis, but since it is installed on a robot, it is only possible to spin the robot in the Z axis.

So what is the appropriate way of doing the calibration here? Should I detatch the IMU and calibrate it over the robot?

Thanks

答:
I'm assuming that your integrated magnetometer and IMU has is doing a level of self calibration. Thus if you spin it around it will use the rate gyros to calibrate the magnetic variations. If you disconnect it from the robot you can calibrate it to itself. But when you do that you will be removing the value of calibrating it on the vehicle.

The vehicle itself will produce both magnetic fields as well as distort magnetic fields. (Respectively hard and soft iron effects) When you're calibrating the magnetometer, to be most useful on your robot it must remain fixed in space with respect to the effects of the robot. Since those are the effects that will be most valuable to calibrate out you'll want to calibrate while attached to the robot.

If you do not expect the vehicle to ever significantly pitch or roll then calibrating the magnetometer is likely less important or valuable to get coverage during your calibration routine.

There's a good overview of the needs of calibration of from Analog Devices As an example of how people have calibrated 1D magnetometers (aka compasses) in a much more analog example in boating via Practical Sailor