virtual farmbot encoder data
parent
1a726295a4
commit
5212cfb2a5
|
@ -84,7 +84,7 @@ export type Xyz = "x" | "y" | "z";
|
|||
export type Axis = Xyz | "all";
|
||||
|
||||
export type BotPosition = Record<Xyz, (number | undefined)>;
|
||||
export type BotLocationData = Record<LocationName, BotPosition> | undefined;
|
||||
export type BotLocationData = Record<LocationName, BotPosition>;
|
||||
|
||||
export type StepsPerMmXY = Record<"x" | "y", (number | undefined)>;
|
||||
|
||||
|
|
|
@ -25,7 +25,11 @@ describe("<FarmDesigner/>", () => {
|
|||
plants: [],
|
||||
toolSlots: [],
|
||||
crops: [],
|
||||
botPosition: { x: undefined, y: undefined, z: undefined },
|
||||
botLocationData: {
|
||||
position: { x: undefined, y: undefined, z: undefined },
|
||||
scaled_encoders: { x: undefined, y: undefined, z: undefined },
|
||||
raw_encoders: { x: undefined, y: undefined, z: undefined },
|
||||
},
|
||||
botMcuParams: bot.hardware.mcu_params,
|
||||
stepsPerMmXY: { x: undefined, y: undefined }
|
||||
};
|
||||
|
|
|
@ -170,7 +170,7 @@ export class FarmDesigner extends React.Component<Props, Partial<State>> {
|
|||
plants={this.props.plants}
|
||||
points={this.props.points}
|
||||
toolSlots={this.props.toolSlots}
|
||||
botPosition={this.props.botPosition}
|
||||
botLocationData={this.props.botLocationData}
|
||||
botSize={botSize}
|
||||
stopAtHome={stopAtHome}
|
||||
hoveredPlant={this.props.hoveredPlant}
|
||||
|
|
|
@ -11,7 +11,7 @@ import {
|
|||
} from "../resources/tagged_resources";
|
||||
import { PlantPointer } from "../interfaces";
|
||||
import { SlotWithTool } from "../resources/interfaces";
|
||||
import { BotPosition, StepsPerMmXY } from "../devices/interfaces";
|
||||
import { BotPosition, StepsPerMmXY, BotLocationData } from "../devices/interfaces";
|
||||
import { isNumber } from "lodash";
|
||||
import { McuParams } from "farmbot/dist";
|
||||
import { AxisNumberProperty, BotSize } from "./map/interfaces";
|
||||
|
@ -46,7 +46,7 @@ export interface Props {
|
|||
plants: TaggedPlantPointer[];
|
||||
toolSlots: SlotWithTool[];
|
||||
crops: TaggedCrop[];
|
||||
botPosition: BotPosition;
|
||||
botLocationData: BotLocationData;
|
||||
botMcuParams: McuParams;
|
||||
stepsPerMmXY: StepsPerMmXY;
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ export interface GardenMapProps {
|
|||
selectedPlant: TaggedPlantPointer | undefined;
|
||||
hoveredPlant: TaggedPlantPointer | undefined;
|
||||
crops: TaggedCrop[];
|
||||
botPosition: BotPosition;
|
||||
botLocationData: BotLocationData;
|
||||
botSize: BotSize;
|
||||
stopAtHome: Record<"x" | "y", boolean>;
|
||||
zoomLvl: number;
|
||||
|
|
|
@ -38,7 +38,11 @@ describe("<GardenPlant/>", () => {
|
|||
plants: [],
|
||||
points: [],
|
||||
toolSlots: [],
|
||||
botPosition: { x: 0, y: 0, z: 0 },
|
||||
botLocationData: {
|
||||
position: { x: 0, y: 0, z: 0 },
|
||||
scaled_encoders: { x: undefined, y: undefined, z: undefined },
|
||||
raw_encoders: { x: undefined, y: undefined, z: undefined },
|
||||
},
|
||||
botSize: {
|
||||
x: { value: 3000, isDefault: true },
|
||||
y: { value: 1500, isDefault: true }
|
||||
|
|
|
@ -21,7 +21,11 @@ import { Dictionary } from "farmbot";
|
|||
describe("<VirtualFarmBot/>", () => {
|
||||
function fakeProps(): VirtualFarmBotProps {
|
||||
return {
|
||||
botPosition: { x: 0, y: 0, z: 0 },
|
||||
botLocationData: {
|
||||
position: { x: 0, y: 0, z: 0 },
|
||||
scaled_encoders: { x: undefined, y: undefined, z: undefined },
|
||||
raw_encoders: { x: undefined, y: undefined, z: undefined },
|
||||
},
|
||||
mapTransformProps: {
|
||||
quadrant: 1, gridSize: { x: 3000, y: 1500 }
|
||||
},
|
||||
|
@ -70,9 +74,11 @@ describe("<VirtualFarmBot/>", () => {
|
|||
it("changes location", () => {
|
||||
const p = fakeProps();
|
||||
p.mapTransformProps.quadrant = 2;
|
||||
p.botPosition = { x: 100, y: 200, z: 0 };
|
||||
p.botLocationData.position = { x: 100, y: 200, z: 0 };
|
||||
const result = shallow(<VirtualFarmBot {...p } />);
|
||||
expect(result.find("#gantry").props().x).toEqual(90);
|
||||
const gantry = result.find("#gantry");
|
||||
expect(gantry.length).toEqual(1);
|
||||
expect(gantry.props().x).toEqual(90);
|
||||
const UTM = result.find("circle").props();
|
||||
expect(UTM.cx).toEqual(100);
|
||||
expect(UTM.cy).toEqual(200);
|
||||
|
@ -102,4 +108,23 @@ describe("<VirtualFarmBot/>", () => {
|
|||
x1: 0, x2: 4, y1: 0, y2: 4
|
||||
});
|
||||
});
|
||||
|
||||
it("shows encoder position", () => {
|
||||
mockStorj["encoderFigure"] = true;
|
||||
const p = fakeProps();
|
||||
p.mapTransformProps.quadrant = 2;
|
||||
p.botLocationData.position = { x: 100, y: 200, z: 0 };
|
||||
p.botLocationData.scaled_encoders = { x: 300, y: 400, z: 0 };
|
||||
const wrapper = shallow(<VirtualFarmBot {...p } />);
|
||||
expect(wrapper.find("#gantry").first().props().x).toEqual(90);
|
||||
expect(wrapper.find("#gantry").last().props().x).toEqual(290);
|
||||
const motorsUTM = wrapper.find("circle").first().props();
|
||||
expect(motorsUTM.cx).toEqual(100);
|
||||
expect(motorsUTM.cy).toEqual(200);
|
||||
expect(motorsUTM.fillOpacity).toEqual(0.75);
|
||||
const encodersUTM = wrapper.find("circle").last().props();
|
||||
expect(encodersUTM.cx).toEqual(300);
|
||||
expect(encodersUTM.cy).toEqual(400);
|
||||
expect(encodersUTM.fillOpacity).toEqual(0.25);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -282,7 +282,7 @@ export class GardenMap extends
|
|||
<FarmBotLayer
|
||||
mapTransformProps={mapTransformProps}
|
||||
visible={!!this.props.showFarmbot}
|
||||
botPosition={this.props.botPosition}
|
||||
botLocationData={this.props.botLocationData}
|
||||
stopAtHome={this.props.stopAtHome}
|
||||
botSize={this.props.botSize}
|
||||
plantAreaOffset={this.props.gridOffset} />
|
||||
|
@ -304,8 +304,8 @@ export class GardenMap extends
|
|||
plantAreaOffset={this.props.gridOffset} />
|
||||
{this.state.selectionBox &&
|
||||
<SelectionBox
|
||||
selectionBox={this.state.selectionBox}
|
||||
mapTransformProps={mapTransformProps} />}
|
||||
selectionBox={this.state.selectionBox}
|
||||
mapTransformProps={mapTransformProps} />}
|
||||
</svg>
|
||||
</svg>
|
||||
</div>;
|
||||
|
|
|
@ -4,7 +4,7 @@ import {
|
|||
TaggedGenericPointer
|
||||
} from "../../resources/tagged_resources";
|
||||
import { State, BotOriginQuadrant } from "../interfaces";
|
||||
import { BotPosition } from "../../devices/interfaces";
|
||||
import { BotPosition, BotLocationData } from "../../devices/interfaces";
|
||||
|
||||
export interface PlantLayerProps {
|
||||
plants: TaggedPlantPointer[];
|
||||
|
@ -92,7 +92,7 @@ export interface GridProps {
|
|||
|
||||
export interface VirtualFarmBotProps {
|
||||
mapTransformProps: MapTransformProps;
|
||||
botPosition: BotPosition;
|
||||
botLocationData: BotLocationData;
|
||||
plantAreaOffset: AxisNumberProperty;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,11 @@ describe("<FarmBotLayer/>", () => {
|
|||
function fakeProps(): FarmBotLayerProps {
|
||||
return {
|
||||
visible: true,
|
||||
botPosition: { x: 0, y: 0, z: 0 },
|
||||
botLocationData: {
|
||||
position: { x: undefined, y: undefined, z: undefined },
|
||||
scaled_encoders: { x: undefined, y: undefined, z: undefined },
|
||||
raw_encoders: { x: undefined, y: undefined, z: undefined },
|
||||
},
|
||||
mapTransformProps: {
|
||||
quadrant: 1, gridSize: { x: 3000, y: 1500 }
|
||||
},
|
||||
|
|
|
@ -10,7 +10,7 @@ export function FarmBotLayer(props: FarmBotLayerProps) {
|
|||
return visible ? <g id="farmbot-layer">
|
||||
<VirtualFarmBot
|
||||
mapTransformProps={mapTransformProps}
|
||||
botPosition={props.botPosition}
|
||||
botLocationData={props.botLocationData}
|
||||
plantAreaOffset={plantAreaOffset} />
|
||||
<BotExtents
|
||||
mapTransformProps={mapTransformProps}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import * as React from "react";
|
||||
import { getXYFromQuadrant, getMapSize } from "./util";
|
||||
import { VirtualFarmBotProps } from "./interfaces";
|
||||
import { VirtualFarmBotProps, AxisNumberProperty } from "./interfaces";
|
||||
import { Session } from "../../session";
|
||||
import { BooleanSetting } from "../../session_keys";
|
||||
import * as _ from "lodash";
|
||||
import { BotOriginQuadrant } from "../interfaces";
|
||||
|
||||
type TrailRecord = Record<"x" | "y", number | undefined>;
|
||||
|
||||
|
@ -17,45 +18,70 @@ function getNewTrailArray(update: TrailRecord) {
|
|||
return arr;
|
||||
}
|
||||
|
||||
function botTrail(
|
||||
array: TrailRecord[],
|
||||
quadrant: BotOriginQuadrant,
|
||||
gridSize: AxisNumberProperty) {
|
||||
return <g id="trail">
|
||||
{array.map((cur: TrailRecord, i: number) => {
|
||||
const prev = array[i - 1]; // previous trail coordinate
|
||||
const opacity = Math.round((i / (array.length - 1)) * 100) / 100;
|
||||
if (i > 0 && _.isNumber(prev.x) && _.isNumber(prev.y)
|
||||
&& _.isNumber(cur.x) && _.isNumber(cur.y)) {
|
||||
const p1 = getXYFromQuadrant(cur.x, cur.y, quadrant, gridSize);
|
||||
const p2 = getXYFromQuadrant(prev.x, prev.y, quadrant, gridSize);
|
||||
return <line id={`trail-line-${i}`} key={i}
|
||||
stroke="red" strokeOpacity={opacity} strokeWidth={opacity * 2}
|
||||
x1={p1.qx} y1={p1.qy} x2={p2.qx} y2={p2.qy} />;
|
||||
}
|
||||
})}
|
||||
</g>;
|
||||
}
|
||||
|
||||
function positionFigure(
|
||||
name: string,
|
||||
position: { qx: number, qy: number },
|
||||
mapSize: AxisNumberProperty,
|
||||
plantAreaOffset: AxisNumberProperty) {
|
||||
const opacity = name.includes("encoder") ? 0.25 : 0.75;
|
||||
return <g id={name}>
|
||||
<rect id="gantry"
|
||||
x={position.qx - 10}
|
||||
y={-plantAreaOffset.y}
|
||||
width={20}
|
||||
height={mapSize.y}
|
||||
fillOpacity={opacity}
|
||||
fill={"#434343"} />
|
||||
<circle id="UTM"
|
||||
cx={position.qx}
|
||||
cy={position.qy}
|
||||
r={35}
|
||||
fillOpacity={opacity}
|
||||
fill={"#434343"} />
|
||||
</g>;
|
||||
}
|
||||
|
||||
export function VirtualFarmBot(props: VirtualFarmBotProps) {
|
||||
const { x, y } = props.botPosition;
|
||||
const { x, y } = props.botLocationData.position;
|
||||
const { mapTransformProps, plantAreaOffset } = props;
|
||||
const { quadrant, gridSize } = mapTransformProps;
|
||||
const mapSize = getMapSize(gridSize, plantAreaOffset);
|
||||
const { qx, qy } = getXYFromQuadrant((x || 0), (y || 0), quadrant, gridSize);
|
||||
const positionQ = getXYFromQuadrant((x || 0), (y || 0), quadrant, gridSize);
|
||||
|
||||
const displayTrail = Session.getBool(BooleanSetting.displayTrail);
|
||||
const update = { x, y };
|
||||
const array = displayTrail ? getNewTrailArray(update) : [];
|
||||
|
||||
const encoderFigure = Session.getBool(BooleanSetting.encoderFigure);
|
||||
const enc = props.botLocationData.scaled_encoders;
|
||||
const encodersQ = getXYFromQuadrant(
|
||||
(enc.x || 0), (enc.y || 0), quadrant, gridSize);
|
||||
|
||||
return <g id="virtual-farmbot">
|
||||
<rect id="gantry"
|
||||
x={qx - 10}
|
||||
y={-plantAreaOffset.y}
|
||||
width={20}
|
||||
height={mapSize.y}
|
||||
fillOpacity={0.75}
|
||||
fill={"#434343"} />
|
||||
<circle id="UTM"
|
||||
cx={qx}
|
||||
cy={qy}
|
||||
r={35}
|
||||
fillOpacity={0.75}
|
||||
fill={"#434343"} />
|
||||
{positionFigure("motor-position", positionQ, mapSize, plantAreaOffset)}
|
||||
{encoderFigure &&
|
||||
positionFigure("encoder-position", encodersQ, mapSize, plantAreaOffset)}
|
||||
{displayTrail &&
|
||||
<g id="trail">
|
||||
{array.map((cur: TrailRecord, i: number) => {
|
||||
const prev = array[i - 1]; // previous trail coordinate
|
||||
const opacity = Math.round((i / (array.length - 1)) * 100) / 100;
|
||||
if (i > 0 && _.isNumber(prev.x) && _.isNumber(prev.y)
|
||||
&& _.isNumber(cur.x) && _.isNumber(cur.y)) {
|
||||
const p1 = getXYFromQuadrant(cur.x, cur.y, quadrant, gridSize);
|
||||
const p2 = getXYFromQuadrant(prev.x, prev.y, quadrant, gridSize);
|
||||
return <line id={`trail-line-${i}`} key={i}
|
||||
stroke="red" strokeOpacity={opacity} strokeWidth={opacity * 2}
|
||||
x1={p1.qx} y1={p1.qy} x2={p2.qx} y2={p2.qy} />;
|
||||
}
|
||||
})}
|
||||
</g>}
|
||||
botTrail(array, quadrant, gridSize)}
|
||||
</g>;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import {
|
|||
selectAllCrops,
|
||||
joinToolsAndSlot
|
||||
} from "../resources/selectors";
|
||||
import { BotPosition, StepsPerMmXY } from "../devices/interfaces";
|
||||
import { BotLocationData, StepsPerMmXY } from "../devices/interfaces";
|
||||
import { isNumber } from "lodash";
|
||||
|
||||
export function mapStateToProps(props: Everything) {
|
||||
|
@ -18,11 +18,15 @@ export function mapStateToProps(props: Everything) {
|
|||
const { plantUUID } = props.resources.consumers.farm_designer.hoveredPlant;
|
||||
const hoveredPlant = plants.filter(x => x.uuid === plantUUID)[0];
|
||||
|
||||
const getBotPosition = (): BotPosition => {
|
||||
const getBotLocationData = (): BotLocationData => {
|
||||
if (props.bot.hardware.location_data) {
|
||||
return props.bot.hardware.location_data.position;
|
||||
return props.bot.hardware.location_data;
|
||||
}
|
||||
return { x: undefined, y: undefined, z: undefined };
|
||||
return {
|
||||
position: { x: undefined, y: undefined, z: undefined },
|
||||
scaled_encoders: { x: undefined, y: undefined, z: undefined },
|
||||
raw_encoders: { x: undefined, y: undefined, z: undefined },
|
||||
};
|
||||
};
|
||||
|
||||
function stepsPerMmXY(): StepsPerMmXY {
|
||||
|
@ -43,7 +47,7 @@ export function mapStateToProps(props: Everything) {
|
|||
toolSlots: joinToolsAndSlot(props.resources.index),
|
||||
hoveredPlant,
|
||||
plants,
|
||||
botPosition: getBotPosition(),
|
||||
botLocationData: getBotLocationData(),
|
||||
botMcuParams: props.bot.hardware.mcu_params,
|
||||
stepsPerMmXY: stepsPerMmXY()
|
||||
};
|
||||
|
|
|
@ -19,6 +19,7 @@ export enum BooleanSetting {
|
|||
mapXL = "mapXL",
|
||||
disableAnimations = "disableAnimations",
|
||||
displayTrail = "displayTrail",
|
||||
encoderFigure = "encoderFigure",
|
||||
}
|
||||
|
||||
export enum NumericSetting {
|
||||
|
|
Loading…
Reference in New Issue