Skip to content

Commit

Permalink
RGB raw color sensor simulator support (#1023)
Browse files Browse the repository at this point in the history
* set-rgbraw-mode-circle-color

* preliminary_sim_rgb_raw_support

* updateRGBWheel.ts

* preliminary-changes

Implemented toggle switches for each RGB component.

* preliminary-changes-2

* final-changes

* rounding-change

So that there is no difference in uart values, as well as values in the label of the toggle switches.

* sim-color-mode-set-defl-val

Prior to this, the color mode was not taken into account. It turns out that the initial value is 50. There is no such index in the array. showPorts didn't output anything for this sensor initially until you chose some color yourself in the simulator. If you look at what the value is there, then 50 is displayed. Therefore, I made the default value 0 - nothing.
  • Loading branch information
THEb0nny authored May 20, 2023
1 parent 6d222c5 commit bf15824
Show file tree
Hide file tree
Showing 10 changed files with 213 additions and 7 deletions.
21 changes: 20 additions & 1 deletion libs/color-sensor/color.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,18 @@ namespace sensors {
|| this.mode == ColorSensorMode.AmbientLightIntensity
|| this.mode == ColorSensorMode.ReflectedLightIntensity)
return this.getNumber(NumberFormat.UInt8LE, 0)
if (this.mode == ColorSensorMode.RefRaw || this.mode == ColorSensorMode.RgbRaw)
if (this.mode == ColorSensorMode.RefRaw)
return this.getNumber(NumberFormat.UInt16LE, 0)
return 0
}

_queryArr(): number[] {
if (this.mode == ColorSensorMode.RgbRaw) {
return [this.getNumber(NumberFormat.UInt16LE, 0), this.getNumber(NumberFormat.UInt16LE, 2), this.getNumber(NumberFormat.UInt16LE, 4)];
}
return [0, 0, 0];
}

_info(): string {
switch (this.mode) {
case ColorSensorMode.Color:
Expand All @@ -106,11 +113,23 @@ namespace sensors {
case ColorSensorMode.AmbientLightIntensity:
case ColorSensorMode.ReflectedLightIntensity:
return `${this._query()}%`;
case ColorSensorMode.RgbRaw:
return "array";
default:
return this._query().toString();
}
}

_infoArr(): string[] {
switch (this.mode) {
case ColorSensorMode.RgbRaw:
const queryArr = this._queryArr().map(number => number.toString());
return queryArr;
default:
return ["0", "0", "0"];
}
}

_update(prev: number, curr: number) {
if (this.calibrating) return; // simply ignore data updates while calibrating
if (this.mode == ColorSensorMode.Color || this.mode == ColorSensorMode.RgbRaw || this.mode == ColorSensorMode.RefRaw)
Expand Down
4 changes: 4 additions & 0 deletions libs/core/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,10 @@ void cUiUpdatePower(void)
return this._query().toString();
}

_infoArr(): string[] {
return [this._query().toString()];
}

_update(prev: number, curr: number) {
}

Expand Down
9 changes: 8 additions & 1 deletion libs/screen/targetoverrides.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,14 @@ namespace brick {
const x = (si.port() - 1) * col + 2;
const inf = si._info();
if (screenMode != ScreenMode.Ports) return;
if (inf) screen.print(inf, x, h - 2 * lineHeight8, 1, inf.length > 4 ? image.font5 : image.font8);
if (inf == "array") {
let infArr = si._infoArr();
for (let data = 0, str = Math.min(infArr.length + 1, 4); data < Math.min(infArr.length, 3); data++, str--) {
screen.print(infArr[data], x, h - str * lineHeight8, 1, infArr[data].length > 4 ? image.font5 : image.font8);
}
} else if (inf) {
screen.print(inf, x, h - 2 * lineHeight8, 1, inf.length > 4 ? image.font5 : image.font8);
}
}
}

