Skip to content

Commit 5f3c09c

Browse files
authored
Sync: commaai/panda:mastersunnypilot/panda:master
2 parents dee9061 + 4cc222c commit 5f3c09c

27 files changed

+1084
-166
lines changed

SConscript

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,9 @@ if os.getenv("FINAL_PROVISIONING"):
161161
flags += ["-DFINAL_PROVISIONING"]
162162
build_project("panda_jungle_h7", base_project_h7, "./board/jungle/main.c", flags)
163163

164+
# body fw
165+
build_project("body_h7", base_project_h7, "./board/body/main.c", ["-DPANDA_BODY"])
166+
164167
# test files
165168
if GetOption('extras'):
166169
SConscript('tests/libpanda/SConscript')

__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,6 @@
88

99
# panda jungle
1010
from .board.jungle import PandaJungle, PandaJungleDFU # noqa: F401
11+
12+
# panda body
13+
from .board.body import PandaBody # noqa: F401

board/boards/cuatro.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ board board_cuatro = {
128128
.read_current_mA = cuatro_read_current_mA,
129129
.set_fan_enabled = cuatro_set_fan_enabled,
130130
.set_ir_power = unused_set_ir_power,
131-
.set_siren = unused_set_siren,
131+
.set_siren = fake_siren_set,
132132
.set_bootkick = cuatro_set_bootkick,
133133
.read_som_gpio = tres_read_som_gpio,
134134
.set_amp_enabled = cuatro_set_amp_enabled

board/boards/tres.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ board board_tres = {
168168
.read_current_mA = unused_read_current,
169169
.set_fan_enabled = tres_set_fan_enabled,
170170
.set_ir_power = tres_set_ir_power,
171-
.set_siren = fake_siren_set,
171+
.set_siren = fake_i2c_siren_set,
172172
.set_bootkick = tres_set_bootkick,
173173
.read_som_gpio = tres_read_som_gpio,
174174
.set_amp_enabled = unused_set_amp_enabled

board/body/__init__.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# python helpers for the body panda
2+
import struct
3+
4+
from panda import Panda
5+
6+
class PandaBody(Panda):
7+
8+
MOTOR_LEFT: int = 1
9+
MOTOR_RIGHT: int = 2
10+
11+
# ****************** Motor Control *****************
12+
@staticmethod
13+
def _ensure_valid_motor(motor: int) -> None:
14+
if motor not in (PandaBody.MOTOR_LEFT, PandaBody.MOTOR_RIGHT):
15+
raise ValueError("motor must be MOTOR_LEFT or MOTOR_RIGHT")
16+
17+
def motor_set_speed(self, motor: int, speed: int) -> None:
18+
self._ensure_valid_motor(motor)
19+
assert -100 <= speed <= 100, "speed must be between -100 and 100"
20+
speed_param = speed if speed >= 0 else (256 + speed)
21+
self._handle.controlWrite(Panda.REQUEST_OUT, 0xe0, motor, speed_param, b'')
22+
23+
def motor_set_target_rpm(self, motor: int, rpm: float) -> None:
24+
self._ensure_valid_motor(motor)
25+
target_deci_rpm = int(round(rpm * 10.0))
26+
assert -32768 <= target_deci_rpm <= 32767, "target rpm out of range (-3276.8 to 3276.7)"
27+
target_param = target_deci_rpm if target_deci_rpm >= 0 else (target_deci_rpm + (1 << 16))
28+
self._handle.controlWrite(Panda.REQUEST_OUT, 0xe4, motor, target_param, b'')
29+
30+
def motor_stop(self, motor: int) -> None:
31+
self._ensure_valid_motor(motor)
32+
self._handle.controlWrite(Panda.REQUEST_OUT, 0xe1, motor, 0, b'')
33+
34+
def motor_get_encoder_state(self, motor: int) -> tuple[int, float]:
35+
self._ensure_valid_motor(motor)
36+
dat = self._handle.controlRead(Panda.REQUEST_IN, 0xe2, motor, 0, 8)
37+
position, rpm_milli = struct.unpack("<ii", dat)
38+
return position, rpm_milli / 1000.0
39+
40+
def motor_reset_encoder(self, motor: int) -> None:
41+
self._ensure_valid_motor(motor)
42+
self._handle.controlWrite(Panda.REQUEST_OUT, 0xe3, motor, 0, b'')

board/body/boards/board_body.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#include "board/body/motor_control.h"
2+
3+
void board_body_init(void) {
4+
motor_init();
5+
motor_encoder_init();
6+
motor_speed_controller_init();
7+
motor_encoder_reset(1);
8+
motor_encoder_reset(2);
9+
10+
// Initialize CAN pins
11+
set_gpio_pullup(GPIOD, 0, PULL_NONE);
12+
set_gpio_alternate(GPIOD, 0, GPIO_AF9_FDCAN1);
13+
set_gpio_pullup(GPIOD, 1, PULL_NONE);
14+
set_gpio_alternate(GPIOD, 1, GPIO_AF9_FDCAN1);
15+
}
16+
17+
board board_body = {
18+
.led_GPIO = {GPIOC, GPIOC, GPIOC},
19+
.led_pin = {7, 7, 7},
20+
.init = board_body_init,
21+
};
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#pragma once
2+
3+
#include <stdint.h>
4+
#include <stdbool.h>
5+
6+
// ******************** Prototypes ********************
7+
typedef void (*board_init)(void);
8+
typedef void (*board_init_bootloader)(void);
9+
typedef void (*board_enable_can_transceiver)(uint8_t transceiver, bool enabled);
10+
11+
struct board {
12+
GPIO_TypeDef * const led_GPIO[3];
13+
const uint8_t led_pin[3];
14+
const uint8_t led_pwm_channels[3]; // leave at 0 to disable PWM
15+
board_init init;
16+
board_init_bootloader init_bootloader;
17+
const bool has_spi;
18+
};
19+
20+
// ******************* Definitions ********************
21+
#define HW_TYPE_BODY 0xB1U

board/body/can.h

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#pragma once
2+
3+
#include <stdbool.h>
4+
#include <stdint.h>
5+
6+
#include "board/can.h"
7+
#include "board/health.h"
8+
#include "board/body/motor_control.h"
9+
#include "board/drivers/can_common_declarations.h"
10+
#include "opendbc/safety/declarations.h"
11+
12+
#define BODY_CAN_ADDR_MOTOR_SPEED 0x201U
13+
#define BODY_CAN_MOTOR_SPEED_PERIOD_US 10000U
14+
#define BODY_BUS_NUMBER 0U
15+
16+
static struct {
17+
bool pending;
18+
int32_t left_target_deci_rpm;
19+
int32_t right_target_deci_rpm;
20+
} body_can_command;
21+
22+
void body_can_send_motor_speeds(uint8_t bus, float left_speed_rpm, float right_speed_rpm) {
23+
CANPacket_t pkt;
24+
pkt.bus = bus;
25+
pkt.addr = BODY_CAN_ADDR_MOTOR_SPEED;
26+
pkt.returned = 0;
27+
pkt.rejected = 0;
28+
pkt.extended = 0;
29+
pkt.fd = 0;
30+
pkt.data_len_code = 8;
31+
int16_t left_speed_deci = left_speed_rpm * 10;
32+
int16_t right_speed_deci = right_speed_rpm * 10;
33+
pkt.data[0] = (uint8_t)((left_speed_deci >> 8) & 0xFFU);
34+
pkt.data[1] = (uint8_t)(left_speed_deci & 0xFFU);
35+
pkt.data[2] = (uint8_t)((right_speed_deci >> 8) & 0xFFU);
36+
pkt.data[3] = (uint8_t)(right_speed_deci & 0xFFU);
37+
pkt.data[4] = 0U;
38+
pkt.data[5] = 0U;
39+
pkt.data[6] = 0U;
40+
pkt.data[7] = 0U;
41+
can_set_checksum(&pkt);
42+
can_send(&pkt, bus, true);
43+
}
44+
45+
void body_can_process_target(int16_t left_target_deci_rpm, int16_t right_target_deci_rpm) {
46+
body_can_command.left_target_deci_rpm = (int32_t)left_target_deci_rpm;
47+
body_can_command.right_target_deci_rpm = (int32_t)right_target_deci_rpm;
48+
body_can_command.pending = true;
49+
}
50+
51+
void body_can_init(void) {
52+
body_can_command.pending = false;
53+
can_silent = false;
54+
can_loopback = false;
55+
(void)set_safety_hooks(SAFETY_BODY, 0U);
56+
set_gpio_output(GPIOD, 2U, 0); // Enable CAN transceiver
57+
can_init_all();
58+
}
59+
60+
void body_can_periodic(uint32_t now) {
61+
if (body_can_command.pending) {
62+
body_can_command.pending = false;
63+
float left_target_rpm = ((float)body_can_command.left_target_deci_rpm) * 0.1f;
64+
float right_target_rpm = ((float)body_can_command.right_target_deci_rpm) * 0.1f;
65+
motor_speed_controller_set_target_rpm(BODY_MOTOR_LEFT, left_target_rpm);
66+
motor_speed_controller_set_target_rpm(BODY_MOTOR_RIGHT, right_target_rpm);
67+
}
68+
69+
static uint32_t last_motor_speed_tx_us = 0;
70+
if ((now - last_motor_speed_tx_us) >= BODY_CAN_MOTOR_SPEED_PERIOD_US) {
71+
float left_speed_rpm = motor_encoder_get_speed_rpm(BODY_MOTOR_LEFT);
72+
float right_speed_rpm = motor_encoder_get_speed_rpm(BODY_MOTOR_RIGHT);
73+
body_can_send_motor_speeds(BODY_BUS_NUMBER, left_speed_rpm, right_speed_rpm);
74+
last_motor_speed_tx_us = now;
75+
}
76+
}

board/body/flash.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#!/usr/bin/env python3
2+
import argparse
3+
import os
4+
import subprocess
5+
6+
from panda import Panda
7+
8+
BODY_DIR = os.path.dirname(os.path.realpath(__file__))
9+
BOARD_DIR = os.path.abspath(os.path.join(BODY_DIR, ".."))
10+
REPO_ROOT = os.path.abspath(os.path.join(BOARD_DIR, ".."))
11+
DEFAULT_FIRMWARE = os.path.join(BOARD_DIR, "obj", "body_h7.bin.signed")
12+
13+
14+
def build_body() -> None:
15+
subprocess.check_call(
16+
f"scons -C {REPO_ROOT} -j$(nproc) board/obj/body_h7.bin.signed",
17+
shell=True,
18+
)
19+
20+
21+
if __name__ == "__main__":
22+
parser = argparse.ArgumentParser()
23+
parser.add_argument("firmware", nargs="?", help="Optional path to firmware binary to flash")
24+
parser.add_argument("--all", action="store_true", help="Flash all Panda devices")
25+
parser.add_argument(
26+
"--wait-usb",
27+
action="store_true",
28+
help="Wait for the panda to reconnect over USB after flashing (defaults to skipping reconnect).",
29+
)
30+
args = parser.parse_args()
31+
32+
firmware_path = os.path.abspath(args.firmware) if args.firmware is not None else DEFAULT_FIRMWARE
33+
34+
build_body()
35+
36+
if not os.path.isfile(firmware_path):
37+
parser.error(f"firmware file not found: {firmware_path}")
38+
39+
if args.all:
40+
serials = Panda.list()
41+
print(f"found {len(serials)} panda(s) - {serials}")
42+
else:
43+
serials = [None]
44+
45+
for s in serials:
46+
with Panda(serial=s) as p:
47+
print("flashing", p.get_usb_serial())
48+
p.flash(firmware_path, reconnect=args.wait_usb)
49+
exit(1 if len(serials) == 0 else 0)

board/body/main.c

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#include <stdint.h>
2+
#include <stdbool.h>
3+
4+
#include "board/config.h"
5+
#include "board/drivers/led.h"
6+
#include "board/drivers/pwm.h"
7+
#include "board/drivers/usb.h"
8+
#include "board/early_init.h"
9+
#include "board/obj/gitversion.h"
10+
#include "board/body/motor_control.h"
11+
#include "board/body/can.h"
12+
#include "opendbc/safety/safety.h"
13+
#include "board/drivers/can_common.h"
14+
#include "board/drivers/fdcan.h"
15+
#include "board/can_comms.h"
16+
17+
extern int _app_start[0xc000];
18+
19+
#include "board/body/main_comms.h"
20+
21+
void debug_ring_callback(uart_ring *ring) {
22+
char rcv;
23+
while (get_char(ring, &rcv)) {
24+
(void)injectc(ring, rcv);
25+
}
26+
}
27+
28+
void __attribute__ ((noinline)) enable_fpu(void) {
29+
SCB->CPACR |= ((3UL << (10U * 2U)) | (3UL << (11U * 2U)));
30+
}
31+
32+
void __initialize_hardware_early(void) {
33+
enable_fpu();
34+
early_initialization();
35+
}
36+
37+
volatile uint32_t tick_count = 0;
38+
39+
void tick_handler(void) {
40+
if (TICK_TIMER->SR != 0) {
41+
if (can_health[0].transmit_error_cnt >= 128) {
42+
(void)llcan_init(CANIF_FROM_CAN_NUM(0));
43+
}
44+
static bool led_on = false;
45+
led_set(LED_RED, led_on);
46+
led_on = !led_on;
47+
tick_count++;
48+
}
49+
TICK_TIMER->SR = 0;
50+
}
51+
52+
int main(void) {
53+
disable_interrupts();
54+
init_interrupts(true);
55+
56+
clock_init();
57+
peripherals_init();
58+
59+
current_board = &board_body;
60+
hw_type = HW_TYPE_BODY;
61+
62+
current_board->init();
63+
64+
REGISTER_INTERRUPT(TICK_TIMER_IRQ, tick_handler, 10U, FAULT_INTERRUPT_RATE_TICK);
65+
66+
led_init();
67+
microsecond_timer_init();
68+
tick_timer_init();
69+
usb_init();
70+
body_can_init();
71+
72+
enable_interrupts();
73+
74+
while (true) {
75+
uint32_t now = microsecond_timer_get();
76+
motor_speed_controller_update(now);
77+
body_can_periodic(now);
78+
}
79+
80+
return 0;
81+
}

0 commit comments

Comments
 (0)