HAPTIX Simulation Scoring Plugin Example - modulabs/gazebo-tutorial GitHub Wiki

Overview

์ด ํŠœํ† ๋ฆฌ์–ผ์€ Valero-Cuevas ๋“ฑ์ด 2003๋…„ ์ž‘์„ฑํ•œ "The strength-dexterity test as a measure of dynamic pinch performance"๋ผ๋Š” ์ œ๋ชฉ์˜ ๋…ผ๋ฌธ์—์„œ ์˜๊ฐ์„ ์–ป์€ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ๊ธฐ๋ฐ˜ ์†์žฌ์ฃผ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด ๋งŒ๋“ค์–ด์ง„ ์ƒˆ๋กœ์šด ์‚ฌ์šฉ์ž handsim world๋ฅผ ์‹ค์Šตํ•œ๋‹ค.

์ด ํŠœํ† ๋ฆฌ์–ผ์—์„œ๋Š” HAPTIX handsim ์„ค์น˜ ๋‹จ๊ณ„๋ฅผ ์ด๋ฏธ ์™„๋ฃŒํ–ˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋ฉฐ, ์‹œ๋ฎฌ๋ ˆ์ด์…˜ world API ํŠœํ† ๋ฆฌ์–ผ์„ ์™„๋ฃŒํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

Running the Simulation Example

๊ฐ€์ œ๋ณด hansim ์ฑ„์  ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์‹œ์ž‘ํ•˜๊ณ , ํ„ฐ๋ฏธ๋„์—์„œ ๊ฐ€์ œ๋ณด๋ฅผ ์‹œ์ž‘ํ•œ๋‹ค:

gazebo --verbose worlds/luke_hand.world

๊ธฐ๋ณธ์ ์œผ๋กœ Luke Hand ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์Šคํฌํ†ฑ ํ™˜๊ฒฝ์„ ์ œ๊ณตํ•œ๋‹ค.

์ด world์—๋Š” SimEventsPlugin์„ ์‚ฌ์šฉํ•˜์—ฌ ์•ž์„œ ์–ธ๊ธ‰ ํ•œ ์ž‘์—… ์™„๋ฃŒ ์ƒํƒœ๋ฅผ ์ถ”์ ํ•˜๋Š” ์Šคํ”„๋ง ์••์ถ• ํ…Œ์ŠคํŠธ๊ฐ€ ์žˆ๋‹ค.

Example Video

์•„๋ž˜๋Š” ํ‚ค๋ณด๋“œ์™€ spacenav options๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์›๊ฒฉ ์กฐ์ข…๋˜๋Š” ์‚ฌ์šฉ์ž world์˜ ์˜ˆ์ด๋‹ค:

IMAGE ALT TEXT HERE

์ด ๋น„๋””์˜ค์—๋Š”, ์† ์‹œ๊ฐํ™” GUI์˜ ์˜ค๋ฅธ์ชฝ ํ•˜๋‹จ์— 3๊ฐœ์˜ ์ž‘์—… ์™„๋ฃŒ ํ‘œ์‹œ ์ ์ด ์žˆ๋‹ค. ์™ผ์ชฝ ๊ฐ€์žฅ ์›ํ˜•์˜ ์ ์€ ๊ตฌ๋ถ€๋Ÿฌ์ง ์—†๋Š” ์ •ํ™•ํ•œ ์••์ถ•์„ ๋‚˜ํƒ€๋‚ด๋ฉฐ, ๋…น์ƒ‰์€ ๊ตฌ๋ถ€๋Ÿฌ์ง ์—†๋Š” ์••์ถ•ํ•˜๋ฉด ๋…น์ƒ‰์„ ๋‚˜ํƒ€๋‚ด๋ฉฐ, ์••์ถ•๋˜์ง€ ์•Š์•˜๊ฑฐ๋‚˜ ๊ตฌ๋ถ€๋Ÿฌ์ง€๋ฉด ๋นจ๊ฐ„์ƒ‰์„ ๋‚˜ํƒ€๋‚ธ๋‹ค. ์ค‘๊ฐ„์— ์›ํ˜• ์ ์€ ์••์ถ• ์œ ์ง€ ์‹œ๊ฐ„์„ ๋‚˜ํƒ€๋‚ด๋ฉฐ, ์Šคํ”„๋ง์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์••์ถ•๋˜์–ด 3์ดˆ ๋™์•ˆ ์œ ์ง€๋˜๋ฉด ํฐ์ƒ‰์—์„œ ๋…น์ƒ‰์œผ๋กœ ํฌ๋ฏธํ•ด์ง„๋‹ค. ์˜ค๋ฅธ์ชฝ ๊ฐ€์žฅ ์›ํ˜•์ธ ์ ์€ ์ž‘์—… ์„ฑ๊ณต์„ ๋‚˜ํƒ€๋‚ด๋ฉฐ ํฐ์ƒ‰์—์„œ ๋…น์ƒ‰์œผ๋กœ ๋ฐ”๋€๋‹ค.

