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