View on GitHub

introduction-to-ros

ROS (Robot Operating System) 入門

問題3解答例

問題3.1

以下をmain関数に追加します.

    ros::NodeHandle pnh("~");

    pnh.getParam("velocity", velocity);
    pnh.getParam("angular_velocity", angular_velocity);
    pnh.getParam("avoid_distance", avoid_distance);
    pnh.getParam("avoid_angle", avoid_angle);

全体像

#include <ros/ros.h>
#include <geometry_msgs/Twist.h>
#include <sensor_msgs/LaserScan.h>

ros::Publisher pub;
ros::Subscriber sub;

// variables
float velocity = 0.2;          // 直進速度
float angular_velocity = 1.57; // 回転速度
float avoid_distance = 1.0;    // これ以上近いと障害物とみなす距離
float avoid_angle = 60;        // 障害物を探索する範囲

void scanCallback(const sensor_msgs::LaserScan &msg)
{
    int center_index = msg.ranges.size() / 2;                                   // ロボット前方方向を表すインデックス
    int index_avoid_angle = avoid_angle * (M_PI / 180.0) / msg.angle_increment; // 障害物を探索する範囲に相当するインデックス
    int start_index = center_index - index_avoid_angle / 2;
    int last_index = center_index + index_avoid_angle / 2;

    bool detect_obstacle = false;
    std::string detect_side;

    for (int i = start_index; i <= last_index; i++)
    {
        float range = msg.ranges[i]; // 距離

        // 値が無効な場合の排除
        if (range < msg.range_min || // エラー値の場合
            range > msg.range_max || // 測定範囲外の場合
            std::isnan(range))       // 無限遠の場合
            ;

        // 値が有効である場合
        else
        {
            if (range < avoid_distance) // 近くに障害物がある場合
            {
                detect_obstacle = true;
                if (i <= center_index)
                {
                    detect_side = "right";
                }
                else
                {
                    detect_side = "left";
                }
                break;
            }
        }
    }

    geometry_msgs::Twist cmd_vel;

    if (detect_obstacle)
    {
        if (detect_side == "right")
        {
            // その場で反時計回り回転
            cmd_vel.linear.x = 0;
            cmd_vel.angular.z = angular_velocity;
            pub.publish(cmd_vel); // publish
        }
        else
        {
            // その場時計回り回転
            cmd_vel.linear.x = 0;
            cmd_vel.angular.z = -angular_velocity;
            pub.publish(cmd_vel); // publish
        }
    }
    else
    {
        // 直進
        cmd_vel.linear.x = velocity;
        cmd_vel.angular.z = 0;
        pub.publish(cmd_vel); // publish
    }
}

int main(int argc, char **argv)
{
    ros::init(argc, argv, "room_circuit_controller");
    ros::NodeHandle n;
    ros::NodeHandle pnh("~");

    pnh.getParam("velocity", velocity);
    pnh.getParam("angular_velocity", angular_velocity);
    pnh.getParam("avoid_distance", avoid_distance);
    pnh.getParam("avoid_angle", avoid_angle);

    pub = n.advertise<geometry_msgs::Twist>("/cmd_vel", 1);
    sub = n.subscribe("/scan", 1, scanCallback);

    ros::spin();
    return 0;
}

問題3.2

パラメータは一例です.

<?xml version="1.0"?>
<launch>
  <include file="$(find my_urdf_tutorial)/launch/robot_simulation.launch" />

  <node name="room_circuit_controller" pkg="room_circuit_controller" type="room_circuit_controller" output="screen">
    <param name="velocity" value="0.5" />
    <param name="angular_velocity" value="1.57" />
    <param name="avoid_distance" value="0.5" />
    <param name="avoid_angle" value="90" />
  </node>
</launch>