์ฒ˜์Œ์—๋Š” ์„ธ ๊ฐœ์˜ ๋™๊ทธ๋ผ๋ฏธ๊ฐ€ ๋นจ๊ฐ„์ƒ‰-ํฐ์ƒ‰-ํฐ์ƒ‰์œผ๋กœ, ์Šคํ”„๋ง์ด ๋ฐฉํ•ด๋ฐ›์ง€ ์•Š์•˜์Œ์„ ๋‚˜ํƒ€๋‚ธ๋‹ค. ์Šคํ”„๋ง์ด ์ถฉ๋ถ„ํžˆ ์••์ถ•๋˜๊ณ  (1~10cm์˜ ์••์ถ• ๊ธธ์ด) ์Šคํ”„๋ง์€ ์ƒ๋Œ€์ ์œผ๋กœ ์ง์„ ์ด๋ฉด (์Šคํ”„๋ง ์ค‘์•™์—์„œ ๋น„ํ‹€๋ฆผ ์Šคํ”„๋ง ์กฐ์ธํŠธ๊ฐ€ 0.1 radian ๋ฏธ๋งŒ์„ ๋‚˜ํƒ€๋ƒ„), ์ฒซ ๋ฒˆ์งธ ์›์ด ๋…น์ƒ‰์œผ๋กœ ๋ฐ”๋€๋‹ค. ์ด ์„ฑ๊ณต์ ์ธ ์••์ถ• ํ•ด์ œ๋ฅผ ์œ„ํ•˜์—ฌ ํƒ€์ด๋จธ๊ฐ€ ์‹œ์ž‘๋˜๊ณ , ๋‘ ๋ฒˆ์งธ ์›์ด ํฐ์ƒ‰์—์„œ ๋…น์ƒ‰์œผ๋กœ ์‚ฌ๋ผ์ง‘๋‹ˆ๋‹ค. ํƒ€์ด๋จธ๊ฐ€ 3์ดˆ์— ๋„๋‹ฌํ•˜๋ฉด ๋‘ ๋ฒˆ์งธ ๋ฐ ์„ธ ๋ฒˆ์งธ ์›์ด ๋…น์ƒ‰์œผ๋กœ ๋ฐ”๋€Œ๋ฉฐ, ํ”„๋กœ๊ทธ๋žจ์€์ด ์‹œํ—˜์„ ์„ฑ๊ณต์ ์ธ ์‹œํ—˜ ์‹œํ–‰์œผ๋กœ ๊ฐ„์ฃผํ•œ๋‹ค.

Relevant Documentations

