Added harvest script.
This commit is contained in:
parent
bab6ca719b
commit
4f1db31164
|
@ -0,0 +1,41 @@
|
|||
# harvest.lua
|
||||
Script for smart harvesting of rectangular farms of multiple crops.
|
||||
|
||||
## Pastebin
|
||||
[ytYCVGsc](https://pastebin.com/ytYCVGsc)
|
||||
|
||||
## Module Requirements
|
||||
* geolyzer
|
||||
* inventory_controller
|
||||
* *equipped hoe*
|
||||
|
||||
## Instructions
|
||||
To operate the program, you simply need to run the program. If no `harvest.conf` config file exists, the program will guide you through the creation of it. For it, you'll need the following information:
|
||||
|
||||
* On what side does the robot start harvesting (left or right)?
|
||||
* How many rows are in the field?
|
||||
* How many columns are in the field?
|
||||
* What crops will be grown?
|
||||
|
||||
For each crop that will be grown, you will need the following pieces of information:
|
||||
|
||||
1. The crop's block name (can be found using the `geolyzer` component.
|
||||
2. The floating point value at which the crop is ready to be harvested. Can also be found with the `geolyzer`.
|
||||
3. The name of the item used to replant the crop. This can be found in the minecraft inventory after pressing `F3 + H` to enable more detailed information for displayed items.
|
||||
|
||||
Once all this information is entered, running the program will harvest the defined area, and drop all gathered items into a chest below the robot's resting point.
|
||||
|
||||
### Diagram of setup
|
||||
The below diagram shows how farms should be set up: the robot faces into the first row, and has a charger behind it to replenish energy after each harvest. A chest or hopper can be placed below the robot for item collection.
|
||||
|
||||
```
|
||||
CR---------
|
||||
---------
|
||||
---------
|
||||
---------
|
||||
---------
|
||||
---------
|
||||
---------
|
||||
---------
|
||||
---------
|
||||
```
|
|
@ -0,0 +1,265 @@
|
|||
-- Harvest Program for robots. Uses a hoe and geolyzer for optimal harvesting.
|
||||
--[[
|
||||
Author: Andrew Lalis
|
||||
File: harvest.lua
|
||||
Version: 1.0
|
||||
Last Modified: 27-09-2018
|
||||
|
||||
Description:
|
||||
This script enables a robot to harvest fields of crops quickly and efficiently.
|
||||
The robot will traverse the field and only harvest crops considered 'done' by
|
||||
their crop definition.
|
||||
--]]
|
||||
|
||||
local robot = require("robot")
|
||||
local component = require("component")
|
||||
local fs = component.filesystem
|
||||
local serial = require("serialization")
|
||||
local geolyzer = component.geolyzer
|
||||
local ic = component.inventory_controller
|
||||
local sides = require("sides")
|
||||
|
||||
local CONFIG_FILE = "harvest.conf"
|
||||
|
||||
local LEFT = 1
|
||||
local RIGHT = 0
|
||||
|
||||
-- List of crops which will be harvested.
|
||||
local crop_definitions = {
|
||||
["harvestcraft:pamsoybeancrop"] = {
|
||||
growth_limit = 0.42,
|
||||
item_name = "harvestcraft:soybeanitem"
|
||||
},
|
||||
["harvestcraft:pamspiceleafcrop"] = {
|
||||
growth_limit = 0.42,
|
||||
item_name = "harvestcraft:spiceleafitem"
|
||||
}
|
||||
}
|
||||
|
||||
-- Repeats the given function until it returns true.
|
||||
local function doUntilSuccess(func)
|
||||
local success = func()
|
||||
while (not success) do
|
||||
success = func()
|
||||
end
|
||||
end
|
||||
|
||||
-- Pre-defined path from turtle docking bay to start of harvest area (first crop).
|
||||
local function goToStart(rows, columns)
|
||||
doUntilSuccess(robot.forward)
|
||||
end
|
||||
|
||||
-- Pre-defined path back to the turtle docking bay.
|
||||
local function goBack(rows, columns)
|
||||
for i=1,(columns-1) do
|
||||
doUntilSuccess(robot.back)
|
||||
end
|
||||
robot.turnRight()
|
||||
for i=1,(rows-1) do
|
||||
doUntilSuccess(robot.back)
|
||||
end
|
||||
robot.turnLeft()
|
||||
doUntilSuccess(robot.back)
|
||||
end
|
||||
|
||||
--[[
|
||||
Select an item, given its name and damage value.
|
||||
item_name - string: The id string for an item.
|
||||
item_data - number: The damage value, or variation of an item. Defaults to zero.
|
||||
return - boolean: True if at least one slot contains the item. That slot is now
|
||||
selected.
|
||||
--]]
|
||||
local function selectItemByName(item_name, item_data)
|
||||
for i=1,16 do
|
||||
local stack = ic.getStackInInternalSlot(i)
|
||||
if (stack ~= nil and stack.name == item_name and stack.damage == item_data) then
|
||||
robot.select(i)
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--[[
|
||||
Checks if the hoe is equipped. Meant to be done before starting a harvest.
|
||||
return - boolean: True if a hoe is equipped, or false if not.
|
||||
--]]
|
||||
local function isHoeEquipped()
|
||||
for i=1,16 do
|
||||
local item_stack = ic.getStackInInternalSlot(i)
|
||||
if (item_stack == nil) then
|
||||
robot.select(i)
|
||||
ic.equip()
|
||||
new_item_stack = ic.getStackInInternalSlot(i)
|
||||
if (new_item_stack ~= nil and string.match(new_item_stack.name, "_hoe")) then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--[[
|
||||
Tries to harvest a plant, if it is one of the crops defined in the crop
|
||||
definitions table above.
|
||||
return - boolean: True if a plant was harvested, false otherwise.
|
||||
--]]
|
||||
local function harvestPlant()
|
||||
local plant_data = geolyzer.analyze(sides.bottom)
|
||||
local crop_definition = crop_definitions[plant_data.name]
|
||||
if (crop_definition == nil) then
|
||||
return false
|
||||
end
|
||||
if (plant_data.growth >= crop_definition.growth_limit) then
|
||||
robot.swingDown()
|
||||
selectItemByName(crop_definition.item_name, 0)
|
||||
robot.placeDown()
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Harvests one row of crops.
|
||||
length - int: The number of plants in this row.
|
||||
return - int: The number of crops that were harvested.
|
||||
--]]
|
||||
local function harvestRow(length)
|
||||
local harvests = 0
|
||||
for i=1,length do
|
||||
if (i > 1) then
|
||||
doUntilSuccess(robot.forward)
|
||||
end
|
||||
if (harvestPlant()) then
|
||||
harvests = harvests + 1
|
||||
end
|
||||
end
|
||||
return harvests
|
||||
end
|
||||
|
||||
--[[
|
||||
At the end of the row, the robot must rotate into the next row, and this is
|
||||
dependent on where the start location is.
|
||||
current_row_index - int: The row the robot is on prior to turning.
|
||||
start_location - int: Whether the robot starts at the left or right.
|
||||
--]]
|
||||
local function turnToNextRow(current_row_index, start_location)
|
||||
if (current_row_index % 2 == start_location) then
|
||||
robot.turnRight()
|
||||
else
|
||||
robot.turnLeft()
|
||||
end
|
||||
doUntilSuccess(robot.forward)
|
||||
if (current_row_index % 2 == start_location) then
|
||||
robot.turnRight()
|
||||
else
|
||||
robot.turnLeft()
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Harvests a two dimensional area defined by rows and columns. The robot starts
|
||||
by moving forward down the first row.
|
||||
rows - int: The number of rows to harvest.
|
||||
columns - int: The number of columns to harvest.
|
||||
start_location - int: 1 for LEFT, 0 for RIGHT.
|
||||
return - int: The total number of crops harvested.
|
||||
--]]
|
||||
local function harvestField(rows, columns, start_location)
|
||||
goToStart(rows, columns)
|
||||
-- Begin harvesting.
|
||||
local harvests = 0
|
||||
for i=1,rows do
|
||||
harvests = harvests + harvestRow(columns)
|
||||
-- Do not turn to the next row on the last row.
|
||||
if (i < rows) then
|
||||
turnToNextRow(i, start_location)
|
||||
end
|
||||
end
|
||||
goBack(rows, columns)
|
||||
return harvests
|
||||
end
|
||||
|
||||
--[[
|
||||
Drops all carried items into an inventory below the robot.
|
||||
return - int: The number of items dropped.
|
||||
--]]
|
||||
local function dropItems()
|
||||
local item_count = 0
|
||||
for i=1,16 do
|
||||
robot.select(i)
|
||||
local stack = ic.getStackInInternalSlot(i)
|
||||
if (stack ~= nil) then
|
||||
doUntilSuccess(robot.dropDown)
|
||||
item_count = item_count + stack.size
|
||||
end
|
||||
end
|
||||
return item_count
|
||||
end
|
||||
|
||||
--[[
|
||||
Reads config from a file.
|
||||
filename - string: The string path/filename.
|
||||
return - table|nil: The table defined in config, or nil if the file does not
|
||||
exist or another error occurs.
|
||||
--]]
|
||||
local function loadConfig(filename)
|
||||
if (fs.exists(filename) and not fs.isDirectory(filename)) then
|
||||
-- Config file exists.
|
||||
file = io.open(filename, "r")
|
||||
local t = serial.unserialize(file:read())
|
||||
file:close()
|
||||
return t
|
||||
else
|
||||
print("No config file " .. filename .. "exists. Please create it before continuing.")
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Guides the user in creating a new config.
|
||||
--]]
|
||||
local function createConfig(filename)
|
||||
local config = {}
|
||||
print("Does your robot start on the left or right of the field?")
|
||||
local input = io.read()
|
||||
if (input == "left") then
|
||||
config.START_LOCATION_RELATIVE = LEFT
|
||||
elseif (input == "right") then
|
||||
config.START_LOCATION_RELATIVE = RIGHT
|
||||
else
|
||||
print("Invalid choice. Should be either left or right.")
|
||||
return nil
|
||||
end
|
||||
print("Enter number of rows.")
|
||||
config.ROWS = tonumber(io.read())
|
||||
print("Enter number of columns.")
|
||||
config.COLS = tonumber(io.read())
|
||||
|
||||
print("How many crops are being harvested?")
|
||||
for i=1,tonumber(io.read()) do
|
||||
print("Crop "..i..": What is the block name? (Use geolyzer to analyze it)")
|
||||
local name = io.read()
|
||||
config.crop_definitions[name] = {}
|
||||
print(" What is the growth threshold for harvesting?")
|
||||
config.crop_definitions[name].growth_limit = tonumber(io.read())
|
||||
print(" What is the item name of this crop?")
|
||||
config.crop_definitions[name].item_name = io.read()
|
||||
end
|
||||
file = io.open(filename, "w")
|
||||
file:write(serial.serialize(config))
|
||||
file:close()
|
||||
end
|
||||
|
||||
local function main()
|
||||
local config = loadConfig(CONFIG_FILE)
|
||||
if (config == nil) then
|
||||
config = createConfig(CONFIG_FILE)
|
||||
end
|
||||
crop_definitions = config.crop_definitions
|
||||
local harvest_count = harvestField(config.ROWS, config.COLS, config.START_LOCATION_RELATIVE)
|
||||
local drop_count = dropItems()
|
||||
print(harvest_count..", "..drop_count)
|
||||
end
|
Loading…
Reference in New Issue