cvl-robot's diary

研究ノート メモメモ https://github.com/dotchang/

メモ:自分にとってだけの貴重な資料

本当に(すごく貴重な情報だと思っているけれど、)単なるメモです。

DC駆動アイリス制御が可能なレンズ、のその規格やコネクタなどの仕様
uniel-denshi.co.jp

swkagami.hatenablog.com
RoboticsやCVの論文を読んでいてわからなかった姿勢の表現をほぼ網羅的に解説。ありがたや。

qiita.com
金谷健一先生の本で紹介されている回転推定のアルゴリズムPython実装。ありがたや。

今日の本文

ATOM CAMを2台ほど買って試してみましたが、これスゲーわ。
ソフトウェアがよくできてます。
ただ、ハードウェアの素性が怪しい気はする。どこが作ってるんだろう?

スゲーわ。
honeylab.hatenablog.jp

自作系四足歩行ロボットが最近熱いようなので情報収集。

2020年1月~5月10日現在までにTwitterで見かけた四足歩行ロボットとそれに関連しそうで面白そうな記事まとめです。

Stanford Pupper
gigazine.net

pupperの前の。

V-Sido4脚

Spot Micro
spotmicroai.readthedocs.io
関連記事
qiita.com

QuRo M5Stack
github.com

オープンソース四脚ロボ「mjbots」

実験用ロボット 名前はまだないのかな?
60317206.blogspot.com

5000円の四足

ツキ

puppyC M5 stick
akiba-pc.watch.impress.co.jp

CHAMP
github.com

Unitree Laikagoのシミュレータ

Unitree A1


www.physical-computing.jp
128万円(税別)

ETH 研究なので趣旨が違うけど。

四足歩行ロボットに搭載可能なSLAM

Google モーションデータからロボットの動作モデル生成
jp.techcrunch.com

Google独学四脚

Cheetah mini CADモデル

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

平沢進的スポット


SPOT SDK

猫モーキャプ

脚機構

パンジャンドラム 四足ではないけれど。

すべての生物が逃げる動き 四足動物

2自由度の関節

人工筋肉

iRobot失敗の歴史

四足関係ないけど忘れないように。勉強しなきゃ。

新年度が始まったのに研究室に足らなかった物を整理するための物欲リスト2020

1.キーボックス

2.ツールワゴン

3.掛け時計

4.OAタップ

5.カーテンというか暗幕

本当に欲しいのは、スミノエのシンプルな黒。ビデオ配信のグリーンバック用緑も欲しい。

6.デスクライト

7.CFカード

EOS5DMark4用

8.指向性ステレオマイクロフォン

Canon 指向性ステレオマイクロフォン DM-E1

Canon 指向性ステレオマイクロフォン DM-E1

  • 発売日: 2016/06/30
  • メディア: 付属品
EOS5DMark4用

9.はかり

10.温湿度計

11.有孔ボード(パンチングボード)

工具掛け用

12.SDカード

EOS5DMark4用およびInsta360Pro2用

13.マイクロSDカード

Insta360Pro2用6枚

14.PCケース

15.ホッチキス

マックス MAX ホチキス ホッチキス 20枚とじ ブルー HD-10D

マックス MAX ホチキス ホッチキス 20枚とじ ブルー HD-10D

  • 発売日: 2002/07/29
  • メディア: オフィス用品

16.ホールパンチ

17.はさみ

18.タイマー

19.USBチェッカー

BitTradeOne ADUSBCIM USB CABLE CHECKER 2

BitTradeOne ADUSBCIM USB CABLE CHECKER 2

  • 発売日: 2019/10/05
  • メディア: Personal Computers

自分用読むべき論文メモ 2019年10月版

Twitterのいいね!したもののまとめです。


森山さんのEPFLが開発したソフトロボティクスアクチュエータの記事。


フィルタについて。

https://twitter.com/motorcontrolman/status/1179010341188952064?s=20


電子部品の未来予測


生態系サイクルによる養殖と栽培


