Skip to content

MOGI-ROS/Kogrob_object_detection

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

29 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Kogrob object detection

Bevezetés

Feladatunk egy olyan Turtlebot 3 segítségével megvalósított projekt létrehozása volt, amelyben a Turtlebotot lehelyezzük egy általunk készített világba, ő végighalad a téren az általunk definiált pályás és mi a ráhelyezett kamera képén neurális háló segítségével azonosítjuk az útjába kerülő tárgyakat/embereket.

A működés demonstrálása

Tartalomjegyzék

  1. Szükséges telepítések
  2. Turtlebot 3 Submodule
  3. Az alkalmazott neurális háló
  4. A világ
  5. Detektálás indítása
  6. Automatikus mozgatás
  7. Összefoglalás

Szükséges telepítések

Mi a fejlesztéseket Ubuntu 20.04 alatt végeztük wsl2 környezetben.
Első lépésben szükségünk van a ROS Noetic full desktop verziójának telepítésére. Emellett még kameraképre és Pythonra is szükségünk van a programot futtató gépre.

sudo apt install ros-noetic-desktop-full
sudo apt install ros-noetic-compressed-image-transport
sudo apt install python3-roslaunch

Et követően a neurális háló megfelelő futtatásához szükségünk van még néhány parancssoros műveletre:

pip install mxnet
pip install gluoncv
pip install opencv-python

Majd húzzuk be ezt a repositoryt a Catkin Workspaceünk src mappájába.

git clone https://github.com/akos-barta/Kogrob_object_detection Fontos megemlíteni, hogy a turtlebot3 repository submoduleként van hozzáadva a projekthez, ezért annak érdekében, hogy ez letöltésre kerüljön a futtató gépre, a parancssoron a Kogrob_object_detection/object_detection mappában a következő két parancsot kell egymás után lefuttatni:

git submodule init
git submodule update

Ezekután a turtlebot3 submodul is meg fog jelenni a könyvtárban.

.bashrc

Hajtottunk végre néhány módosítást a .bashrc fájlban is. Ezeket a következőképpen lehet implementálni egy új terminálból:

marci@DESKTOP-6TB9DMC:~$ cd ~
marci@DESKTOP-6TB9DMC:~$ nano .bashrc

Így megnyitjuk szerkesztésre a fájlt a nano szövegszerkesztőben. Legörgetve a fájl legaljára a következő sorokat kell implementálnunk:

# bash colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[1;36m'
GRAY='\033[0;37m'
LINEARBLUE='\033[1;34m'
# No Color
NC='\033[0m'

# CUDA stuff
export LD_LIBRARY_PATH=/usr/lib/cuda/lib64:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/usr/lib/cuda/include:$LD_LIBRARY_PATH
export PATH=$PATH:/usr/local/cuda/bin

# ROS workspace stuff
source /opt/ros/noetic/setup.bash
#WORKSPACE=~/catkin_ws/devel/setup.bash
WORKSPACE=~/catkin_ws/devel/setup.bash
source $WORKSPACE

# Automatic ROS IP config
IP_ADDRESSES=$(hostname -I | sed 's/ *$//g')
IP_ARRAY=($IP_ADDRESSES)
FIRST_IP=${IP_ARRAY[0]}

if [ "$FIRST_IP" != "" ];
then
    true
    #echo "There are IP addresses!"
else
    echo "Warning FIRST_IP var was empty:" $FIRST_IP
    echo "Maybe client is not connected to any network?"
    FIRST_IP=127.0.0.1
fi

export ROS_MASTER_URI=http://$FIRST_IP:11311
export ROS_IP=$FIRST_IP

echo -e "=============== ${YELLOW}NETWORK DETAILS${NC} ================="
echo -e ${GREEN}ACTIVE IP ADDRESSES:${NC}
echo $IP_ADDRESSES | tr " " "\n"
echo -e ${GREEN}SELECTED IP ADDRESS:${NC} $FIRST_IP

echo -e "============== ${YELLOW}ROS NETWORK CONFIG${NC} ==============="
echo export ROS_MASTER_URI=$ROS_MASTER_URI
echo export ROS_IP=$ROS_IP

