Post

Fixing sim to use Ackermann Arquitecture

Index

Finding issue

Smarts does not explicitly explain how to use the different architectures for the vehicles. For this reason, the task consisted of doing a search of the vehicle class to find where it was assigned one chassis or another. It was more complex than expected because smarts has very modularised classes, but all the physics related classes of the simulator are still a bit green, in fact, most classes are incomplete or with patches for future updates …. that will never arrive.

I found out that for now there is no manual way to choose the vehicle architecture, it depends on how you want to control the vehicle, it is assigned to one chassis or another.

Modifying classes to enable going backwards

Smarts has some problems with driving in backwards, also, it is not a simulator prepared for it, so it is not available. For that reason, several classes serve as a barrier to avoid values that make the speed negative. Also, the vehicle speed calculation was not prepared to calculate negative speeds.

smarts/core/controllers/__init__

  • Modified throttle ranges.

smarts/core/chassis

  • Modified throttle ranges.
  • Speed calculation solved.
  • Modified braking mode independent of the current speed.
  • Negative speeds allowed.

smarts/env/utils/action_conversion

  • Modified throttle ranges.

Once these files have been modified, we can now control the vehicle to drive in any direction and brake correctly!

Modifying training

At this point we must exchange the action space used to use the ackermann chassis. Once this is done, a large part of our programme must be modified.

  • Number of actions increased. Braking action added.
  • Modified neural network input. Actions now take 3 values.
  • Modified the way actions are taken, with the appropriate data type.

The biggest change has been the misalignment class. It had to be completely changed as the logic was already obsolete.

Modifying class Desalignment

Now the positions reached are not completely absolute as there are errors such as friction, braking, etc…. Moreover, in order to disorientate the vehicle, it cannot turn on itself, so its position varies quite a lot. Some parameters can still be tuned but still need more testing.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
class Desalignment:
    def __init__(self, env, max_align_steps=MAX_ALIGN_STEPS):
        self.env = env
        self.max_align_steps = max_align_steps

    def reset(self, observation, rotate=False):
        """Reinicia los parámetros de desalineación."""
        self.moved = False
        self.rotate = rotate
        self.n_steps = 0
        self.accelerate = True
        self.random_offset = np.random.choice([-2, -1.75, -1.5, -1, -0.5, 0, 0.5, 1, 1.5, 1.75, 2])
        # self.random_offset = np.random.choice([-2, 0, 2])
        self.random_rotation = np.random.choice([-0.1, -0.05, 0, 0.05, 0.1])
        self.target = observation["ego_vehicle_state"]["position"][0] + self.random_offset
        self.steering = self.random_rotation
        self.speed = 0
    
    def move_to_random_position(self, current_position, target_position, accelerate, steps):
        """Mueve el vehículo a una posición (target)."""
        throttle = 0
        brake = 0
        steering = 0
        

        distance = target_position - current_position
        if abs(self.speed ) < 3:
            throttle = 1 if distance > 0 else -1
        else:
            throttle = 0

        if abs(distance) < 0.1:
            # print(f"finished, current pose: {current_position}, target pose: {target_position}")
            self.accelerate = False
        
        if not self.accelerate and abs(self.speed) > 0.2:
            brake = 1
            steering = self.steering
            
            
        if steps == self.max_align_steps:
            self.moved = True
            throttle = 0
            brake = 0
            steering = 0
                
        return np.array([throttle, brake, steering], dtype=np.float32)

    def run(self, observation, parking_target):
        """Mueve el vehículo a una posición aleatoria."""
        self.speed = observation['ego_vehicle_state']['speed']
        if not self.moved:
            action = self.move_to_random_position(
                observation["ego_vehicle_state"]["position"][0], self.target, self.accelerate, self.n_steps
            )
            observation, _, terminated, _, _ = self.env.step(action, parking_target)
            self.n_steps += 1
            return observation, terminated

        elif self.n_steps <= self.max_align_steps:
            steering = 0.0
            observation, _, terminated, _, _ = self.env.step(np.array([0.0, 0.0, steering], dtype=np.float32), parking_target)
            self.n_steps += 1
            return observation, terminated

        else:
            return observation, False

    def is_desaligned(self):
        """Devuelve True si la desalineación está en progreso, False si ha terminado."""
        return self.n_steps <= self.max_align_steps
This post is licensed under CC BY 4.0 by the author.