4足走行ロボットMIT Cheetahのソースコードが読めるらしい。


EVの爆破型安全装置。とさか先輩


OpenVSLAM。この手の、乱立気味ではあるけれど、応援したい。


眼球のセマンテックセグメンテーション。ところで、VIVE PRO EYEの眼球画像ってとれるのかしら?


タフさは重要。


軍事ロボットは大嫌いだけれども、考えることは止めてはいけない。


これ、超重要。


メカだけで重力補償。まじかいな。


ヴァーチャルマインクラフトのリアル版みたいな?


両眼立体視の中身の分類


微分可能シミュレータ


月のテクスチャ


PCAの曲線版


文科省に出したシラバスを変えるの、無理だからなぁ


Deep Fly


水中D415。綺麗に撮れるんだねぇ。


これにカメラ埋め込んで、何が見えているのか検証してほしい。


Python deep learning


オープンソースアノテーションツール


ROS過渡期


音声クラス分類


コワイ


ランダムにも色々あるからなぁ


マイクロボクセル


阿武隈川流域のフォトグラメトリ


メタなんとかは、時々理解を超える。


動画ディープラーニング


太陽光に強いイメージセンサ


人間の視覚感度に近いイメージセンサ


磁力線の可視化(これもイメージセンサというのかな?)の新潟のオフダイアゴナル社。


レイテンシ


新型コロナウイルス騒ぎで、非接触の触感センサの需要は急激に伸びそう。


Microsoftのデータ可視化ツール


ナンダカゼンゼンワカッテナイケド


ヒトの色彩の認識について


これは、重要な知見。


奥行き知覚の面白み


まじもんの光学迷彩できてんじゃん。


赤外光と光合成


永久機関の夢


フェーズドアレイレーダー


大事


ロボットグラスピングの学習


上田先生


オープンデータまとめ


古代語の解析


OpenCV DNNのCUDA対応方法


SLAM


触覚


ライブラリ


浮いて見えるディスプレイ


浮いてるディスプレイ


やらなきゃいけなかったはずの仕事。


不便益


触覚


一回乗ってみたい。


ゲームエンジンによる自動運転開発環境


嫌いだけど。


基礎


一般逆行列


20年ぐらい前を思い出す


布導電からの物体推定


おもろい



正直全然ついていけてないけど、わかるようにならねば。


転置畳み込み


自分で調べずに済む


流行をあえて避けよう

物欲


本棚に積みたい一冊。


はやくうってー


Oculus Quest ハック


怪しいモータ


買おうかどうか悩んだけれど。


XARM

大学生活


大学院博士課程に行くなら奨学金をもらえるようにしましょう。
たとえ博士号が取れても、生涯所得で学部卒に勝てない、なんていう事態を防ぐために。


睡眠は午前2時前にちゃんと一定時間とる。


コーヒーの効能


マンガの効能


交渉のアレコレ


ルネッサーンス


鼻呼吸大事


現実。

今日の物欲

そんなに効くなら、パナソニックは人類のためにジアイーノの製造ライセンスを販売してくれればいいのに。

SOHOや研究室に購入しておくべき備品のメモ 2020

(編集中、 もっと増えるし吟味します。)

A4プリンター複合機

安くて比較的コンパクトなカラーレーザー複合機です。
購入後製品登録をすることで1年保障は付きますが、それ以降の故障は買い替えた方が安いぐらいの出張手数料を取られたりしますので、注意が必要です。
保障期間終了前に1年延長保証22000円を購入することもできるようです。

設置台があると、予備の紙とかが置けておさまりが良いです。

保証期間中は、純正トナー。そのあとは、壊れたら廃棄覚悟で安いトナーでもいいかもしれません。

プレゼンテーション用PC

低いスペックのPCで構わないので、日々のミーティングやカンファレンスでの発表用に学生が使えるもの。軽くて小さいものが良い。

パナソニックのlet'snote SVかMac book pro13が良いに決まってるんですけど、高いんですよね。。。