# Chess simulation Gazebo path
export GAZEBO_MODEL_PATH=$GAZEBO_MODEL_PATH:~/catkin_ws/src/mogi_chess_ros_framework/mogi_chess_gazebo/gazebo_models/

# Turtlebot 3 stuff
export TURTLEBOT3_MODEL=burger
export GAZEBO_MODEL_PATH=$GAZEBO_MODEL_PATH:~/catkin_ws/src/Kogrob_object_detection/object_detection/gazebo_models
export LDS_MODEL=LDS-01

echo -e "================= ${YELLOW}ROS WORKSPACE${NC} ================="
echo -e ${GREEN}WORKSPACE SOURCED:${NC} $WORKSPACE | rev | cut -d'/' -f3- | rev
echo -e ${GREEN}GAZEBO MODEL PATH:${NC}
echo $GAZEBO_MODEL_PATH | tr ":" "\n" | sed '/./,$!d'
echo "================================================="

A beillsztést követően Ctrl+X majd a szerkesztő megkérdezi, hogy szeretnénk-e menteni a módosításokat, ekkor mentsük el ugyanazon a néven a .bashrc változtatásait.

Turtlebot 3 Submodule

Néhány apró módosítást végeztünk az eredeti turtlebot3 repositoryn, amelyeket a következőkben szeretnénk összefoglalni.

Kamera hozzáadása

A kamera hozzáadása 2 fájlt érint, a /turtlebot3/turtlebot3_description/urdf/turtlebot3_burger.urdf.xacro és a /turtlebot3/turtlebot3_description/urdf/turtlebot3_burger.gazebo.xacro fájlokat. Az előbbi a robot 3D modelljéhez adja hozzá a kameránk modelljét - egy kb. 8,6 fokkal megemelt piros kockát:

...
  <!-- Camera -->
  <joint type="fixed" name="camera_joint">
    <origin xyz="0.03 0 0.11" rpy="0 -0.15 0"/>
    <child link="camera_link"/>
    <parent link="base_link"/>
    <axis xyz="0 1 0" />
  </joint>

  <link name='camera_link'>
    <pose>0 0 0 0 0 0</pose>
    <inertial>
      <mass value="0.001"/>
      <origin xyz="0 0 0" rpy="0 0 0"/>
      <inertia
          ixx="1e-6" ixy="0" ixz="0"
          iyy="1e-6" iyz="0"
          izz="1e-6"
      />
    </inertial>

    <collision name='collision'>
      <origin xyz="0 0 0" rpy="0 0 0"/> 
      <geometry>
        <box size=".01 .01 .01"/>
      </geometry>
    </collision>

    <visual name='camera_link_visual'>
      <origin xyz="0 0 0" rpy="0 0 0"/>
      <geometry>
        <box size=".02 .02 .02"/>
      </geometry>
    </visual>

  </link>

  <gazebo reference="camera_link">
    <material>Gazebo/Red</material>
  </gazebo>

  <joint type="fixed" name="camera_optical_joint">
    <origin xyz="0 0 0" rpy="-1.5707 0 -1.5707"/>
    <child link="camera_link_optical"/>
    <parent link="camera_link"/>
  </joint>

  <link name="camera_link_optical">
  </link>
...

A másik fájl a kamera modelljéhez tartozó szimulált kamerát hozza létre:

