问:
Inverse kinematics for differential robot knowing linear and angular velocities
I have a differential robot and I am using ROS to run it. When I need to move the robot, I can send commands to it, specifically linear X and angular Z velocities. Linear X is in m/s whereas angular Z is in rad/s.

Know I need to compute what velocities should I set to both wheels in order to meet the linear and angular velocities. I have found this formula:

```<code>velocity_left_cmd = (linear_velocity – angular_velocity * WHEEL_BASE / 2.0)/WHEEL_RADIUS;

velocity_right_cmd = (linear_velocity + angular_velocity * WHEEL_BASE / 2.0)/WHEEL_RADIUS;
</code>```

But it does not seem to be correct. If I put the linear velocity to be 0.5 m/s and angular to be 0.6 rad/s, then having my WHEEL_BASE of 0.14 meters and WHEEL_RADIUS of 0.03 meters, I get very large values, like 15 m/s on one of the wheels. That does not seem to be correct.

What is the right way to get the individual velocities on each wheel?

答:
Your result is correct: I got encoder values by a measurement, which perfectly fit with your equations. However, I don't understand your thoughts.

Firstly, you wrote velocity = rounds per something * circumference. You calculated with rpm, which is rounds per minute (= 60 s). But what to do in case of rps? Then you cannot divide through 60, which is here a quite important step to do.

Secondly, you mentioned that the DIST_PER_RAD is the circumference (2 * pi * r) divided by 2 * pi for a complete revolution, which results just in the radius. In my opinion there must be calculated v = n * 2 * pi * r (with n = number of revolutions in 1/s or 1/min or whatever). Then you'll get the distance, which belongs to n. Example: 1 round per something (s, min, h) is a complete revolution of the wheel in one second, minute or hour. We'll get just the half distance in case of n = 1/2 rounds per something (s, min, h). I.e. it isn't necessary to divide the circumference by 2 * pi.

However, when I calculate the velocity as v = n * 2 * pi * r I don't get the correct results, i.e. in fact the factor 0.1047 is absolutely necessary.

Do you've any idea where my mistake is?


问:
Is it possible to solely use a P-controller for velocity control?
Let's say I want a robot to run at a certain speed. I have one motor attached to each robot rear wheel. The feedback value to the controller comes from an encoder, which outputs pulses per time unit, i.e. the measured variable is speed of the robot.

Something has been bugging me, so please correct me if I am wrong: I don't think it is possible to solely use a P-controller for velocity control. I seems to me that it is impossible to reach the desired target speed if your output signal from the controller (i.e. a velocity value) is proportional to the error value. Then when the error goes towards zero (which is what the P-controller strives for) the output signal (velocity) would go towards zero. But then how can you maintain a non-zero speed? Instead you will probably reach an equilibrium point were the robot velocity control is in a steady-state error. Is this reasoning correct or wrong?

答:
output signal from the controller (i.e. a velocity value) is proportional to the error value

I think there is some confusion here.

In a standard velocity control loop, the controller output cannot be the velocity itself, by definition. Instead, the velocity is the feedback, whereas the controller output is most likely the voltage applied to the electrical motor.

That said, your intuition is correct, a simple P controller is not sufficient for achieving the target velocity.

It is easy to verify that, as result of a zero error, the voltage command will be zero, hence the motor won't spin any longer. Thus, a generic target speed different from zero is not attainable.

More rigorously, if we consider that the transfer function voltage-speed can be well approximated with a first-order response, we end up with no integral in the loop if we close it with a simple P controller. In turn, no integral entails a non-null steady-state error. To compensate for that, one must purposely introduce the I term as it is well known.

ContentLicense: CC BY-SA 4.0


问:
How to derive the inverse kinematic equations for this simple 6-DOF robot?
For the simple 6-DOF shown, we have to solve for the inverse kinematic equations and its resulting figures.

But I'm sorry, I really don't have any idea where to begin. Can someone please help?

What should I do to solve this?

P.s. That's all the information our teacher gave us.

答:
The first step is to create the model of the robot. I recommend you to model the robot using modified denavit hartenberg (There are plenty of book and youtube provide the information you need). Then you can simply use this robotic toolbox and use function like SerialLink.ikine to get the mathematical function of inverse kinematic.

Hope that help :)


问:
Trajectory generation equation from jacobian and inverse kinematics
I just built a 4 DOF Articulated manipulator with open-loop servo motors and the servos signals are generated using a micro-controller. I followed the Angela Sodemann's videos on YouTube, I calculated properly the forward kinematics using Denavit-Hartenberg, Inverse Kinematics and the Jacobian matrix which is in this case the dimensions of the Jacobian matrix are 6x4. All joints are revolute. Now i want to move the end-effector in a particular direction. The manipulator goes in the desired direction but i also want to control its speed using the Jacobian but I cannot take the inverse of the Jacobian since it is not a square matrix. Books on robotics mention 3-rd order/5-th order polynomial for trajectory generation but I could not relate the polynomial equation with the inverse kinematics and the Jacobian matrix. Can anyone suggest on any resources on how to go from here? I will be writing all the code my self in C language without any libraries, or more precisely, how do I learn from here to go to the next nasic step of trajectory generation?

Any response will be greatly appreciated.

Thank you.

EDIT: Someone else had a same problem and was told that if only linear speed control was required, then this could be a solution,

\begin{bmatrix} \dot{x} \\ \dot{y} \\ \dot{z} \\ 0 \\ 0 \\ 0 \end{bmatrix}

I am assuming we are talking about the linear speed of the end-effector here? Have I understood this correctly?

答:
As suggested by ben, i will put my comment as answer.

1st How to control robot

I recommend you to look about resolved motion rate control. It's a complete algorithm to control a robot from path planning, control system, inverse jacobian and simulating plant. (And you can add several other algorithm to measure the state of system if you want too, very good algorithm)

2nd How to inverse non square jacobian

You can inverse non square jacobian by using pseudo-inverse look here Because you jacobian dimension 6x4. Then the pseudo inverse of your jacobian is

A+ = (AT A)^-1 * AT

AT = A transpose

By using pseudoinverse, you also make your robot more robust to singularity

Hope that help


问:
Understanding Arduino bootloader
That is what I came to understand while reading here and there about flashing a new bootloader/understanding what a bootloader is etc etc