Surface Goは普段のメモ書きに手ごろなようです。オフィスが入ってなくて1万円安いアカデミック版もあります。
ペンとカバーキーボードが別売なことに注意。

プレゼン用レーザーポインター+マウス

高いけど、最近は液晶モニターでプレゼンすることも多く、液晶モニターにレーザーポインターは使えないので、マウスモードもあるこのモデルがおすすめ。

大型モニターまたはプロジェクター

今は65インチTVでも相当安い価格で買えますね。探すと12万円ほどの販売店も見つかります。ただ来年は生産調整のため、ちょっと値上がりなんて噂も。

20人以上のミーティングの時にプロジェクターは、有効。
電子黒板タイプが、ミーティングの在り方を変えてくれるかもしれません。

データサーバーNAS

時間が経つとデータは無限に増えていきます。また、HDDはそのうち壊れていくものなので、最低4台以上のモデルを選んでRAIDレベルの高い物を用意した方が良いです。

HDDは、何があってもシーゲートは無しでお願いします。

Wifiルータ

規格の進化が速いので、安いのを頻繁に買い替えるのもあり。

NEC 無線LANルーター Aterm ブラック PA-WG2600HP3

NEC 無線LANルーター Aterm ブラック PA-WG2600HP3

  • メディア: エレクトロニクス
もう直ぐ発売予定のNECの6000番を待ちたい。
NECパーソナル PA-WX6000HP Aterm WX6000HP

NECパーソナル PA-WX6000HP Aterm WX6000HP

  • メディア: エレクトロニクス

ネットワークルータ・ハブ

スマートスイッチが欲しいけど、10Gへの移行を見据えて安いやつでも全然あり。

YAMAHA SWX2210-16G スマートL2スイッチ 16ポート

YAMAHA SWX2210-16G スマートL2スイッチ 16ポート

  • メディア: エレクトロニクス
ヤマハ シンプルL2スイッチ SWX2100-16G

ヤマハ シンプルL2スイッチ SWX2100-16G

  • 発売日: 2015/06/15
  • メディア: エレクトロニクス
QNAPのNASで、4K動画編集するときなどに便利。
QNAP 10GbE対応 12ポート アンマネージドスイッチ QSW-1208-8C

QNAP 10GbE対応 12ポート アンマネージドスイッチ QSW-1208-8C

  • 発売日: 2018/06/19
  • メディア: Personal Computers

ハードウェア・ファイアウォール

Yamahaがそろそろ古いので、Fortinetが良いけど、

ICレコーダー

打合せ記録用に、安定性の高いやつを。

オリンパス OLYMPUS ステレオICレコーダー Voice Trek V-873 ブラック 8GB

オリンパス OLYMPUS ステレオICレコーダー Voice Trek V-873 ブラック 8GB

  • 発売日: 2019/10/11
  • メディア: エレクトロニクス

Meeting Microphone and Speaker

監視カメラ

予算に余裕があれば、シッカリしたやつの方が良いです。監視目的以上に、事故防止とかに役立ちます。

オシロスコープ、ファンクションジェネレータ、周波数アナライザ

電気系研究室ならオシロスコープが一台あっても困りません。
5万未満の単機能オシロスコープでもいい機種がいっぱいありますが、Keysight InfiniiVision DSOX1204Gはファンクションジェネレータを内蔵しているので、これ一台で色々できます。
70MHzで性能が不足するときは、有料で高いですけれど200MHzまで対応可能。トータルで考えると、とてもお安い。

Air Cleaner

気休めなので、ダイキンでもシャープでも好きなメーカーを。

工具セット

for electronics
ホーザンS-10

ホーザンS-76
[asin:B07PD25C14:detail]

ホーザン(HOZAN) 工具セット ハンダゴテ(230V) S-81-230
なんか知らんけど、ごくたまに3万円ぐらいの激安で出てくることがある。
230Vのハンダゴテは完全に無駄になりますが。

ハンダゴテは温度調整機能の付いたものが人気ですね。

