wallbot control Library

Dependencies:   PID

wallbotble/wallbotble.cpp

Committer:
c201075
Date:
2018-06-04
Revision:
0:7edbb986d2d7

File content as of revision 0:7edbb986d2d7:

/* JKsoft Wallbot BLE Library
 *
 * wallbotble.cpp
 *
 * Copyright (c) 2010-2014 jksoft
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "mbed.h"
#include "wallbotble.h"



wallbotble::wallbotble() :  	
	_right_motor(P0_28,P0_30,P0_0) , 
	_left_motor(P0_29,P0_23,P0_24) ,		
	_sw(P0_16,P0_17),
	_outlow(P0_20),
	_statusled(P0_18,P0_19),
	//_f_sensor1(P0_2),_f_sensor2(P0_3),_f_sensor3(P0_4),_f_sensor4(P0_5),
	_f_sensor1(P0_5),_f_sensor2(P0_4),_f_sensor3(P0_3),_f_sensor4(P0_2),
	_right_enc(P0_8),
	_left_enc(P0_6),
	_ctrl_r(Kp, Ki, Kd, RATE),
	_ctrl_l(Kp, Ki, Kd, RATE)
	{ 
		_right_motor = 0.0;
	    _left_motor = 0.0;
	    _outlow = 0;	
		_statusled = 0x3;
		_sw.mode(PullUp);
		//エンコーダのセットアップ(位相差がないのでA相のみを使う簡易エンコーダ)
    	_right_enc.mode(PullNone);
    	_left_enc.mode(PullNone);

		_right_pulses = 0;
		_left_pulses =0;
		
		_right_timer.start();
		_left_timer.start();
		
	    _right_enc.rise(this, &wallbotble::right_count);
	    _right_enc.fall(this, &wallbotble::right_count);
	    
	    _left_enc.rise(this, &wallbotble::left_count);
	    _left_enc.fall(this, &wallbotble::left_count);
	    
		//ラインセンサキャリブレーション値のリセット
		for(int i = 0 ; i < 4 ; i++)
		{
			_calibratedMinimum[i] = 65535;
			_calibratedMaximum[i] = 0;
		}
		//PIDの初期化
	    _ctrl_r.setInputLimits(0,100);
	    _ctrl_l.setInputLimits(0,100); 
	    _ctrl_r.setOutputLimits(0, 1.0);
    	_ctrl_l.setOutputLimits(0, 1.0);
	
		 _right_back = false;
		 _left_back = false;
	    
	}
void wallbotble::control_enable(bool enable){
	if(enable)
		_control_tic.attach(this, &wallbotble::tick_callback,RATE);
	else
		_control_tic.detach();
		
	_ctrl_r.reset();
	_ctrl_l.reset();
		
}
void wallbotble::tick_callback(){
	//現状態を与える
    _ctrl_r.setProcessValue(get_right_rpm());
    _ctrl_l.setProcessValue(get_left_rpm());

	//制御指令
	if(_right_back)
	    _right_motor = -1*_ctrl_r.compute() + ff_r;
	else
	    _right_motor = _ctrl_r.compute() + ff_r;
	    
	if(_left_back)
		_left_motor = -1*_ctrl_l.compute() + ff_l;
    else
	    _left_motor = _ctrl_l.compute() + ff_l;
    	
}

void wallbotble::SetRPM(float leftRPM, float rightRPM){
	_right_back = false;
	_left_back = false;
	
	ff_r = 0.022*rightRPM;
	ff_l = 0.022*leftRPM;
	
	if(rightRPM < 0){
		_right_back = true;
		rightRPM = -1 *rightRPM; 
	}
	if(leftRPM < 0){
		_left_back = true;
		leftRPM = -1 *leftRPM;
	}
	
    _ctrl_r.setSetPoint(rightRPM);	
	_ctrl_l.setSetPoint(leftRPM);
}

float wallbotble::get_right_rpm(){
	//500ms以上パルスが来ていなければ0
	if(_right_timer.read_ms() > 500)
		_right_rpm = 0;
	
	return _right_rpm;
}

float wallbotble::get_left_rpm(){
	//500ms以上パルスが来ていなければ0
	if(_left_timer.read_ms() > 500)
		_left_rpm = 0;
		
	return _left_rpm;
}

void wallbotble::right_count(){
	_right_pulses++;

	static int _right_times[4];
	
	_right_times[_right_pulses%4] = _right_timer.read_ms();
	
	_right_timer.reset();
	_right_timer.start();

	_right_rpm = (60.0/((float)(_right_times[0]+_right_times[1]+_right_times[2]+_right_times[3])/1000.0)) * 4.0/PulsesPerRev ;

}
void wallbotble::left_count(){
	_left_pulses++;
	
	static int _left_times[4];
	
	_left_times[_left_pulses%4] = _left_timer.read_ms();
	
	_left_timer.reset();
	_left_timer.start();

	_left_rpm = (60/((float)(_left_times[0]+_left_times[1]+_left_times[2]+_left_times[3])/1000))* 4/PulsesPerRev;
}
// 自動キャリブレ
void wallbotble::auto_calibrate()
{
    control_enable(false);
    Timer time;
    time.start();
    left_turn(0.7);  
    while(time.read_ms() < 1000)  
        f_sensor_calibrate();  
    right_turn(0.7);  
    while(time.read_ms() < 3000)  
        f_sensor_calibrate();  
    left_turn(0.7);  
    while(time.read_ms() < 4000)  
        f_sensor_calibrate();   
    stop(); 
    time.stop();
}

// キャリブレーションのリセット
void wallbotble::resetCalibration(){
	for(int i = 0 ; i < 4 ; i++)
	{
		_calibratedMinimum[i] = 65535;
		_calibratedMaximum[i] = 0;
	}
}

void wallbotble::left_motor (float duty) {
    _left_motor = duty;
}

void wallbotble::right_motor (float duty) {
    _right_motor = duty;
}

void wallbotble::forward (float duty) {
    _left_motor = duty;
	_right_motor = duty;
}

void wallbotble::backward (float duty) {
    _left_motor = -duty;
	_right_motor = -duty;
}

void wallbotble::left_turn (float duty) {
    _left_motor = -duty;
	_right_motor = duty;
}

void wallbotble::right_turn (float duty) {
    _left_motor = duty;
	_right_motor = -duty;
}

void wallbotble::stop (void) {
    _right_motor = 0.0;
    _left_motor = 0.0;
}

void wallbotble::set_led(char bit) {
	bit |= bit >> 2;
	_statusled = (bit ^ 0x03) & 0x03;
}

void wallbotble::set_led1(char bit) {
	if( bit )
	{
		bit = _statusled ^ 0x03;
		bit = bit | 0x1;
	}
	else
	{
		bit = _statusled ^ 0x03;
		bit = bit & 0x2;
	}
	set_led(bit);
}

void wallbotble::set_led2(char bit) {
	if( bit )
	{
		bit = _statusled ^ 0x03;
		bit = bit | 0x2;
	}
	else
	{
		bit = _statusled ^ 0x03;
		bit = bit & 0x1;
	}
	set_led(bit);
}

/**センサ値を10回読み込み、最大値と最小値を取得する
* センサ毎にライン→ライン外で2回この関数を呼ぶイメージ
* 
*/

