Skip to content

Commit

Permalink
fix: classes improved and docs
Browse files Browse the repository at this point in the history
  • Loading branch information
jpalmeidaalves committed Jan 29, 2025
1 parent 9e12a64 commit 0e37daf
Show file tree
Hide file tree
Showing 6 changed files with 371 additions and 48 deletions.
148 changes: 148 additions & 0 deletions docs/carmotion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# Car Movement System Documentation

## Overview
The Car Movement System is a C++ implementation for controlling a robotic car's movement through servo motors and motor drivers using I2C communication. The system provides control over steering angle and motor speed, integrating with the pigpio library for GPIO control on Raspberry Pi.

## Dependencies
- pigpio library for GPIO control
- I2C enabled on the Raspberry Pi
- Standard C++ libraries (algorithm, cmath, stdexcept)

## Hardware Configuration
### Servo Configuration
- I2C Address: 0x40
- PWM Frequency: ~50Hz
- Steering Channel: 0
- PWM Values:
- Left Maximum (45°): 205
- Center (0°): 307
- Right Maximum (45°): 410

### Motor Configuration
- I2C Address: 0x60
- PWM Frequency: 60Hz
- Channels:
- ENA: Channel 0
- IN1: Channel 1
- IN2: Channel 2
- IN3: Channel 5
- IN4: Channel 6
- ENB: Channel 7

## Class Reference

### carMove Class

#### Constructor
```cpp
carMove();
```
Initializes the car movement system by:
1. Initializing the pigpio library
2. Setting up I2C communication for both servo and motor controllers
3. Configuring PWM frequencies and modes
4. Throws `std::runtime_error` if initialization fails

#### Destructor
```cpp
~carMove();
```
Performs cleanup by:
1. Closing I2C connections
2. Terminating the pigpio library

#### Public Methods

##### setServoAngle
```cpp
void setServoAngle(int angle);
```
Sets the steering angle of the car.
- Parameters:
- `angle`: Integer value between -45 and 45 degrees
- Negative values: Turn left
- Positive values: Turn right
- Zero: Center position
- Automatically clamps values to valid range
##### setMotorSpeed
```cpp
void setMotorSpeed(int speed);
```
Controls the car's motor speed and direction
- Parameters:
- `speed`: Integer value between -100 and 100
- Positive values: Forward motion
- Negative values: Backward motion
- Zero: Stop
- Automatically clamps values to valid range

##### sequence
```cpp
void sequence();
```
Demonstrates basic movement capabilities:
1. Drives forward at full speed (2 seconds)
2. Drives backward at full speed (2 seconds)
3. Turns wheels fully left (1 second)
4. Turns wheels fully right (1 second)
5. Returns to neutral position

#### Private Methods

##### setPWM
```cpp
static void setPWM(int device_handle, int channel, int on_value, int off_value);
```
Low-level PWM control for both servo and motor
- Parameters:
- `device_handle`: I2C device handle
- `channel`: PWM channel number
- `on_value`: PWM signal start time
- `off_value`: PWM signal stop time
## Constants
```cpp
static const int SERVO_ADDR = 0x40; // Servo controller I2C address
static const int MOTOR_ADDR = 0x60; // Motor controller I2C address
static const int STEERING_CHANNEL = 0; // Servo channel for steering
static constexpr int MAX_ANGLE = 45; // Maximum steering angle
static const int SERVO_LEFT_PWM = 205; // PWM value for maximum left turn
static const int SERVO_CENTER_PWM = 307; // PWM value for center position
static const int SERVO_RIGHT_PWM = 410; // PWM value for maximum right turn
```

## Usage Example

```cpp
try {
carMove car;

// Basic movement
car.setMotorSpeed(50); // Move forward at half speed

sleep(2); // Continue for 2 seconds

car.setServoAngle(-30); // Turn left at 30 degrees

sleep(1);

car.setMotorSpeed(0); // Stop
car.setServoAngle(0); // Center wheels

// Run demo sequence
// car.sequence();

} catch (const std::runtime_error& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
```

## Error Handling
The class uses exception handling to manage errors:
- Throws `std::runtime_error` if:
- pigpio initialization fails
- I2C device initialization fails
- All motor and servo commands are bounds-checked to prevent invalid values

177 changes: 177 additions & 0 deletions docs/joystick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
# Joystick Controller Documentation

## Overview
The Joystick Controller is a C++ implementation for handling game controller input using SDL2's GameController API. It provides a flexible interface for mapping controller buttons and axes to car control functions, integrating with the carMove system for controlling a robotic car.

## Dependencies
- SDL2 library with GameController support
- carMove class
- Standard C++ libraries (array, functional, iostream, map, utility)

## Class Reference

### joystick Class

#### Constructor
```cpp
joystick(carMove& car);
```
Initializes the joystick controller system:
1. Initializes SDL2 GameController subsystem
2. Scans for available game controllers
3. Opens the first compatible controller found
4. Sets up default axis mappings for the car
5. Throws `std::runtime_error` if:
- SDL2 initialization fails
- No compatible controller is found
#### Destructor
```cpp
~joystick();
```
Performs cleanup:
1. Closes the game controller connection
2. Shuts down SDL2

#### Public Methods

##### setButtonAction
```cpp
void setButtonAction(int button, Actions actions);
```
Maps a controller button to specific press and release actions
- Parameters:
- `button`: Button identifier (SDL_GameControllerButton value)
- `actions`: Structure containing:
- `onPress`: Function to execute when button is pressed
- `onRelease`: Function to execute when button is released
##### setAxisAction
```cpp
void setAxisAction(int axis, std::function<void(int)> action);
```
Maps a controller axis to a specific action
- Parameters:
- `axis`: Axis identifier (SDL_GameControllerAxis value)
- `action`: Function taking an integer value (-32768 to 32767)