The bootloader is supposed to be the first thing that runs when I power up my Arduino Duemilanove (or micro controllers in general). It does some setup then runs my app. It also listens to the usb cable so that if I upload some code it erases the old one and run the new one. There are 2 sections in the memory, one for the bootloader (S1) and one for the app (S2). Code on S1 can write to S2 but not to S1 (or strongly discouraged I don't remember).

There are things that I don't understand though :

If I upload some new code while my app is running, the upload works. What happened ? I thought that the bootloader gave hand to my app

How can we flash a new bootloader ? If the bootloader is the thing that runs on section 1 (S1) and can only write to S2 and if the bootloader is the only thing that listens to new code uploads, ...

Can you help me correct my thoughts and answer my questions ? Many thanks !

答:
(1) On several Arduino models, there's a 100 nF capacitor (at red dot in diagram) connected between DTR# on the FT232RL (or equivalent) chip and the RESET pin on the CPU.
  (Obtain file arduino-duemilanove-schematic.pdf to see whole schematic.  Also see arduino.cc Duemilanove page.)

DTR# normally sits high, and RESET normally is high due to an internal pullup resistor (eg 20K-50KΩ) so C13 usually has 0 volts across it.  In the Arduino process for programming via USB-serial, a programming cycle starts with DTR# being pulled down for 22ms
(1,2), which pulls RESET low long enough to reset the processor.

After the reset, the bootloader initializes; stores the received program into flash memory; then runs the stored program.

Note, auto-reset can be disabled (on some Arduino models) by cutting a jumper (eg, RESET-EN).  See the “Automatic (Software) Reset” sections or similar of 1,2,3,4.

(2) To flash a new bootloader, you attach a programmer to either the 6-pin ICSP header (marked by green dot in diagram) or to J3 (blue dot).  (Using J3 may require manually pressing S1 to reset the CPU before programming; see 2.)

A bootloader is a program that accepts data to store into flash; or, if no program begins arriving in the first half second or so after a reset (see refs 1-4 above), it starts a previously loaded program.

Programming via SPI (the Serial Peripheral Interface Bus, which uses the SCK, MISO, MOSI, SS pins of ICSP header for high speed full duplex serial data transfer) by contrast is a hardware operation that does not run a program from flash.  Like JTAG, it's one of the built-in hardware-level programming protocols in typical AVR chips.

During SPI programming, RESET is held low and the AVR is like a puppet carrying out directives issued to it by the programmer device.  The AVR is not executing a user-accessible stored program during programming; it is carrying out low-level directives issued to it by the programmer device.  A programming directive precedes each bit of data on the SPI bus.  For an explanation of the serial programming algorithm, see (eg) section 30.8 in doc2549.pdf, ATmega manual #2549P–AVR–10/2012.  Section 30.8.2 on p. 350-351 explains the method.  Table 30-17 on p. 352 shows the directives used to control programming.  These include “Programming Enable”,  “Chip Erase”, “Load Extended Address byte”, “Write Program Memory Page”, etc.

ContentLicense: CC BY-SA 3.0

Title: Understanding Arduino bootloader


问:
Reducing stress on servo axle
I am designing an articulated robot arm that will not need to hold essentially any weight at its end, but that will need to perform thousands of repetitions (currently using MG 996R servos, but might switch if those aren't durable enough). I am a design newbie, and as I've designed it currently, the only point of contact between each joint is the servo axle, meaning the weight of the arm is resting on that servo axle at each joint. I know this will produce undue stress on the axles over time, and I want to design the arm in such a way that the weight of the arm will not be placed on the servo axles. Can anyone point me in the right direction on how I can avoid that? Perhaps examples or principles of how joints can be designed such that the weight of the arm parts below it go through the frame of the arm rather than through the axle. Thanks!</p>

答:
This is commonly done by putting a bearing or two on the axis of servo rotation and making those bearing support the load. Try looking at parts like the Lynxmotion Aluminum "C" Servo Brackets. You can also look at products made by Trossen Robotics to see how they do it. And, search thingiverse.com for "servo joint", you'll see lots of ideas there.

Best of luck!

Title: Reducing stress on servo axle


问:
Need help in loading occupancy_grid map to OpenCV window
I have generated a map named map_1.pgm using map_server package. I want to display it in an OpenCV window. How can I achieve this?

I am currently trying this -

```<code>std::string file_name = "map_1.pgm";
cv::Mat m = cv::imread(file_name.c_str(), 0);

cv::namedWindow("map_1");
cv::imshow("map_one_window", m);

cv::waitKey(0);
</code>```

This is my map_1.yaml

```<code>image: map_1.pgm
resolution: 0.050000
origin: [-100.000000, -100.000000, 0.000000]
negate: 0
occupied_thresh: 0.65
free_thresh: 0.196
</code>```

However, on doing the above steps, I get a big OpenCV window which is completely grey.

How do I solve this problem?

I am attaching the results of xdg-open map_1.pgm.

答:
I am not familiar with ROS maps, but the threshold values in the yaml seem to indicate your map values are floats in the [0,1] range. I think OpenCV will not properly visualize these.

Check the minimum/maximum values in your matrix.

Try to generate a uint8 image with values in the [0,255] range for display, by just multiplying your map values with 255 (you may even have to make it a 3-channel image [with 3 identical channels] for OpenCV to handle it properly).


问:
Voltage not registering when motor is connected?
I'm trying to fix my kid's power wheel. When you press the gas pedal, nothing happens. I took it apart and checked everything. I noticed that when I disconnect the wires from the motor and check them with a DVM, it registers roughly 12v when I press the gas pedal. The weird thing is when I connect the wires to the motor and check the voltage, I don't register anything when I press the gas pedal. I can't figure out what would cause that. Any ideas? Motor shot?</p>

答:
Two reasonable options I can think of for why you're getting zero volts when the system is hooked up:

The battery is shot. Try probing battery voltage - a 12 volt lead-acid battery is dead if the voltage is less than about 11.8 volts. If the battery is fully charged then it should be about 12.8 volts.

The motor is shot. Try probing motor resistance. Typically, if the motor is bad, I would expect a wire break, in which case you'd see an infinite resistance, or the insulation is damaged, shorting the wiring and you'd get zero resistance. Since you're seeing zero volts with the pedal down I would guess the motor is shorted.

If you're probing the motor, be sure you're probing it at the motor with the motor disconnected or else you're probing the entire control circuit, too, which could give false readings. The battery state of charge estimate by measuring voltage is supposed to be with the battery "rested," but it sounds like it's not working so that shouldn't be an issue.

I would guess the battery is shot, but it could also just be that it's not charged. My kids will mess with theirs while it's plugged in, so it could be someone's pulled the charger out after you plugged it in, or unplugged it from the wall outlet or turned a power strip off, etc.


问:
Are Rospy subscriber callbacks executed sequentially for a single topic?
Suppose a ROS node receives new batch of data on a topic while the previous batch is still being processed by callback. Will ROS wait for its completion or will it spin a new thread and run both at the same time?

I'm asking because if they are sequential there is no need for a lock, but if they're not I'd need to use locking inside the callbacks.

I looked up the documentation for the rospy.Subcriber class, but it has no mention of this.

答:
I prototyped a bit to investigate this behaviour. Ran the following node:

```<code>#!/usr/bin/env python
import rospy
from threading import Lock
from std_msgs.msg import String
mutex = Lock()
def handler(data):
    print "Handle called"
    mutex.acquire()
    print "Handle executed"
    import time; time.sleep(10)
    mutex.release()
rospy.init_node('test')
rospy.Subscriber('/foo', String, handler)
rospy.spin()
</code>```

When I publish several individual messages I see that indeed the handler is getting called on another thread while the current handler is still in execution.

```<code>rospy pub /foo std_msgs/String "data: 'hello'"
ctrl-c
rospy pub /foo std_msgs/String "data: 'hello'"
ctrl-c
rospy pub /foo std_msgs/String "data: 'hello'"
ctrl-c
</code>```

I see the output:

```<code>Handle called
Handle executed
Handle called
Handle called
... several seconds later
Handle executed
... several seconds later
Handle executed
</code>```

However, when I publish a msg periodically from the same publish call:

```<code>rospy pub /foo std_msgs/String "data: 'hello'"-r 1 # publish once a second
</code>```

I see this:

```<code>Handle called
Handle executed
... 10 seconds pass
Handle called
Handle executed
... 10 seconds pass
Handle called
Handle executed
</code>```

I know the message is being published once a second, yet it doesn't spawn a new thread for the callback - so something is throttling the msgs until they have been handled.

So the behavior seems to diff depending on if the msgs are arriving from the same process or multiple processes.

I confirmed that it wasn't just a behaviour of rostopic pub by writing a simple node that publishes a msg every second and it behaves the same.

I haven't looked at the ROS code yet so not sure if its the ROS publisher or subscriber code that is throttling in the same process case.

So if you are publishing a topic from a single source then strictly speaking it seems like you don't need a mutex to protect about re-entry by the same topic handler.

However, in my opinion, considering that you (or a future developer) might call the same work function from a different callback or from a timer or from a main loop, or since you can use the same handler for multiple topics (that might come from different processes) and since adding a mutex is pretty easy and low effort and overhead it seems reasonable.

Body:
I prototyped a bit to investigate this behaviour. Ran the following node:

#!/usr/bin/env python
import rospy
from threading import Lock
from std_msgs.msg import String
mutex = Lock()
def handler(data):
    print "Handle called"
    mutex.acquire()
    print "Handle executed"
    import time; time.sleep(10)
    mutex.release()
rospy.init_node('test')
rospy.Subscriber('/foo', String, handler)
rospy.spin()

When I publish several individual messages I see that indeed the handler is getting called on another thread while the current handler is still in execution.

rospy pub /foo std_msgs/String "data: 'hello'"
ctrl-c
rospy pub /foo std_msgs/String "data: 'hello'"
ctrl-c
rospy pub /foo std_msgs/String "data: 'hello'"
ctrl-c

I see the output:

Handle called
Handle executed
Handle called
Handle called
... several seconds later
Handle executed
... several seconds later
Handle executed

However, when I publish a msg periodically from the same publish call:

rospy pub /foo std_msgs/String "data: 'hello'"-r 1 # publish once a second

I see this:

Handle called
Handle executed
... 10 seconds pass
Handle called
Handle executed
... 10 seconds pass
Handle called
Handle executed

I know the message is being published once a second, yet it doesn't spawn a new thread for the callback - so something is throttling the msgs until they have been handled.

So the behavior seems to diff depending on if the msgs are arriving from the same process or multiple processes.

I confirmed that it wasn't just a behaviour of rostopic pub by writing a simple node that publishes a msg every second and it behaves the same.

I haven't looked at the ROS code yet so not sure if its the ROS publisher or subscriber code that is throttling in the same process case.

So if you are publishing a topic from a single source then strictly speaking it seems like you don't need a mutex to protect about re-entry by the same topic handler.

However, in my opinion, considering that you (or a future developer) might call the same work function from a different callback or from a timer or from a main loop, or since you can use the same handler for multiple topics (that might come from different processes) and since adding a mutex is pretty easy and low effort and overhead it seems reasonable.


问:
Eliminate grey space around the saved map
I have mapped my Gazebo environment using the slam_gmapping node. On running map_server map_saver -f map_1.pgm, I am able to save the map to my local disk.

This is how the saved map looks -

As we can see, there is a lot of grey space arond the map. How do I eliminate this? I need to do this because I intend to run some OpenCV algorithms over this map.

This is my map_1.yaml looks like -

```<code>image: map_1.pgm
resolution: 0.050000
origin: [-100.000000, -100.000000, 0.000000]
negate: 0
occupied_thresh: 0.65
free_thresh: 0.196
</code>```

答:
Maybe you are looking to crop the occupancy grid. Map server provides some api's for cropping. This sample script from their documentation would shed some light</p>
```<code>#!/usr/bin/env python

import sys
import yaml
from PIL import Image
import math

def find_bounds(map_image):
    x_min = map_image.size[0]
    x_end = 0
    y_min = map_image.size[1]
    y_end = 0
    pix = map_image.load()
    for x in range(map_image.size[0]):
        for y in range(map_image.size[1]):
            val = pix[x, y]
            if val != 205:  # not unknown
                x_min = min(x, x_min)
                x_end = max(x, x_end)
                y_min = min(y, y_min)
                y_end = max(y, y_end)
    return x_min, x_end, y_min, y_end

def computed_cropped_origin(map_image, bounds, resolution, origin):
00025     """ Compute the image for the cropped map when map_image is cropped by bounds and had origin  """
    ox = origin[0]
    oy = origin[1]
    oth = origin[2]

    # First figure out the delta we have to translate from the lower left corner (which is the origin)
    # in the image system
    dx = bounds[0] * resolution
    dy = (map_image.size[1] - bounds[3]) * resolution

    # Next rotate this by the theta and add to the old origin

    new_ox = ox + dx * math.cos(oth) - dy * math.sin(oth)
    new_oy = oy + dx * math.sin(oth) + dy * math.cos(oth)

    return [new_ox, new_oy, oth]

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print >> sys.stderr, "Usage: %s map.yaml [cropped.yaml]" % sys.argv[0]
        sys.exit(1)

    with open(sys.argv[1]) as f:
        map_data = yaml.safe_load(f)

    if len(sys.argv) > 2:
        crop_name = sys.argv[2]
        if crop_name.endswith(".yaml"):
            crop_name = crop_name[:-5]
        crop_yaml = crop_name + ".yaml"
        crop_image = crop_name + ".pgm"
    else:
        crop_yaml = "cropped.yaml"
        crop_image = "cropped.pgm"

    map_image_file = map_data["image"]
    resolution = map_data["resolution"]
    origin = map_data["origin"]

    map_image = Image.open(map_image_file)

    bounds = find_bounds(map_image)

    # left, upper, right, lower
    cropped_image = map_image.crop((bounds[0], bounds[2], bounds[1] + 1, bounds[3] + 1))

    cropped_image.save(crop_image)
    map_data["image"] = crop_image
    map_data["origin"] = computed_cropped_origin(map_image, bounds, resolution, origin)
    with open(crop_yaml, "w") as f:
        yaml.dump(map_data, f)
</code>```

Body:
Maybe you are looking to crop the occupancy grid. Map server provides some api's for cropping. This sample script from their documentation would shed some light

#!/usr/bin/env python

import sys
import yaml
from PIL import Image
import math

def find_bounds(map_image):
    x_min = map_image.size[0]
    x_end = 0
    y_min = map_image.size[1]
    y_end = 0
    pix = map_image.load()
    for x in range(map_image.size[0]):
        for y in range(map_image.size[1]):
            val = pix[x, y]
            if val != 205:  # not unknown
                x_min = min(x, x_min)
                x_end = max(x, x_end)
                y_min = min(y, y_min)
                y_end = max(y, y_end)
    return x_min, x_end, y_min, y_end

def computed_cropped_origin(map_image, bounds, resolution, origin):
00025     """ Compute the image for the cropped map when map_image is cropped by bounds and had origin  """
    ox = origin[0]
    oy = origin[1]
    oth = origin[2]

    # First figure out the delta we have to translate from the lower left corner (which is the origin)
    # in the image system
    dx = bounds[0] * resolution
    dy = (map_image.size[1] - bounds[3]) * resolution

    # Next rotate this by the theta and add to the old origin

    new_ox = ox + dx * math.cos(oth) - dy * math.sin(oth)
    new_oy = oy + dx * math.sin(oth) + dy * math.cos(oth)

    return [new_ox, new_oy, oth]

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print >> sys.stderr, "Usage: %s map.yaml [cropped.yaml]" % sys.argv[0]
        sys.exit(1)

    with open(sys.argv[1]) as f:
        map_data = yaml.safe_load(f)

    if len(sys.argv) > 2:
        crop_name = sys.argv[2]
        if crop_name.endswith(".yaml"):
            crop_name = crop_name[:-5]
        crop_yaml = crop_name + ".yaml"
        crop_image = crop_name + ".pgm"
    else:
        crop_yaml = "cropped.yaml"
        crop_image = "cropped.pgm"

    map_image_file = map_data["image"]
    resolution = map_data["resolution"]
    origin = map_data["origin"]

    map_image = Image.open(map_image_file)

    bounds = find_bounds(map_image)

    # left, upper, right, lower
    cropped_image = map_image.crop((bounds[0], bounds[2], bounds[1] + 1, bounds[3] + 1))

    cropped_image.save(crop_image)
    map_data["image"] = crop_image
    map_data["origin"] = computed_cropped_origin(map_image, bounds, resolution, origin)
    with open(crop_yaml, "w") as f:
        yaml.dump(map_data, f)


问:
Localization and Mapping in a Small Crop Field
I have a small crop field inside my house and I want to create a map of it. The goal is to create a map so that I can monitor the growth of the plants and do some post processing to analyze the details of individual plant.

Hardware: Since it is a small crop field, I have two poles on either ends of the field with a wire connecting the two poles. the robot/assembly will be hooked to the wire. Therefore, the path of the robot is always fixed. I have a 3D lidar, a camera, IMU and a GPS.

I have interfaced all the sensors with my Nvidia TX2 controller using ROS. In short, I have raw data coming into the system from all sensors. I want some advice regarding how to proceed with this project?

Should I start with localization? As a first step, should I fuse data from the GPS and IMU to get accurate positioning of the system? With the idea that, if I accurately localize my system in the field and then acquire images for every position, is it possible to join the images somehow?

Do I need to implement SLAM here?

答:
If you intend to stitch images together, you don't need to strictly implement slam. As long as there is good overlap between images, you can use SIFT/SURF features to extract matching keypoints and stitch the images together. Take a look at this tutorial on panorama creation.

However, given your setup, I believe SLAM would be the way to go! since you already have ros setup, I'd suggest going forward with the robot_localization package. You can use this package to fuse the GPS and IMU data to get an accurate location of your robot and then use that to transform your images and lidar pointclouds to create a map. To create a map with lidar pointcloud you can use iterative closest points or use a package like rtabmap/octomap.

As a stretch, you can even fuse your lidar pointcloud with images to colorize your map.


答: As mentioned above, you first need to develop the kinematic model of the robot. Try formulating the forward kinematics of the robot. For the inverse kinematics, you can either use geometric or algebraic method. A very good source to learn would be this book: "Introduction to Robotics - Mechanics and Control". In fact, there is a complete solution for forward and inverse kinematics of a 6dof robotics arm. Specifically, the inverse kinematics is solved in the 4th chapter. Here's the Link to the book</p>

Title: How to derive the inverse kinematic equations for this simple 6-DOF robot?

Body:
For the simple 6-DOF shown, we have to solve for the inverse kinematic equations and its resulting figures.

But I'm sorry, I really don't have any idea where to begin. Can someone please help?

What should I do to solve this?

P.s. That's all the information our teacher gave us.


问:
Loop time for self balancing robot
I have been working on a self balancing robot and there are quite a few parameters and one of them is loop execution time (t_loop henceforth). To my understanding, the smaller t_loop, the better it is for the control algorithm. But, since the motors also need to be given sufficient time to react, we cannot make it very small. Also, making t_loop large so that motors have sufficient time to react will make the system unstable. So there has to be some optimum value. I started with 5 milliseconds and started increasing it. At 5 ms the robot is quiet jerky (but it manages to balance). Between 10 and 20 ms, the vibrations become less. The question is how to find the optimum value of t_loop or control loop execution time.   </p>

答:
The answer is not a trivial one. Because,

the system dynamics depends on multiple sub-system dynamics (including software, sensors, and actuators (motors in this case))

finding the optimum value for t_loop, requires finding the best possible controller for all (i.e. several) t_loop values.

It's worth considering the following approach:

assume that the motors have the slowest dynamics (hence they are the bottle-neck for the problem)

the bandwidth of the motors will define the frequency at which they can be successfully commanded (you can utilize an open-loop test code, e.g. a code that runs sine waves for the motors in different frequencies, and the decide when the motors are not able to keep up with the commands)

the frequency that the motors can receive commands is the control frequency (fm). It is best practice to use a 10*fm frequency to control the motor in this case. ref: https://controlguru.com/sample-time-is-a-fundamental-design-and-tuning-specification/

Further than this, you will need to refer to modern-control literature for the following terms:

system bandwidth,

crossover frequency,

nyquist theorem

aliasing

But, I think a deeper dive into control theory is not necessary at this moment.

Title: Loop time for self balancing robot


问:
HMMs vs. CRFs to model time-series force data of robots interacting with environment?
I have a time-series of force data of robots interacting with environment objects with various textures. I would like to develop models of various textures using the time-series data to classify textures into smooth, rough, moderate, etc. categories. For this purpose, will Hidden Markov Models be sufficient or should i use Conditional Random Fields? If I decide to classify into more categories and the distinction between each of are categories are very subtle, in that case what would be a good choice? Will force-data be sufficient to capture all the information I need to classify textures into these categories?

Thanks for your replies :)

答:
Based on your problem description, both HMM (generative model) and CRF (discriminative model) will work. See this discussion for a more in-depth explanation of the two approaches:

What is the difference between a Generative and Discriminative Algorithm?

A suggestion: before choosing an algorithm, start by carefully looking at your numerical data, with MATLAB plots or similar. If the information is multi-dimensional (e.g. force values from multiple sensors), it might be the case that some dimensions (e.g. sensor reads) do not contain useful discriminative information; in this case, compress the data with Principal Component Analysis so that you will have more compact features during training and classification.

Now, with regard to your question:

The difference is that HMMs can represent each of your texture classes with several hidden variables/states, thus capturing the internal temporal evolution of each contact. We can say that HMM better model the "low-level" (intra-class) dynamics of your data. For example, in your case HMMs will permit you to explicitly model three different phases of each data acquisition: (1) start of contact between robot and object; (2) stable part of the contact; (3) end of contact and release. These phases could have different values in time, even for the same object texture, and it could make sense to separate them to improve classification results.

On the other hand, CRFs are more suited for capturing the "high-level" (inter-class) relations of your data distribution, which are sometimes important when the spatio-temporal variability is high, or when the observation features are very similar between two samples belonging to different classes.

Personally I find HMMs easier to use and I would start with those, but your mileage may vary.

If I decide to classify into more categories and the distinction between each of are categories are very subtle, in that case what would be a good choice?

In that case, CRFs can be a more robust choice (see above).

Will force-data be sufficient to capture all the information I need to classify textures into these categories?

Adding visual features (object appearance), especially if captured with high-resolution cameras, could help determine if the object has a rough texture or not.


问:
Quadcopter instability with simple takeoff in autonomous mode
I'm trying to get a quad rotor to fly. The on board controller is an Ardupilot Mega 2.6, being programmed by Arduino 1.0.5.

I'm trying to fly it in simple autonomous mode, no Radio controller involved. I've done a thorough static weight balancing of the assembly (somewhat like this: http://www.youtube.com/watch?v=3nEvTeB2nX4) and the propellers are balanced correctly.

I'm trying to get the quadcopter to lift using this code:

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

int maxspeed = 155;
int minspeed = 0;

Servo motor1;
Servo motor2;
Servo motor3;
Servo motor4;

int val = 0;
int throttleCurveInitialGradient = 1;

void setup()
{

val = minspeed;

motor1.attach(7);
motor2.attach(8);
motor3.attach(11);
motor4.attach(12);

}

void loop()
{
setAllMotors(val);
delay(200);
val>maxspeed?true:val+=throttleCurveInitialGradient;
}

void setAllMotors(int val)
  {
    motor1.write(val);
    motor2.write(val);
    motor3.write(val);
    motor4.write(val);
  }
</code>```

But the issue is, as soon as the quadcopter takes off, it tilts heavily in one direction and topples over.

It looks like one of the motor/propeller is not generating enough thrust for that arm to take-off. I've even tried offsetting the weight balance against the direction that fails to lift, but it doesn't work (and I snapped a few propellers in the process);

Is there something wrong with the way the ESCs are being fired using
the Servo library?

If everything else fails, am I to assume there is something wrong
with the motors?

Do I need to implement a PID controller for self-balancing the roll
and pitch just to get this quadrotor to take off?

Edit 1:    Thanks for all the replies.

I got the PID in place. Actually, it is still a PD controller with the integral gain set to zero.

Here's how I'm writing the angles to the servo:

```<code>motor1.write((int)(val + (kP * pError1) +(kI * iError1) +(kD * dError1)));  //front left
motor2.write((int)(val + (kP * pError2) +(kI * iError2) +(kD * dError2)));  //rear right
motor3.write((int)(val + (kP * pError3) +(kI * iError3) +(kD * dError3)));  //front right
motor4.write((int)(val + (kP * pError4) +(kI * iError4) +(kD * dError4)));  //rear left
</code>```

kI is zero, so I'll ignore that.

With the value of kP set somewhere between 0.00051 to 0.00070, I'm getting an oscillation of steady amplitude around a supposed mean value. But the problem is, the amplitude of oscillation is way too high. It is somewhere around +/- 160 degrees, which looks crazy even on a tightly constrained test rig.

[  Edit 2: How I calculate the term 'pError' - Simple linear thresholding.

I've a precomputed data of the average readings (mean and SD) coming out of the gyro when the IMU is steady. Based on the gyro reading, I classify any motion of the setup as left, right, forward or backward.

For each of these motion, I increase the pError term for two of the motors, i.e, for right tilt, I add pError terms to motors 2 & 3, for left tilt, I add pError term to motors 1 & 4 etc. (check the comment lines in the code snippet given above).

The magnitude of error I assign to the pError term is = abs(current gyro reading) - abs(mean steady-state gyro reading). This value is always positive, therefore the side that is dipping downwards will always have a positive increment in RPM.  ]

As I crank up the derivative gain to around 0.0010 to 0.0015, the oscillation dampens rapidly and the drone comes to a relatively stable attitude hold, but not on the horizontal plane. The oscillation dies down (considerably, but not completely) only to give me a stable quadrotor tilted at 90 - 100 degrees with horizontal.

I'm using only the gyros for calculating the error. The gyros were self calibrated, hence I do expect a fair amount of noise and inaccuracy associated with the error values.

Do you think that is the primary reason for the high amplitude
oscillation?

One other probable reason might be the low update frequency of the errors. I'm updating the errors 6 times a second.

Could that be a probable reason it is taking longer to stabilise the
error?

And, for the steady state error after the wild oscillations dampen, is it necessary to fine tune the integral gain to get rid of that?

Please help.

Edit 3:  I cranked up the frequency of operation to 150+ Hz and what I get now is a very controlled oscillation (within +/- 10 degrees).

I'm yet to tune the derivative gain, following which I plan to recompute the errors for the integral gain using a combination of gyro and accelerometer data.

Edit 4:  I've tuned the P and D gain, resulting in +/- 5 degrees oscillation(approx). I can't get it to any lower than this, no matter how much I try.

There are two challenges about which I'm deeply concerned:

After 5 to 8 seconds of flight, the quadcopter is leaning into one side, albeit slowly.

A) Can this drift be controlled by tuning the integral gain?

B) Can the drift be controlled by using accelerometer + gyro fused data?

C) Given that my drone still shows +/- 5 degrees oscillation, can I consider this the optimal set point for the proportional and derivative gains? Or do I need to search more? (In which case, I'm really at my wits end here!)

答: Is it always the same side that topples? If so, one obvious thing to try to eliminate the possibility that one of your motors is faulty, is to simply switch motor positions and see if the side that topples changes.</p>


答:
Since you are solving an Inverse Kinematics (IK) problem, you should already have the pose (position and orientation) of the end effector (EE) relative to the fixed base of the robot (or the pose of both the base and the EE in one common frame). You should also already know how to generate the Forward Kinematics (FK), which can come in handy.

There are two ways that I generally recommend approaching an IK problem for a robot that you haven't seen before: one where you turn it into a simpler IK problem and one where you look carefully at the FK equations.

For the first one, see if you can find a reference point on the robot that you can locate using only the EE pose which will not move when you rotate the last 1-3 (or more) joints. Once you've found that reference point, you can solve a simpler IK problem to figure out how to use the remaining joints to place the reference point at the desired location.

For the second one, the FK equations will tell you which elements of the EE pose are affected by which of the joints: if the joint variable appears in the equation for the height of the EE, for example, then that joint affects the height. If you can find one element that only has 1 joint variable in it then you can solve that element using the reduced set of equations. This also works if there are 2 elements with only 2 joint variables, as long as they are the same 2 variables in both equations, and so on for more elements.

Hope that helps! As Ben said in his comment, without more details on what you've tried so far we won't be able to provide more than the first steps of a homework problem.

Cheers,
Brandon


问:
Help on the Walking without thinking about it paper!
I was reading the paper, which you can find: https://hal.inria.fr/inria-00567668/document. I got so confused with equation (33) and (34), it seems like instead of an equal sign in eq.(33) on the left that should be a multiplication, which can be supported by the first author's thesis: https://pastel.archives-ouvertes.fr/pastel-01038025/document, eq.(2.62).

But I cannot understand what it means physically, can someone help me understand this!

答:
I think you are correct that the equals sign in equation (33) should not be there, as reinforced by the first author's thesis.

The purpose of those equations are to constrain the MPC-generated footstep positions to ensure that each foot position is within the polygon shown in the following figure relative to the stance foot. In effect, the combination of those matrices will make sure that the generated steps are feasible, as you said.

The challenging part (to me at least) is that they have to do it for all steps from the current one to the end of the MPC, so they need to include details for all of those "future" steps in addition to the current step.

Hope that helps!

Cheers,
Brandon


问:
Sparcification of SLAM with SEIF (Sparse Extended Information Filter)
I am studying SLAM (Simultaneous Localization and Mapping) with textbook "probabilistic robotics".

I cannot understand well about Sparsification step, so I found original paper for that;
https://web.mit.edu/2.166/www/handouts/thrun_et_al_ijrr2004_seifs.pdf

According to this paper, information matrix for the distribution of all variables without passive features can be written as equation (38), this is ok for me, but how equation(40) can be lead ??

It says that using the matrix inversion lemma like annotated (39), but what is "B" matrix here and why has it gone from resulting equation (40) & (41) ...?

Anyone help ??

答:
Open discussion

I have the same question and use the marginalization method (instead of matrix inversion lemma) to get the following derivation.

Note: $z_t$ and $u_t$ are ignored to make the equations shorter in the follwoing derivation.

The equation (38) is the information matrix

for the distribution $p(x_t,Y^0,Y^+|Y^-=0)$

If we separate $Y^0$ and non-$Y^0$ ($x_t$ and $Y^+$) parts in $H'_t$ as

$$
\begin{matrix}
H_{x_tY^+x_tY^+} &  H_{x_tY^+Y^0}  & \\
 H_{Y^0x_tY^+} &  H_{Y^0Y^0}  &
\end{matrix}
$$
, where

$H_{Y^0Y^0}$ is $S_{Y^0}H'_tS_{Y^0}^T$

$H_{x_tY^+x_tY^+}$ is $S_{x_tY^+}H'_tS_{x_tY^+}^T$

$H_{Y^0x_tY^+}$ is $S_{Y^0}H'_tS_{x_tY^+}^T$

$H_{x_tY^+Y^0}$ is $S_{x_tY^+}^TH'_tS_{Y^0}$

And based on the marginalizayion rule:

"from PROBABILISTIC ROBOTICS"

So the informaiton matrix for $p(x_t,Y^+|Y^-=0)$ is

$$
H_{x_tY^+x_tY^+}  - H_{x_tY^+Y^0}(H_{Y^0Y^0})^{-1}H_{Y^0x_tY^+}
$$

equal to

$$
S_{x_tY^+}(H'_t - H'_tS_{Y^0}^T(S_{Y^0}H'_tS_{Y^0}^T)^{-1}S_{Y^0}H'_t)S_{x_tY^+}^T
$$

I am still working on elimiting $S_{x_tY^+}$ ...

I understand this derivation is not even close to an "answer" but think creating another thread is kind of wasting because we already have this thread.


问:
What are joint angles of Kinova Jaco in home position?
I want to work with Kinova Jaco with spherical wrist in CoppeliaSim, because currently I do not have access to a physical manipulator. The model there is in reset configuration (arm fully extended and points up), but I want it to be in home configuration.

Does anyone know what are values of joint positions for Kinova Jaco with spherical wrist in home configuration?

答:
With the quarantine going less strict I finally have an access to a physical Jaco arm.

If someone else will need this info, here are the joint positions of Jaco arm in the home state:

$$
\boldsymbol{\theta}_{home}=\begin{bmatrix}
4.8055, 2.9211, 0.9989, 4.2076, 1.4420, 1.3220
\end{bmatrix}rad
$$
And these are joint positions in retracted state.
$$
\boldsymbol{\theta}_{ret}=\begin{pmatrix}
4.7143, 2.6191, 0.4693, 4.6728, 0.0916, 1.7412
\end{pmatrix}rad
$$
Finally, these are joint positions in retracted state just after you turn on the Jaco and before you do any operation:
$$
\boldsymbol{\theta}_{ret\_off}=\begin{pmatrix}
4.7246, 2.6108, 0.3681, 4.6694, 0.0905, 1.7441
\end{pmatrix}rad
$$


问:
Arduino Uno getting a type of "HANGED" while runing samll code of switc debounce and Serial print
I am using Arduino UNO to read a push button every time it is pressed.Earlier i was simply reading the Digital IO pin to read the count and then i faced the condition of switch debounce regarding which i had asked a question here and get to know that i must use Interrupt instead of reading a digital IO pin but even after using interrupt, i was facing the problem of Switch Debouncing.

So i used this link and code given on this link

```<code>const int buttonPin = 2;    // the number of the pushbutton pin
const int ledPin = 13;      // the number of the LED pin

// Variables will change:
int ledState = HIGH;         // the current state of the output pin
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin

// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);

  // set initial LED state
  digitalWrite(ledPin, ledState);
}

void loop() {
  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

  // check to see if you just pressed the button
  // (i.e. the input went from LOW to HIGH),  and you've waited
  // long enough since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;

      // only toggle the LED if the new button state is HIGH
      if (buttonState == HIGH) {
        ledState = !ledState;
      }
    }
  }

  // set the LED:
  digitalWrite(ledPin, ledState);

  // save the reading.  Next time through the loop,
  // it'll be the lastButtonState:
  lastButtonState = reading;
}
</code>```

and change

```<code> long debounceDelay = 50;
</code>```

to 10(means read any thing ina time gap of 10 mili second) as the code says.Now what is happening, code is running on the board and after some time my board get hang and LED stop toggling on any press of push button and then i had to manually reset my board.I also want to add upon a thing that i am also using a serial port in between when LED toggles or switch is pressed.

I am totally confused why this is happening.There can beone possibility that this is happening because i reduced time gap between two consecutive events to 10 from 50 miliseconds and that might be making AVR get hanged and thus require a manual reset.

答: It get solved automatically and that give me clear hint that when i was using 9v 1 Amp adaptor, because of heat Arduino was getting a type of HANGED..but when i powered it with USB cable..it works fine now.</p>


问:
LiDAR Feature Extraction
I'd like to extract "features" of an environment scanned with a 2D LiDAR.

I tried to create a temporary occupancy map to extract "corners" with the Harris Corner Detector. However LiDAR data is noisy, it creates false corners even after applying a Gaussian filter on the map. I wonder if there are more reliable algorithms for this.

Another method I tried is to use raw data output of the LiDAR, i.e. the $(r,\theta)$ vector, and calculate its first and second derivatives and choose "abrupt changes" as landmarks. This has a major drawback, it is harder to track landmarks when LiDAR position changes since $(r,\theta)$ vectors are totally different.

I appreciate any help. Thanks.

答: You need to use something like RANSAC or Hough line detectors.</p>

Title: LiDAR Feature Extraction


问:
How to choose closest angle when crossing -180 degrees
I'm applying a PID for position control on a diff drive robot, got the angles (orientation )between -pi and pi. It works fine until it needs to change its orientation from (let's say) -170 degrees to 170, when instead of changing its orientation by only 20 degrees it does an entire turn (almost 360) to get to the desired orientation. Does anyone knows how to solve this?</p>

答:
This looks like a common angle wrapping mistake.
I am assuming you're defining your angles between -180° ($-\pi$) to +180° ($\pi$).

Let's say your current heading is -170°.

And you desired heading is 170°.

The error in angle is: 170 - (-170) = 340, so your robot has to do almost a full turn to get to the desired heading.

Since you're defining your angle in the range $\left[ -180 ; 180 \right] $, you should also wrap the error in the same range.
In the example above, this means removing 360, so the error becomes 340 - 360 = -20. Which is what your PID needs to correct the heading.


答:
I still couldn't derive it, but maybe I could prove it thanks to willSapgreen.

Information matrix of distribution $p(x_t, Y^+, Y^0|Y^-=0)$ is $H_t'$;
$$H_t'=S_{x_t,Y^+,Y^0}S^T_{x_t,Y^+,Y^0}H_tS^T_{x_t,Y^+,Y^0}S_{x_t,Y^+,Y^0}$$

This matrix can be written as
$$H_t' = \left(\begin{array}{cc}
H_{x_t,Y^+,x_t,Y^+}&H_{x_t,Y^+,Y^0}\\H_{Y^0,x_t,Y^+}&H_{Y^0,Y^0}
\end{array}\right)\tag{1}$$

Information matrix of marginal distribution $p(x_t, Y^+|Y^-=0)$ is as follows. Note that dimension of $\tilde{H}_{x_t,Y^+,x_t,Y^+}$ is $3n\times3n$ where $n$ is the number of active features that we are going to inactivate.

$$\tilde{H}_{x_t,Y^+,x_t,Y^+}=H_{x_t,Y^+,x_t,Y^+}-H_{x_t,Y^+,Y^0}H^{-1}_{Y^0,Y^0}H_{Y^0,x_t,Y^+}$$

What we need as $H_t^1$ should be as follows. Note that dimension of $H_t^1$ is $3(N+1)\times3(N+1)$ where dimension of $x_t$ is $1\times3$ and $N$ is the number of all features($Y^+,Y^0,Y^-$), and $"0"$ here means zero matrix that has appropriate dimension.
$$H_t^1 = \left(\begin{array}{cc}
\tilde{H}_{x_t,Y^+,x_t,Y^+}&0\\0&0
\end{array}\right)\tag{2}$$

If we calculate equation(38) with using elements of (1), then
$$\begin{align}
H_t'&-H_t'S_{Y^0}(S_{Y^0}^TH_t'S_{Y^0})^{-1}S_{Y^0}^TH_t' \\
&=
\left(\begin{array}{cc}
H_{x_t,Y^+,x_t,Y^+}&H_{x_t,Y^+,Y^0}\\H_{Y^0,x_t,Y^+}&H_{Y^0,Y^0}
\end{array}\right)-
\left(\begin{array}{c}H_{x_t,Y^+,Y^0}\\H_{Y^0,Y^0}\end{array}\right)
H_{Y^0,Y^0}^{-1}
\left(\begin{array}{cc}H_{x_t,Y^+,x_t,Y^+}&H_{x_t,Y^+,Y^0}\end{array}\right)
\\
&=
\left(\begin{array}{cc}
H_{x_t,Y^+,x_t,Y^+}&H_{x_t,Y^+,Y^0}\\H_{Y^0,x_t,Y^+}&H_{Y^0,Y^0}
\end{array}\right)-
\left(\begin{array}{cc}
H_{x_t,Y^+,x_t,Y^+}H_{Y^0,Y^0}^{-1}H_{Y^0,x_t,Y^+}&H_{x_t,Y^+,Y^0}\\H_{Y^0,x_t,Y^+}&H_{Y^0,Y^0}
\end{array}\right)\\
&=
\left(\begin{array}{cc}\tilde{H}_{x_t,Y^+,x_t,Y^+}&0\\0&0\end{array}\right)\\
&=H_t^1
\end{align}$$

Equation (38) can be equalled with (2).

This is not exactly the answer to what I questioned, but this is ok for me.

Title: Sparcification of SLAM with SEIF (Sparse Extended Information Filter)

Body:
I am studying SLAM (Simultaneous Localization and Mapping) with textbook "probabilistic robotics".

I cannot understand well about Sparsification step, so I found original paper for that;
https://web.mit.edu/2.166/www/handouts/thrun_et_al_ijrr2004_seifs.pdf

According to this paper, information matrix for the distribution of all variables without passive features can be written as equation (38), this is ok for me, but how equation(40) can be lead ??

It says that using the matrix inversion lemma like annotated (39), but what is "B" matrix here and why has it gone from resulting equation (40) & (41) ...?

Anyone help ??


问:
What autopilot to purchase APM 2.6 or PixHawk?
I'm a newbie in UAV stuff, your advice would be very helpful, i want to start mapping using fixed wing UAV, but my main choice was APM 2.6, but after some researches, i found that APM 2.6 won't be actively maintained in the future because the future releases will be PixHawk.

i wonder if i should choose APM 2.6 for its stability, on the other side i don't see the benefits of Pixhawk apart having long time support. or being a newbie i should start with something experimental like APM 2.5.2 (cheap chinese version for APM).

Thanks in advance

答:
Pixhawk is released very recently so there is a possibility of bugs associated with software and hardware  which will be fixed as more people use it, report bugs and correct them. APM 2.6 is very much ready to go with lots of reviews and support available online.

So if you wish to be in this field for significantly long time then I would suggest go for Pixhawk. If you are very new with system and also planning to tweak around with code then APM 2.6 is good start.

Chinese version of APM 2.5.2 is surely cheap option to start but beware as there is no warranty on hardware you get.


问:
No difference between UKF and EKF for SLAM
I built EKF and UKF SLAM algorithms. The problem is that I expected to see a difference because of the more precise approximation of the system in the UKF.

Here's a screenshot from the estimated path from both filters [sorry about the German]:

As you can see, the differences are very minor and sum up to an equal performance of both filters within the mean errors for every estimated state. I thought increasing the system noise for a bigger uncertainty would make the advantages of the UKF clearer but it didn't make a difference.

UKF Parameters:
$\alpha$: 0.01,
$\kappa$: 0,
$\beta$: 0.

My question is, what could be the reason for the similiar results of both filters and how can we enhence the UKF performance?

Thanks.

Nvm, the result improved with UKF parameters from a backup. The parameters where to low. New Parameters:
$\alpha$: 0.5,
$\kappa$: 25,
$\beta$: 2.

New Result

Mean error X-Position

EKF 0.7572

UKF 0.2501

mean error Y-Position

EKF 0.4535

UKF 0.1708

Mean error orientation

EKF 0.0112

UKF 0.0083

答:
The EKF is a first-order approximation, which is achieved by linearizing the system about the current state estimate (i.e., the mean). In some cases, the EKF is not stable due to nonlinearities. For example, if the system is highly nonlinear, then the EKF might not work well.

In contrast, the UKF uses the unscented transform , which is a function to estimate a nonlinear transformation applied to a probability distribution. Ideally, the exact nonlinear transformation would be used, but often is not possible or not practical.

The main benefit in using the UKF instead of the EKF is to handle nonlinearities, but the EKF is often less computationally expensive as the Jacobians can be computed analytically offline. If the system is linear, the UKF provides no benefit (as far as I know), and if the system is close to linear, the result of the EKF and UKF will be similar.

I suspect that the linearization is adequate, so the UKF just doesn't provide much benefit.


问:
How do you send multiple data bytes to Irobot Roomba via python serial
So I'm trying to send commands to my Roomba Discovery via python serial and it works fine as long as it only requires the command opcode. The commands that require additional data bytes (like specific movement or music) don't seem to be working. It's an old roomba, however, I do not believe that is the issue as I am able to use Java based applications like RoombaMidi2 from hackingroomba.com. The code below works fine to have the roomba clean for 5 seconds then sleep:

```<code>import serial
import time
import struct