セットから抜けているマイクロニッパーは電子工作に必須ですね。

いっぱいあって、どれを選ぶか悩むね


KTC
for cars, motor-bikes, bycicles

防湿庫

東洋リビング

デスクライト

山田照明が無難なデザインで信頼できる性能かなー。自立スタンドが別売で謎に高いのがネックだけども。

Adobe Create suite (for academic)

これはアカデミック版じゃないです。別の窓口からアカデミック版を買っておくと論文制作に役立ちます。

文房具類

ラベルプリンター

キングジム ラベルライター テプラPRO  SR530

キングジム ラベルライター テプラPRO SR530

  • 発売日: 2006/09/13
  • メディア: オフィス用品

シュレッダー

小さいのを買うといつも後悔するので、大きいのが欲しいんだけど邪魔なのよね。

ラミネータ

ナカバヤシ パーソナルラミネーター クイックラミ A4 Z2722

ナカバヤシ パーソナルラミネーター クイックラミ A4 Z2722

  • 発売日: 2019/06/11
  • メディア: オフィス用品

ゴミ箱

分別用に複数用意しましょう。沼津方式。

良い椅子

本当にいい椅子は10万を軽く超えますが、そんな予算はありません。
3万未満のまともな椅子はこれだけっぽい。ただし異常に重い。

ACタップ

いい加減なメーカーの適当なタップを買って火事の心配をするよりは、信頼できそうなやつを買っといた方が後で後悔が少なくて済みます。

キーボックス

ナカバヤシ キーボックス20個収容 NKB-E02

ナカバヤシ キーボックス20個収容 NKB-E02

  • 発売日: 2009/12/14
  • メディア: オフィス用品
部屋の鍵とか、机の鍵とか、意外と数が多いのでまとめておけると便利。

メモ:ur_rtdeに独自関数を追加したいときの方法

RTDEは、urscriptやその入出力の変数を自前で定義してやる必要があります。URは、入出力のデータの並びの定義をrecipeと呼んでいます。わかってしまえば、たいして難しくないものの、その仕組みはちょっとヤヤコシイので、ur_rtdeに自前の関数を追加したいときのメモを残しておくことにします。

編集する必要があるファイルは、
1. rtde_control.script
2. rtde.h
3. rtde_control.h
4. rtde_control.cpp
です。
rtde_control.scriptにはURScript形式で記述したロボットコマンドを追加します。
rtde.hには、RobotCommandのTypeとRecipeの定義を追加します。
rtde_control.hには、自前スクリプトの呼び出し関数の定義を追加し、rtde_control.cppには、自前スクリプトの呼び出し関数の定義を記述します。入力変数と、出力変数の受け取りも記述します。
定義や関数を追加した後に、cmakeからur_rtdeの再ビルドを行います。

is_within_safety_limits()をコマンド33に追加するときの例

rtde_control.script

    def process_cmd():
        cmd = read_input_integer_register(0)

        if cmd == 1:
            textmsg("movej")
            q = [0, 0, 0, 0, 0, 0]
            q[0] = read_input_float_register(0)

~中略~

        elif cmd == 33:
            textmsg("is_within_safety_limits")
            x = p[0, 0, 0, 0, 0, 0]
            x[0] = read_input_float_register(0)
            x[1] = read_input_float_register(1)
            x[2] = read_input_float_register(2)
            x[3] = read_input_float_register(3)
            x[4] = read_input_float_register(4)
            x[5] = read_input_float_register(5)
            
            val = is_within_safety_limits(x)
            if val == False:
                        write_output_integer_register(1, 0)
            else:
                        write_output_integer_register(1, 1)
            end
            textmsg("is_within_safety_limits done")
        elif cmd == 255:
            textmsg("Received stop!")
        end

        return cmd != 255
    end