##### setAxisMapping
```cpp
void setAxisMapping(carMove& car);
```
Sets up default axis mappings for car control:
1. Left stick X-axis (1): Controls steering angle (-45° to 45°)
2. Right stick Y-axis (5): Controls motor speed (-100% to 100%)
##### listen
```cpp
void listen();
```
Enters the main event processing loop:
1. Continuously polls for controller events
2. Processes button presses and axis movements
3. Exits when specific button combination is pressed (buttons 4 and 6)
4. Handles controller disconnection events

##### printButtonStates
```cpp
void printButtonStates();
```
- When a button is pressed, print its number in the console
- Use this method to map the control buttons

#### Private Methods

##### processEvent
```cpp
void processEvent(const SDL_Event& event);
```
Internal event processing method:
- Handles:
- Button press/release events
- Axis motion events
- Controller disconnection events
- Updates button states
- Executes mapped actions
- Logs event information to console
## Data Structures
### Actions Structure
```cpp
struct Actions {
std::function<void()> onPress; // Function called on button press
std::function<void()> onRelease; // Function called on button release
};
```

### Class Members
```cpp
SDL_GameController* gameController; // Pointer to the active controller
std::map<int, Actions> buttonActions; // Maps buttons to their actions
std::map<int, std::function<void(int)>> axisActions; // Maps axes to their actions
std::array<bool, SDL_CONTROLLER_BUTTON_MAX> buttonStates; // Current button states
```

## Usage Example

```cpp
try {
carMove car;
joystick controller(car);

// Custom button mapping example
controller.setButtonAction(SDL_CONTROLLER_BUTTON_A,
Actions{
[]() { std::cout << "A pressed\n"; },
[]() { std::cout << "A released\n"; }
});

// Custom axis mapping example
controller.setAxisAction(SDL_CONTROLLER_AXIS_LEFTX,
[](int value) {
std::cout << "Left stick X: " << value << "\n";
});

// Start processing controller input
controller.listen();

} catch (const std::runtime_error& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
```

## Event Handling
The class handles several types of SDL events:
1. SDL_CONTROLLERBUTTONDOWN: Button press events
2. SDL_CONTROLLERBUTTONUP: Button release events
3. SDL_CONTROLLERAXISMOTION: Axis movement events
4. SDL_CONTROLLERDEVICEREMOVED: Controller disconnection events

## Default Mappings
- Left Stick X-Axis:
- Range: -32768 to 32767
- Mapped to steering angle: -45° to 45°
- Right Stick Y-Axis:
- Range: -32768 to 32767
- Mapped to motor speed: -100% to 100%

## Error Handling
- Throws `std::runtime_error` for initialization failures
- Handles controller disconnection gracefully
- Validates button and axis indices before processing
- Logs events and errors to standard output

## Safety Considerations
1. Always check for null controller pointer before operations
2. Handle controller disconnection appropriately
3. Implement emergency stop functionality
4. Validate axis values before applying to car controls
5. Consider implementing dead zones for axis inputs

## Maintenance Notes
- Regularly check SDL2 events for controller status
- Monitor controller connection stability
- Consider implementing controller reconnection handling
- Add support for multiple controller types/layouts
- Implement axis calibration functionality if needed
30 changes: 2 additions & 28 deletions examples/baseCar/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,14 @@

#include "platform/joystick/joystick.hpp"

carMove car;

// Function to handle left stick horizontal axis movements (steering)
void moveLeftandRight(int value) {
float fvalue = value * 1.0; // Raw value
std::cout << "Before normalization: " << fvalue << '\n';

// Normalize to a 45-degree range
fvalue = fvalue / 32000.0 * 45;
std::cout << "Servo angle moved to: " << fvalue << " degrees" << '\n';

car.setServoAngle(fvalue);
}

// Function to handle right stick vertical axis movements (engine control)
void moveForwardandBackward(int value) {
value -= 16319; // Adjust for neutral position
value = (value / 165) * -1; // Normalize and invert for correct direction

std::cout << "Engine speed moved to: " << value << '\n';
car.setMotorSpeed(value);
}

auto main() -> int {
try {
carMove car;
joystick controller(car);

// Map left stick horizontal axis to control the servo (steering)
controller.setAxisAction(SDL_CONTROLLER_AXIS_LEFTX, moveLeftandRight);

// Map right stick vertical axis to control the engine (forward/reverse)
controller.setAxisAction(SDL_CONTROLLER_AXIS_RIGHTY, moveForwardandBackward);
// car.sequence(); // Uncomment to test the car sequence

// Start listening for events
controller.listen();

} catch (const std::runtime_error &e) {
Expand Down
6 changes: 3 additions & 3 deletions platform/carMove/carMove.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ class carMove {
static const int STEERING_CHANNEL = 0;

// A constante MAX_ANGLE é 'constexpr' para permitir uso direto em tempo de compilação
static constexpr int MAX_ANGLE = 45;
static constexpr int MAX_ANGLE = 80;

static const int SERVO_LEFT_PWM = 205; // Adjust as needed >> TEST!!
static const int SERVO_LEFT_PWM = 180; // Adjust as needed >> TEST!!
static const int SERVO_CENTER_PWM = 307;
static const int SERVO_RIGHT_PWM = 410;
static const int SERVO_RIGHT_PWM = 435;
};

#endif
Loading

0 comments on commit 0e37daf

Please sign in to comment.