Compare commits

..

8 Commits

13 changed files with 357 additions and 19 deletions

View File

@ -0,0 +1,178 @@
# Gyroboy
Work in progress
```blocks
let motorSpeed1 = 0
let motorSpeed2 = 0
let motorSpeed3 = 0
let motorSpeed = 0
let fallen = false
let motorSpeed0 = 0
let oldControlDrive = 0
let controlDrive = 0
let power = 0
let motorAngle = 0
let gyroAngle = 0
let controlSteering = 0
let state = 0
let motorPosition = 0
let temp = 0
let gyroRate = 0
let timestep = 0
sensors.color1.onColorDetected(ColorSensorColor.Red, function () {
music.playTone(2000, 100)
controlDrive = 0
controlSteering = 0
})
// reads the motor angle and computes the motor speed,
// position
function computeMotors() {
temp = motorAngle
// read angle on both motors
motorAngle = motors.largeD.angle() + motors.largeA.angle()
// and estimate speed as angle difference
motorSpeed0 = motorAngle - temp
// average last 4 speed readings
motorSpeed = (motorSpeed0 + motorSpeed1 + motorSpeed2 + motorSpeed3) / 4 / timestep
// shift all previous recorded speeds by one
motorSpeed3 = motorSpeed2
motorSpeed2 = motorSpeed1
motorSpeed1 = motorSpeed0
// compute position from speed
motorPosition = motorPosition + timestep * motorSpeed
}
// read the gyro rate and computes the angle
function computeGyro() {
gyroRate = sensors.gyro2.rate()
gyroAngle = gyroAngle + timestep * gyroRate
}
function reset() {
state = 0
// sleeping
moods.sleeping.show();
// reset counters
motors.largeA.reset()
motors.largeD.reset()
// motors are unregulated
motors.largeA.setRegulated(false)
motors.largeD.setRegulated(false)
// clear the gyro sensor to remove drift
sensors.gyro2.reset()
// fall detection timer
control.timer2.reset()
// timestep computation timer
control.timer3.reset()
motorAngle = 0
motorPosition = 0
motorSpeed = 0
motorSpeed0 = 0
motorSpeed1 = 0
motorSpeed2 = 0
motorSpeed3 = 0
gyroRate = 0
gyroAngle = 0
fallen = false
power = 0
controlSteering = 0
controlDrive = 0
// awake
moods.awake.show();
gyroAngle = -0.25
state = 1;
}
// compute set point for motor position and required
// motor power
function computePower() {
// apply control and compute desired motor position
motorPosition -= timestep * controlDrive;
// estimate power based on sensor readings and control
// values
power = 0.8 * gyroRate + 15 * gyroAngle + (0.08 * motorSpeed + 0.12 * motorPosition) - 0.01 * controlDrive
// ensure that power stays within -100, 100
if (power > 100) {
power = 100
} else if (power < -100) {
power = -100
}
}
// test if the robot has fallen off
function checkFallen() {
if (Math.abs(power) < 100) {
control.timer2.reset()
}
if (control.timer2.seconds() > 2) {
fallen = true
}
}
// stop all motors and wait for touch button to be
// pressed
function stop() {
motors.stopAllMotors()
state = 0
moods.knockedOut.show();
sensors.touch3.pauseUntil(TouchSensorEvent.Pressed)
moods.neutral.show();
}
sensors.ultrasonic4.onEvent(UltrasonicSensorEvent.ObjectNear, function () {
moods.dizzy.show()
controlSteering = 0
oldControlDrive = controlDrive
controlDrive = -10
motors.mediumC.setSpeed(30, 30, MoveUnit.Degrees);
motors.mediumC.setSpeed(-30, 60, MoveUnit.Degrees);
motors.mediumC.setSpeed(30, 30, MoveUnit.Degrees);
if (Math.randomRange(-1, 1) >= 1) {
controlSteering = 70
} else {
controlSteering = -70
}
loops.pause(4000)
music.playTone(2000, 100)
controlSteering = 0
controlDrive = oldControlDrive
moods.neutral.show()
})
// compute the elapsed time since the last iteration
function computeTimestep() {
timestep = control.timer3.seconds()
control.timer3.reset()
}
sensors.color1.onColorDetected(ColorSensorColor.Green, function () {
moods.winking.show()
controlDrive = 150
controlSteering = 0
})
sensors.color1.onColorDetected(ColorSensorColor.Blue, function () {
moods.middleRight.show()
controlSteering = 70
})
// apply power to motors
function controlMotors() {
motors.largeA.setSpeed(power + controlSteering * 0.1)
motors.largeD.setSpeed(power - controlSteering * 0.1)
}
sensors.color1.onColorDetected(ColorSensorColor.Yellow, function () {
moods.middleLeft.show()
controlSteering = -70
})
sensors.color1.onColorDetected(ColorSensorColor.White, function () {
moods.sad.show();
controlDrive = -75
})
timestep = 0.014
// main loop
loops.forever(function () {
reset()
while (!fallen) {
control.timer3.pauseUntil(5)
computeTimestep()
computeGyro()
computeMotors()
computePower()
controlMotors()
checkFallen()
}
stop()
})
```