ser = serial.Serial("/dev/ttyUSB0", 57600)

ser.write(bytes([128])) # 128: start command
ser.write(bytes([131])) # 131: Safe Mode
time.sleep (0.25)

ser.write(bytes([135])) # 135: clean command
time.sleep (5)

ser.write(bytes([133])) # 133: puts robot to sleep
ser.close()
</code>```

But if I want to do a move command it doesn't seem to work. I've tried:

```<code>ser.write(bytes([137]))
ser.write(bytearray([255, 56]))
ser.write(bytearray([1, 244]))
</code>```

No error, but it doesn't do anything. I've also tried sending it as 1 byte array:

```<code>ser.write(bytearray([137, 255, 56, 1, 244]))
</code>```

Any idea on what I'm doing wrong?

答:
I'm not sure if/how pyserial works with a bytearray, but the way it is typically done is with the struct library.  Here is some sample code:

```<code>import serial
import struct

ser = serial.Serial("/dev/ttyUSB0", 57600)

# compute left and right wheel velocities
right_vel = int(velocity + (rotation/2))
left_vel = int(velocity - (rotation/2))

cmd = struct.pack(">Bhh", 145, right_vel, left_vel)

ser.write(cmd)
ser.flush()
</code>```

I know the ">Bhh" thing can look scary, but it is simply specifying the format of the bytes to transmit over the wire.  Here, you are saying this:

> The bytes will be in big-endian format

B The first thing transmitted (145) is an "unsigned char"

hh The next two things transmitted are "signed short integers".  Note that these are 2 bytes long each.

See this tutorial for more info on using Python to control Create2: Python Tethered Driving for Create 2

Body:
I'm not sure if/how pyserial works with a bytearray, but the way it is typically done is with the struct library.  Here is some sample code:

import serial
import struct

ser = serial.Serial("/dev/ttyUSB0", 57600)

# compute left and right wheel velocities
right_vel = int(velocity + (rotation/2))
left_vel = int(velocity - (rotation/2))

cmd = struct.pack(">Bhh", 145, right_vel, left_vel)

ser.write(cmd)
ser.flush()

I know the ">Bhh" thing can look scary, but it is simply specifying the format of the bytes to transmit over the wire.  Here, you are saying this:

> The bytes will be in big-endian format

B The first thing transmitted (145) is an "unsigned char"

hh The next two things transmitted are "signed short integers".  Note that these are 2 bytes long each.

See this tutorial for more info on using Python to control Create2: Python Tethered Driving for Create 2


问:
What type of electric motor and speed-controlled circuit do I use to bounce a hanging, 5 pound weight? (it's for a Halloween decoration)
I'm trying to make a roughly 5 pound, hanging halloween decoration bounce on a string from about 1-3 times per second, preferably at variable speeds if I can.

I've looked up a simple DC motor circuit with a potentiometer and 3 power transistors CTC-1351 in parallel to act as a speed controller (picture attached), but wanted to verify the right type/powered motor, as well as the correct transistors to be able to lift small weights.

(I'm going to tie a string to a bent metal rod attached to the motor shaft to achieve the oscillating bounce.)

[

答:
I can see several issues with your design. The motor control is just one.

Gearing. For 1-3 bounces per second, that's 60-180 RPM.  Your motor probably goes something like 1750 RPM.  As jsotola commented, you'll need to add a gearbox, or else replace the motor with one that has an integrated gearbox ("gear motor"). You won't be able to reliably control a motor at less than 1/10 its rated speed -- it'll stall, or groan but not move, depending on how you hold your mouth when turning the knob :-).

Resonance. If the weight is to be oscillating on the spring, your system will have a natural frequency. Making the weight heavier, or using a longer or wimpier spring will be slower oscillation; lighter weight or stiffer/shorter spring will be faster.  You should plan on experimenting with springs to get the right bounce speed.

The up-and-down drive from the motor should match the mechanical resonance.  Adjusting motor speed to drive it off-resonance will still sort of work, but not nearly as well. If you really want variable frequency you'll need have some way to adjust the spring length, or pick up and shed weight on the fly, or something. If you drive it at resonance, the resonance will mean the motor doesn't have to do all the heavy lifting. Maybe you could even get away with a smaller motor.

PWM. Controllers for motors as beefy as the one in your picture typically use pulse-width modulation. Your linear setup with pot and transistors is attractively simple and intuitive. But consider that all the electric power that your motor isn't drawing will have to be dissipated as heat by those poor heat-sink-less transistors. A PWM setup, instead of dissipating the power, in effect turns it off for some fraction of the time, many times a second. It will be considerably more complicated, though -- probably including something like an Arduino. Keep those transistors, though, they might yet serve as the switching element.

Crank, or cam. (You only asked about the motor and controller, so this is just kibitzing.) A crank, shaped like the L-shape part that connects a bicycle pedal to the gears, would convert rotary motion from the gearbox shaft into up&down motion of the 5-pound decoration.  If you drive it at mechanical resonance, the weight will bounce on the spring higher than just the crank throw. OTOH you might get interesting behavior by driving with a cam shaped to do something besides sinusoidal -- like a gradual rise followed by a sudden drop.


问:
does lidar sensor output data have spatial locality?
i have a question about the output of lidar sendor (like velodyne vlp-16, etc)

Is there any spatial or temporal locality for output data which is from lidar sensor?
Does the produced output data from lidar sensor are stored in memory position sequentially or randomly?
(which means that if a data from 0x000 and 0x001 point are spatially or temporally related.)

I see that lidar output data is obtained by spherical coordinate system and converted to cartesian coordiate system.
(FIG 9-1, https://greenvalleyintl.com/wp-content/uploads/2019/02/Velodyne-LiDAR-VLP-16-User-Manual.pdf)

And there is a driver code to make un-ordered point cloud data to ordered data
(https://github.com/ros-drivers/velodyne/blob/master/velodyne_pointcloud/include/velodyne_pointcloud/organized_cloudXYZIRT.h)

So, i guess lidar sensor is rotating 360' and sequentially produce the output and save them to certain memory location. So, is that possible to presume that memory address could give us hint for point cloud data information even before the ordering process?

Thank you.
If i have some lidar sensor, then this question could be solved easily. but i don't have one.

答:
You can’t assume the order in memory corresponds to a particular point in space. The Velodyne you are referring rotates to collect data to make a point cloud, but not necessarily in the order that is intuitive without understanding the hardware.

However, the driver of the sensor may have some particular ordering in memory corresponding to the spherical coordinates of the points, but you would need to check the documentation.


问:
Inner current controller benefits
I am currently working on a system with a BLDC motor attached to a non linear spring on which a user can apply a force. Meaning the torque applied on the motor's output is most of the time unknown.

What matters for my application currently is the position of the motor regarding its reference.
I control this motor using a DRV8323 chip and a single PWM as input to this chip. The driver chip is doing the phase commutation itself thanks to Hall sensors.

The control strategy that I currently use is the following :

Given a reference position as input to a PID

The PID compute the position error and gives as output the duty cycle of the PWM send to the DRV8323 chip. (here there is an implicit conversion from position to speed but it works)

It happened to me already that the motor coils burnt because of current going crazy because of bad configuration or mechanical problems. Also, I saw in a lots of article that BLDC motor are most of the time control with nested position > speed > current loops.

So my question are the following :

What would be the benefits of implementing this full nested control architecture for the control compared to my current implementation ? Taking into consideration that what I want to control is the motor position but overshoot, acoustic noise and heat generation are also a concern.

Could a simple if condition on a specific current thresold would be enough to protect the hardware from overccurent accident ?

Thank you in advance for your help !!

答:
What would be the benefits of implementing this full nested control architecture for the control compared to my current implementation

Textbooks are always a great source of information!

Reference: "Feedback Systems - An Introduction for Scientists and Engineers", Karl Johan Astrom, Richard M. Murray.

Could a simple if condition on a specific current thresold would be enough to protect the hardware from overccurent accident

Yes!

Title: Inner current controller benefits


问:
Can a 6 DOF robot have multiple inverse kinematics solution with a constrained rotation/orientation
I trying to understand how manipulators robot works (6 DOF)

I would like to know if the inverse kinematics (IK) solution give only one or multiple solution if we include the rotation (3x3 matrix) of the TCP ?
In others words, can we have the same TCP position and orientation for multiple configuraiton angles of the robot ?

I know that forward kinematics (FK) give only 1 solution (which seems logic) but IK is way more difficult to represent.

Thank in advance !

答:
can we have the same TCP position and orientation for multiple configuraiton angles of the robot

Sure!

The number of DOF of a manipulator tells us if it's possible or not to reach a pose (position + orientation) in the operational space at hand (usually 6-dimensional).

Examples

If we work in a 6D operational space, then we are required to have at least a 6-DOF manipulator to reach a full pose (when this pose is within the allowed range).

If we deal with a planar manipulator and we are interested in attaining only a target position (i.e. no orientation), then we need a 2-DOF manipulator at least.

Same as above but now we include the orientation of the gripper; it follows that we need at least a 3-DOF manipulator.

Notice how I've highlighted the term "at least".

On the other hand, nothing is said about how many joint configurations can resolve the single given target pose.

In general, we have many joint configurations! A clear example of that is provided by a 6-DOF manipulator that can easily move all its joints while keeping the position as well as the orientation of the tip fixed. The latter can be achieved by resorting to the so-called null-space projection method.


问:
Depth camera pixel values to 3D coordinates
I have a robotic arm 6-DOF and an Intel RealSense depth camera. I want to go from pixel values to 3D world coordinates, is it possible with eye-in-hand calibration? If yes can you guide me on how to perform this calibration?
I have done some study on my own but have a lot of doubts.</p>

答:
The steps are pretty easy to implement!

The Realsense provides you with the depth $d$ corresponding to the pixel $(u,v)$. Knowing from the forward kinematics of the robot arm the $4 \times 4$ homogeneous transformation $\mathbf{T}$ from the root reference frame to the 3D frame of the camera attached to the end-effector, the 3D coordinates of the point $\mathbf{p}$ projected in the pixel at hand are:

$$
\mathbf{p} =  \mathbf{T} \cdot \left( \frac{d}{f} \cdot \left( u-\frac{w-1}{2} \right), \; \frac{d}{f} \cdot \left( v-\frac{h-1}{2} \right), \; d, \; 1 \right)',
$$

where the resolution of the camera is $w \times h$ pixels, while $f$ is the camera focal length that you can retrieve from the Realsense API.

Clearly, $\mathbf{T}$ depends on the current configuration of the arm joints.

Bear in mind that the standard reference frame of the camera has the z-axis orthogonal to the image plane and pointing outward, the x-axis pointing rightward, and the y-axis pointing downward as specified by the pinhole camera model.


问:
How Can I Measure the torque applied by a servo motor?
I believe that there must be a tool that can measure $oz-in$ of torque.  I do not trust what the servo manufacturers state on their site for torque values, so I want to test them for myself.

Can anyone suggest a tool which I can use to do this?  I have used fishing scales before, but I need something more sensitive than that and my units are pretty small, such as around $20\; oz-in$.

Thanks.

答:
I'm sure you know that torque is rotational force about an axis. It is a combination of distance from the center of the shaft and the force. It seems that you are being suggested all kinds of fancy tools (no disrespect to anyone), how about keeping it simple and cheap (and a bit inaccurate)? put tape around the shaft to grow the diameter (make it tight so it doesn't compress under the next step). Then put a string and a weight (pennies in a plastic bag). When your motor stalls, measure the weight of the pennies, and multiply it by the radius of the shaft. Since tape doesn't weigh much, and it's offset by the counterweight on the other side, it shouldn't skew your readings too much. It's one way to what you are looking for.

You didn't specify this in questions, but I am assuming you want starting torque, which is the highest anyway, and goes down with speed.

Good luck.


问:
Is this encoder error expected?
I'm working with the iRobot Create 2. When I read the encoder count and sum it for total, I'm able to do so without apparent error. I've used this to 'successfully' estimate position combining with heading from a gyro. However, when I try to estimate velocity from the encoder count, the signal seems pretty noisy.

I'll get maybe 10-15 values that are expected, and then a random outlier or two. For example: If I set the wheels to 100 mm/s and calculate the change of time between cycles (which also appears to agree with the sample time i've set of 0.017s), maybe 10-14 values will be within +-10 of 100mm/s, but then I'll get a one or two values that differ by +-50-100 mm/s.

Is this normal and I'll need to filter for a better estimation, or could there be a possible timing issue? The only thing that really impacts the program speed is the checksum used to initially discard corrupted packets.

答: I had this problem in my project.  If you are sampling very quickly, then sometimes you get zero ticks and sometimes one.  That causes a lot of noise.  The solution is to only calculate velocity after a sampling time AND minimum number of ticks has passed.  I do that in this project.  See discussion in docs; https://github.com/Ezward/Esp32CameraRover2/blob/master/docs/wheel_encoders.md#reducing-noise-in-velocity-measurements</p>

Title: Is this encoder error expected?


问:
3D reconstruction of a moving object from two camera video stream
I have two synchronized video streams of a moving deformable object from two different cameras (same brand/model type) but two different views.

How can I do the 3D reconstruction of this moving object?

The 3D reconstruction needs not be real-time. I already have done the capture and need to do this as a postprocessing step.

A few more details:

My camera is FLIR SC8000 camera which has thermal videography. The current format of video is sfmov (SAF movie) which has 2 bytes (RGB+ count values -as for thermal aspect) and can also be converted to RGB (1 byte per pixel) too in WMV format. I am also able to convert the video stream using th ResearchIR Max+HSDR software to a series of lossless JPEG images that are called Radiometric JPEG (2 bytes per pixel).

答: If the cameras are stationary it should work to use Structure from Motion (https://github.com/mapillary/OpenSfM). Failing that the cameras are stationary you could attempt to create a factor graph in gtsam to solve for the camera movement, object movement, and projections between the cameras and object. See a simple SFM setup here: https://gtsam-jlblanco-docs.readthedocs.io/en/latest/StructureFromMotion.html or here http://nghiaho.com/?p=2379</p>


问:
Torque required to rotate arm with mass at end
I have to calculate the required torque to rotate a point mass of 15N on the end of an 1.2m long arm which I have calculated to be 10kg in mass. The rotation must have a constant angular velocity of 50rad/s. I am just wondering how to calculate the required torque at the joint. I am also wondering how to deal with the inertia and acceleration of the point mass and the rotating arm which relates to torque required. Any help with calculations for this problem would be greatly appreciated.</p>

答:
First let's consider the peak torque required, important for sizing the motor.

The peak torque will be max when the arm is horizontal, rising.  It will be the sum of torques due to the point mass plus that of the arm itself.

Your point mass applies a torque of 15N * 1.2m = ____ N-m.

If the arm's mass is 10kg, its weight is ____ N.

You can model the arm as a point mass at the center of mass.

If it is uniform, the center of mass is at the center of the arm, 0.6 m.

The arm applies a torque of [arm weight] N * 0.6 m = _____N-m.

As long as the actuator can apply torque greater than that, the machine will (eventually) accelerate to the required angular velocity.

Now let's move on to the instantaneous torque, as a function of time, in order to maintain a constant angular velocity.

Let theta be the angle the arm makes with the up-vertical (clock hands at midnight). The moment arm for each of the above torques is proportional to sin theta. So the instantaneous torque will be a sinusoid. Note that half the time the actuator is lifting the weight and the other half it is holding back the weight to keep it from falling freely. This is consistent with sin theta being negative half the time.


答:
What would be the benefits of implementing this full nested control architecture for the control compared to my current implementation ?

There are lots of them, but from the sounds of things the two biggest advantages would be "automatic" current limiting and the inner current loop would present a more linear plant to the outer position or velocity loop.

Could a simple if condition on a specific current thresold would be enough to protect the hardware from overccurent accident ?

If you mean, could you just use the loop you have and cut the power if a limit was exceeded?  Yes, this would protect hardware, but it would be very difficult to smoothly control either the current or the overall plant, because any time the current limit was exceeded the plant would -- from the perspective of the outer controller -- change behavior.

If you mean could you incorporate a current limit by using "if" statements to limit the current command -- yes, by all means, in a computerized control system that's how you do it.

Title: Inner current controller benefits

Body:
I am currently working on a system with a BLDC motor attached to a non linear spring on which a user can apply a force. Meaning the torque applied on the motor's output is most of the time unknown.

What matters for my application currently is the position of the motor regarding its reference.
I control this motor using a DRV8323 chip and a single PWM as input to this chip. The driver chip is doing the phase commutation itself thanks to Hall sensors.

The control strategy that I currently use is the following :

Given a reference position as input to a PID

The PID compute the position error and gives as output the duty cycle of the PWM send to the DRV8323 chip. (here there is an implicit conversion from position to speed but it works)

It happened to me already that the motor coils burnt because of current going crazy because of bad configuration or mechanical problems. Also, I saw in a lots of article that BLDC motor are most of the time control with nested position > speed > current loops.

So my question are the following :

What would be the benefits of implementing this full nested control architecture for the control compared to my current implementation ? Taking into consideration that what I want to control is the motor position but overshoot, acoustic noise and heat generation are also a concern.

Could a simple if condition on a specific current thresold would be enough to protect the hardware from overccurent accident ?

Thank you in advance for your help !!


问:
How to keep a sensor pointed downward
I am using LIDAR to measure a robot's altitude. The robot's orientation relative to the ground is dynamic; i.e. the XY plane tilts relative to the Z axis. I would like the LIDAR to remain pointed close to perfectly downward as the robot tilts.

Some details: the tilts can be large, up to 30 degrees, but are short lived; the robot largely corrects its orientation within a few seconds.

Note, I have considered measuring the robots angle to trigonometrically derive altitude. I have also considered barometric pressure altimeters, but those do not have the reaction time I need.

Apologies if anything here was unclear, thank you.

答:
Your LIDAR will need some active stabilization. Under gravity alone it will sway like a pendulum.

You could start with a web search for "servo gimbal". Resulting hits show complete devices, arduino projects, tuning strategies, hobbyist guides, etc., for drones, copters, UAVs, etc. Your LIDAR mount might benefit from work done for mounting cameras. That suggests a look at camera pan-tilt setups, which sort of combine gimbal and servo motors.

The solution, whether manufactured or DIY, will have a gimbal mount, an accelerometer, servo motors, and a microcontroller.

The gimbal is like a 2 degree of freedom mounting bracket. Your LIDAR would be rigidly fastened to the moving part of the gimbal, and the gimbal's base would be rigidly fastened to your airframe.

The accelerometer, mounted to the LIDAR, measures the tilt (i.e. 1 g, pointing down). It'll be only approximate if your airframe is being chaotically accelerated by violent wind gusts, or in freefall!

The two servo motors tilt the gimbal in the two degrees of freedom. Model airplane servos conveniently bundle motor, geartrain, and control electronics in one little package.

The microcontroller provides the smarts to tie it all together. Its basic control algorithm is pretty simple. Continuously, it reads the "g" vector from the accelerometer, and commands the servos to move the gimbal (hence LIDAR) to counteract any tilt. Fancier coding can try to deal with anomalous responses, or respond to commands from the transmitter.

If you go the DIY route, the arduino is popular and has a broad, supportive user community, but it is by no means the only option (or necessarily the best).  Accelerometers are pretty cheap and light. Servos are engineered to be light.

Title: How to keep a sensor pointed downward


答:
Measuring the force applied to a measured moment arm will give you what is needed to compute the torque.

I think the simplest way is to use a servo horn and a kitchen scale (if you already have one).

On the servo horn, measure the distance from the axis to the mounting hole you'll use. When that arm of the servo horn is horizontal, your measured distance will be the moment arm for the torque.

To measure the force, to use an electronic kitchen scale to measure how much lighter a weight gets when the servo tries to lift it.

Choose a weight a little too heavy for the servo to lift. With the weight on the scale, use string or something and rig the servo to try to lift it at "arm's length" -- that is, with the servo horn arm horizontal. With the weight on the scale, but servo not lifting, zero (tare) the scale.  As the servo struggles to lift the weight, whatever force it exerts will reduce the scale's measured weight, directly reading the force you want, albeit negative.

If you are measuring your only servo, consider that some servo designs cannot tolerate stall. Overheating and broken gears are the symptoms of engineering to minimize weight and manufacturing cost.

Title: How Can I Measure the torque applied by a servo motor?

Body:
I believe that there must be a tool that can measure $oz-in$ of torque.  I do not trust what the servo manufacturers state on their site for torque values, so I want to test them for myself.

Can anyone suggest a tool which I can use to do this?  I have used fishing scales before, but I need something more sensitive than that and my units are pretty small, such as around $20\; oz-in$.

Thanks.


问:
Docker on WSL2: Dockerfile: how to test whether ROS gazebo can connect to already working X server (using its X11 display on Windows)?
I had the following errors and warnings in a ROS project. They showed up using docker-compose or when running a mere container from the image, which strangely had worked once somehow but then later did not open the RViz anymore:

```<code>process[rviz-3]: started with pid [124]
QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-root'
qt.qpa.screen: QXcbConnection: Could not connect to display
Could not connect to any X display.
</code>```

or:

```<code>talker_1      | [Err] [RenderEngine.cc:725] Can't open display:
talker_1      | [Wrn] [RenderEngine.cc:93] Unable to create X window. Rendering will be disabled
talker_1      | [Wrn] [RenderEngine.cc:293] Cannot initialize render engine since render path type is NONE. Ignore this warning ifrendering has been turned off on purpose.
listener_1    |  * /nodes/slam_QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-root'
listener_1    | qt.qpa.screen: QXcbConnection: Could not connect to display
listener_1    | Could not connect to any X display.
listener_1    | [rviz-2] process has died [pid 64, exit code 1, cmd /opt/ros/melodic/lib/rviz/rviz -d /MYPROJECT/src/MYPROJECT_common/config/config.rviz __name:=rviz __log:=/root/.ros/log/8a57a040-8bf6-11eb-bfa4-0242ac120003/rviz-2.log].
</code>```

or:

```<code>talker_1      | [Err] [CameraSensor.cc:112] Unable to create CameraSensor. Rendering is disabled.
</code>```

or:

```<code>WARNING: Unable to locate/open X configuration file.
</code>```

or:

```<code>WARNING: Unable to parse X.Org version string.
</code>```

or:

```<code>Package xorg-server was not found in the pkg-config search path.
Perhaps you should add the directory containing `xorg-server.pc'
to the PKG_CONFIG_PATH environment variable
No package 'xorg-server' found
Option "AllowEmptyInitialConfiguration" "True" added to Screen "Screen0".
</code>```