...
  <!-- Camera -->
  <gazebo reference="camera_link">
    <sensor type="camera" name="camera">
      <update_rate>30.0</update_rate>
      <visualize>false</visualize>
      <camera name="head">
        <horizontal_fov>1.3962634</horizontal_fov>
        <image>
          <width>640</width>
          <height>480</height>
          <format>R8G8B8</format>
        </image>
        <clip>
          <near>0.1</near>
          <far>10.0</far>
        </clip>
        <noise>
          <type>gaussian</type>
          <!-- Noise is sampled independently per pixel on each frame.
               That pixel's noise value is added to each of its color
               channels, which at that point lie in the range [0,1]. -->
          <mean>0.0</mean>
          <stddev>0.007</stddev>
        </noise>
      </camera>
      <plugin name="camera_controller" filename="libgazebo_ros_camera.so">
        <alwaysOn>true</alwaysOn>
        <updateRate>0.0</updateRate>
        <cameraName>camera</cameraName>
        <imageTopicName>image</imageTopicName>
        <cameraInfoTopicName>camera_info</cameraInfoTopicName>
        <frameName>camera_link_optical</frameName>
        <hackBaseline>0.0</hackBaseline>
        <distortionK1>0.0</distortionK1>
        <distortionK2>0.0</distortionK2>
        <distortionK3>0.0</distortionK3>
        <distortionT1>0.0</distortionT1>
        <distortionT2>0.0</distortionT2>
      </plugin>
    </sensor>
  </gazebo>
...

Az alkalmazott neurális háló

Az általunk alkalmazott neurális háló a ssd_512_resnet50_v1_voc névre hallgat. A hálóról bővebb információt a Model Zoo keresztül lehet megtudni. A neurális háló működését az object_detector.py Python node valósítja meg.

net = model_zoo.get_model('ssd_512_resnet50_v1_voc', pretrained=True)

Parancs segítségével első futtatásra letölti a program a Model Zooból a szükséges súlyokat, ezért az első betöltés egy kicsit több időt fog igénybe venni. Ezt következően viszont ugyanezen parancs futásakor a már letöltött modelt fogja betölteni a program. Számunkra a program legérdekesebb része az AIprocess() függvény.

def AI_process(picture):
    # this is the object detector function
    # first of all we have to do some transformation on the image to be able to feed it to the network model
    image_rgb = cv2.cvtColor(picture, cv2.COLOR_BGR2RGB)
    pic = mx.nd.array(image_rgb)
    x, img = data.transforms.presets.ssd.transform_test(pic,short=512)
    class_IDs, scores, bounding_boxes = net(x)

    ax = utils.viz.plot_bbox(img, bounding_boxes[0], scores[0],
                             class_IDs[0], class_names=net.classes)
    
    ax.axis('off')
    plt.tight_layout()

    #the output of the model is a plot, so we have to save it as an image
    fig = ax.get_figure()
    fig.canvas.draw()
    img_data = np.frombuffer(fig.canvas.tostring_rgb(), dtype=np.uint8)
    img_data = img_data.reshape(fig.canvas.get_width_height()[::-1] + (3,))
    pil_img = Image.fromarray(img_data)

    output_file = 'output.jpg'
    pil_img.save(output_file, 'JPEG')

    return output_file

Ahol a függvény a kamera éltal beérkezett képet először átkonvertálja olyan formátumba, amit a neurális háló elfogad, a neurális háló elkészíti a detektált objektumokhoz tartozó jelölő téglalapokat, majd egyesíti azt az eredeti képpel és a kimenetet pedig vissaadja a függvényt meghívó processImage() függvénynek, ahol visszatranszformáljuk a képet és megjelenítjük azt a Detection ablakban.

A világ

roslaunch object_detection object_detection.launch

Mindehhez futtassuk először egy külön ternimálban a roscore parancsot parancs segítségével tudjuk futtatni az általunk készített világot.
Az első futtatás akár több percet is igénybe vehet a Gazebo modellek importálása és letöltése miatt.

alt text

Maga a object_detection.launch fájlban behívjuk az object_detection.world fájlt, illetve hozzáadjuk a robotot az általunk kívánt pozícióban.

