2017-07-07 16:15:36 +02:00
|
|
|
enum Output {
|
2017-10-25 05:16:33 +02:00
|
|
|
//% block="A"
|
2017-07-07 16:15:36 +02:00
|
|
|
A = 0x01,
|
2017-10-25 05:16:33 +02:00
|
|
|
//% block="B"
|
2017-07-07 16:15:36 +02:00
|
|
|
B = 0x02,
|
2017-10-25 05:16:33 +02:00
|
|
|
//% block="C"
|
2017-07-07 16:15:36 +02:00
|
|
|
C = 0x04,
|
2017-10-25 05:16:33 +02:00
|
|
|
//% block="D"
|
2017-07-07 16:15:36 +02:00
|
|
|
D = 0x08,
|
2017-12-12 23:08:45 +01:00
|
|
|
//% block="B+C"
|
2017-12-15 02:01:23 +01:00
|
|
|
BC = Output.B | Output.C,
|
|
|
|
//% block="A+B"
|
|
|
|
AB = Output.A | Output.B,
|
|
|
|
//% block="C+D"
|
|
|
|
CD = Output.C | Output.D,
|
|
|
|
//% block="A+D"
|
|
|
|
AD = Output.B | Output.C,
|
2017-10-25 05:16:33 +02:00
|
|
|
//% block="All"
|
2017-07-07 16:15:36 +02:00
|
|
|
ALL = 0x0f
|
|
|
|
}
|
|
|
|
|
|
|
|
enum OutputType {
|
|
|
|
None = 0,
|
|
|
|
Tacho = 7,
|
|
|
|
MiniTacho = 8,
|
|
|
|
}
|
|
|
|
|
2017-12-14 07:40:40 +01:00
|
|
|
enum MoveUnit {
|
|
|
|
//% block="rotations"
|
|
|
|
Rotations,
|
|
|
|
//% block="degrees"
|
|
|
|
Degrees,
|
|
|
|
//% block="seconds"
|
|
|
|
Seconds
|
|
|
|
}
|
|
|
|
|
2017-10-27 20:01:11 +02:00
|
|
|
namespace motors {
|
2017-07-11 16:58:51 +02:00
|
|
|
let pwmMM: MMap
|
|
|
|
let motorMM: MMap
|
|
|
|
|
|
|
|
const enum MotorDataOff {
|
|
|
|
TachoCounts = 0, // int32
|
|
|
|
Speed = 4, // int8
|
|
|
|
Padding = 5, // int8[3]
|
|
|
|
TachoSensor = 8, // int32
|
|
|
|
Size = 12
|
|
|
|
}
|
|
|
|
|
|
|
|
function init() {
|
|
|
|
if (pwmMM) return
|
|
|
|
pwmMM = control.mmap("/dev/lms_pwm", 0, 0)
|
|
|
|
if (!pwmMM) control.fail("no PWM file")
|
|
|
|
motorMM = control.mmap("/dev/lms_motor", MotorDataOff.Size * DAL.NUM_OUTPUTS, 0)
|
2017-12-13 23:55:14 +01:00
|
|
|
if (!motorMM) control.fail("no motor file")
|
2017-08-08 11:41:47 +02:00
|
|
|
|
2017-10-25 05:28:31 +02:00
|
|
|
resetMotors()
|
2017-08-09 19:02:58 +02:00
|
|
|
|
2017-07-11 16:58:51 +02:00
|
|
|
let buf = output.createBuffer(1)
|
|
|
|
buf[0] = DAL.opProgramStart
|
|
|
|
writePWM(buf)
|
|
|
|
}
|
2017-10-27 09:09:00 +02:00
|
|
|
|
2017-07-11 16:58:51 +02:00
|
|
|
function writePWM(buf: Buffer): void {
|
|
|
|
init()
|
|
|
|
pwmMM.write(buf)
|
|
|
|
}
|
2017-07-07 16:15:36 +02:00
|
|
|
|
2017-08-08 02:39:37 +02:00
|
|
|
function readPWM(buf: Buffer): void {
|
|
|
|
init()
|
|
|
|
pwmMM.read(buf);
|
|
|
|
}
|
|
|
|
|
2017-07-07 16:15:36 +02:00
|
|
|
function mkCmd(out: Output, cmd: number, addSize: number) {
|
2017-10-27 20:01:11 +02:00
|
|
|
const b = output.createBuffer(2 + addSize)
|
2017-07-07 16:15:36 +02:00
|
|
|
b.setNumber(NumberFormat.UInt8LE, 0, cmd)
|
|
|
|
b.setNumber(NumberFormat.UInt8LE, 1, out)
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
2017-10-25 05:28:31 +02:00
|
|
|
function resetMotors() {
|
|
|
|
reset(Output.ALL)
|
2017-10-27 09:09:00 +02:00
|
|
|
}
|
2017-10-25 05:16:33 +02:00
|
|
|
|
2017-10-27 11:52:42 +02:00
|
|
|
/**
|
|
|
|
* Stops all motors
|
|
|
|
*/
|
2017-12-14 22:07:10 +01:00
|
|
|
//% blockId=motorStopAll block="stop all motors"
|
2017-12-15 02:01:23 +01:00
|
|
|
//% weight=97
|
|
|
|
//% group="Motion"
|
2017-10-27 11:52:42 +02:00
|
|
|
export function stopAllMotors() {
|
|
|
|
const b = mkCmd(Output.ALL, DAL.opOutputStop, 0)
|
|
|
|
writePWM(b)
|
|
|
|
}
|
|
|
|
|
2017-10-25 05:16:33 +02:00
|
|
|
//% fixedInstances
|
|
|
|
export class Motor extends control.Component {
|
2017-12-14 07:40:40 +01:00
|
|
|
private _port: Output;
|
|
|
|
private _large: boolean;
|
|
|
|
|
|
|
|
private _initialized: boolean;
|
|
|
|
private _brake: boolean;
|
2017-10-27 10:47:25 +02:00
|
|
|
|
2017-10-27 09:09:00 +02:00
|
|
|
constructor(port: Output, large: boolean) {
|
2017-10-25 05:16:33 +02:00
|
|
|
super();
|
2017-12-14 07:40:40 +01:00
|
|
|
this._port = port;
|
|
|
|
this._large = large;
|
|
|
|
this._brake = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
private __init() {
|
|
|
|
if (!this._initialized) {
|
|
|
|
// specify motor size on this port
|
|
|
|
const b = mkCmd(this._port, DAL.opOutputSetType, 1)
|
|
|
|
b.setNumber(NumberFormat.Int8LE, 2, this._large ? 0x07 : 0x08)
|
|
|
|
writePWM(b)
|
|
|
|
}
|
2017-10-25 05:16:33 +02:00
|
|
|
}
|
2017-08-08 02:39:37 +02:00
|
|
|
|
2017-12-15 02:01:23 +01:00
|
|
|
/**
|
|
|
|
* Gets the port where this motor is connected
|
|
|
|
*/
|
|
|
|
//%
|
|
|
|
//% group="Motion"
|
|
|
|
port(): Output {
|
|
|
|
return this._port;
|
|
|
|
}
|
|
|
|
|
2017-10-25 05:16:33 +02:00
|
|
|
/**
|
2017-12-14 07:54:08 +01:00
|
|
|
* Sets the speed of the motor.
|
|
|
|
* @param speed the speed from ``100`` full forward to ``-100`` full backward, eg: 50
|
2017-10-25 05:16:33 +02:00
|
|
|
*/
|
2017-12-15 02:01:23 +01:00
|
|
|
//% blockId=motorSetSpeed block="set speed of `icons.motorLarge` %motor|to %speed|%"
|
2017-12-14 07:40:40 +01:00
|
|
|
//% on.fieldEditor=toggleonoff
|
|
|
|
//% weight=99 blockGap=8
|
2017-12-14 07:54:08 +01:00
|
|
|
//% speed.min=-100 speed.max=100
|
2017-12-15 02:01:23 +01:00
|
|
|
//% group="Motion"
|
2017-12-14 07:54:08 +01:00
|
|
|
setSpeed(speed: number) {
|
|
|
|
this.__init();
|
|
|
|
speed = Math.clamp(-100, 100, speed >> 0);
|
|
|
|
if (!speed) { // always stop
|
2017-10-31 05:29:18 +01:00
|
|
|
this.stop();
|
2017-12-14 07:40:40 +01:00
|
|
|
} else {
|
2017-12-15 02:01:23 +01:00
|
|
|
const b = mkCmd(this._port, DAL.opOutputSpeed, 1)
|
|
|
|
b.setNumber(NumberFormat.Int8LE, 2, speed)
|
|
|
|
writePWM(b)
|
2017-10-27 10:47:25 +02:00
|
|
|
}
|
2017-10-25 05:16:33 +02:00
|
|
|
}
|
2017-07-07 16:15:36 +02:00
|
|
|
|
2017-10-25 05:16:33 +02:00
|
|
|
/**
|
2017-12-14 07:40:40 +01:00
|
|
|
* Moves the motor by a number of rotations, degress or seconds
|
|
|
|
* @param value the move quantity, eg: 2
|
|
|
|
* @param unit the meaning of the value
|
2017-12-12 01:07:46 +01:00
|
|
|
* @param speed the speed from ``100`` full forward to ``-100`` full backward, eg: 50
|
2017-10-25 05:16:33 +02:00
|
|
|
*/
|
2017-12-14 07:54:08 +01:00
|
|
|
//% blockId=motorMove block="move `icons.motorLarge` %motor|for %value|%unit|at %speed|%"
|
2017-12-15 02:01:23 +01:00
|
|
|
//% weight=98 blockGap=8
|
2017-12-14 07:40:40 +01:00
|
|
|
//% speed.min=-100 speed.max=100
|
2017-12-15 02:01:23 +01:00
|
|
|
//% group="Motion"
|
2017-12-14 07:54:08 +01:00
|
|
|
move(value: number, unit: MoveUnit, speed: number) {
|
|
|
|
this.output(value, unit, speed, 0);
|
2017-12-14 07:40:40 +01:00
|
|
|
}
|
2017-12-15 02:01:23 +01:00
|
|
|
|
2017-12-14 07:54:08 +01:00
|
|
|
private output(value: number, unit: MoveUnit, speed: number, turnRatio: number) {
|
2017-12-14 07:40:40 +01:00
|
|
|
this.__init();
|
2017-12-14 07:54:08 +01:00
|
|
|
speed = Math.clamp(-100, 100, speed >> 0);
|
|
|
|
if (!speed) {
|
2017-12-14 07:40:40 +01:00
|
|
|
this.stop();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
turnRatio = Math.clamp(-200, 200, turnRatio >> 0);
|
|
|
|
let useSteps: boolean;
|
|
|
|
let stepsOrTime: number;
|
|
|
|
switch (unit) {
|
|
|
|
case MoveUnit.Rotations:
|
|
|
|
stepsOrTime = (value * 360) >> 0;
|
|
|
|
useSteps = true;
|
|
|
|
break;
|
|
|
|
case MoveUnit.Degrees:
|
|
|
|
stepsOrTime = value >> 0;
|
|
|
|
useSteps = true;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
stepsOrTime = value;
|
|
|
|
useSteps = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-12-15 02:01:23 +01:00
|
|
|
step(this._port, {
|
|
|
|
useSteps: useSteps,
|
|
|
|
step1: 0,
|
|
|
|
step2: stepsOrTime,
|
|
|
|
step3: 0,
|
|
|
|
speed: speed,
|
|
|
|
useBrake: this._brake
|
|
|
|
})
|
2017-10-25 05:16:33 +02:00
|
|
|
}
|
|
|
|
|
2017-10-31 05:29:18 +01:00
|
|
|
/**
|
|
|
|
* Stops the motor
|
|
|
|
*/
|
2017-12-14 07:40:40 +01:00
|
|
|
private stop() {
|
|
|
|
this.__init();
|
2017-12-15 02:01:23 +01:00
|
|
|
stop(this._port);
|
2017-12-07 07:41:51 +01:00
|
|
|
}
|
2017-10-31 05:29:18 +01:00
|
|
|
|
2017-10-27 10:47:25 +02:00
|
|
|
/**
|
|
|
|
* Sets the automatic brake on or off when the motor is off
|
|
|
|
* @param brake a value indicating if the motor should break when off
|
|
|
|
*/
|
2017-11-16 22:05:50 +01:00
|
|
|
//% blockId=outputMotorSetBrakeMode block="set `icons.motorLarge` %motor|brake %brake"
|
2017-10-27 10:47:25 +02:00
|
|
|
//% brake.fieldEditor=toggleonoff
|
2017-12-14 07:40:40 +01:00
|
|
|
//% weight=60 blockGap=8
|
2017-12-15 02:01:23 +01:00
|
|
|
//% group="Motion"
|
2017-10-27 10:47:25 +02:00
|
|
|
setBrake(brake: boolean) {
|
2017-12-14 07:54:08 +01:00
|
|
|
this.__init();
|
2017-12-14 07:40:40 +01:00
|
|
|
this._brake = brake;
|
2017-10-27 10:47:25 +02:00
|
|
|
}
|
|
|
|
|
2017-10-27 11:52:42 +02:00
|
|
|
/**
|
|
|
|
* Reverses the motor polarity
|
|
|
|
*/
|
2017-11-16 22:05:50 +01:00
|
|
|
//% blockId=motorSetReversed block="set `icons.motorLarge` %motor|reversed %reversed"
|
2017-10-27 11:52:42 +02:00
|
|
|
//% reversed.fieldEditor=toggleonoff
|
2017-12-14 07:40:40 +01:00
|
|
|
//% weight=59
|
2017-12-15 02:01:23 +01:00
|
|
|
//% group="Motion"
|
2017-10-27 11:52:42 +02:00
|
|
|
setReversed(reversed: boolean) {
|
2017-12-14 07:40:40 +01:00
|
|
|
this.__init();
|
|
|
|
const b = mkCmd(this._port, DAL.opOutputPolarity, 1)
|
2017-10-27 11:52:42 +02:00
|
|
|
b.setNumber(NumberFormat.Int8LE, 2, reversed ? -1 : 1);
|
|
|
|
writePWM(b)
|
|
|
|
}
|
|
|
|
|
2017-10-25 05:16:33 +02:00
|
|
|
/**
|
|
|
|
* Gets motor actual speed.
|
|
|
|
* @param motor the port which connects to the motor
|
|
|
|
*/
|
2017-11-16 22:05:50 +01:00
|
|
|
//% blockId=motorSpeed block="`icons.motorLarge` %motor|speed"
|
2017-12-14 07:40:40 +01:00
|
|
|
//% weight=72 blockGap=8
|
2017-12-15 02:01:23 +01:00
|
|
|
//% group="Sensors"
|
2017-10-27 11:52:42 +02:00
|
|
|
speed(): number {
|
2017-12-14 07:40:40 +01:00
|
|
|
this.__init();
|
|
|
|
return getMotorData(this._port).actualSpeed;
|
2017-10-27 09:09:00 +02:00
|
|
|
}
|
2017-10-27 11:52:42 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets motor step count.
|
|
|
|
* @param motor the port which connects to the motor
|
|
|
|
*/
|
2017-11-16 22:05:50 +01:00
|
|
|
//% blockId=motorCount block="`icons.motorLarge` %motor|count"
|
2017-12-14 07:40:40 +01:00
|
|
|
//% weight=71 blockGap=8
|
2017-12-15 02:01:23 +01:00
|
|
|
//% group="Sensors"
|
2017-10-27 11:52:42 +02:00
|
|
|
count(): number {
|
2017-12-14 07:40:40 +01:00
|
|
|
this.__init();
|
|
|
|
return getMotorData(this._port).count;
|
2017-10-27 11:52:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets motor tacho count.
|
|
|
|
* @param motor the port which connects to the motor
|
|
|
|
*/
|
2017-11-16 22:05:50 +01:00
|
|
|
//% blockId=motorTachoCount block="`icons.motorLarge` %motor|tacho count"
|
2017-12-14 07:40:40 +01:00
|
|
|
//% weight=70
|
2017-12-15 02:01:23 +01:00
|
|
|
//% group="Sensors"
|
2017-10-27 11:52:42 +02:00
|
|
|
tachoCount(): number {
|
2017-12-14 07:40:40 +01:00
|
|
|
this.__init();
|
|
|
|
return getMotorData(this._port).tachoCount;
|
2017-10-27 11:52:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Clears the motor count
|
|
|
|
*/
|
2017-12-15 02:01:23 +01:00
|
|
|
//% group="Motion"
|
2017-10-27 11:52:42 +02:00
|
|
|
clearCount() {
|
2017-12-14 07:40:40 +01:00
|
|
|
this.__init();
|
|
|
|
const b = mkCmd(this._port, DAL.opOutputClearCount, 0)
|
2017-10-27 11:52:42 +02:00
|
|
|
writePWM(b)
|
|
|
|
for (let i = 0; i < DAL.NUM_OUTPUTS; ++i) {
|
2017-12-14 07:40:40 +01:00
|
|
|
if (this._port & (1 << i)) {
|
2017-10-27 11:52:42 +02:00
|
|
|
motorMM.setNumber(NumberFormat.Int32LE, i * MotorDataOff.Size + MotorDataOff.TachoSensor, 0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-12-15 02:01:23 +01:00
|
|
|
* Resets the motor.
|
2017-10-27 11:52:42 +02:00
|
|
|
*/
|
2017-12-14 07:40:40 +01:00
|
|
|
//% blockId=motorReset block="reset `icons.motorLarge` %motor"
|
2017-12-14 22:07:10 +01:00
|
|
|
//% weight=20
|
2017-12-15 02:01:23 +01:00
|
|
|
//% group="Motion"
|
2017-10-27 11:52:42 +02:00
|
|
|
reset() {
|
2017-12-14 07:40:40 +01:00
|
|
|
this.__init();
|
|
|
|
reset(this._port);
|
2017-12-15 02:01:23 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//% whenUsed fixedInstance block="large A"
|
|
|
|
export const largeA = new Motor(Output.A, true);
|
|
|
|
|
|
|
|
//% whenUsed fixedInstance block="large B"
|
|
|
|
export const largeB = new Motor(Output.B, true);
|
|
|
|
|
|
|
|
//% whenUsed fixedInstance block="large C"
|
|
|
|
export const largeC = new Motor(Output.C, true);
|
|
|
|
|
|
|
|
//% whenUsed fixedInstance block="large D"
|
|
|
|
export const largeD = new Motor(Output.D, true);
|
|
|
|
|
|
|
|
//% whenUsed fixedInstance block="medium A"
|
|
|
|
export const mediumA = new Motor(Output.A, false);
|
|
|
|
|
|
|
|
//% whenUsed fixedInstance block="medium B"
|
|
|
|
export const mediumB = new Motor(Output.B, false);
|
|
|
|
|
|
|
|
//% whenUsed fixedInstance block="medium C"
|
|
|
|
export const mediumC = new Motor(Output.C, false);
|
|
|
|
|
|
|
|
//% whenUsed fixedInstance block="medium D"
|
|
|
|
export const mediumD = new Motor(Output.D, false);
|
|
|
|
|
|
|
|
//% fixedInstances
|
|
|
|
export class SynchedMotorPair extends control.Component {
|
|
|
|
private _ports: Output;
|
|
|
|
private _brake: boolean;
|
|
|
|
|
|
|
|
constructor(ports: Output) {
|
|
|
|
super();
|
|
|
|
this._ports = ports;
|
|
|
|
this._brake = false;
|
|
|
|
}
|
2017-12-14 07:40:40 +01:00
|
|
|
|
|
|
|
/**
|
2017-12-15 02:01:23 +01:00
|
|
|
* Sets the speed of the motor.
|
|
|
|
* @param speed the speed from ``100`` full forward to ``-100`` full backward, eg: 50
|
2017-12-14 07:40:40 +01:00
|
|
|
*/
|
2017-12-15 02:01:23 +01:00
|
|
|
//% blockId=motorPairSetSpeed block="set speed of `icons.motorLarge` %motor|to %speed|%"
|
|
|
|
//% on.fieldEditor=toggleonoff
|
|
|
|
//% weight=99 blockGap=8
|
|
|
|
//% speed.min=-100 speed.max=100
|
|
|
|
//% group="Chassis"
|
|
|
|
setSpeed(speed: number) {
|
|
|
|
speed = Math.clamp(speed >> 0, -100, 100);
|
|
|
|
if (!speed) {
|
|
|
|
stop(this._ports);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
syncMotors(this._ports, {
|
|
|
|
speed: speed,
|
|
|
|
turnRatio: 0,
|
|
|
|
useBrake: !!this._brake
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the automatic brake on or off when the motor is off
|
|
|
|
* @param brake a value indicating if the motor should break when off
|
|
|
|
*/
|
|
|
|
//% blockId=motorPairSetBrakeMode block="set `icons.motorLarge` %chassis|brake %brake"
|
|
|
|
//% brake.fieldEditor=toggleonoff
|
|
|
|
//% weight=60 blockGap=8
|
|
|
|
//% group="Chassis"
|
|
|
|
setBrake(brake: boolean) {
|
|
|
|
this._brake = brake;
|
2017-10-27 11:52:42 +02:00
|
|
|
}
|
2017-12-14 07:40:40 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Turns the motor and the follower motor by a number of rotations
|
|
|
|
* @param value the move quantity, eg: 2
|
|
|
|
* @param unit the meaning of the value
|
|
|
|
* @param speed the speed from ``100`` full forward to ``-100`` full backward, eg: 50
|
2017-12-14 22:25:27 +01:00
|
|
|
* @param steering the ratio of power sent to the follower motor, from ``-100`` to ``100``
|
2017-12-14 07:40:40 +01:00
|
|
|
*/
|
2017-12-15 02:01:23 +01:00
|
|
|
//% blockId=motorPairTurn block="move steering %chassis|at %speed|%|steer %turnRadio|%|by %value|%unit"
|
2017-12-14 07:40:40 +01:00
|
|
|
//% weight=9 blockGap=8
|
2017-12-14 22:25:27 +01:00
|
|
|
//% steering.min=-100 steering=100
|
2017-12-14 22:07:10 +01:00
|
|
|
//% inlineInputMode=inline
|
2017-12-15 02:01:23 +01:00
|
|
|
//% group="Chassis"
|
2017-12-14 22:25:27 +01:00
|
|
|
moveSteering(steering: number, speed: number, value: number, unit: MoveUnit) {
|
2017-12-15 02:01:23 +01:00
|
|
|
speed = Math.clamp(-100, 100, speed >> 0);
|
|
|
|
if (!speed) {
|
|
|
|
stop(this._ports);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const turnRatio = Math.clamp(-200, 200, steering + 100 >> 0);
|
|
|
|
let useSteps: boolean;
|
|
|
|
let stepsOrTime: number;
|
|
|
|
switch (unit) {
|
|
|
|
case MoveUnit.Rotations:
|
|
|
|
stepsOrTime = (value * 360) >> 0;
|
|
|
|
useSteps = true;
|
|
|
|
break;
|
|
|
|
case MoveUnit.Degrees:
|
|
|
|
stepsOrTime = value >> 0;
|
|
|
|
useSteps = true;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
stepsOrTime = value;
|
|
|
|
useSteps = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
syncMotors(this._ports, {
|
|
|
|
useSteps: useSteps,
|
|
|
|
speed: speed,
|
|
|
|
turnRatio: turnRatio,
|
|
|
|
stepsOrTime: stepsOrTime,
|
|
|
|
useBrake: this._brake
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-12-14 22:25:27 +01:00
|
|
|
/**
|
|
|
|
* The Move Tank block can make a robot drive forward, backward, turn, or stop.
|
|
|
|
* Use the Move Tank block for robot vehicles that have two Large Motors,
|
|
|
|
* with one motor driving the left side of the vehicle and the other the right side.
|
|
|
|
* You can make the two motors go at different speeds or in different directions
|
|
|
|
* to make your robot turn.
|
|
|
|
* @param value the amount of movement, eg: 2
|
|
|
|
* @param unit
|
|
|
|
* @param speedLeft the speed on the left motor, eg: 50
|
|
|
|
* @param speedRight the speed on the right motor, eg: 50
|
|
|
|
*/
|
2017-12-15 02:01:23 +01:00
|
|
|
//% blockId=motorPairTank block="move tank %chassis|left %speedLeft|%|right %speedRight|%|by %value|%unit"
|
2017-12-14 22:25:27 +01:00
|
|
|
//% weight=9 blockGap=8
|
|
|
|
//% speedLeft.min=-100 speedLeft=100
|
|
|
|
//% speedRight.min=-100 speedRight=100
|
|
|
|
//% inlineInputMode=inline
|
2017-12-15 02:01:23 +01:00
|
|
|
//% group="Chassis"
|
2017-12-14 22:25:27 +01:00
|
|
|
moveTank(speedLeft: number, speedRight: number, value: number, unit: MoveUnit) {
|
|
|
|
speedLeft = Math.clamp(speedLeft >> 0, -100, 100);
|
|
|
|
speedRight = Math.clamp(speedRight >> 0, -100, 100);
|
2017-12-15 02:01:23 +01:00
|
|
|
const steering = (speedRight * 100 / speedLeft) >> 0;
|
2017-12-14 22:25:27 +01:00
|
|
|
this.moveSteering(speedLeft, steering, value, unit);
|
|
|
|
}
|
2017-07-07 16:15:36 +02:00
|
|
|
}
|
|
|
|
|
2017-12-15 02:01:23 +01:00
|
|
|
//% whenUsed fixedInstance block="large B+C"
|
|
|
|
export const largeBC = new SynchedMotorPair(Output.BC);
|
2017-10-27 09:09:00 +02:00
|
|
|
|
2017-12-15 02:01:23 +01:00
|
|
|
//% whenUsed fixedInstance block="large A+D"
|
|
|
|
export const largeAD = new SynchedMotorPair(Output.AD);
|
2017-10-27 09:09:00 +02:00
|
|
|
|
2017-12-15 02:01:23 +01:00
|
|
|
//% whenUsed fixedInstance block="large A+B"
|
|
|
|
export const largeAB = new SynchedMotorPair(Output.AB);
|
2017-10-27 09:09:00 +02:00
|
|
|
|
2017-12-15 02:01:23 +01:00
|
|
|
//% whenUsed fixedInstance block="large C+D"
|
|
|
|
export const largeCD = new SynchedMotorPair(Output.CD);
|
2017-10-25 05:16:33 +02:00
|
|
|
|
|
|
|
function reset(out: Output) {
|
2017-07-11 16:18:59 +02:00
|
|
|
let b = mkCmd(out, DAL.opOutputReset, 0)
|
2017-07-07 16:15:36 +02:00
|
|
|
writePWM(b)
|
|
|
|
}
|
|
|
|
|
2017-08-08 11:41:47 +02:00
|
|
|
function outOffset(out: Output) {
|
|
|
|
for (let i = 0; i < DAL.NUM_OUTPUTS; ++i) {
|
|
|
|
if (out & (1 << i))
|
|
|
|
return i * MotorDataOff.Size
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2017-10-25 05:16:33 +02:00
|
|
|
interface MotorData {
|
2017-08-08 11:41:47 +02:00
|
|
|
actualSpeed: number; // -100..+100
|
|
|
|
tachoCount: number;
|
|
|
|
count: number;
|
|
|
|
}
|
|
|
|
|
|
|
|
// only a single output at a time
|
2017-10-25 05:16:33 +02:00
|
|
|
function getMotorData(out: Output): MotorData {
|
2017-12-13 23:55:14 +01:00
|
|
|
init()
|
2017-08-08 11:41:47 +02:00
|
|
|
let buf = motorMM.slice(outOffset(out), MotorDataOff.Size)
|
|
|
|
return {
|
|
|
|
actualSpeed: buf.getNumber(NumberFormat.Int8LE, MotorDataOff.Speed),
|
|
|
|
tachoCount: buf.getNumber(NumberFormat.Int32LE, MotorDataOff.TachoCounts),
|
|
|
|
count: buf.getNumber(NumberFormat.Int32LE, MotorDataOff.TachoSensor),
|
|
|
|
}
|
|
|
|
}
|
2017-08-08 02:39:37 +02:00
|
|
|
|
2017-12-12 22:20:25 +01:00
|
|
|
interface SyncOptions {
|
|
|
|
useSteps?: boolean;
|
|
|
|
speed: number;
|
|
|
|
turnRatio: number;
|
2017-12-14 07:40:40 +01:00
|
|
|
stepsOrTime?: number;
|
2017-12-12 22:20:25 +01:00
|
|
|
useBrake?: boolean;
|
|
|
|
}
|
|
|
|
|
|
|
|
function syncMotors(out: Output, opts: SyncOptions) {
|
|
|
|
const cmd = opts.useSteps ? DAL.opOutputStepSync : DAL.opOutputTimeSync;
|
|
|
|
const b = mkCmd(out, cmd, 11);
|
|
|
|
const speed = Math.clamp(-100, 100, opts.speed);
|
|
|
|
const turnRatio = Math.clamp(-200, 200, opts.turnRatio);
|
|
|
|
|
|
|
|
b.setNumber(NumberFormat.Int8LE, 2, speed)
|
|
|
|
// note that b[3] is padding
|
|
|
|
b.setNumber(NumberFormat.Int16LE, 4 + 4 * 0, turnRatio)
|
|
|
|
// b[6], b[7] is padding
|
|
|
|
b.setNumber(NumberFormat.Int32LE, 4 + 4 * 1, opts.stepsOrTime || 0)
|
|
|
|
b.setNumber(NumberFormat.Int8LE, 4 + 4 * 2, opts.useBrake ? 1 : 0)
|
|
|
|
writePWM(b)
|
|
|
|
}
|
|
|
|
|
2017-10-25 05:16:33 +02:00
|
|
|
interface StepOptions {
|
2017-07-07 16:15:36 +02:00
|
|
|
power?: number;
|
|
|
|
speed?: number; // either speed or power has to be present
|
|
|
|
step1: number;
|
|
|
|
step2: number;
|
|
|
|
step3: number;
|
|
|
|
useSteps?: boolean; // otherwise use milliseconds
|
2017-08-08 02:39:37 +02:00
|
|
|
useBrake?: boolean;
|
2017-07-07 16:15:36 +02:00
|
|
|
}
|
|
|
|
|
2017-12-12 23:08:45 +01:00
|
|
|
function start(out: Output) {
|
|
|
|
const b = mkCmd(out, DAL.opOutputStart, 0)
|
|
|
|
writePWM(b);
|
|
|
|
}
|
|
|
|
|
2017-12-14 07:40:40 +01:00
|
|
|
function stop(out: Output) {
|
|
|
|
const b = mkCmd(out, DAL.opOutputStop, 1)
|
|
|
|
b.setNumber(NumberFormat.UInt8LE, 2, this.brake ? 1 : 0)
|
|
|
|
writePWM(b);
|
|
|
|
}
|
|
|
|
|
2017-10-25 05:16:33 +02:00
|
|
|
function step(out: Output, opts: StepOptions) {
|
2017-07-11 16:18:59 +02:00
|
|
|
let op = opts.useSteps ? DAL.opOutputStepSpeed : DAL.opOutputTimeSpeed
|
2017-07-07 16:15:36 +02:00
|
|
|
let speed = opts.speed
|
|
|
|
if (speed == null) {
|
|
|
|
speed = opts.power
|
2017-07-11 16:18:59 +02:00
|
|
|
op = opts.useSteps ? DAL.opOutputStepPower : DAL.opOutputTimePower
|
2017-07-07 16:15:36 +02:00
|
|
|
if (speed == null)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
speed = Math.clamp(-100, 100, speed)
|
|
|
|
|
|
|
|
let b = mkCmd(out, op, 15)
|
|
|
|
b.setNumber(NumberFormat.Int8LE, 2, speed)
|
|
|
|
// note that b[3] is padding
|
|
|
|
b.setNumber(NumberFormat.Int32LE, 4 + 4 * 0, opts.step1)
|
|
|
|
b.setNumber(NumberFormat.Int32LE, 4 + 4 * 1, opts.step2)
|
|
|
|
b.setNumber(NumberFormat.Int32LE, 4 + 4 * 2, opts.step3)
|
2017-08-08 02:39:37 +02:00
|
|
|
b.setNumber(NumberFormat.Int8LE, 4 + 4 * 3, opts.useBrake ? 1 : 0)
|
2017-07-07 16:15:36 +02:00
|
|
|
writePWM(b)
|
|
|
|
}
|
|
|
|
|
|
|
|
const types = [0, 0, 0, 0]
|
|
|
|
export function setType(out: Output, type: OutputType) {
|
2017-07-11 16:18:59 +02:00
|
|
|
let b = mkCmd(out, DAL.opOutputSetType, 3)
|
2017-07-07 16:15:36 +02:00
|
|
|
for (let i = 0; i < 4; ++i) {
|
|
|
|
if (out & (1 << i)) {
|
|
|
|
types[i] = type
|
|
|
|
}
|
|
|
|
b.setNumber(NumberFormat.UInt8LE, i + 1, types[i])
|
|
|
|
}
|
|
|
|
writePWM(b)
|
|
|
|
}
|
2017-07-10 10:10:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
interface Buffer {
|
|
|
|
[index: number]: number;
|
|
|
|
// rest defined in buffer.cpp
|
2017-07-07 16:15:36 +02:00
|
|
|
}
|