luke_hand.world์—์„œ ์ƒˆ๋กœ์šด libSimEventsPlugin.so ํ”Œ๋Ÿฌ๊ทธ์ธ ๋ธ”๋Ÿญ์„ ์ถ”๊ฐ€ํ•œ๋‹ค:

    <plugin name="SimEvents" filename="libSimEventsPlugin.so">
      <!-- spring 3 -->
      <event>
        <name>compressed_bottom</name>
        <type>joint</type>
        <model>spring_buckle_test_3</model>
        <joint>joint_bottom_1</joint>
        <range>
          <type>position</type>
          <min>-0.10</min>
          <max>-0.01</max>
        </range>
      </event>
      <event>
        <name>buckled_x</name>
        <type>joint</type>
        <model>spring_buckle_test_3</model>
        <joint>joint_1_2</joint>
        <range>
          <type>normalized_angle</type>
          <min>-0.1</min>
          <max> 0.1</max>
        </range>
      </event>
      <event>
        <name>buckled_y</name>
        <type>joint</type>
        <model>spring_buckle_test_3</model>
        <joint>joint_2_3</joint>
        <range>
          <type>normalized_angle</type>
          <min>-0.1</min>
          <max> 0.1</max>
        </range>
      </event>
      <!-- spring 2 -->
      <event>
        <name>compressed_bottom</name>
        <type>joint</type>
        <model>spring_buckle_test_2</model>
        <joint>joint_bottom_1</joint>
        <range>
          <type>position</type>
          <min>-0.10</min>
          <max>-0.01</max>
        </range>
      </event>
      <event>
        <name>buckled_x</name>
        <type>joint</type>
        <model>spring_buckle_test_2</model>
        <joint>joint_1_2</joint>
        <range>
          <type>normalized_angle</type>
          <min>-0.1</min>
          <max> 0.1</max>
        </range>
      </event>
      <event>
        <name>buckled_y</name>
        <type>joint</type>
        <model>spring_buckle_test_2</model>
        <joint>joint_2_3</joint>
        <range>
          <type>normalized_angle</type>
          <min>-0.1</min>
          <max> 0.1</max>
        </range>
      </event>
      <!-- spring 1 -->
      <event>
        <name>compressed_bottom</name>
        <type>joint</type>
        <model>spring_buckle_test_1</model>
        <joint>joint_bottom_1</joint>
        <range>
          <type>position</type>
          <min>-0.10</min>
          <max>-0.01</max>
        </range>
      </event>
      <event>
        <name>buckled_x</name>
        <type>joint</type>
        <model>spring_buckle_test_1</model>
        <joint>joint_1_2</joint>
        <range>
          <type>normalized_angle</type>
          <min>-0.1</min>
          <max> 0.1</max>
        </range>
      </event>
      <event>
        <name>buckled_y</name>
        <type>joint</type>
        <model>spring_buckle_test_1</model>
        <joint>joint_2_3</joint>
        <range>
          <type>normalized_angle</type>
          <min>-0.1</min>
          <max> 0.1</max>
        </range>
      </event>
    </plugin>

(์ฐธ๊ณ ๋ฅผ ์œ„ํ•ด SDF ํ˜•์‹์— ๋Œ€ํ•œ ์„ค๋ช…์„œ๊ฐ€ ์žˆ์œผ๋ฉฐ ์—ฌ๊ธฐ์—๋Š” SDF๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ world์™€ ๋ชจ๋ธ์„ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•œ ๊ธฐ๋ณธ ํŠœํ† ๋ฆฌ์–ผ์ด ์žˆ๋‹ค.)

๊ทธ๋ฆฌ๊ณ  ์ด์–ด์ง€๋Š” ์ฝ”๋“œ ๋ธ”๋ก์€ SimEventsPlugin ๋ฐ์ดํ„ฐ์˜ ๊ฒฐ๊ณผ๋ฅผ ํ•ด์„ํ•˜๋Š” ๊ฒƒ์ด๋ฉฐ HaptixGUIPlugin.cc์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

