Ubuntu18.04にGPU(RTX2070)のドライバを入れる
注意: lowlatency-kernelでは使えないので,generic-kernelに変更してください.
# nouveauの存在を確認 $ lsmod | grep -i nouveau
nouveauを無効化するために,/etc/modprobe.d/blacklist-nouveau.conf
に以下を書き込みます.
blacklist nouveau options nouveau modeset=0
更新し,再起動します.
$ sudo update-initramfs -u $ reboot
以下のコマンドで何も表示されなくなっていればOKです.
$ lsmod | grep -i nouveau
ドライバ・CUDAのインストール
# 以前にインストールしたドライバ・CUDAをアンインストール $ sudo apt purge nvidia-* $ sudo apt purge cuda-* # aptのリポジトリに追加 sudo add-apt-repository ppa:graphics-drivers/ppa sudo apt update # インストール可能なドライバ一覧表示 $ ubuntu-drivers devices # インストール $ sudo ubuntu-drivers autoinstall (または,$ sudo apt install nvidia-driver-450 )
再起動してから,
$ nvidia-smi
でGPUの使用状況が見れるはず.
$ nvcc -V $ sudo apt install nvidia-cuda-toolkit ( $ reboot ) $ nvidia-smi
VSCodeで日本語LaTexオンラインプレビュー
texlive
$ sudo apt install texlive-full
拡張機能の追加
LaTex Workshopを追加する.
設定の変更
(Ctrl+Shift+P) でコマンドパレットを開き,Preferences: Open Settings (JSON)
の中に以下を書く.
{ "editor.tabSize": 4, "editor.detectIndentation": false, "files.encoding": "utf8", "vim.insertModeKeyBindings": [ { "before": ["j", "j"], "after": ["<Esc>"] } ], // 自動保存 "files.autoSave":"off", "latex-workshop.view.pdf.viewer": "tab", "latex-workshop.view.pdf.zoom":"auto", "latex-workshop.latex.autoClean.run":"onBuilt", "latex-workshop.latex.autoBuild.cleanAndRetry.enabled": true, "latex-workshop.latex.tools": [ { "command": "platex", "args": [ "-interaction=nonstopmode", "-synctex=1", "-jobname=\"%DOCFILE%\"", "-kanji=utf8", "-guess-input-enc", "%DOCFILE%.tex" ], "name": "Step 1: platex" }, { "command": "platex", "args": [ "-synctex=1", "-jobname=\"%DOCFILE%\"", "-kanji=utf8", "-guess-input-enc", "%DOCFILE%.tex" ], "name": "Step 2: platex" }, { "command": "dvipdfmx", "args": [ "%DOCFILE%" ], "name": "Step 3: dvipdfmx" } ], "latex-workshop.latex.recipes": [ { "name": "toolchain", "tools": [ "Step 1: platex", "Step 2: platex", "Step 3: dvipdfmx", ] } ], }
毎回<Esc>を押しに行くのが面倒とお思いのあなたへ(VSCode, Vim)
jjを割り当てる
(Ctrl+Shift+P) でコマンドパレットを開き,Preferences: Open Settings (JSON)
の中に以下を書く.
{ "editor.tabSize": 4, "editor.detectIndentation": false, "files.encoding": "utf8", "vim.insertModeKeyBindings": [ { "before": ["j", "j"], "after": ["<Esc>"] } ] }
ctrl + ;でターミナルとエディタを切り替える
(Ctrl+Shift+P) でコマンドパレットを開き,Preferences: Open Keyboard Shortcuts Files
の中に以下を書く.
[ { "key": "Ctrl+j", "command": "extension.vim_escape", "when": "editorTextFocus && vim.active && !inDebugRepl" }, { "key": "ctrl+;", "command": "workbench.action.terminal.focus" }, { "key": "ctrl+;", "command": "workbench.action.focusActiveEditorGroup", "when": "terminalFocus" }, { "key": "ctrl+w", "command": "workbench.action.closeActiveEditor", "when": "editorTextFocus" }, { "key": "ctrl+shift+right", "command": "workbench.action.moveEditorToNextGroup", "when": "editorTextFocus" }, { "key": "ctrl+shift+left", "command": "workbench.action.moveEditorToPreviousGroup", "when": "editorTextFocus" }, { "key": "ctrl+shift+tab", "command": "workbench.action.previousEditor", "when": "editorTextFocus" }, { "key": "ctrl+tab", "command": "workbench.action.nextEditor", "when": "editorTextFocus" }, { "key": "tab", "command": "tab", "when": "editorTextFocus" }, { "key": "ctrl+shift+c", "command": "editor.action.clipboardCopyAction", "when": "!terminalFocus" } ]
(おまけ)vscodeでよく使うショートカットキーメモ
- エクスプローラとエディタの切り替え
Ctrl + Shift + E
- エディタの分割
Ctrl + \
- エディタグループの切り替え(なければ作成)
Ctrl + 数字
- アクティブタブを隣のエディタグループへ移動
Ctrl + Alt + ←→
- アクティブなタブを終了
Ctrl + w
Qt5チュートリアル(C++, Ubuntu)
前回の記事でPyQtによるGUIプログラミングを紹介しました.
今回はC++で同じようなことをやっていきます.
PythonからC++になった瞬間にコンパイルエラー等が起きまくって大変な目に会いますが,この記事通りに進めればできる(はず?)です.
環境構築
各自適当に$ sudo apt install qt5*
とか調べながらQt5を入れてください.
やってみましょう
- ディレクトリの作成
$ mkdir qt_tutorial
- mainwindow.cppの作成
qt_tutorialディレクトリの中にmainwindow.cppを作り,以下を書き込みます.
#include <QtWidgets/QApplication> #include <QtWidgets/QLabel> #include <QtWidgets/QPushButton> #include <QtWidgets/QGridLayout> int main(int argc, char *argv[]) { QApplication app(argc, argv); QWidget window; window.setGeometry(1300, 300, 1000, 850); window.setWindowTitle("test"); QGridLayout *layout = new QGridLayout; window.setLayout(layout); QPushButton *button = new QPushButton("終了",0); QObject::connect(button, SIGNAL(clicked()), &app, SLOT(quit())); layout->addWidget(button); window.show(); return app.exec(); }
- コンパイル作業
$ qmake -project
qt_tutorial.proの最後にQT += widgets
を加えてから,
$ qmake qt_tutorial.pro $ make $ ./qt_tutorial
以上!!
PyQt5で始めるGUIプログラミング
GUIプログラミング入門
てきとうなuiファイル(test.ui)を作成して,以下のコードを実行すれば,こんな感じのGUIが簡単に作成できます.
#!/usr/bin/env python # -*- coding:utf-8 -*- import sys, os from PyQt5 import QtCore, QtMultimedia, uic from PyQt5.QtWidgets import * from PyQt5.QtGui import QIcon # -------------------------------------GUI描画 ---------------------------------------------------------- class MainMenu(QWidget): def __init__(self, parent=None): super(MainMenu, self).__init__() ui_file = uic.loadUiType("test.ui", self)[0] self.ui = ui_file() self.ui.setupUi(self) # クリックイベント self.ui.pose_init.clicked.connect(self.button_clicked) self.ui.start_moving.clicked.connect(self.button_clicked) self.ui.publish.clicked.connect(self.button_clicked) self.ui.excute.clicked.connect(self.button_clicked) self.ui.go_home.clicked.connect(self.button_clicked) self.ui.quit.clicked.connect(self.button_clicked) # ボタンのクリック音の設定 self.mediaPlayer = QtMultimedia.QMediaPlayer(self) self.app_root = os.path.abspath(os.path.dirname(sys.argv[0])) sound=QtMultimedia.QMediaContent(QtCore.QUrl.fromLocalFile(os.path.join(self.app_root,"click.wav"))) self.mediaPlayer.setMedia(sound) # クリック処理 def button_clicked(self): self.mediaPlayer.stop() self.mediaPlayer.play() # ---------------------------- メイン関数 ---------------------------------------------------------- def main(): app = QApplication([]) window = MainMenu() window.show() sys.exit(app.exec_()) # -------------------------- プログラム開始点 ------------------------------------------------------- if __name__ == '__main__': main()
Git使い方メモ
GitとGitHub
Gitとはバージョン管理ツールです.Gitを使うと,GitHubというウェブサービス上にリポジトリをコピーすることができます.
Gitの初期設定
$ git config --global user.name "氏名" $ git config --global user.email "メアド" $ git config --global core.editor code
を実行するとホームディレクトリに.gitconfigファイルが出来上がっているはずです.
Gitの準備
$ git init
とすると,ディレクトリ内に.gitというディレクトリができます.
$ git remote add origin git@github.com:ユーザー名/リポジトリ名.git
Gitの流れ
gitの使い方の基本は →pull→add→commit→push→ です.
- add : ファイルの選択
$ git add ファイル名 $ git add . ←すべてのファイルを指定
とすることで,コミット(作ったファイルを管理対象にする)の対象として選択することができます.
addしたかどうかを忘れてしまった時は,
$ git status
で確認できます.赤い文字で書かれているファイルは変更してaddしていないファイルです.
さらに,変更内容も確認したい時は,
$ git diff
とします.
- commit : 選択したファイルの記録
$ git commit -m "コミットメッセージ"
- push : リモートにファイルをアップロード
$ git push origin master
- pull : リモートのファイルをダウンロード
$ git pull origin master
commitの履歴やコミットメッセージの確認
$ git log
で確認できます.
$ git log -p
で変更内容の確認もできます.
(補足1)nothing to commit, working tree cleanと怒られたら
$ git pull --rebase origin master
(補足2)強引にマージ
$ git merge -Xtheirs (マージしたいbranch名) --allow-unrelated-histories
ROS MelodicでOpenCV(テニスボールの位置検出)
前回ROS MelodicでOpenCV - 機械屋の呟き、ROS上でOpenCVを使う準備をしたので、実際に使ってみます。
サンプルコード
以下のコードをopencv_test.cppに書き、ビルドします。
#include <ros/ros.h> #include <image_transport/image_transport.h> #include <cv_bridge/cv_bridge.h> #include <sensor_msgs/image_encodings.h> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui.hpp> static const std::string OPENCV_WINDOW = "Image window"; class ImageConverter{ ros::NodeHandle nh_; image_transport::ImageTransport it_; image_transport::Subscriber image_sub_; image_transport::Publisher image_pub_; public: // コンストラクタ ImageConverter() : it_(nh_){ // カラー画像をサブスクライブ image_sub_ = it_.subscribe("/image_raw", 1, &ImageConverter::imageCb, this); // 処理した画像をパブリッシュ image_pub_ = it_.advertise("/image_topic", 1); } // デストラクタ ~ImageConverter(){ cv::destroyWindow(OPENCV_WINDOW); } // コールバック関数 void imageCb(const sensor_msgs::ImageConstPtr& msg){ cv::Point2f center, p1; float radius; cv_bridge::CvImagePtr cv_ptr, cv_ptr2, cv_ptr3; try{ // ROSからOpenCVの形式にtoCvCopy()で変換。cv_ptr->imageがcv::Matフォーマット。 cv_ptr = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::BGR8); cv_ptr3 = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::MONO8); }catch (cv_bridge::Exception& e){ ROS_ERROR("cv_bridge exception: %s", e.what()); return; } cv::Mat hsv_image, color_mask, gray_image, bin_image, cv_image2, cv_image3; // RGB表色系をHSV表色系へ変換して、hsv_imageに格納 cv::cvtColor(cv_ptr->image, hsv_image, CV_BGR2HSV); // 色相(Hue), 彩度(Saturation), 明暗(Value, brightness) // 指定した範囲の色でマスク画像color_mask(CV_8U:符号なし8ビット整数)を生成 // マスク画像は指定した範囲の色に該当する要素は255(8ビットすべて1)、それ以外は0 //cv::inRange(hsv_image, cv::Scalar(0, 0, 100, 0) , cv::Scalar(180, 45, 255, 0), color_mask); // 白 //cv::inRange(hsv_image, cv::Scalar(150, 100, 50, 0) , cv::Scalar(180, 255, 255, 0), color_mask); // 赤 cv::inRange(hsv_image, cv::Scalar(20, 50, 50, 0) , cv::Scalar(100, 255, 255, 0), color_mask); // 黄 // ビット毎の論理積。マスク画像は指定した範囲以外は0で、指定範囲の要素は255なので、ビット毎の論理積を適用すると、指定した範囲の色に対応する要素はそのままで、他は0になる。 cv::bitwise_and(cv_ptr->image, cv_ptr->image, cv_image2, color_mask); // グレースケールに変換 cv::cvtColor(cv_image2, gray_image, CV_BGR2GRAY); // 閾値70で2値画像に変換 cv::threshold(gray_image, bin_image, 80, 255, CV_THRESH_BINARY); // エッジを検出するためにCannyアルゴリズムを適用 //cv::Canny(gray_image, cv_ptr3->image, 15.0, 30.0, 3); // ウインドウに円を描画 //cv::circle(cv_ptr->image, cv::Point(100, 100), 20, CV_RGB(0,255,0)); // 輪郭を格納するcontoursにfindContours関数に渡すと輪郭を点の集合として入れてくれる std::vector<std::vector<cv::Point>> contours; cv::findContours(bin_image, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); // 輪郭線を格納 try{ // 各輪郭をcontourArea関数に渡し、最大面積を持つ輪郭を探す double max_area=0; int max_area_contour=-1; for(int j=0; j<contours.size(); j++){ double area = cv::contourArea(contours.at(j)); if(max_area<area){ max_area=area; max_area_contour=j; } } // 最大面積を持つ輪郭の最小外接円を取得 cv::minEnclosingCircle(contours.at(max_area_contour), center, radius); ROS_INFO("radius = %f", radius); // 最小外接円を描画 cv::circle(cv_ptr->image, center, radius, cv::Scalar(0,0,255),3,4); cv::circle(cv_image2, center, radius, cv::Scalar(0,0,255),3,4); cv::circle(bin_image, center, radius, cv::Scalar(0,0,255),3,4); }catch(CvErrorCallback){ } // 画面中心から最小外接円の中心へのベクトルを描画 p1 = cv::Point2f(cv_ptr->image.size().width/2,cv_ptr->image.size().height/2); cv::arrowedLine(cv_ptr->image, p1, center, cv::Scalar(0, 255, 0, 0), 3, 8, 0, 0.1); // 画像サイズは縦横1/4に変更 cv::Mat cv_half_image, cv_half_image2, cv_half_image3, cv_half_image4, cv_half_image5; cv::resize(cv_ptr->image, cv_half_image,cv::Size(),0.5,0.5); cv::resize(cv_image2, cv_half_image2,cv::Size(),0.5,0.5); //cv::resize(cv_ptr3->image, cv_half_image3,cv::Size(),0.5,0.5); cv::resize(gray_image, cv_half_image4,cv::Size(),0.5,0.5); cv::resize(bin_image, cv_half_image5,cv::Size(),0.5,0.5); // ウインドウ表示 cv::imshow("Original Image", cv_half_image); cv::imshow("Result Image", cv_half_image2); //cv::imshow("Edge Image", cv_half_image3); //cv::imshow("Gray Image", cv_half_image4); cv::imshow("Binary Image", cv_half_image5); cv::waitKey(3); // エッジ画像をパブリッシュ。OpenCVからROS形式にtoImageMsg()で変換。 image_pub_.publish(cv_ptr3->toImageMsg()); } }; int main(int argc, char** argv) { ros::init(argc, argv, "image_converter"); ImageConverter ic; ros::spin(); return 0; }
実行
$ roscore $ rosrun uvc_camera uvc_camera_node image:=/image_raw $ rosrun opencv_tutorials opencv_test