rtde.h

  class RobotCommand
  {
   public:
    enum Type
    {
      NO_CMD = 0,

~中略~

      GET_INVERSE_KINEMATICS = 31,
      PROTECTIVE_STOP = 32,
      IS_WITHIN_SAFETY_LIMITS = 33, ///// added
      STOP = 255
    };

    enum Recipe
    {
      RECIPE_1 = 1,

~中略~

      RECIPE_11 = 11,
      RECIPE_12 = 12 ///// added
    };

rtde_control.h

~前略~

  RTDE_EXPORT std::vector<double> getInverseKinematics(const std::vector<double> &x, const std::vector<double> &qnear,
      double max_position_error=1e-10, double max_orientation_error=1e-10);

  RTDE_EXPORT int getIsWithinSafetyLimits(const std::vector<double> &x); ///// added

  /**
    * @brief Triggers a protective stop on the robot. Can be used for testing and debugging.
    */
  RTDE_EXPORT bool triggerProtectiveStop();

~中略~
  private:
    int getIsWithinSafetyLimitsValue(); ///// added

~後略~

rtde_control.cpp

RTDEControlInterface::RTDEControlInterface(std::string hostname, int port) : hostname_(std::move(hostname)), port_(port)
{
 ~前略~

  // Setup input recipes

  ~中略~

  // Recipe_12
  std::vector<std::string> is_within_safety_limits_input = {
      "input_int_register_0",    "input_double_register_0", "input_double_register_1", "input_double_register_2",
      "input_double_register_3", "input_double_register_4", "input_double_register_5"};
  rtde_->sendInputSetup(is_within_safety_limits_input);

 ~後略~
  }
}


bool RTDEControlInterface::reconnect()
{
~前略~

  // Setup input recipes
  // Recipe 1

~中略~

  // Recipe_12
  std::vector<std::string> is_within_safety_limits_input = {
      "input_int_register_0",    "input_double_register_0", "input_double_register_1", "input_double_register_2",
      "input_double_register_3", "input_double_register_4", "input_double_register_5"};
  rtde_->sendInputSetup(is_within_safety_limits_input);

  // Init Robot state
 ~後略~
}

int RTDEControlInterface::getIsWithinSafetyLimitsValue()
{
  if (robot_state_ != nullptr)
  {
    return robot_state_->getOutput_int_register_1();
  }
  else
  {
    throw std::logic_error("Please initialize the RobotState, before using it!");
  }
}

int RTDEControlInterface::getIsWithinSafetyLimits(const std::vector<double> &x)
{
  RTDE::RobotCommand robot_cmd;
  robot_cmd.type_ = RTDE::RobotCommand::Type::IS_WITHIN_SAFETY_LIMITS;
  robot_cmd.recipe_id_ = RTDE::RobotCommand::Recipe::RECIPE_12;
  robot_cmd.val_ = x;
  if (sendCommand(robot_cmd))
  {
    return getIsWithinSafetyLimitsValue();
  }
  else
  {
    return -1;
  }
}

double型のベクターを渡したいだけなのに、頭に "input_int_register_0" がついているのは、ベクターの大きさを暗黙のうちに渡すような仕組みになっているからです。明示的には渡しません。

実行例

#include <ur_rtde/rtde_control_interface.h>
#include <thread>
#include <chrono>
#include <iostream>

using namespace ur_rtde;

int main(int argc, char* argv[])
{
  RTDEControlInterface rtde_control("192.168.0.1");

  // int movec_mode = 0;
  std::vector<double> tcp_pose1 = {-0.143, -0.435, 0.20, -0.001, 3.12, 0.04};
  std::vector<double> tcp_pose2 = {-0.143, -0.51, 0.21, -0.001, 3.12, 0.04};
  std::vector<double> tcp_pose3 = {0.4, 0.4, 10.0, 0.0, 3.14159, 0.0};

  //rtde_control.getInverseKinematics();
  std::cout << "getIsWithinSafetyLimits" << std::endl;
  bool result;
  result = rtde_control.getIsWithinSafetyLimits(tcp_pose1);
  std::cout << result << std::endl;
  result = rtde_control.getIsWithinSafetyLimits(tcp_pose2);
  std::cout << result << std::endl;
  result = rtde_control.getIsWithinSafetyLimits(tcp_pose3);
  std::cout << result << std::endl;

  return 0;
}