or:

```<code>ERROR: Unable to write to directory '/etc/X11'.
</code>```

Because of all of these errors and warnings, it slowly and all of a sudden caught my mind that it might be about that X / X11 :)...

I left my project aside since the errors and warnings could have been caused by the image itself. Instead, I started from scratch, using a general guide with an easy image. I am following Running ROS with GUI in Docker using Windows Subsystem for Linux 2 (WSL2) about how to setup the X server on Windows and use it as the output of the ROS gazebo visualization. In order to automate the setup test and have a better overview, I put it in this Dockerfile:

--- Start of the Dockerfile ---

```<code># Start this Dockerfile by going to the Dockerfile's directory in terminal and enter
#docker build -t ros-test .

FROM osrf/ros:kinetic-desktop-full
#ARG HOSTNAME

RUN apt-get update && \
    apt-get install -y dbus

RUN apt-get install -y mesa-utils libgl1-mesa-glx

ENV LIBGL_ALWAYS_INDIRECT=0
# "host.docker.internal" only works in Docker Desktop, on WSL distro, you will need to run with either
# your Windows computer name (like "DESKTOP-1234567") or with your Windows computer IP "xxx.xxx.xxx.xxx", for example:
# docker run -it --name ros-test -e DISPLAY=xxx.xxx.xxx.xxx:0.0 -e LIBGL_ALWAYS_INDIRECT=0 osrf/ros:kinetic-desktop-full bash
ENV DISPLAY=host.docker.internal:0.0
#ENV DISPLAY=$HOSTNAME:0.0
#ENV DISPLAY=DESKTOP-1234567:0.0
#ENV DISPLAY=xxx.xxx.xxx.xxx:0.0

RUN bash -c "echo 'source /opt/ros/kinetic/setup.bash' >> ~/.bashrc; \
    source ~/.bashrc"
</code>```

