可変ブログ

色々メモとか。とりあえず自分が分かるように。その後、なるべく人が見て分かるように。可変。

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のセットアップ

ここら辺を参考に




・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にルーターの機能を付ける場合はここら辺


RaspberryPiに中継(ブリッジ)機能を付ける場合はここら辺



今回は単純なアクセスポイント化(インターネット接続なし、DHCP機能なし)をやりたかったので、hostapd周辺だけの設定だったので簡単でした。
ざっくりやったこと。
・wlan0のIPを固定
・hostapdをインストール
・hostapd.confを編集
・wlan0をUP
・hostapd実行



ちなみに今回と逆のパターンで
RaspberryPiで無線を受けて、それを有線にながすのはイーサネットコンバータというらしい。

Raspberry Pi3を無線LANコンバータにする -blog SkyofFantasy-



マウスキーボード共有ソフトSynergyのインストール

一つのマウスキーボードをネットワーク越しに複数PCで使いまわすソフトSynergyのインストール方法



ビルド済みのものはここらへんから




ソースはここらへんから

githubwikiコンパイル方法が書いてあります。



古いソースのビルド方法はもう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;
}




f:id:shibafu3:20200522102142p:plain

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;

}