今日の本文

大きなテレビが安い。

今なら同じSONYの4kチューナーを買って、ソニーに申請すると3万円返ってくる。実質4Kチューナーをタダでもらえたうえで300円得する計算になります。

www.sony.jp

メモ:onRobot社のRG2GripperをURスクリプトを使って、ur_rtdeから動かしたいときのスクリプトのサンプル

ロボットアームUR5eに取り付けたonRobot社RG2グリッパーを、URScriptを使って、自前のc++プログラムから操作するときのサンプルを紹介します。

UR5eの駆動方法

UR5eを動かすための方法は、URScriptを使う(port 30000~30002)か、RTDE(Real-Time Data Exchange, port 30004)[0]を使うかに分かれます。
ROSIndustrialなどは中でURScriptを叩いているそうですが、URScriptの応答は速くなくロボットハードウェアの性能を全て引き出すことは難しいです。
ロボットの性能を引き出すために、RTDE経由でコマンドを送る方が良く、そこに着目した幾つかのグループでRTDEをラップして便利に使いやすくするライブラリの開発[1][2][3]が進められています。
一方で、onRobotのRG2はRTDEではなく、URScriptから呼び出す必要が有ります。
ここでは、開発が現在進行形で進んでいるソースコードがきれいなur_rtdeを使って、そこからURScriptを呼び出す方法を試してみたいと思います。

onRobot社のマニュアルによれば、簡単にURScriptからRG2関数を呼べるようになるのでは?

RG2関数がURScriptにロードされるのは、PolyScope内だけです。外部から呼び出すことはできません。
onRobot社のマニュアルに不備があります。

ur_rtdeのScriptClient

ur_rtdeはいくつかのコンポーネントから構成されており、RTDEReceiveInterface、RTDEControlInterface、RTDEIOInterface、ScriptClientなどがあります。
うまく使えばRTDEIOInterfaceを使ってRG2グリッパーを動かすことができるかもしれませんが、まだノウハウの蓄積がないのでわかりません。
ここでは、ScriptClientを使ってURScriptを流し込む方法で動かしてみたいと思います。

ソースコードのサンプル

ファイルに書いたスクリプトを読み込む方法と、平書きしたstringを渡す方法の2つがあります。
URScriptでは、scriptの中のタブとか改行コードとかがシビアに影響します。デバッグもし辛いので慎重に確認してください。
実機を動作させるときには、電源をOnにして、polyscopeのタブレットからリモートコントロールができるように設定しておく必要がありますので、忘れないでください。

ofApp.h

#pragma once

#include "ofMain.h"

#include <ur_rtde/rtde_receive_interface.h>
#include <ur_rtde/rtde_control_interface.h>
#include <ur_rtde/script_client.h>

class ofApp : public ofBaseApp{

	public:
		void setup();
		void update();
		void draw();

		void RG2(int width, int force);

		std::shared_ptr<ur_rtde::RTDEReceiveInterface> rtde_receive;
		std::shared_ptr<ur_rtde::RTDEControlInterface> rtde_control;
		std::shared_ptr<ur_rtde::ScriptClient> script_client;
};

ofApp.cpp

#include "ofApp.h"
#pragma comment(lib, "rtde.lib")

//--------------------------------------------------------------
void ofApp::setup(){
	script_client = std::make_shared<ur_rtde::ScriptClient>("192.168.1.1", 5, 5, 30002); // Polyscope ver. 5.5 port 30002

	script_client->connect();
	if (script_client->isConnected()) {
		script_client->sendScript("data/RG2.script");
		std::cout << "send command" << std::endl;
        }
}

void ofApp::update()
{
}

void ofApp::draw()
{
}