--- End of the Dockerfile ---

Here are the steps how you could get the Dockerfile working on WSL2, no matter whether you use Docker Desktop or a Linux distro. It is put in tiny steps so that it can be followed by newcomers, I will not shrink it to its core since it might also help someone like this.

```<code># Download vcxsrv from https://sourceforge.net/projects/vcxsrv/
# install
# start XLaunch.exe (Desktop link)
# choose next (multiple windows, display number -1)
# start no client
# (check Clipboard, this is checked by default), uncheck "Native opengl", check "Disable access control"
# finish without saving the configuration

# start container from image with:
#docker run -it --name ros-test -e DISPLAY=host.docker.internal:0.0 -e LIBGL_ALWAYS_INDIRECT=0 osrf/ros:kinetic-desktop-full bash
#docker run -it --name ros-test -e DISPLAY=xxx.xxx.xxx.xxx:0.0 -e LIBGL_ALWAYS_INDIRECT=0 osrf/ros:kinetic-desktop-full bash
#docker run -it --name ros-test -e DISPLAY=DESKTOP-1234567:0.0 -e LIBGL_ALWAYS_INDIRECT=0 osrf/ros:kinetic-desktop-full bash

# If the following commands do not work since there is already such a container name, you can
#docker stop ros-test
#docker rm ros-test
# If this is not possible and you are asked to force "(must force)", use
#docker rm ros-test -f
# before you go on.

# since environment variables are set already in the image, you can also start with:
# If you use Docker Desktop, `DISPLAY=host.docker.internal:0.0` is standard:
#docker run -it --name ros-test -e ros-test bash
# If you use a distro on WSL2, you need to find out your IP using ipconfig in Windows PowerShell (Drahtlos-LAN-Adapter WLAN: --> IPv4-Adresse  . . . . . . . . . . :):
#docker run -it --name ros-test -e DISPLAY=xxx.xxx.xxx.xxx:0.0 ros-test bash
# If you use a distro on WSL2, you can also ask for your hostname in Windows PowerShell by entering `hostname` and run it like this:
#docker run -it --name ros-test -e DISPLAY=DESKTOP-1234567:0.0 ros-test bash

# or if you want to see the content of all directories:
#docker run -it --volume :./:./ --name ros-test ros-test bash
#docker run -it --volume :./:./ --name ros-test -e DISPLAY=xxx.xxx.xxx.xxx:0.0 ros-test bash
#docker run -it --volume :./:./ --name ros-test -e DISPLAY=DESKTOP-1234567:0.0 ros-test bash

# If you have already run the container, but the bash is not there, or you want to start a second container in another terminal, use
#docker exec -it ros-test bash

# If the container is not running, but is already there (`docker ps -a`) start it again.
#docker start ros-test
#docker exec -it ros-test bash

# Open a second terminal with the same container so that you have two bash terminals open.
#docker exec -it ros-test bash

# In the first terminal:
#roscore
</code>```

