Skip to content

Instantly share code, notes, and snippets.

@satakagi
Last active November 28, 2018 12:36
Show Gist options
  • Save satakagi/dd6d9a83764529be368b9a73a2ce9f85 to your computer and use it in GitHub Desktop.
Save satakagi/dd6d9a83764529be368b9a73a2ce9f85 to your computer and use it in GitHub Desktop.
PWM H-Bridhe Motor Driver for CHIRIMEN RPi3 using L298N and PCA9685 CASE-1
// サーボではなく、純粋にPWM出力装置としてPCA9685を使います
// based on http://www.geocities.jp/zattouka/GarageHouse/micon/Motor/PCA9685/shield1.htm
// Programmed by Satoru Takagi
var PCA9685_PWM = function(i2cPort,slaveAddress){
this.i2cPort = i2cPort;
this.i2cSlave = null;
this.slaveAddress = slaveAddress;
this.frequency=null;
};
PCA9685_PWM.prototype = {
sleep: function(ms){
return new Promise((resolve)=>{setTimeout(resolve,ms);});
},
init: async function(frequency,noSetZero){
// frequency : in Hz
// angleRange : -angleRange to +angleRange degrees
if(this.frequency){
console.log("alredy initialised");
}
if ( frequency ){
this.frequency = frequency;
} else {
this.frequency = 60; // default: 60Hz
}
var freq = Math.floor((25000000/(4096*this.frequency))-1);
if ( freq < 0x03 || freq > 0xff ){
throw Error("Frequency should be between 24Hz to 1526Hz");
}
var i2cSlave = await this.i2cPort.open(this.slaveAddress);
this.i2cSlave = i2cSlave;
await this.i2cSlave.write8(0x00,0x00);
await this.i2cSlave.write8(0x01,0x04);
await this.i2cSlave.write8(0x00,0x10);
await this.i2cSlave.write8(0xfe,freq);
await this.i2cSlave.write8(0x00,0x00);
await this.i2cSlave.write8(0x06,0x00);
await this.i2cSlave.write8(0x07,0x00);
await this.sleep(300);
if ( !noSetZero ){
for ( var pwmPort = 0 ; pwmPort < 16 ; pwmPort ++ ){
await this.setPWM(pwmPort , 0 );
}
}
},
setPWM: async function(pwmPort,dutyRatio){
// dutyRatio : 0.0(OFF) .. 1.0(ON)
// console.log(pwmPort,angle)
const portStart = 8;
const portInterval = 4;
if(this.i2cSlave == null){
throw Error("i2cSlave Address does'nt yet open!");
}
if ( pwmPort < 0 || pwmPort > 15 ){
throw Error("PWM Port should be between 0 to 15");
}
if ( dutyRatio < 0 || dutyRatio > 1 ){
throw Error("dutyRatio should be between 0.0 to 1.0");
}
var ticks = Math.floor(4095 * dutyRatio);
var tickH = (( ticks >> 8 ) & 0x0f);
var tickL = (ticks & 0xff);
var pwm = Math.round(portStart + pwmPort * portInterval);
await this.i2cSlave.write8( pwm + 1, tickH);
await this.i2cSlave.write8( pwm, tickL);
}
};
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>GPIO-I2C-PWMHBridge</title>
</head>
<body>
<script src="../../../polyfill/polyfill.js"></script>
<script src="../../drivers/i2c-PCA9685_PWM.js"></script>
<script src="pwhb.js"></script>
<h1>GPIO H-Bridge Motor drive (with PWM)</h1>
<input type="button" onclick="free()" value="BRAKE"></input>
<input type="button" onclick="fwd()" value="FOWARD"></input>
<input type="button" onclick="rev()" value="REVERSE"></input>
<!-- <input type="button" onclick="brake()" value="BRAKE"></input> L298NではGPIO 0,0でもブレーキモードになるらしい -->
<br>
<input type="button" onclick="pwm(0)" value="0%(FREE)"></input> <!-- PWM 0%を指定することでフリーになるらしい -->
<input type="button" onclick="pwm(0.2)" value="20%"></input>
<input type="button" onclick="pwm(0.4)" value="40%"></input>
<input type="button" onclick="pwm(0.6)" value="60%"></input>
<input type="button" onclick="pwm(0.8)" value="80%"></input>
<input type="button" onclick="pwm(1.0)" value="100%"></input>
<div>
<img src="PWMHBridge.png" height="500">
</div>
</body>
</html>
// Hブリッジモータードライバは正転[1,0]・逆転[0,1]・ブレーキ[1,1]・フリー[0,0]の4状態を
// GPIOの2つの信号線を使って指示します
// さらにPCA9685のPWMをEnableラインに入力して速度をコントロールします。
var portAddrs = [20,21]; // HブリッジコントローラをつなぐGPIOポート番号
var portPromise;
var pca9685pwmPromise;
onload =async function(){ // ポートを初期化するための非同期関数
try{
console.log("onload");
var gpioAccess = await navigator.requestGPIOAccess(); // thenの前の関数をawait接頭辞をつけて呼び出します。
var ports = [];
var i2cAccess = await navigator.requestI2CAccess();
var i2cPort = i2cAccess.ports.get(1);
var pca9685pwm = new PCA9685_PWM(i2cPort, 0x40);
await pca9685pwm.init(100);
for ( var i = 0 ; i < 2 ; i++ ){
ports[i] = gpioAccess.ports.get(portAddrs[i]);
await ports[i].export("out");
}
for ( var i = 0 ; i < 2 ; i++ ){
ports[i].write(0);
}
portPromise = ports;
pca9685pwmPromise = pca9685pwm;
} catch (error) {
console.error("error", error);
}
}
async function pwm(ratio){
var pca9685pwm = await pca9685pwmPromise;
await pca9685pwm.setPWM(0,ratio);
}
async function free(){
var ports = await portPromise;
ports[0].write(0);
ports[1].write(0);
}
async function brake(){
var ports = await portPromise;
ports[0].write(1);
ports[1].write(1);
await sleep(300); // 300ms待機してフリー状態にします
ports[0].write(0);
ports[1].write(0);
}
async function fwd(){
var ports = await portPromise;
ports[0].write(1);
ports[1].write(0);
}
async function rev(){
var ports = await portPromise;
ports[0].write(0);
ports[1].write(1);
}
// 単に指定したms秒スリープするだけの非同期処理関数
// この関数の定義方法はとりあえず気にしなくて良いです。コピペしてください。
function sleep(ms){
return new Promise( function(resolve) {
setTimeout(resolve, ms);
});
}
@satakagi
Copy link
Author

このコードの実体配線図はこちら
pwmhbridge

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment