前面简单说了下整个工程的文件,这篇文章主要记录下TriodeCar的main.ts的开发过程
小车原理
如图所示,当小车偏离轨道向左时,右边的光敏电阻会来到黑色跑道的上方,光敏电阻阻值变高,而左边的光敏电阻处于白色地面,此时,LL点的电压会比LR点的电压低,此时,比较器U1A的正向电压高于反向电压,1号引脚输出高电平。同理,U1B的正向电压低于反向电压,7号引脚输出低电平。从而控制左边电机正转,小车右拐,R6和D2离开黑色跑道,直到左边的传感器探测到黑跑道,原理与前面类似。小车在前进过程中不断重复以上动作,从而达到前进的目的。
巡线积木
TriodeCar中,巡线传感器用是光敏电阻,所以需要模拟输入引脚,这里接的是P1和P2。根据这里的JavaScript例子,读取引脚的代码为pins.analogReadPin(AnalogPin.P2)
export enum Patrol { //两个下拉选项 //% blockId="patrolLeft" block="left" PatrolLeft = 2, //% blockId="patrolRight" block="right" PatrolRight = 1 } /** * Read line tracking sensor. //备注 */ //% weight=20 //block权重,决定了block的显示顺序。 //% blockId=read_Patrol block="read |%patrol line tracking sensor" //block的名字,block的ID(ID在多语言适配的时候用得到)。 //% patrol.fieldEditor="gridpicker" patrol.fieldOptions.columns=2 //下拉选项 export function ReadLDR(patrol: Patrol): number { //这里类型是number,返回模拟引脚的数值 if (patrol == Patrol.PatrolLeft) { //如果下拉选的是左边,就读取P2数值 return pins.analogReadPin(AnalogPin.P2) } else if (patrol == Patrol.PatrolRight) { //如果下拉选的是右边,就读取P1数值 return pins.analogReadPin(AnalogPin.P1) } else { return -1 } }
车的方向
由于TriodeCar是三极管驱动的小车,只有前进和停止选项,高电平停止,低电平转动,左拐是右边电机转,右拐是左边电机转。根据原理图P15是右边电机,P14是左边电机。
export enum direction { //四个选项,前进,后退,左拐,右拐 //% blockId="foward" block="go foward" foward = 1, //% blockId="stop" block="stop" stop = 2, //% blockId="turnleft" block="turn left" left = 3, //% blockId="turnright" block="turn right" right = 4, } /** * CarDirection. */ //% blockId=IR_Enable block="let the car |%direction" //% direction.fieldEditor="gridpicker" direction.fieldOptions.columns=4 //% weight=93 blockGap=8 export function CarDirection(Direction: direction): void { if (Direction == direction.foward) { pins.servoSetPulse(AnalogPin.P14, 4000) //left pins.servoSetPulse(AnalogPin.P15, 4000) //right } else if (Direction == direction.stop) { pins.digitalWritePin(DigitalPin.P14, 1) //left pins.digitalWritePin(DigitalPin.P15, 1) //right } else if (Direction == direction.left) { pins.digitalWritePin(DigitalPin.P14, 1) //left pins.servoSetPulse(AnalogPin.P15, 4000) //right } else if (Direction == direction.right) { pins.servoSetPulse(AnalogPin.P14, 4000) //left pins.digitalWritePin(DigitalPin.P15, 1) //right } }
控制车速
这里控制车速用的是pwm,利用占空比来调速
export enum motor { //两个选项,左电机和右电机 //% blockId="leftmotor" block="Left Motor" left = 1, //% blockId="rightmotor" block="Right Motor" right = 2, } /** * Set the speed of Triode-Car motor. */ //% weight=90 //% blockId=motor_MotorRun block="|%motor|move Foward at speed|%speed" //% speed.min=0 speed.max=10 //% motor.fieldEditor="gridpicker" motor.fieldOptions.columns=2 export function motorRun(Motor: motor, speed: number = 5): void { let pulsetime = Math.map(speed, 1, 10, 12000, 0) //将1到10映射到12000到0,从而达到控制速度 if (Motor == motor.left) { if (speed == 0) { pins.digitalWritePin(DigitalPin.P14, 1) //left } else { pins.servoSetPulse(AnalogPin.P14, pulsetime) } } if (Motor == motor.right) { if (speed == 0) { pins.digitalWritePin(DigitalPin.P15, 1) //right } else { pins.servoSetPulse(AnalogPin.P15, pulsetime) } } }
最终代码
/** * @file pxt-triodecar/main.ts * @brief BananaPi's triodecar makecode library. * @n This is a MakeCode graphical programming education robot. * * @copyright [BananPi](http://banana-pi.org), 2021 * @copyright MIT Lesser General Public License * * @author [email](1445788683@qq.com) * @date 2021-03-23 */ enum PingUnit { //% block="cm" Centimeters, //% block="inches" Inches } //% weight=0 color=#FF7256 icon="\uf1b9" block="TriodeCar" namespace triodecar { export enum Patrol { //% blockId="patrolLeft" block="left" PatrolLeft = 2, //% blockId="patrolRight" block="right" PatrolRight = 1 } export enum direction { //% blockId="foward" block="go foward" foward = 1, //% blockId="stop" block="stop" stop = 2, //% blockId="turnleft" block="turn left" left = 3, //% blockId="turnright" block="turn right" right = 4, } export enum motor { //% blockId="leftmotor" block="Left Motor" left = 1, //% blockId="rightmotor" block="Right Motor" right = 2, } /** * Read line tracking sensor. */ //% weight=20 //% blockId=read_Patrol block="read |%patrol line tracking sensor" //% patrol.fieldEditor="gridpicker" patrol.fieldOptions.columns=2 export function ReadLDR(patrol: Patrol): number { if (patrol == Patrol.PatrolLeft) { return pins.analogReadPin(AnalogPin.P2) } else if (patrol == Patrol.PatrolRight) { return pins.analogReadPin(AnalogPin.P1) } else { return -1 } } /** * CarDirection. */ //% blockId=IR_Enable block="let the car |%direction" //% direction.fieldEditor="gridpicker" direction.fieldOptions.columns=4 //% weight=93 blockGap=8 export function CarDirection(Direction: direction): void { if (Direction == direction.foward) { pins.servoSetPulse(AnalogPin.P14, 4000) //left pins.servoSetPulse(AnalogPin.P15, 4000) //right } else if (Direction == direction.stop) { pins.digitalWritePin(DigitalPin.P14, 1) //left pins.digitalWritePin(DigitalPin.P15, 1) //right } else if (Direction == direction.left) { pins.digitalWritePin(DigitalPin.P14, 1) //left pins.servoSetPulse(AnalogPin.P15, 4000) //right } else if (Direction == direction.right) { pins.servoSetPulse(AnalogPin.P14, 4000) //left pins.digitalWritePin(DigitalPin.P15, 1) //right } } /** * Set the speed of Triode-Car motor. */ //% weight=90 //% blockId=motor_MotorRun block="|%motor|move Foward at speed|%speed" //% speed.min=0 speed.max=10 //% motor.fieldEditor="gridpicker" motor.fieldOptions.columns=2 export function motorRun(Motor: motor, speed: number = 5): void { let pulsetime = Math.map(speed, 1, 10, 12000, 0) if (Motor == motor.left) { if (speed == 0) { pins.digitalWritePin(DigitalPin.P14, 1) //left } else { pins.servoSetPulse(AnalogPin.P14, pulsetime) } } if (Motor == motor.right) { if (speed == 0) { pins.digitalWritePin(DigitalPin.P15, 1) //right } else { pins.servoSetPulse(AnalogPin.P15, pulsetime) } } } /** * Read ultrasonic sensor. */ //% blockId=ultrasonic_sensor block="read ultrasonic sensor |%unit " //% weight=95 advanced=true export function Ultrasonic(unit: PingUnit, maxCmDistance = 500): number { let d pins.digitalWritePin(DigitalPin.P12, 1); basic.pause(1) pins.digitalWritePin(DigitalPin.P12, 0); if (pins.digitalReadPin(DigitalPin.P13) == 0) { pins.digitalWritePin(DigitalPin.P12, 0); //sleep_us(2); pins.digitalWritePin(DigitalPin.P12, 1); //sleep_us(10); pins.digitalWritePin(DigitalPin.P12, 0); d = pins.pulseIn(DigitalPin.P13, PulseValue.High, maxCmDistance * 58);//readPulseIn(1); } else { pins.digitalWritePin(DigitalPin.P12, 0); pins.digitalWritePin(DigitalPin.P12, 1); d = pins.pulseIn(DigitalPin.P13, PulseValue.Low, maxCmDistance * 58);//readPulseIn(0); } let x = d / 39; if (x <= 0 || x > 500) { return 0; } switch (unit) { case PingUnit.Centimeters: return Math.idiv(d, 58); case PingUnit.Inches: return Math.idiv(d, 148); default: return d ; } } }
暂无评论