And now comes the actual code line in question:

```<code># After roscore has started, start on a second terminal and enter:
#gazebo worlds/pioneer2dx.world
</code>```

This gazebo worlds/pioneer2dx.world does not open any window; it is already good that it does not throw any error either. The question remains: How can I test a gazebo visualization (no matter which) in the X11 window with the given image?

答:
This command opens the RViz in an X11 window of the Windows X server.

After roscore has started, start a second terminal and enter (according to http://gazebosim.org/tutorials?tut=ros_roslaunch) (you do not need to have the firewall deactivated for this to run, at least in my case):

```<code>roslaunch gazebo_ros empty_world.launch

#For killing the app, press Ctrl+C in the roscore terminal
</code>```

This setting also works in docker-compose, see this example which starts many containers in one go. The docker-compose now opens RViz in the X11 window on Windows X server with just one terminal command.

Body:
This command opens the RViz in an X11 window of the Windows X server.

After roscore has started, start a second terminal and enter (according to http://gazebosim.org/tutorials?tut=ros_roslaunch) (you do not need to have the firewall deactivated for this to run, at least in my case):

roslaunch gazebo_ros empty_world.launch

#For killing the app, press Ctrl+C in the roscore terminal

This setting also works in docker-compose, see this example which starts many containers in one go. The docker-compose now opens RViz in the X11 window on Windows X server with just one terminal command.


问:
Docker - Dockerfile: /bin/bash: catkin_init_workspace / catkin_make: command not found
I follow the guide of kinetic - Installing from source and put the steps in a Dockerfile.

At this point, I get an error, although I follow exactly the guide, and although it works in the bash of the container created on the image before these lines, and although Catkin command not found shows the same - in bash, not in Docker, though.

```<code>RUN /bin/bash -c 'echo "source /opt/ros/kinetic/setup.bash" >> ~/.bashrc &&\
    source ~/.bashrc &&\
    mkdir -p ~/catkin_ws/src &&\
    cd ~/catkin_ws/src &&\
    catkin_init_workspace &&\
    cd ~/catkin_ws &&\
    catkin_make'
</code>```

Commenting catkin_init_workspace out, it throws catkin_make: command not found, and keeping it, it throws catkin_init_workspace: command not found of course.

答:
In a Dockerfile, you cannot add the setup.bash to the .bashrc and then source the .bashrc. Instead, you want to source the setup.bash in one go:

```<code>RUN /bin/bash -c 'source /opt/ros/kinetic/setup.bash &&\
    mkdir -p ~/catkin_ws/src &&\
    cd ~/catkin_ws/src &&\
    #catkin_init_workspace &&\
    cd ~/catkin_ws &&\
    catkin_make'
</code>```

And the line

```<code>catkin_init_workspace
</code>```

can be removed, the container also works without it.

Half of the credits go to catkin_make command not found executing by a dockerfile.

Body:
In a Dockerfile, you cannot add the setup.bash to the .bashrc and then source the .bashrc. Instead, you want to source the setup.bash in one go:

RUN /bin/bash -c 'source /opt/ros/kinetic/setup.bash &&\
    mkdir -p ~/catkin_ws/src &&\
    cd ~/catkin_ws/src &&\
    #catkin_init_workspace &&\
    cd ~/catkin_ws &&\
    catkin_make'

And the line

catkin_init_workspace

can be removed, the container also works without it.

Half of the credits go to catkin_make command not found executing by a dockerfile.