RaspberryPiでサーボモーターをPWM制御する。
RaspberryPi3 でハードウェアPWM出力できるピンは12, 13, 18,19の4つ
そのうち、独立して制御できるのは「12と13」か「18と19」。「12と18」、「13と19」は同じ制御しかできない。
あらかじめこんな感じでピンをセットアップしておく
wiringPiSetupGpio();
pinMode(18, PWM_OUTPU);
pwmSetMode(PWM_MODE_MS);
主に使う関数はこの三つ
pwmSetMode(int mode); pwmSetRange(unsigned int range); pwmSetClock(int divisor);
pwmSetMode(int mode)でPWMをバランスモードかマークスペースモードか選択する。
デフォルトはバランスモードになっているらしい。
PWMの周波数はpwmSetRange(unsigned int range)とpwmSetClock(int divisor)で決める。
最後にpwmWrite(18, num)で出力。
計算方法はここを参照しました。
ちなみに、pwmSetClock()は(pwmSetRange()も?)は2つの出力ピンで共通なため注意。
たとえば、2つのプログラムを同時に動かしてPWMを同時に制御しようとして、
それぞれのプログラムでpwmSetClock()を呼ぶと、後から実行された方で上書きされてしまう。
pythonで書く場合
他参考
Raspberry Piのセットアップ
ここら辺を参考に
- Raspbianのインストールと最強の初期設定 | 純規の暇人趣味ブログ
- Raspberry Pi 3 Model B をインストールしてSSH接続できるようにしてみる – CLARA ONLINE techblog
・DDwinをダウンロード
・OSイメージをダウンロード。
デスクトップとLITEの違いはデスクトップ環境が込みでインストールするかどうか。
コンソール操作だけでいい人はLITEでOK。
・DDwinでSDカードにイメージを書き込み。
管理者権限で実行すること。書き込み先を間違えないように超要注意。
・いきなりWi-Fi経由でSSH接続したい場合はSDカードのルートにsshという名前の空ファイルとwpa_supplicant.confというファイルを置いておく。
dhcpcd.confも同じようにファイルを置いて設定できた気がする。
ちなみにNOOBSを使ったインストール方法はここを参照
NOOBS無印とNOOBSLITEの違いはOSをダウンロードするタイミング
デスクトップ環境を最初からダウンロードするか、インストール時にダウンロードするか。
NOOBSはOSではなくOSのインストーラ
RaspberryPiをWi-fiのアクセスポイントにする。
RaspberryPiにルーターの機能を付ける場合はここら辺
- Raspberry Piの無線LANアクセスポイント化 - DesignAssembler
- Pi 3をWifi AccessPoint化(Raspbian stretch Lite 2018): new_western_elec
- How to Set up a Raspberry Pi as a Wireless Access Point
- Raspberry Pi3 無線LAN AP化 ~ 偉大なるノッポとプリン
RaspberryPiに中継(ブリッジ)機能を付ける場合はここら辺
今回は単純なアクセスポイント化(インターネット接続なし、DHCP機能なし)をやりたかったので、hostapd周辺だけの設定だったので簡単でした。
ざっくりやったこと。
・wlan0のIPを固定
・hostapdをインストール
・hostapd.confを編集
・wlan0をUP
・hostapd実行
ちなみに今回と逆のパターンで
RaspberryPiで無線を受けて、それを有線にながすのはイーサネットコンバータというらしい。
Raspberry Pi3を無線LANコンバータにする -blog SkyofFantasy-
マウスキーボード共有ソフトSynergyのインストール
一つのマウスキーボードをネットワーク越しに複数PCで使いまわすソフトSynergyのインストール方法
ビルド済みのものはここらへんから
- GitHub - brahma-dev/synergy-stable-builds: Downloads : https://brahma-dev.github.io/synergy-stable-builds/
- Releases · brahma-dev/synergy-stable-builds · GitHub
- Npackd
ソースはここらへんから
- GitHub - symless/synergy-core: Open source core of Synergy, the keyboard and mouse sharing tool
- https://github.com/symless/synergy
githubのwikiにコンパイル方法が書いてあります。
古いソースのビルド方法はもうgithubに載っていないのでここを参照
※2019/01/08追記
いつの間にかリポジトリのあった
sudo apt install synergy quicksynergy
SOM (自己組織化マップ) 作ってみた。
ここら辺を参考に。
#ifdef _DEBUG //Debugモードの場合 #pragma comment(lib,"C:\\opencv\\build\\x86\\vc12\\lib\\opencv_world300d.lib") // opencv_core #else //Releaseモードの場合 #pragma comment(lib,"C:\\opencv\\build\\x86\\vc12\\lib\\opencv_world300.lib") #endif #include <iostream> #include <vector> #include <stdlib.h> #include "opencv2/opencv.hpp" #include "opencv2/core.hpp" #include "opencv2/highgui.hpp" #include <omp.h> using namespace std; using namespace cv; class Node{ public : vector<double> param; Node(){ param = vector<double>(3); } }; class SomLearn{ int learning_range; double learning_rate; public: vector< vector<Node> > map; SomLearn(int x, int y){ map = vector< vector<Node> >(x, vector<Node>(y)); InitMap(); } int InitMap(){ srand(10); for (int i = 0; i < map.size(); ++i){ for (int j = 0; j < map[0].size(); ++j){ for (int k = 0; k < map[0][0].param.size(); ++k){ map[i][j].param[k] = double(rand() / double(RAND_MAX) * 255.0); } } } return 0; } double GetEuqridDinstance(Node data1, Node data2){ double n = 0; for (int i = 0; i < data1.param.size(); ++i){ n += (data2.param[i] - data1.param[i]) * (data2.param[i] - data1.param[i]); } return n; } int GetMinIndex(Node data, int &i_index, int &j_index){ double min_val = 0; double temp = 0; i_index = 0; j_index = 0; min_val = GetEuqridDinstance(data, map[0][0]); for (int i = 0; i < map.size(); ++i){ for (int j = 0; j < map[0].size(); ++j){ temp = GetEuqridDinstance(data, map[i][j]); if (min_val > temp){ min_val = temp; i_index = i; j_index = j; } } } return 0; } int Exposure(Node data){ int i_index = 0; int j_index = 0; GetMinIndex(data, i_index, j_index); int i_small = i_index - learning_range; int i_big = i_index + 1 + learning_range; int j_small = j_index - learning_range; int j_big = j_index + 1 + learning_range; if (i_small < 0){ i_small = 0; } if (map.size() < i_big){ i_big = map.size(); } if (j_small < 0){ j_small = 0; } if (map[0].size()< j_big){ j_big = map[0].size(); } for (int i = i_small; i < i_big; ++i){ for (int j = j_small; j < j_big; ++j){ for (int k = 0; k < data.param.size(); ++k){ map[i][j].param[k] += (data.param[k] - map[i][j].param[k]) * learning_rate; } } } return 0; } int Train(vector<Node> &node, int learning_range_in, double learning_rate_in){ learning_range = learning_range_in; learning_rate = learning_rate_in; for (int i = 0; i < node.size(); ++i){ Exposure(node[i]); } return 0; } }; int main(){ vector<Node> node(100); srand(1000); for (int i = 0; i < node.size(); ++i){ for (int k = 0; k < node[0].param.size(); ++k){ node[i].param[k] = double(rand()) / double(RAND_MAX) * 255.0; } } int x = 30; int y = 30; int lrange = 6; double lrate = 0.01; SomLearn som(x, y); Mat src(Size(som.map.size(), som.map[0].size()), CV_8UC3, Scalar::all(0)); Mat dst(Size(som.map.size(), som.map[0].size()), CV_8UC3, Scalar::all(0)); for (int i = 0; i < som.map.size(); ++i){ for (int j = 0; j < som.map[0].size(); ++j){ for (int k = 0; k < som.map[0][0].param.size(); ++k){ src.at<Vec3b>(Point(i, j))[k] = som.map[i][j].param[k]; } } } som.Train(node, lrange, lrate); for (int i = 0; i < som.map.size(); ++i){ for (int j = 0; j < som.map[0].size(); ++j){ for (int k = 0; k < som.map[0][0].param.size(); ++k){ dst.at<Vec3b>(Point(i, j))[k] = som.map[i][j].param[k]; } } } //resize(src, src, Size(), 25, 25); //resize(dst, dst, Size(), 25, 25); imshow("src", src); imshow("dst", dst); waitKey(0); return 0; }
voronoi図を作ってみた。
ここのアルゴリズムを参考にして作りました。
voronoifield.hpp
#ifndef VORONOIFIELD_HPP #define VORONOIFIELD_HPP #include "opencv2/opencv.hpp" #include <vector> #include <omp.h> class Voronoi{ double CalcDistance(cv::Point a, cv::Point b){ return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); } void CellProcessing(cv::Point center, cv::Point side){ if ((side.x < 0) || (image_size.x <= side.x) || (side.y < 0) || (image_size.y <= side.y)){ return; } if (cells[side.x][side.y].flag == MOTHER){ if (cells[center.x][center.y].flag == NONE){ cells[center.x][center.y].flag = DETECTED; cells[center.x][center.y].distance = CalcDistance(center, side); cells[center.x][center.y].point_mother = side; } else if (cells[center.x][center.y].flag == DETECTED){ if (cells[center.x][center.y].distance > CalcDistance(center, side)){ cells[center.x][center.y].distance = CalcDistance(center, side); cells[center.x][center.y].point_mother = side; } } } else if (cells[side.x][side.y].flag == DETECTED){ if (cells[center.x][center.y].flag == NONE){ cells[center.x][center.y].flag = DETECTED; cells[center.x][center.y].distance = CalcDistance(center, cells[side.x][side.y].point_mother); cells[center.x][center.y].point_mother = cells[side.x][side.y].point_mother; } else if (cells[center.x][center.y].flag == DETECTED){ if (cells[center.x][center.y].distance > CalcDistance(center, cells[side.x][side.y].point_mother)){ cells[center.x][center.y].distance = CalcDistance(center, cells[side.x][side.y].point_mother); cells[center.x][center.y].point_mother = cells[side.x][side.y].point_mother; } } } } public: class cell_info{ public: int flag; cv::Point point_mother; double distance; cell_info(){ flag = 0; point_mother = cv::Point(-1, -1); distance = 0; } }; cv::Point image_size; double max_distance; std::vector<std::vector<cell_info> > cells; int NONE; int MOTHER; int DETECTED; Voronoi(){ NONE = 0; MOTHER = 1; DETECTED = -1; } Voronoi(cv::Point size){ NONE = 0; MOTHER = 1; DETECTED = -1; SetMap(size); } void SetMap(cv::Point size){ image_size = size; cells = std::vector<std::vector<cell_info> >(image_size.x, std::vector<cell_info>(image_size.y)); max_distance = CalcDistance(cv::Point(0, 0), size); } void SetPoints(std::vector<cv::Point> points){ for (std::vector<cv::Point>::iterator itr = points.begin(); itr < points.end(); ++itr){ if ((itr->x < 0) || (image_size.x <= itr->x) || (itr->y < 0) || (image_size.y <= itr->y)){ return; } cells[itr->x][itr->y].flag = MOTHER; } } void CreateVoronoi(){ for (int k = image_size.x; k >= 1; k /= 2){ double naname = sqrt(k*k + k* k); #pragma omp parallel for for (int i = 0; i < image_size.x; ++i){ for (int j = 0; j < image_size.y; ++j){ CellProcessing(cv::Point(i, j), cv::Point(i - k, j - k)); CellProcessing(cv::Point(i, j), cv::Point(i + k, j - k)); CellProcessing(cv::Point(i, j), cv::Point(i - k, j + k)); CellProcessing(cv::Point(i, j), cv::Point(i + k, j + k)); CellProcessing(cv::Point(i, j), cv::Point(i, j - k)); CellProcessing(cv::Point(i, j), cv::Point(i, j + k)); CellProcessing(cv::Point(i, j), cv::Point(i - k, j)); CellProcessing(cv::Point(i, j), cv::Point(i + k, j)); } } } } void GetImage(cv::Mat &image){ #pragma omp parallel for for (int i = 0; i < image_size.x; ++i){ for (int j = 0; j < image_size.y; ++j){ image.at<unsigned char>(cv::Point(i, j)) = cells[i][j].distance * (512 / max_distance); } } } void GetData(cv::Mat &image, double max_d){ #pragma omp parallel for for (int i = 0; i < image_size.x; ++i){ for (int j = 0; j < image_size.y; ++j){ image.at<double>(cv::Point(i, j)) = cells[i][j].distance / max_d; } } } }; #endif
main.cpp
#include "voronoifield.hpp" /*標準入出力ライブラリ*/ #include <iostream> /*可変長リストライブラリ*/ #include <vector> /*OpenCVライブラリ*/ #include "opencv2/opencv.hpp" #include "opencv2/highgui/highgui_c.h" /*処理時間測定用ライブラリ*/ #include <time.h> #include <omp.h> using namespace std; using namespace cv; int main() { int i = 2; Voronoi voronoi(Point(128 * i, 128 * i)); //vector<Point> points(7); //points[0] = Point(32 * i, 32 * i); //points[1] = Point(20 * i, 10 * i); //points[2] = Point(4 * i, 50 * i); //points[3] = Point(50 * i, 33 * 8); //points[4] = Point(100 * i, 100 * i); //points[5] = Point(100 * i, 10 * i); //points[6] = Point(10 * i, 100 * i); vector<Point> points; for (int x = 100; x < 140; ++x){ for (int y = 100; y < 130; ++y){ points.push_back(Point(x, y)); } } for (int x = 10; x < 14; ++x){ for (int y = 10; y < 13; ++y){ points.push_back(Point(x, y)); } } voronoi.SetPoints(points); voronoi.CreateVoronoi(); Mat image = Mat(voronoi.image_size, CV_8UC1, Scalar::all(0)); voronoi.GetImage(image); imshow("voronoi", image); waitKey(0); return 0; }