void ofApp::RG2(int width, int force)
{
	int offset_width = 9; // 9.2[mm];
	int target_width = offset_width + width;
	if (target_width > 110) target_width = 110;
	else if (target_width < 0) target_width = 0;

	if (script_client->isConnected()) {
		std::string cmd_str;
		cmd_str = "def RG2():\n";
		cmd_str += "\tdef bit(input):\n";
		cmd_str += "\t\tmsb = 65536\n";
		cmd_str += "\t\tlocal i = 0\n";
		cmd_str += "\t\tlocal output = 0\n";
		cmd_str += "\t\twhile i < 17:\n";
		cmd_str += "\t\t\tset_digital_out(8, True)\n";
		cmd_str += "\t\t\tif input >= msb :\n";
		cmd_str += "\t\t\t\tinput = input - msb\n";
		cmd_str += "\t\t\t\tset_digital_out(9, False)\n";
		cmd_str += "\t\t\telse :\n";
		cmd_str += "\t\t\t\tset_digital_out(9, True)\n";
		cmd_str += "\t\t\tend\n";
		cmd_str += "\t\t\tif get_digital_in(8):\n";
		cmd_str += "\t\t\t\toutput = 1\n";
		cmd_str += "\t\t\tend\n";
		cmd_str += "\t\t\tsync()\n";
		cmd_str += "\t\t\tset_digital_out(8, False)\n";
		cmd_str += "\t\t\tsync()\n";
		cmd_str += "\t\t\tinput = input * 2\n";
		cmd_str += "\t\t\toutput = output * 2\n";
		cmd_str += "\t\t\ti = i + 1\n";
		cmd_str += "\t\tend\n";
		cmd_str += "\t\treturn output\n";
		cmd_str += "\tend\n";
		cmd_str += "\tdef RG2(target_width = 110, target_force = 40):\n";
		cmd_str += "\t\tbit(0)\n";
		cmd_str += "\t\tsleep(0.024)\n";
		cmd_str += "\t\trg_data = floor(target_width) * 4\n";
		cmd_str += "\t\trg_data = rg_data + floor(target_force / 2) * 4 * 111\n";
		cmd_str += "\t\trg_data = rg_data + 32768\n";
		cmd_str += "\t\tbit(rg_data)\n";
		cmd_str += "\t\twhile get_digital_in(9) == True:\n";
		cmd_str += "\t\t\tsync()\n";
		cmd_str += "\t\tend\n";
		cmd_str += "\t\twhile get_digital_in(9) == False:\n";
		cmd_str += "\t\t\tsync()\n";
		cmd_str += "\t\tend\n";
		cmd_str += "\tend\n";
		cmd_str += "\tRG2(" + std::to_string(target_width) + "," + std::to_string(rg2_force) + ")\n";
		cmd_str += "end\n";
		cmd_str += "run program\n";
		script_client->sendScriptCommand(cmd_str);

		std::cout << cmd_str << std::endl;
	}
}

RG2.script

def RG2():
	def bit(input):
		msb=65536
		local i=0
		local output=0
		while i<17:
			set_digital_out(8,True)
			if input>=msb:
				input=input-msb
				set_digital_out(9,False)
			else:
				set_digital_out(9,True)
			end
			if get_digital_in(8):
				output=1
			end
			sync()
			set_digital_out(8,False)
			sync()
			input=input*2
			output=output*2
			i=i+1
		end
		return output
	end
	def RG2(target_width=110, target_force=40):
		bit(0)
		sleep(0.024)
		rg_data=floor(target_width)*4
		rg_data=rg_data+floor(target_force/2)*4*111
		rg_data=rg_data+32768
		bit(rg_data)
		while get_digital_in(9) == True:
			sync()
		end
		while get_digital_in(9) == False:
			sync()
		end
	end
	RG2(100, 40)
end
run program


References:
[0] https://www.universal-robots.com/how-tos-and-faqs/how-to/ur-how-tos/real-time-data-exchange-rtde-guide-22229/
[1] pypi.org
[2] gitlab.com
[3] github.com
[4] bitbucket.org