Expand Down
34 changes: 32 additions & 2 deletions sim/state/color.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,27 @@ namespace pxsim {
id = NodeType.ColorSensor;

private color: number = 0;
private colors: number[] = [0, 0, 0];

constructor(port: number) {
super(port);
this.mode = -1;
this.modeReturnArr = false;
}

getDeviceType() {
return DAL.DEVICE_TYPE_COLOR;
}

isModeReturnArr() {
return this.modeReturnArr;
}

setColors(colors: number[]) {
this.colors = colors;
this.setChangedState();
}

setColor(color: number) {
this.color = color;
this.setChangedState();
Expand All @@ -41,10 +52,29 @@ namespace pxsim {
return this.color;
}

getValues() {
return this.colors;
}

setMode(mode: number) {
this.mode = mode;
if (this.mode == ColorSensorMode.RefRaw) this.color = 512;
else this.color = 50;
if (this.mode == ColorSensorMode.RefRaw) {
this.color = 512;
this.colors = [0, 0, 0];
this.modeReturnArr = false;
} else if (this.mode == ColorSensorMode.RgbRaw) {
this.color = 0;
this.colors = [128, 128, 128];
this.modeReturnArr = true;
} else if (this.mode == ColorSensorMode.Colors) {
this.color = 0; // None defl color
this.colors = [0, 0, 0];
this.modeReturnArr = false;
} else { // Reflection or ambiend light
this.color = 50;
this.colors = [0, 0, 0];
this.modeReturnArr = false;
}
this.changed = true;
this.modeChanged = true;
}
Expand Down
11 changes: 11 additions & 0 deletions sim/state/sensor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace pxsim {
protected mode: number;
protected valueChanged: boolean;
protected modeChanged: boolean;
protected modeReturnArr: boolean;

constructor(port: number) {
super(port);
Expand All @@ -19,14 +20,23 @@ namespace pxsim {
return false;
}

public isModeReturnArr() {
return this.modeReturnArr;
}

public getValue() {
return 0;
}

public getValues() {
return [0];
}

setMode(mode: number) {
this.mode = mode;
this.changed = true;
this.modeChanged = true;
this.modeReturnArr = false;
}

getMode() {
Expand Down Expand Up @@ -84,4 +94,5 @@ namespace pxsim {
return this.changed;
}
}

}
10 changes: 9 additions & 1 deletion sim/state/uart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,15 @@ namespace pxsim {
if (node && node.isUart()) {
// Actual
const index = 0; //UartOff.Actual + port * 2;
util.map16Bit(data, UartOff.Raw + DAL.MAX_DEVICE_DATALENGTH * 300 * port + DAL.MAX_DEVICE_DATALENGTH * index, Math.floor(node.getValue()))
if (!node.isModeReturnArr()) {
const value = Math.round(node.getValue());
util.map16Bit(data, UartOff.Raw + DAL.MAX_DEVICE_DATALENGTH * 300 * port + DAL.MAX_DEVICE_DATALENGTH * index, value);
} else {
const values = node.getValues();
for (let i = 0, offset = 0; i < values.length; i++, offset += 2) {
util.map16Bit(data, UartOff.Raw + DAL.MAX_DEVICE_DATALENGTH * 300 * port + DAL.MAX_DEVICE_DATALENGTH * index + offset, Math.round(values[i]));
}
}
// Status
data[UartOff.Status + port] = node.valueChange() ? UartStatus.UART_PORT_CHANGED : UartStatus.UART_DATA_READY;
}
Expand Down
2 changes: 2 additions & 0 deletions sim/visuals/board.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,8 @@ namespace pxsim.visuals {
const state = ev3board().getInputNodes()[port] as ColorSensorNode;
if (state.getMode() == ColorSensorMode.Colors) {
view = new ColorGridControl(this.element, this.defs, state, port);
} else if (state.getMode() == ColorSensorMode.RgbRaw) {
view = new ColorRGBWheelControl(this.element, this.defs, state, port);
} else if (state.getMode() == ColorSensorMode.Reflected) {
view = new ColorWheelControl(this.element, this.defs, state, port);
} else if (state.getMode() == ColorSensorMode.RefRaw) {
Expand Down
126 changes: 126 additions & 0 deletions sim/visuals/controls/colorRGBWheel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
namespace pxsim.visuals {

export class ColorRGBWheelControl extends ControlView<ColorSensorNode> {
private group: SVGGElement;
private colorGradient: SVGLinearGradientElement[] = [];
private reporter: SVGTextElement[] = [];
private rect: SVGElement[] = [];
private printOffsetH = 16;
private rgbLetters: string[] = ["R", "G", "B"];
private rectNames: string[] = ["rectR", "rectG", "rectB"];
private captured: boolean = false;
private classVal: string;

getInnerWidth() {
return 120;
}

getInnerHeight() {
return 192;
}

private getReporterHeight() {
return 70;
}

private getSliderWidth() {
return 24;
}

private getSliderHeight() {
return 100;
}

private getMaxValue() {
return 512;
}

private mapValue(x: number, inMin: number, inMax: number, outMin: number, outMax: number) {
return (x - inMin) * (outMax - outMin) / (inMax - inMin) + outMin;
}

updateState() {
if (!this.visible) return;
const node = this.state;
const values = node.getValues();
let inverseValue: number[] = [];
for (let i = 0; i < 3; i++) {
inverseValue[i] = this.getMaxValue() - values[i];
inverseValue[i] = this.mapValue(inverseValue[i], 0, this.getMaxValue(), 0, 100);
svg.setGradientValue(this.colorGradient[i], inverseValue[i] + "%");
this.reporter[i].textContent = this.rgbLetters[i] + ": " + `${parseFloat((values[i]).toString()).toFixed(0)}`;
}
}

updateColorLevel(pt: SVGPoint, parent: SVGSVGElement, ev: MouseEvent) {
if (!this.classVal) this.classVal = (ev.target as HTMLElement).classList.value;
let cur = svg.cursorPoint(pt, parent, ev);
let index = this.rectNames.findIndex(i => i == this.classVal);
const bBox = this.rect[index].getBoundingClientRect();
const height = bBox.height;
let t = Math.max(0, Math.min(1, (height + bBox.top / this.scaleFactor - cur.y / this.scaleFactor) / height));
const state = this.state;
let colorsVal = this.state.getValues();
colorsVal[index] = t * this.getMaxValue();
state.setColors(colorsVal);
}

getInnerView(parent: SVGSVGElement, globalDefs: SVGDefsElement) {
this.group = svg.elt("g") as SVGGElement;

let gc = "gradient-color-" + this.getPort();
let prevColorGradient: SVGLinearGradientElement[] = [];
for (let i = 0; i < 3; i++) {
prevColorGradient[i] = globalDefs.querySelector(`#${gc + "-" + i}`) as SVGLinearGradientElement;
this.colorGradient[i] = prevColorGradient[i] ? prevColorGradient[i] : svg.linearGradient(globalDefs, gc + "-" + i, false);
svg.setGradientValue(this.colorGradient[i], "50%");
svg.setGradientColors(this.colorGradient[i], "black", "yellow");
}

let reporterGroup: SVGElement[] = [];
for (let i = 0; i < 3; i++) {
reporterGroup[i] = pxsim.svg.child(this.group, "g");

reporterGroup[i].setAttribute("transform", `translate(${this.getWidth() / 2}, ${18 + this.printOffsetH * i})`);
this.reporter[i] = pxsim.svg.child(reporterGroup[i], "text", { 'text-anchor': 'middle', 'class': 'sim-text number large inverted', 'style': 'font-size: 18px;' }) as SVGTextElement;
}

let sliderGroup: SVGElement[] = [];
for (let i = 0; i < 3; i++) {
sliderGroup[i] = pxsim.svg.child(this.group, "g");
const translateX = (this.getWidth() / 2 - this.getSliderWidth() / 2 - 36) + 36 * i;
sliderGroup[i].setAttribute("transform", `translate(${translateX}, ${this.getReporterHeight()})`);

this.rect[i] = pxsim.svg.child(sliderGroup[i], "rect", {
"width": this.getSliderWidth(),
"height": this.getSliderHeight(),
"style": `fill: url(#${gc + "-" + i})`
}
);
}

let pt = parent.createSVGPoint();
for (let i = 0; i < 3; i++) {
touchEvents(this.rect[i], ev => {
if (this.captured && (ev as MouseEvent).clientY) {
ev.preventDefault();
this.updateColorLevel(pt, parent, ev as MouseEvent);
}
}, ev => {
this.captured = true;
if ((ev as MouseEvent).clientY) {
this.rect[i].setAttribute('cursor', '-webkit-grabbing');
this.rect[i].setAttribute('class', this.rectNames[i]);
this.updateColorLevel(pt, parent, ev as MouseEvent);
}
}, () => {
this.captured = false;
this.classVal = '';
this.rect[i].setAttribute('cursor', '-webkit-grab');
});
}

return this.group;
}
}
}
2 changes: 0 additions & 2 deletions sim/visuals/controls/colorWheel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,6 @@ namespace pxsim.visuals {

const rect = pxsim.svg.child(sliderGroup, "rect",
{
"x": 0,
"y": 0,
"width": this.getSliderWidth(),
"height": this.getSliderHeight(),
"style": `fill: url(#${gc})`
Expand Down
1 change: 1 addition & 0 deletions sim/visuals/nodes/colorSensorView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ namespace pxsim.visuals {

switch (mode) {
case ColorSensorMode.Colors: this.updateSensorLightVisual('#0062DD'); return; // blue
case ColorSensorMode.RgbRaw: this.updateSensorLightVisual('#0062DD'); return; // blue
case ColorSensorMode.Reflected: this.updateSensorLightVisual('#F86262'); return; // red
case ColorSensorMode.RefRaw: this.updateSensorLightVisual('#F86262'); return; // red
case ColorSensorMode.Ambient: this.updateSensorLightVisual('#67C3E2'); return; // light blue
Expand Down

0 comments on commit bf15824

Please sign in to comment.