View File

@ -4,34 +4,24 @@
*/
const enum BrickLight {
//% block=off enumval=0
//% blockIdentity=brick.lightPattern
Off = 0,
//% block=green enumval=1
//% blockIdentity=brick.lightPattern
Green = 1,
//% block=red enumval=2
//% blockIdentity=brick.lightPattern
Red = 2,
//% block=orange enumval=3
//% blockIdentity=brick.lightPattern
Orange = 3,
//% block="green flash" enumval=4
//% blockIdentity=brick.lightPattern
GreenFlash = 4,
//% block="red flash" enumval=5
//% blockIdentity=brick.lightPattern
RedFlash = 5,
//% block="orange flash" enumval=6
//% blockIdentity=brick.lightPattern
OrangeFlash = 6,
//% block="green pulse" enumval=7
//% blockIdentity=brick.lightPattern
GreenPulse = 7,
//% block="red pulse" enumval=8
//% blockIdentity=brick.lightPattern
RedPulse = 8,
//% block="orange pulse" enumval=9
//% blockIdentity=brick.lightPattern
OrangePulse = 9,
}

View File

@ -13,7 +13,8 @@
"color-sensor": "file:../color-sensor",
"touch-sensor": "file:../touch-sensor",
"ultrasonic-sensor": "file:../ultrasonic-sensor",
"gyro-sensor": "file:../gyro-sensor"
"gyro-sensor": "file:../gyro-sensor",
"mood": "file:../mood"
},
"public": true
}

3
libs/mood/README.md Normal file
View File

@ -0,0 +1,3 @@
# mood
A package to put the EV3 in various moods.

View File

@ -0,0 +1,17 @@
{
"brick.Mood": "A mood",
"brick.Mood.show": "Shows the mood on the EV3",
"brick.showMood": "Shows a mood",
"moods.angry": "An angry mood",
"moods.awake": "A awake mood",
"moods.dizzy": "A dizzy mood",
"moods.knockedOut": "A knocked out mood",
"moods.love": "In love mood",
"moods.middleLeft": "Looking around left",
"moods.middleRight": "Looking around right",
"moods.neutral": "In a neutral mood",
"moods.sad": "A sad mood",
"moods.sleeping": "A sleeping mood",
"moods.tired": "A tired mood",
"moods.winking": "In laughing mood"
}

View File

@ -0,0 +1,8 @@
{
"brick.showMood|block": "show mood %mood=mood_image_picker",
"brick|block": "brick",
"moods|block": "moods",
"{id:category}Brick": "Brick",
"{id:category}Moods": "Moods",
"{id:group}Screen": "Screen"
}

125
libs/mood/mood.ts Normal file
View File