<?xml version="1.0" encoding="UTF-8"?>
<launch>

    <!--Robot arguments-->
    <arg name="model" default="burger" doc="model type [burger, waffle, waffle_pi]"/>
    <arg name="x_pos" default="0.0"/>
    <arg name="y_pos" default="-3.0"/>
    <arg name="z_pos" default="0.0"/>

    <!-- Start up simulated world -->
    <include file="$(find gazebo_ros)/launch/empty_world.launch">
        <arg name="world_name" value="$(find object_detection)/worlds/object_detection.world"/>
        <arg name="paused" value="false"/>
        <arg name="use_sim_time" value="true"/>
        <arg name="gui" value="true"/>
        <arg name="headless" value="false"/>
        <arg name="debug" value="false"/>
    </include>
     
    <!-- TurtleBot3 -->
    <param name="robot_description" command="$(find xacro)/xacro --inorder $(find turtlebot3_description)/urdf/turtlebot3_$(arg model).urdf.xacro" />
    <node name="spawn_urdf" pkg="gazebo_ros" type="spawn_model" args="-urdf -model turtlebot3 -x $(arg x_pos) -y $(arg y_pos) -z $(arg z_pos) -param robot_description" />
    
</launch>

A világban legegyszerűbben a roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch futtatásával van lehetőségünk mozogni.

Detektálás indítása

Következő lépésben már futtathatjuk az object_detector.py nodeunkat egy külön terminálban, amely hatására felugrik két ablak az egyik tartamazza kameraképet, a másikon pedig a neurális háló által detektált objektumok lesznek megtalálhatók.
alt text
alt text

Összegezve ezen négy parancs egyidejű futtatása szükséges kézzel történő mozgatás esetén:

roscore
roslaunch object_detection object_detection.launch
roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch
rosrun object_detection object_detector.py

Automatikus mozgatás

Lehetőségünk van a robotot automatikusan is mozgatni a movement.py node futtatásával egy külön terminálban. Ennek hatására a robot egy általunk definiált pályán fog végighaladni. Maga a node a fizikából jól ismert s=v*t összefüggés segítségével számolja, hogy meddig kell ahhoz mozognia, hogy 1 méternyi utat megtegyen. A program. A Ctrl+C billenytű kombináció htására pedig a robot megáll és ezzel együtt a node is leállításra kerül. Viszont észrevettünk egy olyan hibát, ami folytán amennyiben kiadjuk a robotnak a gazebos környezetben, hogy végezzen egyenes vonalú egyenletes mozgást, ő mindig le fog térni a pályáról és egy bizonyos idő elteltével beáll a rácsvonalakra átlós irányú (45°-kal elforgatott) pályára. Viszont amennyiben alapból ilyen irányban indítjuk el a robotot, akkor képes egyenes vonalú egyenletes mozgást végezni. éppen ezért létrehoztunk egy object_detection_45degree.world fájlt, amely 45 fokban van elforgatva.
alt text

Az ehhez tartozó külön Launch fájl pedig az object_detection_45degree.launch Összesítve ebben az esetben is négy különböző parancs egyidejű, külön terminálban történő futtatására van szükség. Ezek:

roscore
roslaunch object_detection object_detection_45degree.launch
rosrun object_detection object_detector.py
rosrun object_detection movement.py

Összefoglalás

A tesztelések során azt tapasztaltuk, hogy a neurális háló viszonylag pontosan detektálta az útjába kerülő objektumokat. Természetes találkozhatunk anomáliákkal is a futtatás során. Példának okáért a kerekekkel rendelkező ágyat hajlamos a modell kocsiként felismerni. Ennek oka lehet az is, hogy a modell tanítása valós képpekkel történt, illetve abból is adódhat, hogy ilyen jellegő mintán nem lett betanítva.

alt text

Kísérlet jelleggel pedig elhelyeztünk az egyik szobában egy fehér dummyt, ugyanis kíváncsiak voltunk, hogy vajon őt emberként ismeri-e fel. A tapasztalataink azok voltak, hogy ebben az esetben a model nem ismerte fel egyáltalán semmit a szobában, amit helyes eredményként konstatáltunk.

alt text

Természetesen fejlesztési lehetőségként meg lehet említeni, hogy esetleg kipróbálhatnánk több különböző modellt ugyanezen feladat elvégzésére, illetve akár saját modellt is alkothatnánk, amely kifejezetten a szimulált környezetben lenne betanítva.

Fejlesztők

Barta Ákos
Hanák Zoltán
Horváth Marcell

RIP Balu

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Python 60.3%
  • CMake 39.7%