void HaptixGUIPlugin::ScoringUpdate()
{
  while(!quit)
  {
    if (this->hxInitialized)
    {
      // hardcoded, tasks 0, 1, 2 are the spring tests
      // hide if task id is greater than 2
      if (this->currentTaskId > 2)
      {
        this->springScoreItem[0]->setBrush(QBrush(QColor(255, 0, 0, 0)));
        this->springScoreItem[1]->setBrush(QBrush(QColor(255, 0, 0, 0)));
        this->springScoreItem[2]->setBrush(QBrush(QColor(255, 0, 0, 0)));
        this->springScoreItem[0]->setPen(QPen(QColor(153, 255, 0, 0)));
        this->springScoreItem[1]->setPen(QPen(QColor(153, 255, 0, 0)));
        this->springScoreItem[2]->setPen(QPen(QColor(153, 255, 0, 0)));
      }
      else
      {
        if (this->springCompressed && !this->springBuckled)
        {
          gazebo::common::Time compressDuration =
            gazebo::common::Time::GetWallTime() -
            this->springCompressedStartTime;
          if (compressDuration > this->springCompressedPassDuration)
          {
            // success! spring compressed correctly for 3 seconds.
            gzdbg << "task completed!\n";
            this->springScoreItem[0]->setBrush(QBrush(QColor(0, 255, 0, 255)));
            this->springScoreItem[1]->setBrush(QBrush(QColor(0, 255, 0, 255)));
            this->springScoreItem[2]->setBrush(QBrush(QColor(0, 255, 0, 255)));
          }
          else
          {
            double timeLeft = (this->springCompressedPassDuration -
                               compressDuration).Double();
            // spring compressed correctly, just a few more seconds...
            gzdbg << "compressed, great work! Please hold it for"
                  << " [" << timeLeft
                  << "] more seconds!\n";
            this->springScoreItem[0]->setBrush(
                QBrush(QColor(0, 255, 0, 255)));
            this->springScoreItem[1]->setBrush(
                QBrush(QColor(static_cast<int>(
                255*(timeLeft/this->springCompressedPassDuration.Double())),
                255, 0, 255)));
            this->springScoreItem[2]->setBrush(
                QBrush(QColor(static_cast<int>(
                255*(timeLeft/this->springCompressedPassDuration.Double())),
                255, 0, 0)));
          }
        }
        else
        {
          if (!this->springCompressed)
          {
            gzdbg << "spring not compressed, try squeezing it [some more]!\n";
            this->springScoreItem[0]->setBrush(QBrush(QColor(255, 0, 0, 255)));
            this->springScoreItem[1]->setBrush(QBrush(QColor(255, 0, 0, 0)));
            this->springScoreItem[2]->setBrush(QBrush(QColor(255, 0, 0, 0)));
          }
          else if (this->springBuckled)
          {
            gzdbg << "spring buckled, try to keep it straight!\n";
            this->springScoreItem[0]->setBrush(QBrush(QColor(0, 255, 0, 255)));
            this->springScoreItem[1]->setBrush(QBrush(QColor(0, 0, 255, 255)));
            this->springScoreItem[2]->setBrush(QBrush(QColor(0, 0, 255, 0)));
          }
          else
          {
            // user has not started compressing the spring
            // or the spring has bucked beyond tolerance.
            // gzerr << "Red!\n";
            // gzerr << "compressed [" << this->springCompressed
            //       << "] buckled [" << this->springBuckled << "]\n";
            this->springScoreItem[0]->setBrush(QBrush(QColor(255, 0, 0, 255)));
            this->springScoreItem[1]->setBrush(QBrush(QColor(255, 0, 0, 0)));
            this->springScoreItem[2]->setBrush(QBrush(QColor(255, 0, 0, 0)));
            this->springScoreItem[0]->setPen(QPen(QColor(153, 255, 0, 255)));
            this->springScoreItem[1]->setPen(QPen(QColor(153, 255, 0, 255)));
            this->springScoreItem[2]->setPen(QPen(QColor(153, 255, 0, 255)));
          }
        }
      }
    }
    usleep(100000);  // 10Hz max on scoring check
  }
}

/////////////////////////////////////////////////
void HaptixGUIPlugin::PollTracking

์„ธ ๊ฐœ์˜ ์›์˜ ์ƒ‰์„ ์ ‘์ด‰ ์„ผ์„œ ์‹œ๊ฐํ™”์— ์‚ฌ์šฉ๋˜๋Š” ์† ๊ทธ๋ฆผ์˜ ์˜ค๋ฅธ์ชฝ ์•„๋ž˜์ชฝ์œผ๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ ์ž‘์—… ์™„๋ฃŒ ์ƒํƒœ๋ฅผ ์ถ”์ ํ•˜๋„๋ก GUI ๋น„์ฃผ์–ผ์„ ์—…๋ฐ์ดํŠธํ•œ๋‹ค.HaptixGUIPlugin::ScoringUpdate ํ•จ์ˆ˜๋Š” ์ž์ฒด ์Šค๋ ˆ๋“œ์—์„œ ์ƒ์„ฑ๋œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์—ฌ๊ธฐ์„œ ์ฐธ๊ณ ํ•œ HaptixGUIPlugin::OnSimEvents ํ•จ์ˆ˜๋Š” SimEventsPlugin์— ์˜ํ•ด ๊ฒŒ์‹œ๋œ ์ƒํƒœ ์—…๋ฐ์ดํŠธ'๋ฅผ ๊ตฌ๋…ํ•ฉ๋‹ˆ๋‹ค.

์ฐธ๊ณ ๋กœ, Gazebo SimEvents API ๋ฌธ์„œ๋Š” ์—ฌ๊ธฐ์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํ”Œ๋Ÿฌ๊ทธ์ธ์€ ์‹œ๋ฎฌ๋ ˆ์ด์…˜๋œ ์Šคํ”„๋ง ์กฐ์ธํŠธ์˜ ๋ณ€ํ™”๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๊ธฐ ์œ„ํ•ด ๊ฐ€์ œ๋ณด topic /gazebo/sim_events๋ฅผ ๊ตฌ๋…ํ•œ๋‹ค.

โš ๏ธ **GitHub.com Fallback** โš ๏ธ