@ -0,0 +1,125 @@
namespace brick {
/**
* Shows a mood
*/
//% weight=90
//% blockId=moodShow block="show mood %mood=mood_image_picker"
//% weight=101 group="Screen" blockGap=8
export function showMood(mood: Mood) {
if(mood)
mood.show();
}
/**
* A mood
*/
//% fixedInstances
export class Mood {
private image: Image;
private sound: Sound;
private light: BrickLight;
constructor(image: Image, sound: Sound, light: BrickLight) {
this.image = image;
this.sound = sound;
this.light = light;
}
/**
* Shows the mood on the EV3
*/
show() {
brick.setLight(this.light);
brick.showImage(this.image);
music.playSoundEffectUntilDone(this.sound);
loops.pause(20);
}
}
/**
* An image
* @param image the image
*/
//% blockId=mood_image_picker block="%image" shim=TD_ID
//% image.fieldEditor="images"
//% image.fieldOptions.columns=4
//% image.fieldOptions.width=400
//% group="Screen" weight=0 blockHidden=1
export function __moodImagePicker(mood: Mood): Mood {
return mood;
}
}
namespace moods {
/**
* A sleeping mood
*/
//% fixedInstance jres=images.eyesSleeping
export const sleeping = new brick.Mood(images.eyesSleeping, sounds.expressionsSnoring, BrickLight.OrangePulse);
/**
* A awake mood
*/
//% fixedInstance jres=images.eyesAwake
export const awake = new brick.Mood(images.eyesAwake, sounds.informationActivate, BrickLight.Orange);
/**
* A tired mood
*/
//% fixedInstance jres=images.eyesTiredMiddle
export const tired = new brick.Mood(images.eyesTiredMiddle, sounds.expressionsSneezing, BrickLight.OrangeFlash);
/**
* An angry mood
*/
//% fixedInstance jres=images.eyesAngry
export const angry = new brick.Mood(images.eyesAngry, sounds.animalsDogGrowl, BrickLight.RedPulse);
/**
* A sad mood
*/
//% fixedInstance jres=images.eyesTear
export const sad = new brick.Mood(images.eyesTear, sounds.animalsDogWhine, BrickLight.Red);
/**
* A dizzy mood
*/
//% fixedInstance jres=images.eyesDizzy
export const dizzy = new brick.Mood(images.eyesDizzy, sounds.expressionsUhOh, BrickLight.OrangeFlash);
/**
* A knocked out mood
*/
//% fixedInstance jres=images.eyesKnockedOut
export const knockedOut = new brick.Mood(images.eyesKnockedOut, sounds.informationError, BrickLight.RedFlash);
/**
* Looking around left
*/
//% fixedInstance jres=images.eyesMiddleLeft
export const middleLeft = new brick.Mood(images.eyesMiddleLeft, sounds.informationAnalyze, BrickLight.Off);
/**
* Looking around right
*/
//% fixedInstance jres=images.eyesMiddleRight
export const middleRight = new brick.Mood(images.eyesMiddleRight, sounds.informationAnalyze, BrickLight.Off);
/**
* In love mood
*/
//% fixedInstance jres=images.eyesLove
export const love = new brick.Mood(images.eyesLove, sounds.expressionsMagicWand, BrickLight.GreenPulse);
/**
* In laughing mood
*/
//% fixedInstance jres=images.eyesWinking
export const winking = new brick.Mood(images.eyesWinking, sounds.expressionsLaughing1, BrickLight.GreenFlash);
/**
* In a neutral mood
*/
//% fixedInstance jres=images.eyesNeutral
export const neutral = new brick.Mood(images.eyesNeutral, undefined, BrickLight.Green);
}

15
libs/mood/pxt.json Normal file
View File

@ -0,0 +1,15 @@
{
"name": "mood",
"description": "The EV3 mood library",
"files": [
"README.md",
"mood.ts"
],
"testFiles": [
],
"public": true,
"dependencies": {
"core": "file:../core",
"music": "file:../music"
}
}

View File

@ -23,7 +23,7 @@
"music.setTempo": "Set the tempo a number of beats per minute (bpm).",
"music.setTempo|param|bpm": "The new tempo in beats per minute, eg: 120",
"music.setVolume": "Set the output volume of the sound synthesizer.",
"music.setVolume|param|volume": "the volume 0...256, eg: 128",
"music.setVolume|param|volume": "the volume 0...100, eg: 50",
"music.stopAllSounds": "Play a tone through the speaker for some amount of time.",
"music.tempo": "Return the tempo in beats per minute (bpm).\nTempo is the speed (bpm = beats per minute) at which notes play. The larger the tempo value, the faster the notes will play."
}

View File

@ -13,7 +13,7 @@
namespace music {
uint8_t currVolume = 2;
uint8_t currVolume = 50;
uint8_t *lmsSoundMMap;
int writeDev(void *data, int size) {
@ -25,16 +25,16 @@ int writeDev(void *data, int size) {
/**
* Set the output volume of the sound synthesizer.
* @param volume the volume 0...256, eg: 128
* @param volume the volume 0...100, eg: 50
*/
//% weight=96
//% blockId=synth_set_volume block="set volume %volume"
//% parts="speaker" blockGap=8
//% volume.min=0 volume.max=256
//% volume.min=0 volume.max=100
//% help=music/set-volume
//% weight=1
void setVolume(int volume) {
currVolume = max(0, min(100, volume * 100 / 256));
currVolume = max(0, min(100, volume));
}
#define SOUND_CMD_BREAK 0

View File

@ -3,12 +3,12 @@ declare namespace music {
/**
* Set the output volume of the sound synthesizer.
* @param volume the volume 0...256, eg: 128
* @param volume the volume 0...100, eg: 50
*/
//% weight=96
//% blockId=synth_set_volume block="set volume %volume"
//% parts="speaker" blockGap=8
//% volume.min=0 volume.max=256
//% volume.min=0 volume.max=100
//% help=music/set-volume
//% weight=1 shim=music::setVolume
function setVolume(volume: int32): void;

View File

@ -1,6 +1,6 @@
{
"name": "pxt-ev3",
"version": "0.0.67",
"version": "0.0.69",
"description": "LEGO Mindstorms EV3 for Microsoft MakeCode",
"private": true,
"keywords": [

View File

@ -16,6 +16,7 @@
"libs/infrared-sensor",
"libs/gyro-sensor",
"libs/chassis",
"libs/mood",
"libs/ev3",
"libs/storage",
"libs/datalog",