diff --git a/scripts/ai/AIUtil.lua b/scripts/ai/AIUtil.lua index a0edf70a1..8ec5dfb2a 100644 --- a/scripts/ai/AIUtil.lua +++ b/scripts/ai/AIUtil.lua @@ -54,7 +54,7 @@ function AIUtil.calculateTightTurnOffset(vehicle, vehicleTurningRadius, course, local tightTurnOffset local function smoothOffset(offset) - return (offset + 3 * (previousOffset or 0 )) / 4 + return (offset + 4 * (previousOffset or 0 )) / 5 end -- first of all, does the current waypoint have radius data? diff --git a/scripts/ai/PurePursuitController.lua b/scripts/ai/PurePursuitController.lua index 3d187801a..9aa92d1c4 100644 --- a/scripts/ai/PurePursuitController.lua +++ b/scripts/ai/PurePursuitController.lua @@ -241,15 +241,6 @@ function PurePursuitController:switchControlledNode() end end ---- Compatibility function to return the original waypoint index as in vehicle.Waypoints. This --- is the same as self.currentWpNode.ix unless we have combined courses where the legacy CP code --- concatenates all courses into one Waypoints array (as opposed to the AIDriver which splits these --- combined courses into its parts). The rest of the CP code however (HUD, reverse, etc.) works with --- vehicle.Waypoints and vehicle.cp.waypointIndex and therefore expects the combined index -function PurePursuitController:getCurrentOriginalWaypointIx() - return self.course.waypoints[self:getCurrentWaypointIx()].cpIndex -end - function PurePursuitController:update() if not self.course then self:debugSparse('no course set.') diff --git a/scripts/ai/controllers/ImplementController.lua b/scripts/ai/controllers/ImplementController.lua index a8a6d2147..753cef243 100644 --- a/scripts/ai/controllers/ImplementController.lua +++ b/scripts/ai/controllers/ImplementController.lua @@ -90,7 +90,7 @@ end function ImplementController:onFinishRow(isHeadlandTurn) end -function ImplementController:onTurnEndProgress(workStartNode, shouldLower, isLeftTurn) +function ImplementController:onTurnEndProgress(workStartNode, reversing, shouldLower, isLeftTurn) end --- Any object this controller wants us to ignore, can register here a callback at the proximity controller diff --git a/scripts/ai/controllers/PlowController.lua b/scripts/ai/controllers/PlowController.lua index 1503e41f5..db2ea2674 100644 --- a/scripts/ai/controllers/PlowController.lua +++ b/scripts/ai/controllers/PlowController.lua @@ -6,6 +6,13 @@ PlowController = CpObject(ImplementController) function PlowController:init(vehicle, implement) ImplementController.init(self, vehicle, implement) self.plowSpec = self.implement.spec_plow + -- towed (not hitch mounted) and can reverse + self.towed = AIUtil.getFirstReversingImplementWithWheels(vehicle, true) + -- temporarily store the direction of the last turn. This hack is for the case when for some reason + -- the plow was not rotated into the working position before lowering. If that's the case, onLowering will + -- rotate it but it needs to know which direction to lower, which, however is not known at that point + -- anymore + self.lastTurnIsLeftTurn = CpTemporaryObject() end @@ -98,22 +105,44 @@ function PlowController:onFinishRow(isHeadlandTurn) end end + +--- making sure the plow is in the working position when lowering +-- TODO: this whole magic hack would not be necessary if we moved the actual lowering into onTurnEndProgress() +function PlowController:onLowering() + -- if we just turned (that is, not starting to work) + local lastTurnIsLeftTurn = self.lastTurnIsLeftTurn:get() + if lastTurnIsLeftTurn ~= nil and + self:isRotatablePlow() and not self:isFullyRotated() and not self:isRotationActive() then + self:debug('Lowering, rotating plow to working position (last turn is left %s).', lastTurnIsLeftTurn) + -- rotation direction depends on the direction of the last turn + self.implement:setRotationMax(lastTurnIsLeftTurn) + end +end + --- This is called in every loop when we approach the start of the row, the location where --- the plow must be lowered. Currently AIDriveStrategyFieldworkCourse takes care of the lowering, --- here we only make sure that the plow is rotated to the work position (from the center position) --- in time. ---@param workStartNode number node where the work starts as calculated by TurnContext +---@param reversing boolean driving in reverse now ---@param shouldLower boolean the implement should be lowered as we are close to the work start (this --- should most likely be calculated here in the controller, but for now, we get it from an argument ---@param isLeftTurn boolean is this a left turn? -function PlowController:onTurnEndProgress(workStartNode, shouldLower, isLeftTurn) +function PlowController:onTurnEndProgress(workStartNode, reversing, shouldLower, isLeftTurn) + self.lastTurnIsLeftTurn:set(isLeftTurn or false, 2000) if self:isRotatablePlow() and not self:isFullyRotated() and not self:isRotationActive() then -- more or less aligned with the first waypoint of the row, start rotating to working position - -- or, when it should have been lowered, that is, we are too late, not aligned yet, but - -- rotate anyway if CpMathUtil.isSameDirection(self.implement.rootNode, workStartNode, 30) or shouldLower then - self:debug('Rotating plow to working position now.') - self.implement:setRotationMax(isLeftTurn) + if self.towed then + -- let towed plows remain in the center position while reversing to the start of the row + if not reversing then + self:debug('Rotating towed plow to working position.') + self.implement:setRotationMax(isLeftTurn) + end + else + self:debug('Rotating hitch-mounted plow to working position.') + self.implement:setRotationMax(isLeftTurn) + end end end end diff --git a/scripts/ai/turns/AITurn.lua b/scripts/ai/turns/AITurn.lua index 17918be28..2118efaee 100644 --- a/scripts/ai/turns/AITurn.lua +++ b/scripts/ai/turns/AITurn.lua @@ -586,7 +586,7 @@ function CourseTurn:endTurn(dt) -- keep driving on the turn course until we need to lower our implements local shouldLower, dz = self.driveStrategy:shouldLowerImplements(self.turnContext.workStartNode, self.ppc:isReversing()) self.driveStrategy:raiseControllerEvent(AIDriveStrategyCourse.onTurnEndProgressEvent, - self.turnContext.workStartNode, shouldLower, self.turnContext:isLeftTurn()) + self.turnContext.workStartNode, self.ppc:isReversing(), shouldLower, self.turnContext:isLeftTurn()) if shouldLower then if not self.implementsLowered then -- have not started lowering implements yet diff --git a/scripts/dev/DevHelper.lua b/scripts/dev/DevHelper.lua index e91645158..14edeb11d 100644 --- a/scripts/dev/DevHelper.lua +++ b/scripts/dev/DevHelper.lua @@ -47,10 +47,6 @@ function DevHelper:update() -- make sure not calling this for something which does not have courseplay installed (only ones with spec_aiVehicle) if g_currentMission.controlledVehicle and g_currentMission.controlledVehicle.spec_aiVehicle then - if self.vehicle ~= g_currentMission.controlledVehicle then - --self.vehicleData = PathfinderUtil.VehicleData(g_currentMission.controlledVehicle, true) - end - self.vehicle = g_currentMission.controlledVehicle self.node = g_currentMission.controlledVehicle:getAIDirectionNode() lx, _, lz = localDirectionToWorld(self.node, 0, 0, 1) @@ -169,6 +165,8 @@ function DevHelper:keyEvent(unicode, sym, modifier, isDown) if ok then self.course = course end + elseif bitAND(modifier, Input.MOD_LALT) ~= 0 and isDown and sym == Input.KEY_n then + self:togglePpcControlledNode() end end @@ -182,11 +180,13 @@ function DevHelper:draw() for key, value in pairs(self.data) do table.insert(data, {name = key, value = value}) end - DebugUtil.renderTable(0.65, 0.3, 0.013, data, 0.05) + DebugUtil.renderTable(0.65, 0.27, 0.013, data, 0.05) self:showFillNodes() self:showAIMarkers() + self:showDriveData() + if not self.tNode then self.tNode = createTransformGroup("devhelper") link(g_currentMission.terrainRootNode, self.tNode) @@ -268,6 +268,25 @@ function DevHelper:showAIMarkers() end +function DevHelper:togglePpcControlledNode() + if not self.vehicle then return end + local strategy = self.vehicle:getCpDriveStrategy() + if not strategy then return end + if strategy.ppc:getControlledNode() == AIUtil.getReverserNode(self.vehicle) then + strategy.pcc:resetControlledNode() + else + strategy.ppc:setControlledNode(AIUtil.getReverserNode(self.vehicle)) + end +end + +function DevHelper:showDriveData() + if not self.vehicle then return end + local strategy = self.vehicle:getCpDriveStrategy() + if not strategy then return end + strategy.ppc:update() + strategy.reverser:getForwardDriveData() +end + -- make sure to recreate the global dev helper whenever this script is (re)loaded if g_devHelper then g_devHelper:delete() diff --git a/scripts/util/CpRemainingTime.lua b/scripts/util/CpRemainingTime.lua index b037067b2..c6e2c6a53 100644 --- a/scripts/util/CpRemainingTime.lua +++ b/scripts/util/CpRemainingTime.lua @@ -52,7 +52,7 @@ end function CpRemainingTime:update(dt) if g_currentMission.controlledVehicle == self.vehicle and self.DEBUG_ACTIVE and CpDebug:isChannelActive(self.debugChannel, self.vehicle) then - DebugUtil.renderTable(0.4, 0.4, 0.018, { + DebugUtil.renderTable(0.2, 0.2, 0.018, { {name = "time", value = CpGuiUtil.getFormatTimeText(self.time)}, {name = "optimal speed", value = MathUtil.mpsToKmh(self:getOptimalSpeed())}, {name = "optimal time", value = CpGuiUtil.getFormatTimeText(self:getOptimalCourseTime(self.course, self.lastIx))},