Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update forest firefighters to R2023b #19

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion projects/forest_firefighters/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This simulation features a small forest wildfire and a few firefighter robots: a
Users can run the wildfire simulation and program the behavior of the robots to fight the fire.
They can also improve the models of the robot and even design new ones.

**Warning**: This project works only with Webots R2021b.
**Updates**: - 01/02/2024 updated for version R2023b.


![fire](https://user-images.githubusercontent.com/12995815/131650395-876f5ce5-ecdc-4eb7-83bc-a86f94709e32.png)
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
50 changes: 40 additions & 10 deletions projects/forest_firefighters/controllers/fire/fire.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,22 +41,23 @@ def __init__(self, node):
self.smoke = None
self.fire_count = 0
self.translation = node.getField('translation').getSFVec3f()
self.scale = node.getField('size').getSFFloat() / 10
self.scale = node.getField('scale').getSFFloat()
self.robustness = random.uniform(self.ROBUSTNESS_VARIATION, self.ROBUSTNESS_VARIATION)
node.getField('burnt').setSFBool(False) # Ensure normal tree as initial state

def stopFire(self):
if self.fire:
fire_translation_field = self.fire.getField('translation')
fire_translation = fire_translation_field.getSFVec3f()
t = [fire_translation[0], fire_translation[1], fire_translation[2]]
t[1] = 10000000
# t[2] = 1000000
angel-ayala marked this conversation as resolved.
Show resolved Hide resolved
fire_translation_field.setSFVec3f(t)
self.fire = None
if self.smoke:
smoke_translation_field = self.smoke.getField('translation')
smoke_translation = smoke_translation_field.getSFVec3f()
t = [smoke_translation[0], smoke_translation[1], smoke_translation[2]]
t[1] = 10000000
t[2] = 1000000
smoke_translation_field.setSFVec3f(t)
self.smoke = None

Expand Down Expand Up @@ -100,6 +101,7 @@ def cleanWater(self):
if altitude < 0:
self.waterBalls.remove(waterBall)
waterBall.remove()

def altitude(self):
return self.node.getField('translation').getSFVec3f()[2]

Expand All @@ -111,6 +113,8 @@ class Wind():
def __init__(self):
self.intensity = random.random()
self.angle = random.uniform(0, 2 * math.pi)
print('Wind angle', self.angle)
print('Wind intensity', self.intensity)
angel-ayala marked this conversation as resolved.
Show resolved Hide resolved

def evolve(self):
if self.RANDOM_EVOLUTION:
Expand All @@ -131,10 +135,17 @@ def correctedDistance(self, tree1, tree2, propagation_radius): # distance betwe
x_wind = self.intensity * math.cos(self.angle)
y_wind = self.intensity * math.sin(self.angle)
dx = tree1.translation[0] + propagation_radius * x_wind - tree2.translation[0]
dy = tree1.translation[1] + propagation_radius * y_wind - tree2.translation[1]
dz = tree1.translation[2] - tree2.translation[2]
dy = tree1.translation[1] - tree2.translation[1]
dz = tree1.translation[2] + propagation_radius * y_wind - tree2.translation[2]
return math.sqrt(dx * dx + dy * dy + dz * dz)

def fire_shape_url(shape_node):
if shape_node.getBaseTypeName() == 'Shape':
appr_node = shape_node.getField('appearance').getSFNode()
return appr_node.getField('url').getMFString(0)
else:
print('Node is not an instance of Shape, nothing to return')
return None

class Fire(Supervisor):
FLAME_CYCLE = 13 # there are 13 images in the flame animation
Expand All @@ -157,6 +168,7 @@ def __init__(self):
self.trees = []

self.robots = []
self.fire_sprites = []

n = self.children.getCount()
for i in range(n):
Expand Down Expand Up @@ -198,6 +210,19 @@ def ignite(self, tree):
tree.fire_scale_field = tree.fire.getField('scale')
tree.fire_translation = tree.fire_translation_field.getSFVec3f()

node_child = tree.fire.getProtoField('children').getMFNode(0)
if node_child.getBaseTypeName() == 'Shape':
appr_node = node_child.getField('appearance').getSFNode()
tree.fire_shape_field = appr_node.getField('url')

if len(self.fire_sprites) == 0:
self.fire_sprites.append(fire_shape_url(node_child))
for i in range(self.FLAME_CYCLE):
node_child = tree.fire.getProtoField('children').getMFNode(i)
if node_child.getBaseTypeName() == 'Pose':
txr_node = node_child.getField('children').getMFNode(0)
self.fire_sprites.append(fire_shape_url(txr_node))

def burn(self, tree):
if self.update_fire:
tree.fire_count += 1
Expand All @@ -206,11 +231,14 @@ def burn(self, tree):
if tree.fire_count == self.FLAME_PEAK * self.FLAME_CYCLE:
tree.node.getField('burnt').setSFBool(True)
tree.fire_scale_field.setSFVec3f([tree.fire_scale, tree.fire_scale, tree.fire_scale])

if tree.fire_scale < tree.scale:
tree.stopFire()
t = [tree.fire_translation[0], tree.fire_translation[1], tree.fire_translation[2]]
t[1] -= 100000 * tree.fire_scale * (tree.fire_count % 13)
tree.fire_translation_field.setSFVec3f(t)
if tree.fire:
sprite_field = tree.fire.getField('spriteBase')
sprite_field.setMFString(0, '../protos/' + self.fire_sprites[tree.fire_count % self.FLAME_CYCLE])
self.propagate(tree)
if tree.fire_count == 1:
smoke = f'Smoke {{ translation {tree.translation[0]} {tree.translation[1]} {tree.translation[2]} ' \
Expand Down Expand Up @@ -246,7 +274,7 @@ def checkExtinction(self, tree): # check and extinct the fire if there is water
if water_radius / robot.MAX_WATER_RADIUS > fire_size:
tree.stopFire()
return True
return False
return False

def run(self):
start_fire_now = False
Expand All @@ -257,9 +285,10 @@ def run(self):

message = self.wwiReceiveText()
if message:
print('message', message)
angel-ayala marked this conversation as resolved.
Show resolved Hide resolved
self.wind.update(message)
self.wind.evolve()

self.wwiSendText('{"angle":%f, "intensity":%f}' % (self.wind.angle, self.wind.intensity))

for robot in self.robots:
Expand All @@ -279,18 +308,19 @@ def run(self):
self.update_fire = False
self.fire_clock += 1

extinction = []
extinction = []
for tree in self.trees:
if tree.fire:
self.burn(tree)
extinction.append(self.checkExtinction(tree))

if True in extinction:
self.ignite(random.choice(self.trees))
else:
for robot in self.robots: # the simulation starts when the mavic got an altitude > 40
if not start_fire_now and robot.name == "Mavic 2 PRO" and robot.altitude() > 40:
start_fire_now = True
print('waiting altitude', start_fire_now)
angel-ayala marked this conversation as resolved.
Show resolved Hide resolved

controller = Fire()
controller.run()
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ function drawDial() {

// x and y axis
drawAxis('red', Math.PI / 2, 'x')
drawAxis('green', 0, 'y')
drawAxis('blue', 0, 'z')
}

function drawAxis(color, angle, letter) {
Expand Down
55 changes: 29 additions & 26 deletions projects/forest_firefighters/protos/Fire.proto
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
#VRML_SIM R2021b utf8
#VRML_SIM R2023b utf8
# license: Creative Commons Attribution 4.0 International License.
# license url: https://creativecommons.org/licenses/by/4.0/legalcode
# A fire with flame animation

EXTERNPROTO "Fire/FlameAppearance.proto"

PROTO Fire [
field SFVec3f translation 0 0 0
field SFRotation rotation 0 0 1 0
field SFVec3f scale 1 1 1
field MFString spriteBase "Fire/textures/fire_00.png"
]
{
Transform {
Expand All @@ -15,7 +18,7 @@ PROTO Fire [
scale IS scale
children [
DEF FLAME Shape {
appearance FlameAppearance {}
appearance FlameAppearance { url IS spriteBase }
geometry DEF FLAME_GEOMETRY IndexedFaceSet {
coord Coordinate {
point [
Expand Down Expand Up @@ -52,86 +55,86 @@ PROTO Fire [
}
}
Transform {
translation 0 100000 0
translation 0 0 100000.0
children Shape {
appearance FlameAppearance { url "textures/fire_01.png" }
appearance FlameAppearance { url "Fire/textures/fire_01.png" }
geometry USE FLAME_GEOMETRY
}
}
Transform {
translation 0 200000 0
translation 0 0 200000.0
children Shape {
appearance FlameAppearance { url "textures/fire_02.png" }
appearance FlameAppearance { url "Fire/textures/fire_02.png" }
geometry USE FLAME_GEOMETRY
}
}
Transform {
translation 0 300000 0
translation 0 0 300000.0
children Shape {
appearance FlameAppearance { url "textures/fire_03.png" }
appearance FlameAppearance { url "Fire/textures/fire_03.png" }
geometry USE FLAME_GEOMETRY
}
}
Transform {
translation 0 400000 0
translation 0 0 400000.0
children Shape {
appearance FlameAppearance { url "textures/fire_04.png" }
appearance FlameAppearance { url "Fire/textures/fire_04.png" }
geometry USE FLAME_GEOMETRY
}
}
Transform {
translation 0 500000 0
translation 0 0 500000.0
children Shape {
appearance FlameAppearance { url "textures/fire_05.png" }
appearance FlameAppearance { url "Fire/textures/fire_05.png" }
geometry USE FLAME_GEOMETRY
}
}
Transform {
translation 0 600000 0
translation 0 0 600000.0
children Shape {
appearance FlameAppearance { url "textures/fire_06.png" }
appearance FlameAppearance { url "Fire/textures/fire_06.png" }
geometry USE FLAME_GEOMETRY
}
}
Transform {
translation 0 700000 0
translation 0 0 700000.0
children Shape {
appearance FlameAppearance { url "textures/fire_07.png" }
appearance FlameAppearance { url "Fire/textures/fire_07.png" }
geometry USE FLAME_GEOMETRY
}
}
Transform {
translation 0 800000 0
translation 0 0 800000.0
children Shape {
appearance FlameAppearance { url "textures/fire_08.png" }
appearance FlameAppearance { url "Fire/textures/fire_08.png" }
geometry USE FLAME_GEOMETRY
}
}
Transform {
translation 0 900000 0
translation 0 0 900000.0
children Shape {
appearance FlameAppearance { url "textures/fire_09.png" }
appearance FlameAppearance { url "Fire/textures/fire_09.png" }
geometry USE FLAME_GEOMETRY
}
}
Transform {
translation 0 1000000 0
translation 0 0 1000000.0
children Shape {
appearance FlameAppearance { url "textures/fire_10.png" }
appearance FlameAppearance { url "Fire/textures/fire_10.png" }
geometry USE FLAME_GEOMETRY
}
}
Transform {
translation 0 1100000 0
translation 0 0 1100000.0
children Shape {
appearance FlameAppearance { url "textures/fire_11.png" }
appearance FlameAppearance { url "Fire/textures/fire_11.png" }
geometry USE FLAME_GEOMETRY
}
}
Transform {
translation 0 1200000 0
translation 0 0 1200000.0
children Shape {
appearance FlameAppearance { url "textures/fire_12.png" }
appearance FlameAppearance { url "Fire/textures/fire_12.png" }
geometry USE FLAME_GEOMETRY
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#VRML_SIM R2021b utf8
#VRML_SIM R2023b utf8
# license: Creative Commons Attribution 4.0 International License.
# license url: https://creativecommons.org/licenses/by/4.0/legalcode
# A flame appearance
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#VRML_SIM R2021b utf8
#VRML_SIM R2022a utf8
# license: Creative Commons Attribution 4.0 International License.
# license url: https://creativecommons.org/licenses/by/4.0/legalcode
# A flame appearance
Expand Down
218 changes: 108 additions & 110 deletions projects/forest_firefighters/protos/Sassafras.proto

Large diffs are not rendered by default.

Loading