diff --git a/FS25_ADSmartPickup/adCpBridge.lua b/FS25_ADSmartPickup/adCpBridge.lua index 71fe46d..4d12418 100644 --- a/FS25_ADSmartPickup/adCpBridge.lua +++ b/FS25_ADSmartPickup/adCpBridge.lua @@ -176,6 +176,19 @@ function ADCpBridge.getRefillFillType(vehicle) return nil end +-- Hvor meget af påfyldningsvaren sættet har tilbage (liter, alle fyldenheder med varen). +function ADCpBridge.getRefillLevel(vehicle, fillType) + local total = 0 + for _, object in ipairs(collect(vehicle)) do + pcall(function() + for index, unit in ipairs(object.spec_fillUnit ~= nil and object.spec_fillUnit.fillUnits or {}) do + if unit.fillType == fillType then total = total + (object:getFillUnitFillLevel(index) or 0) end + end + end) + end + return total +end + -- Stop køretøjets AI-job (Courseplay/hjælper). function ADCpBridge.stop(vehicle) pcall(function() diff --git a/FS25_ADSmartPickup/adFieldWork.lua b/FS25_ADSmartPickup/adFieldWork.lua index 52e3ce5..7fa4bf5 100644 --- a/FS25_ADSmartPickup/adFieldWork.lua +++ b/FS25_ADSmartPickup/adFieldWork.lua @@ -13,6 +13,9 @@ ADFieldWork.COURSE_WAIT_MS = 180000 ADFieldWork.PLAYER_DRIVING_KMH = 3 -- riven skal være udfoldet og i gang, før nedlægningsområdet måles ADFieldWork.WINDROW_MEASURE_MS = 10000 +-- mangler der sæt, prøves igen efter så lang tid (ikke hvert sekund over hele flåden) +ADFieldWork.NO_RIG_RETRY_MS = 30000 +ADFieldWork.REFILL_ROLES = {seeder = true, fertilizer = true, limer = true, weeder = true} local function log(...) ADFieldJobs.log(...) end local function note(...) ADFieldJobs.note(...) end @@ -298,7 +301,7 @@ function ADFieldWork.dispatch(adEnv, field, info, decision) rigs = rig ~= nil and {rig} or nil end if rigs == nil then - note(field.id, {reason = {key = "spu_field_reason_" .. tostring(why), role = role, args = args}}) + note(field.id, {reason = {key = "spu_field_reason_" .. tostring(why), role = role, args = args}, retryAt = now() + ADFieldWork.NO_RIG_RETRY_MS}) return end local count = #rigs @@ -340,19 +343,50 @@ local function prepareCollector(adEnv, field, info, assignment) return true end --- Påfyldning undervejs (såmaskine/sprøjte/spreder): AutoDrive LOAD med automatisk påfyldningsmål og --- hjælper = Courseplay. Når CP melder tom (onCpEmpty), kører AD til nærmeste påfyldning af varen, fylder --- op, kører tilbage til F-markøren og genstarter CP. Courseplay og AutoDrive er bygget til netop dette. +-- Nærmeste påfyldning af varen: en læssestation gården har adgang til, med varen på lager, en AutoDrive- +-- markør ved triggeren og vej fra traktoren. (AutoDrives eget "automatiske påfyldningsmål" er slået fra i +-- AutoDrive — AutoDrive.automaticPickupTarget = false — så vi finder stedet selv, som silovalget.) +function ADFieldWork.findRefillMarker(adEnv, vehicle, fillType, x, z) + local farmId = vehicle:getOwnerFarmId() + local best, bestDistance = nil, math.huge + local ok = pcall(function() + for _, station in pairs(g_currentMission.storageSystem:getLoadingStations()) do + local supported = station.getAISupportedFillTypes ~= nil and station:getAISupportedFillTypes() or {} + if g_currentMission.accessHandler:canFarmAccess(farmId, station) and supported[fillType] + and (station:getFillLevel(fillType, farmId) or 0) > 0 then + local wayPointId = adEnv.ADTriggerManager:getMarkerAtStation(station, vehicle, 10) + local wayPoint = wayPointId ~= nil and wayPointId > 0 and adEnv.ADGraphManager:getWayPointById(wayPointId) or nil + if wayPoint ~= nil then + local distance = (wayPoint.x - x) ^ 2 + (wayPoint.z - z) ^ 2 + if distance < bestDistance and ADUnloadWait.hasRouteTo(adEnv, vehicle, wayPointId) then + best, bestDistance = wayPointId, distance + end + end + end + end + end) + return ok and best or nil +end + +-- Påfyldning undervejs (såmaskine/sprøjte/spreder): AutoDrive LOAD med hjælper = Courseplay. Når CP melder +-- tom (onCpEmpty), kører AD til påfyldningen (2. markør), fylder op, kører tilbage til F-markøren (1. markør) +-- og genstarter CP. Findes ingen påfyldning, stopper sættet når det er tomt ("tom for …", se finish). local function prepareRefill(adEnv, field, info, assignment) local vehicle = assignment.vehicle local fillType = ADCpBridge.getRefillFillType(vehicle) if fillType == nil then return end + assignment.refillFillType = fillType + local name = g_fillTypeManager ~= nil and g_fillTypeManager:getFillTypeNameByIndex(fillType) or tostring(fillType) + local refillId = ADFieldWork.findRefillMarker(adEnv, vehicle, fillType, info.x, info.z) + if refillId == nil then + log(field.id, "ingen påfyldning af %s med AutoDrive-markør fundet — '%s' stopper når den er tom", tostring(name), ADRuns.vehicleLabel(vehicle)) + return + end local module = stateModule(vehicle) local ok = pcall(function() module:setMode(adEnv.AutoDrive.MODE_LOAD) module:setFirstMarkerByWayPointId(info.markerId) - module:setSecondMarkerByWayPointId(info.markerId) - module:setAutomaticPickupTarget(true) + module:setSecondMarkerByWayPointId(refillId) module:setFillType(fillType) module:setStartHelper(true) module.usedHelper = helperCp(adEnv) @@ -361,8 +395,8 @@ local function prepareRefill(adEnv, field, info, assignment) end) if ok then assignment.adHandlesEnd = true - local name = g_fillTypeManager ~= nil and g_fillTypeManager:getFillTypeNameByIndex(fillType) or tostring(fillType) - log(field.id, "'%s' fyldes op med %s af AutoDrive når den er tom", ADRuns.vehicleLabel(vehicle), tostring(name)) + local marker = adEnv.ADGraphManager:getMapMarkerByWayPointId(refillId) + log(field.id, "'%s' fyldes op med %s ved %s af AutoDrive når den er tom", ADRuns.vehicleLabel(vehicle), tostring(name), tostring(marker ~= nil and marker.name or refillId)) end end @@ -493,6 +527,13 @@ end -- Sættet er færdigt: rest til lager (læsse-/aflæsningsvogn), ellers parkering. local function finishAssignment(adEnv, assignment) local vehicle = assignment.vehicle + -- tom såmaskine/sprøjte der ikke blev fyldt op: arbejdet er IKKE færdigt — marken må ikke gå videre + if assignment.refillFillType ~= nil and ADCpBridge.getRefillLevel(vehicle, assignment.refillFillType) <= 0 then + local name = g_fillTypeManager ~= nil and g_fillTypeManager:getFillTypeNameByIndex(assignment.refillFillType) or "?" + ADFieldWork.release(assignment) + fail(assignment.fieldId, string.format("'%s' er tom for %s — fyld op, så fortsætter marken", ADRuns.vehicleLabel(vehicle), tostring(name))) + return + end log(assignment.fieldId, "%s '%s' færdig", assignment.role, ADRuns.vehicleLabel(vehicle)) -- læssevogn/påfyldte sæt parkeres af AutoDrive selv (onCpFinished med parkering sat) local park = not assignment.adHandlesEnd and parkMarkerId(adEnv, vehicle) or nil diff --git a/docs/TESTPLAN-markarbejde.md b/docs/TESTPLAN-markarbejde.md index 0e81482..68d660c 100644 --- a/docs/TESTPLAN-markarbejde.md +++ b/docs/TESTPLAN-markarbejde.md @@ -94,9 +94,12 @@ Afgrøde "Samme som høstet", Tromle Ja. Kalk Ja. - [ ] **5.3 Såning.** Såmaskinen sættes til afgrøden (`setSeedIndex`), og den rigtige afgrøde spirer. - [ ] **5.4 Ude af såperioden.** Afgrøde der ikke kan sås nu → status " kan ikke sås i denne periode", ingen udsendelse. -- [ ] **5.5 Tom for frø / påfyldning.** Såmaskine med lidt frø: når den er tom midt på marken, kører - AutoDrive selv til nærmeste frø-påfyldning, fylder op, kører tilbage, og Courseplay fortsætter. - Log: `… fyldes op med SEEDS af AutoDrive når den er tom`. (Kræver et sted AutoDrive kan læsse frø.) +- [ ] **5.5 Tom for frø / påfyldning.** Såmaskine med lidt frø. Moden leder efter en læssestation med frø + på lager og en AutoDrive-markør ved triggeren (fx en silo/big-bag-station med SEEDS). + - Findes den: log `… fyldes op med SEEDS ved af AutoDrive når den er tom`. Når den er tom + midt på marken, kører AutoDrive derhen, fylder op, kører tilbage, og Courseplay fortsætter. + - Findes den ikke: log `ingen påfyldning af SEEDS med AutoDrive-markør fundet …`. Når den er tom: + rød besked `'…' er tom for SEEDS — fyld op, så fortsætter marken`, og marken går IKKE videre. - [ ] **5.6 Bar mark alene.** Vælg en bar mark (stub/pløjet) → **Start nu** → kun klargøring/såning. ## 6. Pleje mens afgrøden vokser @@ -141,5 +144,5 @@ Afgrøde "Samme som høstet", Tromle Ja. Kalk Ja. | Combine-unloader | stationsvalg ud fra silovalget | `ingen aflæsningsstation Courseplay kan bruge` | | Multi-tool | `multiTools` + `laneOffset` + `Course:setPosition` | Begge maskiner kører samme bane | | Sideriver | fortegn på forskydningen | Læssevognen kører ved siden af skåret | -| Påfyldning | AutoDrive LOAD med automatisk påfyldningsmål | Sættet står stille når det er tomt | +| Påfyldning | AutoDrive LOAD til den læssestation moden fandt (AutoDrives eget automatiske mål er slået fra i AutoDrive) | Sættet står ved påfyldningen og læsser ikke, eller kører ikke tilbage | | Ukrudt | `weedSystem`-værdi ≥ 2 = tæt | Ukrudtsbehandling uden ukrudt, eller aldrig |