Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
//モータドライバを用いて鉄道模型を制御するためのライブラリ
//十三車両製作所
//グローバル変数
var pwmNo1;
var pwmNo2;
var pwmNo3;
var pwmNo4;
var pwmNo5;
var pwmNo6;
var pwmNo1Flug = 0;
var pwmNo2Flug = 0;
var pwmNo3Flug = 0;
var pwmNo4Flug = 0;
var pwmNo5Flug = 0;
var pwmNo6Flug = 0;
var pwmAllot = new Array();
var IO0OutputFlug = 0;
var IO1OutputFlug = 0;
var IO2OutputFlug = 0;
var IO3OutputFlug = 0;
var IO4OutputFlug = 0;
var IO5OutputFlug = 0;
var IO6OutputFlug = 0;
var IO7OutputFlug = 0;
var IO8OutputFlug = 0;
var IO9OutputFlug = 0;
var IO10OutputFlug = 0;
var IO11OutputFlug = 0;
var IO9OutputFlug = 0;
//自動運転パッケージ(2点方式)
function AutoTrainOperation_2PointEndless(ATO_2PE){
//各引数が定義されていない場合の初期化
if(typeof ATO_2PE.Phase === "undefined"){
//制御フェーズ。0は異常状態。
ATO_2PE.Phase = 0;
}
if(typeof ATO_2PE.TargetSpeed === "undefined"){
//目標速度。
ATO_2PE.TargetSpeed = 100;
}
if(typeof ATO_2PE.VehicleSpeed === "undefined"){
//現在速度。
ATO_2PE.VehicleSpeed = 0;
}
if(typeof ATO_2PE.SpeedRange === "undefined"){
//速度幅。
ATO_2PE.SpeedRange = 3;
}
if(typeof ATO_2PE.StationStopSpeed === "undefined"){
//駅停車前速度km/h。
ATO_2PE.StationStopSpeed = 20;
}
if(typeof ATO_2PE.Sensor1 === "undefined"){
//センサ1。
ATO_2PE.Sensor1 = false;
}
if(typeof ATO_2PE.Sensor2 === "undefined"){
//センサ2。
ATO_2PE.Sensor2 = false;
}
if(typeof ATO_2PE.SettedStationStopTime === "undefined"){
//停車時間設定値。
ATO_2PE.SettedStationStopTime = 20;
}
if(typeof ATO_2PE.StationStopTime === "undefined"){
//駅に停車してからの時間。
ATO_2PE.StationStopTime = 0;
}
if(typeof ATO_2PE.StepTime === "undefined"){
//制御周期(ミリ秒)。
ATO_2PE.StepTime = 50;
}
if(typeof ATO_2PE.PNotch === "undefined"){
//力行ノッチ。
ATO_2PE.PNotch = 5;
}
if(typeof ATO_2PE.BNotch === "undefined"){
//ブレーキノッチ。
ATO_2PE.BNotch = -5;
}
if(typeof ATO_2PE.MinimumTimeOfRunning === "undefined"){
//フェーズ切替最小時間
ATO_2PE.MinimumTimeOfRunning = 20;
}
if(typeof ATO_2PE.RunningTime === "undefined"){
//走行時間
ATO_2PE.RunningTime = 0;
}
//ローカル変数定義
var ATONotch = 0;//
var ConstantSpeedRunningFlug = 0;
var Phase = ATO_2PE.Phase;
var StationStopTime = ATO_2PE.StationStopTime;
var PNotch = ATO_2PE.PNotch;
var BNotch = ATO_2PE.BNotch;
var RunningTime = ATO_2PE.RunningTime;
//フェーズ制御
if(Phase == 1){
//フェーズ1。出発準備が整い出発している状態
//目標速度まで力行する。目標速度に到達したら定速走行する。
if(ATO_2PE.VehicleSpeed < ATO_2PE.TargetSpeed){
ATONotch = PNotch;
ConstantSpeedRunningFlug = 0;
}
else if(ATO_2PE.VehicleSpeed > ATO_2PE.TargetSpeed + ATO_2PE.SpeedRange){
ATONotch = BNotch;
ConstantSpeedRunningFlug = 0;
}
else if(ATO_2PE.VehicleSpeed > ATO_2PE.TargetSpeed){
ATONotch = PNotch;
ConstantSpeedRunningFlug = 1;
}
else{
ATONotch = 0;
ConstantSpeedRunningFlug = 0;
}
//走行時間を積算する。
RunningTime = RunningTime + ATO_2PE.StepTime / 1000;
//1つ目のセンサを踏んだらフェーズを進める。
if(ATO_2PE.Sensor1 == true & RunningTime > ATO_2PE.MinimumTimeOfRunning ){
Phase = 2;
}
//駅停車時間を0にする。
StationStopTime = 0;
}
else if(Phase == 2){
//フェーズ2。1つめのセンサが反応した状態。
//駅停止前速度まで減速する。
if(ATO_2PE.VehicleSpeed > ATO_2PE.StationStopSpeed){
ATONotch = BNotch;
ConstantSpeedRunningFlug = 0;
}
else if(ATO_2PE.VehicleSpeed < ATO_2PE.StationStopSpeed - ATO_2PE.SpeedRange){
ATONotch = PNotch;
ConstantSpeedRunningFlug = 0;
}
else{
ATONotch = 0;
ConstantSpeedRunningFlug = 0;
}
//走行時間を初期化する。
RunningTime = 0;
//2つ目のセンサを踏んだらフェーズを進める。
if(ATO_2PE.Sensor2 == true){
Phase = 3;
}
}
else if(Phase == 3){
//フェーズ3。停止センサが反応した状態。
//速度が0km/hになるまで減速する。
ATONotch = BNotch;
ConstantSpeedRunningFlug = 0;
//速度が0km/hになってから所定の停車時間が経過したしたあとフェーズを1にする。
if(ATO_2PE.VehicleSpeed <= 0){
if(StationStopTime < ATO_2PE.SettedStationStopTime){
StationStopTime = StationStopTime + ATO_2PE.StepTime / 1000;
}
else{
Phase = 1;
}
}
}
else{
//フェーズが上記以上の場合。
//異常状態であると判断し、速度が0km/hになるまで減速する。
ATONotch = BNotch;
ConstantSpeedRunningFlug = 0;
}
//変数を返す。
return{Notch:ATONotch, Phase:Phase, StationStopTime:StationStopTime, ConstantSpeedRunningFlug:ConstantSpeedRunningFlug, RunningTime:RunningTime};
}
//列車駆動パッケージ(マスコン操作画面で駆動(駆動音別方式テスト))。
function TrainMotorDrivePackage_Mascon_SoundTest(TMDP){
//速度計算
var SpeedCalcResult
SpeedCalcResult = SpeedCalc({LV:TMDP.SpeedCalcLV, NotchValue:TMDP.NotchValue, PowerNotchStepNum:TMDP.PowerNotchStepNum, BrakeNotchStepNum:TMDP.BrakeNotchStepNum, MaxSpeed:TMDP.MaxSpeed, StartAcceleration:TMDP.StartAcceleration, MaxDecceleration:TMDP.MaxDecceleration, EmergencyDecceleration:TMDP.EmergencyDecceleration, CoastingDecceleration:TMDP.CoastingDecceleration, StepTime:TMDP.StepTime, ConstantSpeedSwitchValue:TMDP.ConstantSpeedSwitchValue, SpeedValue:TMDP.SpeedValue, ConstantPowerAreaStartSpeed:TMDP.ConstantPowerAreaStartSpeed, CharacteristicAreaStartSpeed:TMDP.CharacteristicAreaStartSpeed, CoastingDeccelerationParameter_A:TMDP.CoastingDeccelerationParameter_A, CoastingDeccelerationParameter_B:TMDP.CoastingDeccelerationParameter_B, EmergencyStop:TMDP.EmergencyStop});
//モータ音駆動計算(PWM周波数を設定)(列車種類を消した)
var SoundFromMotorResult
SoundFromMotorResult = SoundFromMotor({TrainName:TMDP.TrainName, SpeedValue:SpeedCalcResult.SpeedValue, NotchValue:TMDP.NotchValue, CoastingFrequency:TMDP.BaseFrequency, MotorKind:TMDP.MotorKind});
//モータ音駆動計算(PWM周波数を設定)(列車種類を消した)
var SoundFromMotorResult_2
SoundFromMotorResult_2 = SoundFromMotor({TrainName:"KQ-2100", SpeedValue:SpeedCalcResult.SpeedValue, NotchValue:TMDP.NotchValue, CoastingFrequency:TMDP.BaseFrequency, MotorKind:TMDP.MotorKind});
//速度をDutyに変換
var DutyConvertorResult
DutyConvertorResult = DutyConvertor({DutyA:TMDP.DutyA, DutyB:TMDP.DutyB, SpeedA:TMDP.SpeedA, SpeedB:TMDP.SpeedB, SpeedValue:SpeedCalcResult.SpeedValue, EmergencyStop:TMDP.EmergencyStop});
//PWM駆動する。
var TrainMotorDrivePWMResult
TrainMotorDrivePWMResult = TrainMotorDrivePWM({PwmPin:TMDP.PwmPin, MaxDuty:TMDP.MaxDuty, FrequencyValue:TMDP.BaseFrequency, DutyValue:DutyConvertorResult.DutyValue, EmergencyStop:TMDP.EmergencyStop});
//音用のPWM出力(1音目)
var SoundPulse_1
SoundPulse_1 = TrainMotorDrivePWM({PwmPin:TMDP.PwmPin_2, FrequencyValue:SoundFromMotorResult.FrequencyValue, DutyValue:TMDP.SoundDuty_1, EmergencyStop:TMDP.EmergencyStop});
//音用のPWM出力(2音目)
var SoundPulse_2
SoundPulse_2 = TrainMotorDrivePWM({PwmPin:TMDP.PwmPin_3, FrequencyValue:SoundFromMotorResult_2.FrequencyValue, DutyValue:TMDP.SoundDuty_2, EmergencyStop:TMDP.EmergencyStop});
//Duty、周波数、速度、加速度、Duty補正値を返す。
return{DutyValue:DutyConvertorResult.DutyValue, FrequencyValue:TrainMotorDrivePWMResult.FrequencyValue, SpeedValue:SpeedCalcResult.SpeedValue, AccelerationValue:SpeedCalcResult.AccelerationValue, DutyCorrectionValue:SoundFromMotorResult.DutyCorrectionValue};
}
//列車駆動パッケージ(マスコン操作画面で駆動)。
function TrainMotorDrivePackage_Mascon(TMDP){
//速度計算
var SpeedCalcResult
SpeedCalcResult = SpeedCalc({LV:TMDP.SpeedCalcLV, NotchValue:TMDP.NotchValue, PowerNotchStepNum:TMDP.PowerNotchStepNum, BrakeNotchStepNum:TMDP.BrakeNotchStepNum, MaxSpeed:TMDP.MaxSpeed, StartAcceleration:TMDP.StartAcceleration, MaxDecceleration:TMDP.MaxDecceleration, EmergencyDecceleration:TMDP.EmergencyDecceleration, CoastingDecceleration:TMDP.CoastingDecceleration, StepTime:TMDP.StepTime, ConstantSpeedSwitchValue:TMDP.ConstantSpeedSwitchValue, SpeedValue:TMDP.SpeedValue, ConstantPowerAreaStartSpeed:TMDP.ConstantPowerAreaStartSpeed, CharacteristicAreaStartSpeed:TMDP.CharacteristicAreaStartSpeed, CoastingDeccelerationParameter_A:TMDP.CoastingDeccelerationParameter_A, CoastingDeccelerationParameter_B:TMDP.CoastingDeccelerationParameter_B, EmergencyStop:TMDP.EmergencyStop});
//モータ音駆動計算(PWM周波数を設定)
var SoundFromMotorResult
SoundFromMotorResult = SoundFromMotor({TrainName:TMDP.TrainName, SpeedValue:SpeedCalcResult.SpeedValue, NotchValue:TMDP.NotchValue, CoastingFrequency:TMDP.BaseFrequency, MotorKind:TMDP.MotorKind});
//速度をDutyに変換
var DutyConvertorResult
DutyConvertorResult = DutyConvertor({DutyA:TMDP.DutyA, DutyB:TMDP.DutyB, SpeedA:TMDP.SpeedA, SpeedB:TMDP.SpeedB, SpeedValue:SpeedCalcResult.SpeedValue, DutyCorrectionValue:SoundFromMotorResult.DutyCorrectionValue, EmergencyStop:TMDP.EmergencyStop});
//PWM駆動する。
var TrainMotorDrivePWMResult
TrainMotorDrivePWMResult = TrainMotorDrivePWM({PwmPin:TMDP.PwmPin, MaxDuty:TMDP.MaxDuty, FrequencyValue:SoundFromMotorResult.FrequencyValue, DutyValue:DutyConvertorResult.DutyValue, EmergencyStop:TMDP.EmergencyStop});
//Duty、周波数、速度、加速度、Duty補正値を返す。
return{DutyValue:DutyConvertorResult.DutyValue, FrequencyValue:TrainMotorDrivePWMResult.FrequencyValue, SpeedValue:SpeedCalcResult.SpeedValue, AccelerationValue:SpeedCalcResult.AccelerationValue, DutyCorrectionValue:SoundFromMotorResult.DutyCorrectionValue};
}
//列車駆動パッケージ(ボリューム操作画面で駆動)。
function TrainMotorDrivePackage_Volume(TMDP_V){
//速度計算(表示用) ボリューム制御では、ボリューム操作で直接Duty比を操作するため、速度はあくまで表示用。
var SpeedCalcResult
SpeedCalcResult = SpeedCalc_Disp({DutyA:TMDP_V.DutyA, DutyB:TMDP_V.DutyB, SpeedA:TMDP_V.SpeedA, SpeedB:TMDP_V.SpeedB, MaxSpeed:TMDP_V.MaxSpeed, DutyValue:TMDP_V.DutyValue, EmergencyStop:TMDP_V.EmergencyStop});
//PWM駆動する。
var TrainMotorDrivePWMResult
TrainMotorDrivePWMResult = TrainMotorDrivePWM({PwmPin:TMDP_V.PwmPin, MaxDuty:TMDP_V.MaxDuty, FrequencyValue:TMDP_V.FrequencyValue, DutyValue:TMDP_V.DutyValue, EmergencyStop:TMDP_V.EmergencyStop});
//Duty、周波数、速度を返す。
return{DutyValue:TrainMotorDrivePWMResult.DutyValue, FrequencyValue:TrainMotorDrivePWMResult.FrequencyValue, SpeedValue:SpeedCalcResult.SpeedValue};
}
//速度計算機能(表示用)
function SpeedCalc_Disp(SCL_D){
//各引数が定義されていない場合の初期化
if(typeof SCL_D.DutyA === "undefined"){
//DutyA[%]
SCL_D.DutyA = 0;
}
if(typeof SCL_D.DutyB === "undefined"){
//DutyB[%]
SCL_D.DutyB = 100;
}
if(typeof SCL_D.SpeedA === "undefined"){
//SpeedA[km/h]
SCL_D.SpeedA = 0;
}
if(typeof SCL_D.SpeedB === "undefined"){
//SpeedB[km/h]
SCL_D.SpeedB = 100;
}
if(typeof SCL_D.MaxSpeed === "undefined"){
//最高速度[km/h]
SCL_D.MaxSpeed = 400;
}
if(typeof SCL_D.EmergencyStop === "undefined"){
//非常停止フラグ
SCL_D.EmergencyStop = 0;
}
//Duty比を速度[km/h]に変換する。(速度がDuty比に対して線形に比例することを前提としている。)
var A=0;
var B=0;
var DutyValue=0;
var SpeedValue=0;
A = (SCL_D.SpeedB - SCL_D.SpeedA)/(SCL_D.DutyB - SCL_D.DutyA);
B = SCL_D.SpeedA - A * SCL_D.DutyA;
SpeedValue = A * SCL_D.DutyValue + B;
//速度上限[km/h]が設定されている場合、速度[km/h]を制限する。(一応マイナスにならないようにも制限)
if(SpeedValue > SCL_D.MaxSpeed){
SpeedValue = SCL_D.MaxSpeed;
}
else if(SpeedValue < 0){
SpeedValue = 0;
}
//非常停止フラグが立っている場合は速度[km/h]を0に設定する。
if(SCL_D.EmergencyStop != 0){
SpeedValue = 0;
}
//速度[km/h]を返す
return{SpeedValue:SpeedValue};
}
//速度計算機能
function SpeedCalc(SCL1){
//各引数が定義されていない場合の初期化
if(typeof SCL1.LV === "undefined"){
//機能レベル[LV] とりあえず1
SCL1.LV = 1;
}
else if(typeof SCL1.LV < 1){
//機能レベル[LV] 1より小さい値は設定していないため、とりあえず1にしておく。
SCL1.LV = 1;
}
else if(typeof SCL1.LV > 2){
//機能レベル[LV] 2より大きい値は設定していないため、とりあえず1にしておく。
SCL1.LV = 1;
}
if(typeof SCL1.NotchValue === "undefined"){
//現在のノッチ[段] とりあえずノッチOFF
SCL1.NotchValue = 0;
}
if(typeof SCL1.PowerNotchStepNum === "undefined"){
//力行ノッチ段数[段] とりあえず。一般的な段数
SCL1.PowerNotchStepNum = 5;
}
if(typeof SCL1.BrakeNotchStepNum === "undefined"){
//ブレーキノッチ段数[段] とりあえず。一般的な段数
SCL1.BrakeNotchStepNum = 7;
}
if(typeof SCL1.MaxSpeed === "undefined"){
//最高速度[km/h] とりあえず首都圏在来線最速
SCL1.MaxSpeed = 130;
}
if(typeof SCL1.StartAcceleration === "undefined"){
//最大加速度[km/h/s] とりあえず首都圏在来線最大
SCL1.StartAcceleration = 3.3;
}
if(typeof SCL1.MaxDecceleration === "undefined"){
//常用最大減速度[km/h/s] とりあえず首都圏在来線の一般的な値
SCL1.MaxDecceleration = 3.5;
}
if(typeof SCL1.EmergencyDecceleration === "undefined"){
//非常減速度[km/h/s] とりあえず首都圏在来線の一般的な値
SCL1.EmergencyDecceleration = 4.5;
}
if(typeof SCL1.CoastingDecceleration === "undefined"){
//惰行時減速度[km/h/s] なんとなくこんなもん
SCL1.CoastingDecceleration = 0.2;
}
if(typeof SCL1.StepTime === "undefined"){
//計算周期[秒] とりあえず0.01秒
SCL1.StepTime = 10;
}
if(typeof SCL1.ConstantSpeedSwitchValue === "undefined"){
//定速走行スイッチ[0:OFF 1:ON]
SCL1.ConstantSpeedSwitchValue = 0;
}
if(typeof SCL1.SpeedValue === "undefined"){
//現在速度[km/h]
SCL1.SpeedValue = 0;
}
if(typeof SCL1.ConstantPowerAreaStartSpeed === "undefined"){
//定出力領域開始速度[km/h] とりあえず
SCL1.ConstantPowerAreaStartSpeed = 40;
}
if(typeof SCL1.CharacteristicAreaStartSpeed === "undefined"){
//特性領域開始速度[km/h] とりあえず
SCL1.CharacteristicAreaStartSpeed = 80;
}
if(typeof SCL1.CoastingDeccelerationParameter_A === "undefined"){
//惰行時減速度パラメータ_A とりあえず
SCL1.CoastingDeccelerationParameter_A = 0.00001;
}
if(typeof SCL1.CoastingDeccelerationParameter_B === "undefined"){
//惰行時減速度パラメータ_B とりあえず
SCL1.CoastingDeccelerationParameter_B = 0.00001;
}
if(typeof SCL1.EmergencyStop === "undefined"){
//非常停止フラグ
SCL1.EmergencyStop = 0;
}
//ノッチに応じた加速度を計算する。
var AccelerationValue = 0;
var CoastingDecceleration;
CoastingDecceleration = SCL1.CoastingDecceleration;
//ノッチが力行の場合
if(SCL1.NotchValue > 0){
//機能LV1の加速度計算(ノッチ段数に応じて加速度が変化。終端速度はノッチ段数に関わらず同じ。)
if(SCL1.LV == 1){
AccelerationValue = SCL1.StartAcceleration * SCL1.NotchValue / SCL1.PowerNotchStepNum - CoastingDecceleration;//ノッチ段数に応じた加速度から惰行時の減速度を引いた値として計算。
//定速スイッチがONである場合、加速度を0にする。
if(SCL1.ConstantSpeedSwitchValue == 1){
AccelerationValue = 0;
}
}
//機能LV2の加速度計算(ノッチに応じて終端速度が変化。加速度はノッチ段数に関わらず同じ。)こっちの方が実際の電車に近い加速感が得られる。(いつか気動車用の機能LVも作りたい)
//機能LV2における加速度計算は、右ページの「電気車における速度制御」の記載を参考にしている。http://www.wikiwand.com/ja/%E9%9B%BB%E6%B0%97%E8%BB%8A%E3%81%AE%E9%80%9F%E5%BA%A6%E5%88%B6%E5%BE%A1
else if(SCL1.LV == 2){
var AccelerationConstantTorqueArea
var AccelerationConstantPowerArea
var AccelerationCharacteristicArea
//惰行時の減速度を計算。直線平たん路における走行抵抗(惰行時に列車を減速させる力)は速度に対する2次方程式で近似できるため、惰行時減速度パラメータでそれっぽい計算式を使用し求める。走行抵抗については、右ページの「走行抵抗の表現式」のあたりを参照。https://ja.wikipedia.org/wiki/%E5%88%97%E8%BB%8A%E6%8A%B5%E6%8A%97
CoastingDecceleration = SCL1.CoastingDeccelerationParameter_A * SCL1.SpeedValue * SCL1.SpeedValue + SCL1.CoastingDeccelerationParameter_B * SCL1.SpeedValue + SCL1.CoastingDecceleration;
//定トルク領域(始動時から定出力領域開始速度[km/h]に到達するまで)の加速度を計算
AccelerationConstantTorqueArea = SCL1.StartAcceleration;
//定出力領域(定出力領域開始速度[km/h]から特性領域開始速度[km/h]に到達するまで)の加速度を計算
AccelerationConstantPowerArea = AccelerationConstantTorqueArea * SCL1.ConstantPowerAreaStartSpeed * SCL1.NotchValue / SCL1.PowerNotchStepNum / SCL1.SpeedValue;
//特性領域(特性領域開始速度[km/h]以降)の加速度を計算
AccelerationCharacteristicArea = AccelerationConstantTorqueArea * SCL1.ConstantPowerAreaStartSpeed * SCL1.CharacteristicAreaStartSpeed * (SCL1.NotchValue / SCL1.PowerNotchStepNum) * (SCL1.NotchValue / SCL1.PowerNotchStepNum) / SCL1.SpeedValue;
//定トルク、定出力、特性の各領域のうち最も小さい加速度を最終的な加速度として出力する。
AccelerationValue = Math.min(AccelerationConstantTorqueArea, AccelerationConstantPowerArea, AccelerationCharacteristicArea);
AccelerationValue = AccelerationValue - CoastingDecceleration;
//定速スイッチがONである場合、加速度を0にする。
if(SCL1.ConstantSpeedSwitchValue == 1){
//力行加速度が正の場合は定速走行可能なため加速度を0にする。
if(AccelerationValue > 0){
AccelerationValue = 0;
}
}
}
}
//ノッチがブレーキの場合
else if(SCL1.NotchValue < 0){
//非常ブレーキの場合
if(SCL1.NotchValue < SCL1.BrakeNotchStepNum * -1){
AccelerationValue = -1 * SCL1.EmergencyDecceleration - CoastingDecceleration;
}
//常用ブレーキ(B1~非常ブレーキの1個手前まで)の場合
else{
AccelerationValue = SCL1.MaxDecceleration * SCL1.NotchValue / SCL1.BrakeNotchStepNum - CoastingDecceleration;
}
}
//ノッチがOFF(ニュートラル)の場合
else{
AccelerationValue = -1 * CoastingDecceleration;
}
//上までの処理で求めた加速度を積分して速度を計算する。
var SpeedValue=0;
SpeedValue = SCL1.SpeedValue + AccelerationValue * (SCL1.StepTime / 1000);
if(SpeedValue > SCL1.MaxSpeed){
SpeedValue = SCL1.MaxSpeed;
}
else if(SpeedValue < 0){
SpeedValue = 0;
}
//非常停止フラグが立っている場合は加速度及び速度を0に設定する。
if(SCL1.EmergencyStop != 0){
SpeedValue = 0;
AccelerationValue = 0;
}
//速度と減速度を返す
return{SpeedValue:SpeedValue, AccelerationValue:AccelerationValue};
}
//モータ音駆動
function SoundFromMotor(SFM){
//各引数が定義されていない場合の初期化
if(typeof SFM.TrainName === "undefined"){
//列車種類
SFM.TrainName = "NoTrain";
}
if(typeof SFM.SpeedValue === "undefined"){
//速度[km/h]
SFM.SpeedValue = 0;
}
if(typeof SFM.NotchValue === "undefined"){
//ノッチ[段]
SFM.NotchValue = 0;
}
if(typeof SFM.CoastingFrequency === "undefined"){
//惰行時の周波数[kHz]
SFM.CoastingFrequency = 20000;
}
if(typeof SFM.MotorKind === "undefined"){
//モータ種類
SFM.MotorKind = "NoSound";
}
//音データ選択。音のバリエーションを増やす場合はここにデータを追加していく。
var SoundData
if(SFM.TrainName === "JRE-209"){
//JR東日本209系タイプ(GTOサイリスタVVVF) なお、値は適当
//SoundDataは、奇数番目に速度[km/h]、偶数番目に周波数[Hz]を設定
SoundData = [0,400,
5,400,
10,1000,
10.1,600,
20,1200,
20.1,800,
30,1200,
30.1,400,
36,600,
36.1,250,
130,600];
}
else if(SFM.TrainName === "KQ-2100"){
//京急2100系タイプ(GTOサイリスタVVVF。いわゆるドレミファインバータ) なお、値は適当
//SoundDataは、奇数番目に速度[km/h]、偶数番目に周波数[Hz]を設定
SoundData = [0,349,
3.0,349,
3.01,392,
3.4,392,
3.41,440,
3.8,440,
3.81,466,
4.2,466,
4.21,523,
4.6,523,
4.61,587,
5.0,587,
5.01,622,
5.4,622,
5.41,698,
5.8,698,
5.81,784,
13.0,784,
13.01,1000,
16.0,1200,
16.01,800,
19.0,1000,
19.01,700,
23.0,900,
23.01,250,
130,600,
];
}
else{
//列車種類がNoTrainのばあいは、終始惰行時の周波数を出力
SoundData = [0,SFM.CoastingFrequency,
1000,SFM.CoastingFrequency];
}
//現在の速度を音データに当てはめて、周波数を探索する。
var FrequencyValue = 0;
for(var i = 0; i + 1 < SoundData.length / 2; i++){
if(SFM.SpeedValue >= SoundData[i*2]){
if(SFM.SpeedValue < SoundData[(i+1)*2]){
//線形補完で周波数を計算
var A
var B
A = (SoundData[i*2+1] - SoundData[(i+1)*2+1])/(SoundData[i*2] - SoundData[(i+1)*2]);
B = SoundData[(i+1)*2+1] - A * SoundData[(i+1)*2];
FrequencyValue = A * SFM.SpeedValue + B;
//計算が終了したらループを抜ける
break;
}
}
}
//この段階で周波数が何も設定されていない場合はとりあえず惰行時の周波数に設定
if(FrequencyValue == 0){
FrequencyValue = SFM.CoastingFrequency;
}
//ノッチが減速で速度が0km/hの場合惰行時の周波数に設定(まぁないとは思うけど)
if(SFM.NotchValue < 0 & SFM.SpeedValue == 0){
FrequencyValue = SFM.CoastingFrequency;
}
//ノッチOFFの場合は惰行時の周波数に設定
if(SFM.NotchValue == 0){
FrequencyValue = SFM.CoastingFrequency;
}
//Duty比の補正係数[%/Hz]を設定する。(同じDuty比でも、周波数が変化すると模型の走行速度も変化してしまう。そうすると、周波数が切り替わった直後に速度が急変動し、リアルではなくなる。それを防止するため、補正係数を用いてDUTYを調整し、どの周波数でも模型の走行速度が変わらないようにする。)
var DutyCorrectionValue;
var DutyCorrectionRate;
if(SFM.MotorKind === "Kato-FryWheel"){
//補正係数[%/Hz]を入力(今の値は適当。この値は、今後、周波数ごとの速度特性を実測してから設定する。)
DutyCorrectionRate = 0.01;
}
else{
//補正係数[%/Hz]を入力
DutyCorrectionRate = 0;
}
//惰行時の周波数を基準としてDuty補正値を計算
DutyCorrectionValue = (FrequencyValue - SFM.CoastingFrequency) * DutyCorrectionRate;
//周波数とDuty補正値を返す
return{FrequencyValue:FrequencyValue, DutyCorrectionValue:DutyCorrectionValue};
}
//速度をDutyに変換する
function DutyConvertor(DC){
//各引数が定義されていない場合の初期化
if(typeof DC.DutyA === "undefined"){
//DutyA[%]
DC.DutyA = 0;
}
if(typeof DC.DutyB === "undefined"){
//DutyB[%]
DC.DutyB = 100;
}
if(typeof DC.SpeedA === "undefined"){
//SpeedA[km/h]
DC.SpeedA = 0;
}
if(typeof DC.SpeedB === "undefined"){
//SpeedB[km/h]
DC.SpeedB = 100;
}
if(typeof DC.SpeedValue === "undefined"){
//現在の速度[km/h]
DC.SpeedValue = 0;
}
if(typeof DC.DutyCorrectionValue === "undefined"){
//Duty比の補正係数
DC.DutyCorrectionValue = 0;
}
if(typeof DC.EmergencyStop === "undefined"){
//非常停止フラグ
DC.EmergencyStop = 0;
}
//速度(km/h)をDuty(%)に変換する。
var A;
var B;
var DutyValue;
A = (DC.DutyB - DC.DutyA)/(DC.SpeedB - DC.SpeedA);
B = DC.DutyA - A * DC.SpeedA;
DutyValue = A * DC.SpeedValue + B;
//周波数補正を実施
DutyValue = DutyValue + DC.DutyCorrectionValue;
//非常停止フラグが1の場合はDuty比を0にする。
if(DC.EmergencyStop != 0){
DutyValue = 0;
}
//Duty比[%]を返す
return{DutyValue:DutyValue};
}
//電車駆動用の関数。直接Duty比を指定して駆動する。
function TrainMotorDrivePWM(TMDPWM){
//各引数が定義されていない場合の初期化
if(typeof TMDPWM.PwmPin === "undefined"){
//PWM駆動するピン とりあえずエラーが起こる様に存在しないピンを設定。
TMDPWM.PwmPin = 13;
}
if(typeof TMDPWM.MaxDuty === "undefined"){
//最大Duty比[%]
TMDPWM.MaxDuty = 100;
}
if(typeof TMDPWM.DutyValue === "undefined"){
//駆動Duty比[%]
TMDPWM.DutyValue = 0;
}
if(typeof TMDPWM.FrequencyValue === "undefined"){
//駆動周波数[Hz]
TMDPWM.FrequencyValue = 20000;
}
if(typeof TMDPWM.MaxFrequencyValue === "undefined"){
//最大駆動周波数[Hz] 
TMDPWM.MaxFrequencyValue = 20000;
}
if(typeof TMDPWM.MinFrequencyValue === "undefined"){
//最大駆動周波数[Hz]
TMDPWM.MinFrequencyValue = 10;
}
if(typeof TMDPWM.EmergencyStop === "undefined"){
//非常停止フラグ
TMDPWM.EmergencyStop = 0;
}
//指定のPINではじめてPWM駆動する場合は、obniz.getFreePwm()を実行し、開いているPWMを確保してからPWM駆動をスタートする。
if(pwmAllot[TMDPWM.PwmPin] == null || pwmAllot[TMDPWM.PwmPin] == 0){
if(pwmNo1Flug == 0){
pwmNo1 = obniz.getFreePwm();
pwmNo1.start({io:TMDPWM.PwmPin});
pwmAllot[TMDPWM.PwmPin] = 1;
pwmNo1Flug = 1;
}
else if(pwmNo2Flug == 0){
pwmNo2 = obniz.getFreePwm();
pwmNo2.start({io:TMDPWM.PwmPin});
pwmAllot[TMDPWM.PwmPin] = 2;
pwmNo2Flug = 1;
}
else if(pwmNo3Flug == 0){
pwmNo3 = obniz.getFreePwm();
pwmNo3.start({io:TMDPWM.PwmPin});
pwmAllot[TMDPWM.PwmPin] = 3;
pwmNo3Flug = 1;
}
else if(pwmNo4Flug == 0){
pwmNo4 = obniz.getFreePwm();
pwmNo4.start({io:TMDPWM.PwmPin});
pwmAllot[TMDPWM.PwmPin] = 4;
pwmNo4Flug = 1;
}
else if(pwmNo5Flug == 0){
pwmNo5 = obniz.getFreePwm();
pwmNo5.start({io:TMDPWM.PwmPin});
pwmAllot[TMDPWM.PwmPin] = 5;
pwmNo5Flug = 1;
}
else if(pwmNo6Flug == 0){
pwmNo6 = obniz.getFreePwm();
pwmNo6.start({io:TMDPWM.PwmPin});
pwmAllot[TMDPWM.PwmPin] = 6;
pwmNo6Flug = 1;
}
}
//指定のPINのPWMの周波数とDuty比を変更
var FrequencyValue;
var DutyValue;
FrequencyValue = parseInt(TMDPWM.FrequencyValue);
FrequencyValue = Math.min(FrequencyValue, TMDPWM.MaxFrequencyValue);//最大駆動周波数以下に制限
FrequencyValue = Math.max(FrequencyValue, TMDPWM.MinFrequencyValue,10);//最小駆動周波数以上に制限,10Hz以下だと挙動がおかしくなるため、10以上は死守。
DutyValue = Math.min(TMDPWM.DutyValue,TMDPWM.MaxDuty,100);//100以上はあり得ないのでとりあえず。
DutyValue = Math.max(DutyValue,0);
if(TMDPWM.EmergencyStop != 0){
DutyValue = 0;
}
if(pwmAllot[TMDPWM.PwmPin] == 1){
pwmNo1.freq(FrequencyValue);
pwmNo1.duty(DutyValue);
}
else if(pwmAllot[TMDPWM.PwmPin] == 2){
pwmNo2.freq(FrequencyValue);
pwmNo2.duty(DutyValue);
}
else if(pwmAllot[TMDPWM.PwmPin] == 3){
pwmNo3.freq(FrequencyValue);
pwmNo3.duty(DutyValue);
}
else if(pwmAllot[TMDPWM.PwmPin] == 4){
pwmNo4.freq(FrequencyValue);
pwmNo4.duty(DutyValue);
}
else if(pwmAllot[TMDPWM.PwmPin] == 5){
pwmNo5.freq(FrequencyValue);
pwmNo5.duty(DutyValue);
}
else if(pwmAllot[TMDPWM.PwmPin] == 6){
pwmNo6.freq(FrequencyValue);
pwmNo6.duty(DutyValue);
}
//最終的なDutyと駆動周波数を返す
return{DutyValue:DutyValue, FrequencyValue:FrequencyValue};
}
//ピンのHighLowを実施。ピンNo、出力電圧、出力値を設定。
function TrainDriveDirection(TDD){
//各引数が定義されていない場合の初期化
if(typeof TDD.DirectionPin === "undefined"){
TDD.DirectionPin = 13;
}
if(typeof TDD.OutputVoltage === "undefined"){
TDD.OutputVoltage = 5;
}
if(typeof TDD.DirectionValue === "undefined"){
TDD.DirectionValue = 0;
}
//PIN0
if(TDD.DirectionPin == 0){
//電圧設定
if(TDD.OutputVoltage == 3 && IO0OutputFlug != 3){
obniz.io0.drive("3v");
IO0OutputFlug = 3;
}
else if(TDD.OutputVoltage == 3 && IO0OutputFlug != 5){
obniz.io0.drive("5v");
IO0OutputFlug = 5;
}
//出力設定
if(TDD.DirectionValue == 1){
 obniz.io0.output(true);
}
else{
obniz.io0.output(false);
}
}
//PIN1
else if(TDD.DirectionPin == 1){
//電圧設定
if(TDD.OutputVoltage == 3 && IO1OutputFlug != 3){
obniz.io1.drive("3v");
IO1OutputFlug = 3;
}
else if(TDD.OutputVoltage == 3 && IO1OutputFlug != 5){
obniz.io1.drive("5v");
IO1OutputFlug = 5;
}
//出力設定
if(TDD.DirectionValue == 1){
 obniz.io1.output(true);
}
else{
obniz.io1.output(false);
}
}
//PIN2
else if(TDD.DirectionPin == 2){
//電圧設定
if(TDD.OutputVoltage == 3 && IO2OutputFlug != 3){
obniz.io2.drive("3v");
IO2OutputFlug = 3;
}
else if(TDD.OutputVoltage == 3 && IO2OutputFlug != 5){
obniz.io2.drive("5v");
IO2OutputFlug = 5;
}
//出力設定
if(TDD.DirectionValue == 1){
 obniz.io2.output(true);
}
else{
obniz.io2.output(false);
}
}
//PIN3
else if(TDD.DirectionPin == 3){
//電圧設定
if(TDD.OutputVoltage == 3 && IO3OutputFlug != 3){
obniz.io3.drive("3v");
IO3OutputFlug = 3;
}
else if(TDD.OutputVoltage == 3 && IO3OutputFlug != 5){
obniz.io3.drive("5v");
IO3OutputFlug = 5;
}
//出力設定
if(TDD.DirectionValue == 1){
 obniz.io3.output(true);
}
else{
obniz.io3.output(false);
}
}
//PIN4
else if(TDD.DirectionPin == 4){
//電圧設定
if(TDD.OutputVoltage == 3 && IO4OutputFlug != 3){
obniz.io4.drive("3v");
IO4OutputFlug = 3;
}
else if(TDD.OutputVoltage == 3 && IO4OutputFlug != 5){
obniz.io4.drive("5v");
IO4OutputFlug = 5;
}
//出力設定
if(TDD.DirectionValue == 1){
 obniz.io4.output(true);
}
else{
obniz.io4.output(false);
}
}
//PIN5
else if(TDD.DirectionPin == 5){
//電圧設定
if(TDD.OutputVoltage == 3 && IO5OutputFlug != 3){
obniz.io5.drive("3v");
IO5OutputFlug = 3;
}
else if(TDD.OutputVoltage == 3 && IO5OutputFlug != 5){
obniz.io5.drive("5v");
IO5OutputFlug = 5;
}
//出力設定
if(TDD.DirectionValue == 1){
 obniz.io5.output(true);
}
else{
obniz.io5.output(false);
}
}
//PIN6
else if(TDD.DirectionPin == 6){
//電圧設定
if(TDD.OutputVoltage == 3 && IO6OutputFlug != 3){
obniz.io6.drive("3v");
IO6OutputFlug = 3;
}
else if(TDD.OutputVoltage == 3 && IO6OutputFlug != 5){
obniz.io6.drive("5v");
IO6OutputFlug = 5;
}
//出力設定
if(TDD.DirectionValue == 1){
 obniz.io6.output(true);
}
else{
obniz.io6.output(false);
}
}
//PIN7
else if(TDD.DirectionPin == 7){
//電圧設定
if(TDD.OutputVoltage == 3 && IO7OutputFlug != 3){
obniz.io7.drive("3v");
IO7OutputFlug = 3;
}
else if(TDD.OutputVoltage == 3 && IO7OutputFlug != 5){
obniz.io7.drive("5v");
IO7OutputFlug = 5;
}
//出力設定
if(TDD.DirectionValue == 1){
 obniz.io7.output(true);
}
else{
obniz.io7.output(false);
}
}
//PIN8
else if(TDD.DirectionPin == 8){
//電圧設定
if(TDD.OutputVoltage == 3 && IO8OutputFlug != 3){
obniz.io8.drive("3v");
IO8OutputFlug = 3;
}
else if(TDD.OutputVoltage == 3 && IO8OutputFlug != 5){
obniz.io8.drive("5v");
IO8OutputFlug = 5;
}
//出力設定
if(TDD.DirectionValue == 1){
 obniz.io8.output(true);
}
else{
obniz.io8.output(false);
}
}
//PIN9
else if(TDD.DirectionPin == 9){
//電圧設定
if(TDD.OutputVoltage == 3 && IO9OutputFlug != 3){
obniz.io9.drive("3v");
IO9OutputFlug = 3;
}
else if(TDD.OutputVoltage == 3 && IO9OutputFlug != 5){
obniz.io9.drive("5v");
IO9OutputFlug = 5;
}
//出力設定
if(TDD.DirectionValue == 1){
  obniz.io9.output(true);
}
else{
obniz.io9.output(false);
IO9OutputFlug = 0;
}
}
//PIN10
else if(TDD.DirectionPin == 10){
//電圧設定
if(TDD.OutputVoltage == 3 && IO10OutputFlug != 3){
obniz.io10.drive("3v");
IO10OutputFlug = 3;
}
else if(TDD.OutputVoltage == 3 && IO10OutputFlug != 5){
obniz.io10.drive("5v");
IO10OutputFlug = 5;
}
//出力設定
if(TDD.DirectionValue == 1){
 obniz.io10.output(true);
}
else{
obniz.io10.output(false);
}
}
//PIN11
else if(TDD.DirectionPin == 11){
//電圧設定
if(TDD.OutputVoltage == 3 && IO11OutputFlug != 3){
obniz.io11.drive("3v");
IO11OutputFlug = 3;
}
else if(TDD.OutputVoltage == 3 && IO11OutputFlug != 5){
obniz.io11.drive("5v");
IO11OutputFlug = 5;
}
//出力設定
if(TDD.DirectionValue == 1){
 obniz.io11.output(true);
}
else{
obniz.io11.output(false);
}
}
}
<!DOCTYPE html>
<html xml:lang="ja" lang="ja">
<head>
<meta charset="utf-8">
<!-- <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no, shrink-to-fit=no" /> -->
<meta name="viewport" content="width=960,initial-scale=1,maximum-scale=1.0, user-scalable=1">
<title>鉄道模型コントローラ(十三車両製作所)</title>
<script src="https://obniz.io/js/jquery-3.2.1.min.js"></script>
<script src="https://unpkg.com/obniz@2.0.1/obniz.js" crossorigin="anonymous"></script>
<script src="https://docs.opencv.org/3.4.7/opencv.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.8.0"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="./ModelRailroadControlLibrary.js"></script>
<script src="https://webrtc.github.io/adapter/adapter-5.0.4.js" type="text/javascript"></script>
<script src="./utils.js" type="text/javascript"></script>
<style type="text/css">
/*画面遷移に関するStyle設定*/
body {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
#wrapper {
width: 100%;
height: 100%;
/* position: absolute; */
top: 0;
left: 0;
background-color: #ccc;
overflow: hidden;
}
#mask {
width: 500%;
height: 100%;
background-color: #eee;
}
.item {
width: 20%;
height: 100%;
float: left;
background-color: #ddd;
}
.content {
width: 960px;
height: 500px;
top: 0%;
margin: 0 auto;
background-color: #aaa;
position: relative;
}
.selected {
background: #fff;
font-weight: 700;
}
.clear {
clear: both;
}
/*フォントに関するStyle設定*/
.font-style1 {
font-size: 40px;
}
.font-style2 {
font-size: 30px;
}
.font-style2_1 {
font-size: 20px;
}
.font-style3 {
font-size: 30px;
text-align: center;
}
.pointindex {
margin-top: 1px;
margin-right: 1px;
margin-left: 1px;
background-color: gray;
font-size: 30px;
color: white;
text-align: center;
}
.pointtext {
margin-top: 20px;
margin-right: 10px;
background-color: lightgray;
font-size: 30px;
text-align: center;
}
.valuedisplay2_1 {
margin-top: 0px;
margin-right: 10px;
background-color: black;
color: white;
font-size: 30px;
text-align: center;
width: 100px;
}
.valuedisplay2_2 {
margin-top: 0px;
margin-right: 10px;
background-color: black;
color: white;
font-size: 25px;
text-align: center;
width: 220px;
height: 45px;
}
.font-style-direction {
margin-top: 10px;
margin-left: 0px;
color: white;
font-size: 30px;
text-align: center;
width: 150px;
}
/* 各種表示ディスプレイ設定 */
output.display1_1 {
margin-top: 10px;
margin-right: 10px;
background-color: black;
color: white;
font-size: 40px;
text-align: center;
width: 190px;
}
output.display1_2 {
margin-top: 10px;
width: 300px;
height: 200px;
background-color: black;
color: white;
font-size: 30px;
white-space: normal;
}
output.display1_3 {
margin-top: 10px;
width: 300px;
height: 200px;
background-color: black;
color: white;
font-size: 30px;
white-space: normal;
}
output.display1_4 {
margin-top: 10px;
width: 300px;
height: 200px;
background-color: black;
color: white;
font-size: 30px;
white-space: normal;
}
/*マスコン操作スライドバーに関するStyle設定*/
.mascon_slider input[type=range] {
-webkit-appearance: none;
/*デフォルトのデザインをリセット*/
-moz-appearance: none;
appearance: none;
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
-o-transform: rotate(90deg);
transform: rotate(90deg);
background: #000;
margin-top: 195px;
margin-left: -150px;
border-radius: 0px;
width: 390px;
height: 15px;
}
.mascon_slider input[type=range]::-webkit-slider-thumb {
box-shadow: 3px 1px 1px #000000, 0px 0px 1px #0d0d0d;
border: 1px solid #000000;
height: 80px;
width: 40px;
border-radius: 10%;
background: linear-gradient(90deg, darkgray, black);
cursor: pointer;
-webkit-appearance: none;
/* 以下は つまみの縦位置調整 */
margin-top: -14px;
/* (つまみの高さ - トラックの高さ) / 2 。つまみの高さは border を含む */
}
/*ボリューム操作スライドバーに関するStyle設定*/
.volume_slider input[type=range] {
-webkit-appearance: none;
/*デフォルトのデザインをリセット*/
-moz-appearance: none;
appearance: none;
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
-o-transform: rotate(90deg);
transform: rotate(90deg);
background: #000;
margin-top: 195px;
margin-left: -150px;
border-radius: 0px;
width: 390px;
height: 15px;
}
.volume_slider input[type=range]::-webkit-slider-thumb {
box-shadow: 3px 1px 1px #000000, 0px 0px 1px #0d0d0d;
border: 1px solid #000000;
height: 80px;
width: 40px;
border-radius: 10%;
background: linear-gradient(90deg, darkgray, black);
cursor: pointer;
-webkit-appearance: none;
/* 以下は つまみの縦位置調整 */
margin-top: -14px;
/* (つまみの高さ - トラックの高さ) / 2 。つまみの高さは border を含む */
}
/*ポイント操作スライドバーに関するStyle設定*/
.point_slider input[type=range] {
-webkit-appearance: none;
/*デフォルトのデザインをリセット*/
-moz-appearance: none;
appearance: none;
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
-o-transform: rotate(90deg);
transform: rotate(90deg);
background: #000;
margin-top: 100px;
margin-left: -20px;
border-radius: 0px;
width: 150px;
height: 15px;
}
.point_slider input[type=range]::-webkit-slider-thumb {
box-shadow: 3px 1px 1px #000000, 0px 0px 1px #0d0d0d;
border: 1px solid #000000;
height: 80px;
width: 40px;
border-radius: 10%;
background: linear-gradient(90deg, darkgray, black);
cursor: pointer;
-webkit-appearance: none;
/* 以下は つまみの縦位置調整 */
margin-top: 0px;
/* (つまみの高さ - トラックの高さ) / 2 。つまみの高さは border を含む */
}
/*進行方向設定スライドバーに関するStyle設定*/
.direction_slider input[type=range] {
-webkit-appearance: none;
/*デフォルトのデザインをリセット*/
-moz-appearance: none;
appearance: none;
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
-o-transform: rotate(90deg);
transform: rotate(90deg);
background: #000;
margin-top: -12px;
margin-left: -30px;
border-radius: 0px;
width: 145px;
height: 15px;
}
.direction_slider input[type=range]::-webkit-slider-thumb {
box-shadow: 3px 1px 1px #000000, 0px 0px 1px #0d0d0d;
border: 1px solid #000000;
height: 60px;
width: 50px;
border-radius: 100%;
background: linear-gradient(90deg, darkgray, black);
cursor: pointer;
-webkit-appearance: none;
/* 以下は つまみの縦位置調整 */
margin-top: 0px;
/* (つまみの高さ - トラックの高さ) / 2 。つまみの高さは border を含む */
}
/* 定速走行ボタンに関するStyle設定 */
input.button2 {
/* 文字サイズを1.4emに指定 */
font-size: 30px;
/* 文字の太さをboldに指定 */
font-weight: bold;
/* 縦方向に10px、
* 横方向に30pxの余白を指定 */
padding: 10px 30px;
margin-top: 10px;
border-radius: 5px;
box-shadow: 2px 2px 3px 1px #666;
-moz-box-shadow: 2px 2px 3px 1px #666;
-webkit-box-shadow: 2px 2px 3px 1px #666;
border: 1px solid #000000;
background: lightgray;
}
/* 自動運転ボタンに関するStyle設定 */
input.button3 {
/* 文字サイズを1.4emに指定 */
font-size: 30px;
/* 文字の太さをboldに指定 */
font-weight: bold;
/* 縦方向に10px、
* 横方向に30pxの余白を指定 */
padding: 10px 30px;
margin-top: 10px;
border-radius: 5px;
box-shadow: 2px 2px 3px 1px #666;
-moz-box-shadow: 2px 2px 3px 1px #666;
-webkit-box-shadow: 2px 2px 3px 1px #666;
border: 1px solid #000000;
background: lightgray;
}
/* ページ遷移ボタンに関するStyle設定 */
input.button4 {
/* 文字サイズを1.4emに指定 */
font-size: 30px;
/* 文字の太さをboldに指定 */
font-weight: bold;
/* 縦方向に10px、
* 横方向に30pxの余白を指定 */
width: 200px;
height: 70px;
margin-top: 10px;
border-radius: 5px;
box-shadow: 2px 2px 3px 1px #666;
-moz-box-shadow: 2px 2px 3px 1px #666;
-webkit-box-shadow: 2px 2px 3px 1px #666;
border: 1px solid #000000;
background: lightgray;
}
/* ページ遷移ボタン(選択中画面)に関するStyle設定 */
input.button5 {
/* 文字サイズを1.4emに指定 */
font-size: 30px;
/* 文字の太さをboldに指定 */
font-weight: bold;
/* 縦方向に10px、
* 横方向に30pxの余白を指定 */
width: 200px;
height: 70px;
margin-top: 10px;
border-radius: 5px;
box-shadow: 2px 2px 3px 1px #666;
-moz-box-shadow: 2px 2px 3px 1px #666;
-webkit-box-shadow: 2px 2px 3px 1px #666;
border: 1px solid #000000;
background: #F7FE2E;
}
/* ▲10と▼10ボタンの設定 */
input.button6 {
/* 文字サイズを1.4emに指定 */
font-size: 25px;
/* 文字の太さをboldに指定 */
font-weight: bold;
/* 縦方向に10px、
* 横方向に30pxの余白を指定 */
width: 90px;
height: 60px;
margin-top: 10px;
border-radius: 5px;
box-shadow: 2px 2px 3px 1px #666;
-moz-box-shadow: 2px 2px 3px 1px #666;
-webkit-box-shadow: 2px 2px 3px 1px #666;
border: 1px solid #000000;
background: lightgray;
}
/* ボックスレイアウトの設定(1枚目。なお、1枚目で設定したスタイルを他ページでも流用している。) */
#layout01 {
background-color: lightgray;
float: left;
/* 回り込み */
width: 720px;
height: 420px;
}
#layout01_01 {
background-color: gray;
float: left;
/* 回り込み */
width: 70px;
height: 420px;
}
#layout01_02 {
background-color: lightgray;
float: left;
/* 回り込み */
width: 210px;
height: 420px;
}
#layout01_02_01 {
background-color: lightgray;
height: 75px;
}
#layout01_02_02 {
background-color: gray;
height: 150px;
width: 190px;
margin-top: 15px;
}
#layout01_02_02_01 {
background-color: gray;
float: left;
/* 回り込み */
height: 70px;
width: 90px;
margin-top: 80px;
}
#layout01_02_02_02 {
background-color: gray;
float: left;
/* 回り込み */
height: 45px;
width: 100px;
margin-top: 5px;
}
#layout01_03 {
background-color: lightgray;
float: left;
/* 回り込み */
width: 310px;
height: 420px;
}
#layout01_03_01 {
background-color: lightgray;
}
#layout01_03_02 {
background-color: lightgray;
}
#layout01_04 {
background-color: gray;
float: left;
/* 回り込み */
width: 70px;
height: 420px;
}
#layout01_04_01 {
background-color: orange;
text-align: right;
font-size: 18px;
color: black;
height: 25px;
}
#layout01_04_02 {
background-color: yellow;
text-align: right;
font-size: 18px;
color: black;
height: 25px;
}
#layout01_04_03 {
background-color: green;
text-align: right;
font-size: 18px;
color: white;
height: 25px;
}
#layout01_04_04 {
background-color: blue;
text-align: right;
font-size: 18px;
color: white;
height: 25px;
}
#layout01_04_05 {
background-color: gray;
height: 2px;
}
#layout01_04_06 {
background-color: gray;
height: 16px;
}
#layout01_04_07 {
background-color: lightgray;
height: 0px;
}
#layout01_05 {
background-color: gray;
float: left;
/* 回り込み */
width: 20px;
height: 420px;
}
#layout01_06 {
background-color: lightgray;
float: left;
/* 回り込み */
width: 30px;
height: 420px;
}
#layout01_07 {
background-color: #aaa;
float: left;
/* 回り込み */
width: 15px;
height: 420px;
}
/* ボックスレイアウトの設定(2枚目。) */
#layout02_01 {
background-color: gray;
float: left;
/* 回り込み */
width: 70px;
height: 420px;
}
#layout02_01_01 {
background-color: gray;
height: 20px;
}
#layout02_01_02 {
background-color: gray;
height: 0px;
margin-top: 10px;
border-style: solid;
border-width: 350px 0 0 70px;
border-color: transparent transparent transparent #ffffff;
}
/* ボックスレイアウトの設定(3枚目。) */
#layout03_01 {
background-color: lightgray;
float: left;
/* 回り込み */
width: 30px;
height: 420px;
}
#layout03_02 {
background-color: lightgray;
float: left;
/* 回り込み */
width: 200px;
height: 420px;
}
#layout03_02_01 {
background-color: lightgray;
float: left;
/* 回り込み */
height: 30px;
}
#layout03_02_02 {
background-color: lightgray;
float: left;
/* 回り込み */
height: 100px;
}
#layout03_03 {
background-color: lightgray;
float: left;
/* 回り込み */
width: 290px;
height: 420px;
}
#layout03_04 {
background-color: lightgray;
float: left;
/* 回り込み */
width: 200px;
height: 420px;
}
/* ボックスレイアウトの設定(4枚目。) */
#layout04_01 {
background-color: lightgray;
float: left;
/* 回り込み */
width: 120px;
height: 420px;
}
#layout04_02 {
background-color: lightgray;
height: 70px;
}
#layout04_03 {
background-color: lightgray;
height: 90px;
}
#layout04_04 {
background-color: lightgray;
height: 30px;
}
</style>
<style>
#camera_row {
text-align: center;
}
.camera_col {
text-align: center;
display: inline-block;
}
#canvasSource {
text-align: center;
margin: auto;
}
</style>
</head>
<body>
<!-- <div id="obniz-debug"></div> -->
<div id="camera_row" style="display: none">
<div class="camera_col" id="camera_video_col" style="height: 100%; width: 100%;">
<p class="err" id="errorMessage"></p>
<video id="videoInput" width=0 style="display:none;" autoplay playsinline></video>
<canvas id="canvasSource" width=128 height=64 onmousedown="OnMousedown(event);" onmousemove="OnMousemove(event);"
onmouseup="OnMouseup(event);"></canvas>
<canvas id="canvasOutput" width=0 style="display:none;"></canvas>
<canvas id="canvasRec" width=0 style="display:none;"></canvas>
</div>
</div>
<div id="wrapper">
<div id="mask">
<!-- 1画面目 マスコン操作画面 -->
<div id="item1" class="item">
<a name="item1"></a>
<div class="content">
<h2 class=font-style3> </h2>
<div id="layout01">
<div id="layout01_01">
<div class="mascon_slider">
<input id="slider" type="range" value="0" min="-8" max="5" />
</div>
</div>
<div id="layout01_04">
<div id="layout01_04_06"></div>
<div id="layout01_04_01">EB&nbsp;&nbsp;</div>
<div id="layout01_04_05"></div>
<div id="layout01_04_02">B7&nbsp;&nbsp;</div>
<div id="layout01_04_05"></div>
<div id="layout01_04_02">B6&nbsp;&nbsp;</div>
<div id="layout01_04_05"></div>
<div id="layout01_04_02">B5&nbsp;&nbsp;</div>
<div id="layout01_04_05"></div>
<div id="layout01_04_02">B4&nbsp;&nbsp;</div>
<div id="layout01_04_05"></div>
<div id="layout01_04_02">B3&nbsp;&nbsp;</div>
<div id="layout01_04_05"></div>
<div id="layout01_04_02">B2&nbsp;&nbsp;</div>
<div id="layout01_04_05"></div>
<div id="layout01_04_02">B1&nbsp;&nbsp;</div>
<div id="layout01_04_05"></div>
<div id="layout01_04_03">N&nbsp;&nbsp;</div>
<div id="layout01_04_05"></div>
<div id="layout01_04_04">P1&nbsp;&nbsp;</div>
<div id="layout01_04_05"></div>
<div id="layout01_04_04">P2&nbsp;&nbsp;</div>
<div id="layout01_04_05"></div>
<div id="layout01_04_04">P3&nbsp;&nbsp;</div>
<div id="layout01_04_05"></div>
<div id="layout01_04_04">P4&nbsp;&nbsp;</div>
<div id="layout01_04_05"></div>
<div id="layout01_04_04">P5&nbsp;&nbsp;</div>
</div>
<div id="layout01_05">
</div>
<div id="layout01_06">
</div>
<div id="layout01_02">
<form name="form1" id="form1">
<div id="layout01_02_01">
<output name="notch" class="display1_1"></output>
</div>
<div id="layout01_02_01">
<output name="speed" class="display1_1"></output>
</div>
</form>
<div id="layout01_02_01">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<input type=button value="定速" id=Const class=button2>
</div>
<div id="layout01_02_02">
<div id="layout01_02_02_01">
<div class="direction_slider">
<input id="slider_dr1" type="range" value="0" min="-1" max="1" />
</div>
</div>
<div id="layout01_02_02_02">
<span class=font-style-direction>前進</span>
</div>
<div id="layout01_02_02_02">
<span class=font-style-direction>中立</span>
</div>
<div id="layout01_02_02_02">
<span class=font-style-direction>後進</span>
</div>
</div>
</div>
<div id="layout01_03">
<div id="layout01_03_01">
<form name="form3">
<output name="display1_2" class="display1_2"></output>
</form>
</div>
<div id="layout01_03_02">
<input type=button value="自動運転" id=AutoCluise class=button3>
<input type=button value="デバッグ" id=Debug class=button3>
</div>
</div>
</div>
<div id="layout01_07">
</div>
<input type=button value="マスコン台" class=button5 onClick="location.href='#item1',ControlPage = 0"
id=MasconControl>
<br>
<input type=button value="簡易運転台" class=button4 onClick="location.href='#item2',ControlPage = 1"
id=VolumeControl>
<br>
<input type=button value="駆動設定" class=button4 onClick="location.href='#item3'">
<br>
<input type=button value="ポイント" class=button4 onClick="location.href='#item4'">
<br>
<input type=button value="カメラ制御" class=button4 onClick="location.href='#item5'">
<br>
</div>
</div>
<!-- 2画面目 ボリューム操作画面 -->
<div id="item2" class="item">
<a name="item2"></a>
<div class="content">
<h2 class=font-style3> </h2>
<div id="layout01">
<div id="layout01_01">
<div class="volume_slider">
<input id="volume_slider" type="range" value="0" min="0" max="100" />
</div>
</div>
<div id="layout02_01">
<div id="layout02_01_01">
</div>
<div id="layout02_01_02">
Speed
</div>
<div id="layout02_01_01">
</div>
</div>
<div id="layout01_05">
</div>
<div id="layout01_06">
</div>
<div id="layout01_02">
<form name="form4" id="form4">
<div id="layout01_02_01">
<output name="duty" class="display1_1"></output>
</div>
<div id="layout01_02_01">
<output name="speed" class="display1_1"></output>
</div>
</form>
<div id="layout01_02_01">
<input type=button value="▲10" id=lower10 class=button6>&nbsp;&nbsp;<input type=button value="▼10"
id=upper10 class=button6>
</div>
<div id="layout01_02_02">
<div id="layout01_02_02">
<div id="layout01_02_02_01">
<div class="direction_slider">
<input id="slider_dr2" type="range" value="0" min="-1" max="1" />
</div>
</div>
<div id="layout01_02_02_02">
<span class=font-style-direction>前進</span>
</div>
<div id="layout01_02_02_02">
<span class=font-style-direction>中立</span>
</div>
<div id="layout01_02_02_02">
<span class=font-style-direction>後進</span>
</div>
</div>
</div>
</div>
<div id="layout01_03">
<div id="layout01_03_01">
<form name="form7">
<output name="display1_3" class="display1_3"></output>
</form>
</div>
<div id="layout01_03_02">
<input type=button value="自動運転" id=AutoCluise2 class=button3>
<input type=button value="デバッグ" id=Debug2 class=button3>
</div>
</div>
</div>
<div id="layout01_07">
</div>
<input type=button value="マスコン台" class=button4 onClick="location.href='#item1',ControlPage = 0"
id=MasconControl>
<br>
<input type=button value="簡易運転台" class=button5 onClick="location.href='#item2',ControlPage = 1"
id=VolumeControl>
<br>
<input type=button value="駆動設定" class=button4 onClick="location.href='#item3'">
<br>
<input type=button value="ポイント" class=button4 onClick="location.href='#item4'">
<br>
<input type=button value="カメラ制御" class=button4 onClick="location.href='#item5'">
<br>
</div>
</div>
<!-- 3画面目 駆動設定画面 -->
<div id="item3" class="item">
<a name="item3"></a>
<div class="content">
<h2 class=font-style3> </h2>
<div id="layout01">
<div id="layout03_01">
</div>
<div id="layout03_02">
<div id="layout03_02_01">
</div>
<form name="form2" id="form2">
<div id="layout03_02_02">
<span class=font-style2>DutyA</span>
<br>
<input type="text" name="dutyA" value="10" class="valuedisplay2_1" id="dutyAid"
onchange="dutyAchange();">
<span class=font-style2_1>%</span>
<br>
<span class=font-style2>DutyB</span>
<br>
<input type="text" name="dutyB" value="40" class="valuedisplay2_1" id="dutyBid"
onchange="dutyBchange();">
<span class=font-style2_1>%</span>
<br>
<span class=font-style2>SpedB</span>
<br>
<input type="text" name="speedB" value="120" class="valuedisplay2_1" id="speedBid"
onchange="speedBchange();">
<span class=font-style2_1>km/h</span>
<br>
<span class=font-style2>PWM周波数</span>
<br>
<input type="text" name="freq" class="valuedisplay2_1" value="20000" id="freqid"
onchange="freqchange();">
<span class=font-style2_1>Hz</span>
<br>
</div>
</form>
</div>
<div id="layout03_03">
<form name="form2" id="form2">
<span class=font-style2>モータ駆動音</span>
<select name="motorsound" id="motorsound" class="valuedisplay2_2">
<option value="NoTrain">NoTrain</option>
<option value="JRE-209">JR東日本 209系</option>
<option value="KQ-2100">京浜急行 2100系</option>
</select>
<br>
<span class=font-style2>モータ車種類</span>
<select name="motorkind" id="motorkind" class="valuedisplay2_2">
<option value="TOMIX-Normal">TOMIXモータ</option>
<option value="KATO-Normal">KATOモータ</option>
<option value="GM-Normal">GMモータ</option>
<option value="GM-Coreless">GMコアレスモータ</option>
</select>
</form>
</div>
<div id="layout03_04">
<form name="form2" id="form2">
<span class=font-style2>加速度</span>
<br>
<input type="text" name="accel" class="valuedisplay2_1" value="3.3" id="accelid"
onchange="accelchange();">
<span class=font-style2_1>km/h/s</span>
<br>
<span class=font-style2>常用減速度</span>
<br>
<input type="text" name="deccel" class="valuedisplay2_1" value="3.5" id="deccelid"
onchange="deccelchange();">
<span class=font-style2_1>km/h/s</span>
<br>
<span class=font-style2>非常減速度</span>
<br>
<input type="text" name="EB" class="valuedisplay2_1" value="4.5" id="EBid" onchange="EBchange();">
<span class=font-style2_1>km/h/s</span>
<br>
</form>
</div>
</div>
<div id="layout01_07">
</div>
<input type=button value="マスコン台" class=button4 onClick="location.href='#item1',ControlPage = 0"
id=MasconControl>
<br>
<input type=button value="簡易運転台" class=button4 onClick="location.href='#item2',ControlPage = 1"
id=VolumeControl>
<br>
<input type=button value="駆動設定" class=button5 onClick="location.href='#item3'">
<br>
<input type=button value="ポイント" class=button4 onClick="location.href='#item4'">
<br>
<input type=button value="カメラ制御" class=button4 onClick="location.href='#item5'">
<br>
</div>
</div>
<!-- 4画面目 ポイント操作画面 -->
<div id="item4" class="item">
<a name="item4"></a>
<div class="content">
<h2 class=font-style3> </h2>
<div id="layout01">
<div id="layout04_01">
<div id="layout04_02">
<div class=pointindex></div>
</div>
<div id="layout04_04">
<div class=pointtext>直進</div>
</div>
<div id="layout04_03">
<div class="point_slider">
<input id="slider_pd1" type="range" value="0" min="0" max="1" />
</div>
</div>
<div id="layout04_04">
<div class=pointtext>曲進</div>
</div>
</div>
<div id="layout04_01">
<div id="layout04_02">
<div class=pointindex></div>
</div>
<div id="layout04_04">
<div class=pointtext></div>
</div>
<div id="layout04_03">
<div class="point_slider">
<input id="slider_pd2" type="range" value="0" min="0" max="1" />
</div>
</div>
<div id="layout04_04">
<div class=pointtext></div>
</div>
</div>
<div id="layout04_01">
<div id="layout04_02">
<div class=pointindex></div>
</div>
<div id="layout04_04">
<div class=pointtext></div>
</div>
<div id="layout04_03">
<div class="point_slider">
<input id="slider_pd3" type="range" value="0" min="0" max="1" />
</div>
</div>
<div id="layout04_04">
<div class=pointtext></div>
</div>
</div>
<div id="layout04_01">
<div id="layout04_02">
<div class=pointindex></div>
</div>
<div id="layout04_04">
<div class=pointtext></div>
</div>
<div id="layout04_03">
<div class="point_slider">
<input id="slider_pd4" type="range" value="0" min="0" max="1" />
</div>
</div>
<div id="layout04_04">
<div class=pointtext></div>
</div>
</div>
<div id="layout04_01">
<div id="layout04_02">
<div class=pointindex></div>
</div>
<div id="layout04_04">
<div class=pointtext></div>
</div>
<div id="layout04_03">
<div class="point_slider">
<input id="slider_pd5" type="range" value="0" min="0" max="1" />
</div>
</div>
<div id="layout04_04">
<div class=pointtext></div>
</div>
</div>
<div id="layout04_01">
<div id="layout04_02">
<div class=pointindex></div>
</div>
<div id="layout04_04">
<div class=pointtext></div>
</div>
<div id="layout04_03">
<div class="point_slider">
<input id="slider_pd6" type="range" value="0" min="0" max="1" />
</div>
</div>
<div id="layout04_04">
<div class=pointtext></div>
</div>
</div>
</div>
<div id="layout01_07">
</div>
<input type=button value="マスコン台" class=button4 onClick="location.href='#item1',ControlPage = 0"
id=MasconControl>
<br>
<input type=button value="簡易運転台" class=button4 onClick="location.href='#item2',ControlPage = 1"
id=VolumeControl>
<br>
<input type=button value="駆動設定" class=button4 onClick="location.href='#item3'">
<br>
<input type=button value="ポイント" class=button5 onClick="location.href='#item4'">
<br>
<input type=button value="カメラ制御" class=button4 onClick="location.href='#item5'">
<br>
</div>
</div>
<div id="item5" class="item">
<a name="item5"></a>
<div class="content">
<h2 class="font-style3"> </h2>
<div id="layout01">
<div id="layout01_01">
<div class="mascon_slider">
<label>色閾値小<input type="range" id="rangeMin" max=255 value=22>: <span id="lbThresMin"></span></label>
</div>
</div>
<div id="layout01_01">
<div class="mascon_slider">
<label>色閾値大<input type="range" id="rangeMax" max=255 value=255>: <span id="lbThresMax"></span></label>
</div>
</div>
<div id="layout01_01">
<div class="mascon_slider">
<label>動体閾値<input type="range" id="rangeMove" max=255 value=22>: <span id="lbThresMove"></span></label>
</div>
</div>
<div id="layout01_05">
</div>
<div id="layout01_06">
</div>
<div id="layout01_02" style="width:140px">
<div class="chart-container" style="position: relative; height:320px; width:100px; margin:10px">
<canvas id="chartMove"></canvas>
</div>
</div>
<div id="layout01_03">
<div id="layout01_03_01">
<form name="form8">
<output name="display1_4" class="display1_4"></output>
<input type="button" id="btnCameraStartStop" value="カメラ起動" disabled class="button3"
onclick="cameraStartStop()"></input>
<input type="button" id="btnControlStartStop" value="列車制御開始" class="button3"></input>
</form>
</div>
<div id="layout01_03_02">
</div>
</div>
</div>
<div id="layout01_07">
</div>
<input type=button value="マスコン台" class=button4 onClick="location.href='#item1',ControlPage = 0"
id=MasconControl>
<br>
<input type=button value="簡易運転台" class=button4 onClick="location.href='#item2',ControlPage = 1"
id=VolumeControl>
<br>
<input type=button value="駆動設定" class=button4 onClick="location.href='#item3'">
<br>
<input type=button value="ポイント" class=button4 onClick="location.href='#item4'">
<br>
<input type=button value="カメラ制御" class=button5 onClick="location.href='#item5'">
<br>
</div>
</div>
</div>
</div>
</div>
<script>
//OpenCVの読み込みが終わるまでStart押せないようにする
window.onload = function () {
let cv_load = setInterval(function () {
if (typeof cv.CV_8UC4 !== "undefined") {
$("#btnCameraStartStop").attr('disabled', false);
clearInterval(cv_load);
}
}, 500);
}
</script>
<script>
//動体検知
let utils = new Utils('errorMessage');
let streaming = false;
let videoInput = document.getElementById('videoInput');
let btnCameraStartStop = document.getElementById('btnCameraStartStop');
let canvasSource = document.getElementById('canvasSource');
let canvasOutput = document.getElementById('canvasOutput');
let canvasRec = document.getElementById('canvasRec');
let src_ctx = canvasSource.getContext('2d');
let out_ctx = canvasOutput.getContext('2d');
let rec_ctx = canvasRec.getContext('2d');
var chart;
var camera_mag = 1;
const dispdisp3 = document.form8.display1_4;//カメラ制御画面のメインディスプレイ(一番大きいやつ)
function set_camera_mag() {
// カメラ画像のcanvasのサイズ調整(なるべく大きく)
var camera_max_h = 0;
camera_max_h = window.innerHeight - 520 - 30;
if (camera_max_h < 200) {
camera_max_h = 200;
}
$('#camera_row').css('display', '');
$('#camera_row').css('height', camera_max_h + 'px');
camera_mag = Math.min($('#camera_video_col').height() * 0.95 / videoInput.videoHeight, $('#camera_video_col').width() * 0.95 / videoInput.videoWidth);
$('#canvasSource').css('transform', `translate(0px,${videoInput.height * (camera_mag - 1) / 2}px)scale(${camera_mag},${camera_mag})`);
}
function cameraStartStop() {
console.log("cameraStartStop");
if (!streaming) {
utils.clearError();
utils.startCamera('qvga', onVideoStarted, 'videoInput', 'environment');
} else {
utils.stopCamera();
onVideoStopped();
}
}
function onVideoStarted() {
console.log("onVideoStarted");
streaming = true;
btnCameraStartStop.value = 'カメラ停止';
videoInput.height = videoInput.videoHeight;
videoInput.width = videoInput.videoWidth;
set_camera_mag();
console.log("video size: ", videoInput.width, videoInput.height, ", scale: ", camera_mag);
start();
}
function onVideoStopped() {
streaming = false;
src_ctx.clearRect(0, 0, canvasOutput.width, canvasOutput.height);
btnCameraStartStop.value = 'カメラ起動';
}
function start() {
let video = document.getElementById('videoInput');
let src = new cv.Mat(video.height, video.width, cv.CV_8UC4);
let cap = new cv.VideoCapture(video);
let gray = new cv.Mat(video.height, video.width, cv.CV_8UC4);
let before = new cv.Mat(video.height, video.width, cv.CV_8UC4);
let b1 = new cv.Mat();
let mdframe = new cv.Mat();
let thresh = new cv.Mat();
let rect;
let thresh_roi;
const FPS = 20;
let first_flag = true;
makeChart();
function processVideoMoving() {
if (!streaming) {
src.delete();
gray.delete();
before.delete();
b1.delete();
mdframe.delete();
thresh.delete();
return;
}
let begin = Date.now();
cap.read(src);
cv.cvtColor(src, gray, cv.COLOR_RGBA2GRAY);
if (first_flag) {
gray.copyTo(before);
first_flag = false;
}
cv.addWeighted(gray, 0.5, before, 0.5, 2.2, before);
// cv.accumulateWeighted(gray, before, 0.5);
cv.convertScaleAbs(before, b1, 1, 0);
cv.absdiff(gray, b1, mdframe);
let delay = 1000 / FPS - (Date.now() - begin);
setTimeout(processVideoMoving, delay);
// 動いているエリアの面積を計算してちょうどいい検出結果を抽出する
let min = Number($("#rangeMin").val());
let max = Number($("#rangeMax").val());
let thresh_move = Number($("#rangeMove").val());
$("#lbThresMin").html(min);
$("#lbThresMax").html(max);
$("#lbThresMove").html(thresh_move);
cv.threshold(mdframe, thresh, min, max, cv.THRESH_BINARY);
if (rect_s_decided_flag == true) {
drawCircle(src, rect_sx, rect_sy, 0);
if (rect_e_decided_flag == true) {
drawCircle(src, rect_ex, rect_ey, 1);
rect = new cv.Rect(Math.min(rect_sx, rect_ex), Math.min(rect_sy, rect_ey), Math.max(rect_sx - rect_ex, rect_ex - rect_sx), Math.max(rect_sy - rect_ey, rect_ey - rect_sy));
thresh_roi = thresh.roi(rect);
cv.imshow('canvasOutput', thresh_roi);
$('#dataArea').html(Math.round(Number(cv.mean(thresh_roi)[0])));
updateChart(cv.mean(thresh_roi)[0]);
if (cv.mean(thresh_roi)[0] > thresh_move) {
onMovingDetected();
}
}
}
cv.imshow('canvasSource', src);
if (rect_s_decided_flag == true && rect_e_decided_flag == true) {
drawRect(src_ctx);
}
};
setTimeout(processVideoMoving, 0);
}
// タップで図形描画
var MIN_WIDTH = 3;
var MIN_HEIGHT = 3;
var rect_MousedownFlg = false;
var rect_sx = 0;
var rect_sy = 0;
var rect_ex = 0;
var rect_ey = 0;
var rect_s_decided_flag = false;
var rect_e_decided_flag = false;
function getTurningAround(color) {
if (color >= 88 && color <= 168) {
return 255;
} else {
return 255 - color;
}
}
function OnMousedown(event) {
console.log("onMousedown");
}
function onTouchstart(event) {
console.log("onTouchstart");
}
function OnMousemove(event) {
}
function onTouchmove(event) {
}
function drawRect(ctx) {
ctx.beginPath();
ctx.moveTo(rect_sx, rect_sy);
ctx.lineTo(rect_ex, rect_sy);
ctx.moveTo(rect_sx, rect_ey);
ctx.lineTo(rect_ex, rect_ey);
ctx.moveTo(rect_ex, rect_sy);
ctx.lineTo(rect_ex, rect_ey);
ctx.moveTo(rect_sx, rect_sy);
ctx.lineTo(rect_sx, rect_ey);
ctx.stroke();
}
function drawCircle(dst, x, y, c) {
let lcolor = new cv.Scalar(255, 0, 0);
if (c == 1) {
lcolor = new cv.Scalar(0, 255, 0);
}
let p1 = new cv.Point(x, y);
cv.circle(dst, p1, 5, lcolor, cv.FILLED);
}
function onTouchend(event) {
let ev_x = event.changedTouches[0].pageX;
let ev_y = event.changedTouches[0].pageY;
console.log("onTouchend", ev_x, ev_y);
decidePoint(event, ev_x, ev_y);
}
function OnMouseup(event) {
let ev_x = event.clientX;
let ev_y = event.clientY;
console.log("OnMouseup", ev_x, ev_y);
decidePoint(event, ev_x, ev_y);
}
//END
function decidePoint(event, ev_x, ev_y) {
console.log(rect_s_decided_flag, rect_e_decided_flag);
if (rect_s_decided_flag == true && rect_e_decided_flag == true) {
rect_s_decided_flag = false;
rect_e_decided_flag = false;
rect_sx = 0; rect_sy = 0;
rect_ex = 0; rect_ey = 0;
dispdisp3.value = "判定領域を削除しました";
return;
}
var rect = event.target.getBoundingClientRect();
if (rect_s_decided_flag == false) {
rect_sx = rect_ex = (ev_x - rect.left) / camera_mag;
rect_sy = rect_ey = (ev_y - rect.top) / camera_mag;
console.log("rect_s: ", rect_sx, rect_sy);
var imagedata = src_ctx.getImageData(rect_sx, rect_sy, 1, 1);
src_ctx.strokeStyle = `rgb(${getTurningAround(imagedata.data[0])},
${getTurningAround(imagedata.data[1])},
${getTurningAround(imagedata.data[2])})`;
src_ctx.lineWidth = 2;
src_ctx.setLineDash([2, 3]);
rect_s_decided_flag = true;
dispdisp3.value = "判定領域の初めの角を指定しました";
return;
}
if (rect_s_decided_flag == true && rect_e_decided_flag == false) {
rect_ex = (ev_x - rect.left) / camera_mag;
rect_ey = (ev_y - rect.top) / camera_mag;
console.log("rect_s: ", rect_sx, rect_sy, ", rect_e: ", rect_ex, rect_ey);
rect_e_decided_flag = true;
dispdisp3.value = "判定領域を指定しました";
}
drawRect(src_ctx);
if (rect_sx === rect_ex && rect_sy === rect_ey) {
// src_ctx.drawImage(canvasSource, 0, 0);
rect_ex = rect_ey = 0;
rect_e_decided_flag == false;
// canvasRec.width = canvasRec.height = 1;
}
canvasRec.width = Math.abs(rect_sx - rect_ex);
canvasRec.height = Math.abs(rect_sy - rect_ey);
if (!(canvasRec.width >= MIN_WIDTH && canvasRec.height >= MIN_HEIGHT)) {
src_ctx.drawImage(canvasSource, 0, 0);
rect_sx = rect_ex = 0;
rect_sy = rect_ey = 0;
canvasRec.width = canvasRec.height = 1;
} else {
rec_ctx.drawImage(canvasSource,
Math.min(rect_sx, rect_ex), Math.min(rect_sy, rect_ey),
Math.max(rect_sx - rect_ex, rect_ex - rect_sx), Math.max(rect_sy - rect_ey, rect_ey - rect_sy),
0, 0, canvasRec.width, canvasRec.height);
}
}
function makeChart() {
let chart_data = {
type: 'bar',
data: {
labels: ['move'],
datasets: [{
label: '',
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(255, 99, 132)',
data: [0,]
}]
},
options: {
scales: {
yAxes: [{
ticks: {
min: 0,
max: 255,
}
}]
},
legend: {
display: false
},
maintainAspectRatio: false
}
};
var chart_ctx = document.getElementById('chartMove').getContext('2d');
chart = new Chart(chart_ctx, chart_data);
}
function updateChart(x) {
chart.data.datasets[0].data = [x];
chart.update();
}
var auto_control_flag = false;
var in_control_flag = false;
$('#btnControlStartStop').on('click', function () {
if (auto_control_flag == false) {
$('#btnControlStartStop').val('列車制御停止');
} else {
$('#btnControlStartStop').val('列車制御開始');
}
auto_control_flag = !auto_control_flag;
});
function onMovingDetected() {
dispdisp3.value = "列車が通過しました。";
if (auto_control_flag == true && in_control_flag == false) {
dispdisp3.value = "列車が通過しました。減速します";
onTrainDetected();
}
setTimeout(function () {
dispdisp3.value = "";
}, 3000);
}
function onTrainDetected() {
setTimeout(function () {
in_control_flag = true;
location.href = '#item1';
$("#slider").val("-7").trigger('input');
var checkSpeed = setInterval(function () {
if (SpeedValue < 1) {
clearInterval(checkSpeed);
setTimeout(function () {
departure();
}, 5000);
}
}, 1000);
}, 1000);
}
function departure() {
dispdisp3.value = "";
location.href = '#item1';
$("#slider").val("2").trigger('input');
in_control_flag = false;
}
</script>
<script>
////変数設定
//obnizの基本設定(消すとobnizが動かなくなる)
var ObnizID = "8569-2135";
var obniz = new Obniz(ObnizID);
//ピンアサインに関する設定
var PWMPIN = 1;//PWMのパルスを出力するピン
var DirectionPIN = 0;//進行方向を設定するピン
var Point1PIN = 2;//ポイントを制御するピン
var Point2PIN = 3;//ポイントを制御するピン
var Point3PIN = 4;//ポイントを制御するピン
var Point4PIN = 5;//ポイントを制御するピン
var Point5PIN = 6;//ポイントを制御するピン
var Point6PIN = 7;//ポイントを制御するピン
var Point1Use = 1;//ポイント使用フラグ(0:使用しない、1:使用する)
var Point2Use = 1;//ポイント使用フラグ(0:使用しない、1:使用する)
var Point3Use = 0;//ポイント使用フラグ(0:使用しない、1:使用する)
var Point4Use = 0;//ポイント使用フラグ(0:使用しない、1:使用する)
var Point5Use = 0;//ポイント使用フラグ(0:使用しない、1:使用する)
var Point6Use = 0;//ポイント使用フラグ(0:使用しない、1:使用する)
//制御周期
var StepTimeValue = 50; //ミリ秒
//PWM駆動に関する変数(設定)
var DutyA = 0;//DutyA値[%]
var DutyB = 0;//DutyB値[%]
var SpeedB = 0;//SpeedB値[km/h]
var AccelerationValue = 0;//最大加速度[km/h/s]
var DeccelerationValue = 0;//最大減速度(常用ブレーキ)[km/h/s]
var EBValue = 0;//減速度(非常ブレーキ)[km/h/s]
var FrequencyValue = 0;//PWM駆動周波数[Hz]
//PWM駆動に関する変数(状態)
var DutyValue = 0;//Duty値[%]
var NotchValue = 0;//ノッチ値(正値:力行ノッチ、0:惰行ノッチ、負値:減速ノッチ)
var SpeedValue = 0;//速度[km/h]
var Direction = 0;//進行方向(-1:後進、0:中立、1:前進)
var ConstantSpeedSwitchValue = 0;//定速走行スイッチ値(0:定速OFF、1:定速ON)
var SpeedReturn;//「ModelRailroadControlLibrary.js」内の関数からのリターン値を一手に引き受ける変数
var DutyInput = 0;//Duty値[%]
var ControlPage = 0;//開いている制御画面(0:マスコン画面、1:ボリューム画面)
var TrainKind = "NoTrain";//列車種類
//ディスプレイに関する変数
var NotchName = "N";//ノッチ値表示用ディスプレイに表示する文字
var DisplayContents = "";//メインディスプレイに表示する文字
var DisplayCount = 0;//ディスプレイ表示時間カウント数
var DisplayTime = 5;//ディスプレイ表示時間[s]
//ポイント駆動に関する変数
var PointValue1 = 0