void wallbotble::f_sensor_calibrate(void) {

	unsigned short max_sensor_values[4];
	unsigned short min_sensor_values[4];
	
	for(char j=0;j<10;j++)
	{
		unsigned short sensor_values[4] = { _f_sensor1.read_u16(),
											 _f_sensor2.read_u16(),
											 _f_sensor3.read_u16(),
											 _f_sensor4.read_u16()
										   };
		   
		for(int i=0;i<4;i++)
		{
			// set the max we found THIS time
			if(j == 0 || max_sensor_values[i] < sensor_values[i])
				max_sensor_values[i] = sensor_values[i];

			// set the min we found THIS time
			if(j == 0 || min_sensor_values[i] > sensor_values[i])
				min_sensor_values[i] = sensor_values[i];
		}
	}
	
	// record the min and max calibration values
	for(char i=0;i<4;i++)
	{
		if(min_sensor_values[i] > _calibratedMaximum[i])	//より大きな最小値へ更新
			_calibratedMaximum[i] = min_sensor_values[i];
		if(max_sensor_values[i] < _calibratedMinimum[i])	//より小さな最大値へ更新
			_calibratedMinimum[i] = max_sensor_values[i];
	}
	
}

// ラインの推定位置を返す。-1500~0(中央)~1500
// ラインセンサの出力が低すぎる場合(ロスト)は、前回値から判定し、0か3000を返す
short wallbotble::GetLinePosition(void) {
	unsigned char i, on_line = 0;
	unsigned long avg = 0; // this is for the weighted total, which is long before division
	unsigned int sum = 0; // this is for the denominator which is <= 64000
	static int last_value=0; // assume initially that the line is left.
	
	readCalibrated();
	
	for(i=0;i<4;i++) {
		int value = sensor_values[i];

		// keep track of whether we see the line at all
		if(value > 450) {
			on_line = 1;
		}
		
		// only average in values that are above a noise threshold
		if(value > 50) {
			avg += (long)(value) * (i * 1000);
			sum += value;
		}
	}

	if(!on_line)//ラインをロストしていたら、前回値から右端、左端として出力する
	{
		if(last_value < 0)
			return -1500;
		else
			return 1500;

	}

	last_value = avg/sum -1500;

	return last_value;
}

// ラインセンサ値を補正し0から1000にマッピングしてsensor_valuesにロードする。
// 0 はキャリブレートmin以下を、1000はキャリブレートmax以上を意味します。
// キャリブレートmin,maxはセンサ毎にストアされています。
void wallbotble::readCalibrated(){
	unsigned short raw_values[4] = { _f_sensor1.read_u16(),
									 _f_sensor2.read_u16(),
									 _f_sensor3.read_u16(),
									 _f_sensor4.read_u16()
								   };

#if DBG
	printf("raw(%d,%d,%d,%d)",raw_values[0],raw_values[1],raw_values[2],raw_values[3]);
#endif
		   
   	for(int i=0;i<4;i++)
	{
   		unsigned int denominator = _calibratedMaximum[i] - _calibratedMinimum[i];
		
		signed int x = 0;
		if(denominator != 0)
			x = (((signed long)raw_values[i]) - _calibratedMinimum[i]) * 1000 / denominator;
		
		if(x < 0)
			x = 0;
		else if(x > 1000)
			x = 1000;
			
		sensor_values[i] = x;
	}
   
}

int wallbotble::GetSw(void) {
	return(_sw ^ 0x3);
}