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

Version 1.6.3 #313

Merged
merged 22 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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 firmware/src/adc/adc.c
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ void ADC_DTSE_Init(void)
PAC55XX_ADC->DTSETRIGENT0TO3.TRIG1CFGIDX = 12; // DTSE Trigger 1 Sequence Configuration Entry Index
PAC55XX_ADC->DTSETRIGENT0TO3.TRIG1EDGE = ADCDTSE_TRIGEDGE_RISING; // PWMA0 rising edge

pac5xxx_timer_a_ccctr1_value_set((timer_freq_hz / 2 / PWM_FREQ_HZ) - 2);
pac5xxx_timer_a_ccctr1_value_set((TIMER_FREQ_HZ/(2*PWM_FREQ_HZ)) - 2);

//===== Setup DTSE Sequence B (sense current) - Starts at Entry 12 =====
pac5xxx_dtse_seq_config(12, ADC0, EMUX_AIO10, 0, 0);
Expand Down
2 changes: 1 addition & 1 deletion firmware/src/can/can_endpoints.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@


uint8_t (*avlos_endpoints[79])(uint8_t * buffer, uint8_t * buffer_len, Avlos_Command cmd) = {&avlos_protocol_hash, &avlos_uid, &avlos_fw_version, &avlos_hw_revision, &avlos_Vbus, &avlos_Ibus, &avlos_power, &avlos_temp, &avlos_calibrated, &avlos_errors, &avlos_save_config, &avlos_erase_config, &avlos_reset, &avlos_enter_dfu, &avlos_scheduler_errors, &avlos_controller_state, &avlos_controller_mode, &avlos_controller_warnings, &avlos_controller_errors, &avlos_controller_position_setpoint, &avlos_controller_position_p_gain, &avlos_controller_velocity_setpoint, &avlos_controller_velocity_limit, &avlos_controller_velocity_p_gain, &avlos_controller_velocity_i_gain, &avlos_controller_velocity_deadband, &avlos_controller_velocity_increment, &avlos_controller_current_Iq_setpoint, &avlos_controller_current_Id_setpoint, &avlos_controller_current_Iq_limit, &avlos_controller_current_Iq_estimate, &avlos_controller_current_bandwidth, &avlos_controller_current_Iq_p_gain, &avlos_controller_current_max_Ibus_regen, &avlos_controller_current_max_Ibrake, &avlos_controller_voltage_Vq_setpoint, &avlos_controller_calibrate, &avlos_controller_idle, &avlos_controller_position_mode, &avlos_controller_velocity_mode, &avlos_controller_current_mode, &avlos_controller_set_pos_vel_setpoints, &avlos_comms_can_rate, &avlos_comms_can_id, &avlos_motor_R, &avlos_motor_L, &avlos_motor_pole_pairs, &avlos_motor_type, &avlos_motor_offset, &avlos_motor_direction, &avlos_motor_calibrated, &avlos_motor_I_cal, &avlos_motor_errors, &avlos_encoder_position_estimate, &avlos_encoder_velocity_estimate, &avlos_encoder_type, &avlos_encoder_bandwidth, &avlos_encoder_calibrated, &avlos_encoder_errors, &avlos_traj_planner_max_accel, &avlos_traj_planner_max_decel, &avlos_traj_planner_max_vel, &avlos_traj_planner_t_accel, &avlos_traj_planner_t_decel, &avlos_traj_planner_t_total, &avlos_traj_planner_move_to, &avlos_traj_planner_move_to_tlimit, &avlos_traj_planner_errors, &avlos_homing_velocity, &avlos_homing_max_homing_t, &avlos_homing_retract_dist, &avlos_homing_warnings, &avlos_homing_stall_detect_velocity, &avlos_homing_stall_detect_delta_pos, &avlos_homing_stall_detect_t, &avlos_homing_home, &avlos_watchdog_enabled, &avlos_watchdog_triggered, &avlos_watchdog_timeout };
uint32_t avlos_proto_hash = 4118115615;
uint32_t avlos_proto_hash = 3526126264;

uint32_t _avlos_get_proto_hash(void)
{
Expand Down
5 changes: 4 additions & 1 deletion firmware/src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,16 +129,19 @@
#define BOARD_REV_IDX 21
#endif

#define TIMER_FREQ_HZ (ACLK_FREQ_HZ >> TXCTL_PS_DIV)

static const float one_by_sqrt3 = 0.57735026919f;
static const float two_by_sqrt3 = 1.15470053838f;
static const float threehalfpi = 4.7123889f;
static const float pi = PI;
static const float halfpi = PI * 0.5f;
static const float quarterpi = PI * 0.25f;
static const int32_t timer_freq_hz = ACLK_FREQ_HZ >> TXCTL_PS_DIV;
static const float twopi_by_enc_ticks = TWOPI / ENCODER_TICKS;
static const float twopi_by_hall_sectors = TWOPI / HALL_SECTORS;

_Static_assert (TIMER_FREQ_HZ % (2*PWM_FREQ_HZ) == 0, "Timer frequency not an integer multiple of PWM frequency");

typedef struct
{
float A;
Expand Down
6 changes: 3 additions & 3 deletions firmware/src/gatedriver/gatedriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,17 @@ void gate_driver_set_duty_cycle(const FloatTriplet *dc);
//=============================================
static inline void m1_u_set_duty(const float duty)
{
uint16_t val = ((uint16_t)(duty * (timer_freq_hz/PWM_FREQ_HZ) )) >>1;
uint16_t val = ((uint16_t)(duty * (TIMER_FREQ_HZ/PWM_FREQ_HZ) )) >>1;
PAC55XX_TIMERA->CCTR4.CTR = val;
}
static inline void m1_v_set_duty(const float duty)
{
uint16_t val = ((uint16_t)(duty * (timer_freq_hz/PWM_FREQ_HZ) )) >>1;
uint16_t val = ((uint16_t)(duty * (TIMER_FREQ_HZ/PWM_FREQ_HZ) )) >>1;
PAC55XX_TIMERA->CCTR5.CTR = val;
}
static inline void m1_w_set_duty(const float duty)
{
uint16_t val = ((uint16_t)(duty * (timer_freq_hz/PWM_FREQ_HZ) )) >>1;
uint16_t val = ((uint16_t)(duty * (TIMER_FREQ_HZ/PWM_FREQ_HZ) )) >>1;
PAC55XX_TIMERA->CCTR6.CTR = val;
}

Expand Down
2 changes: 1 addition & 1 deletion firmware/src/timer/timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ void Timer_Init(void)
{
// Configure Timer A Controls
pac5xxx_timer_clock_config(TimerA, TXCTL_CS_ACLK, TXCTL_PS_DIV); // Configure timer clock input for ACLK, divider
pac5xxx_timer_base_config(TimerA, (timer_freq_hz/2/PWM_FREQ_HZ), AUTO_RELOAD,
pac5xxx_timer_base_config(TimerA, (TIMER_FREQ_HZ/(2*PWM_FREQ_HZ)), AUTO_RELOAD,
TxCTL_MODE_UPDOWN, TIMER_SLAVE_SYNC_DISABLE); // Configure timer frequency and count mode

// Configure Dead time generators
Expand Down
6 changes: 4 additions & 2 deletions studio/Python/tests/test_base_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,17 @@ def test_position_control(self):
Test position control
"""
self.check_state(0)
self.tm.motor.I_cal = 5
self.tm.controller.current.Iq_limit = 5
self.try_calibrate()
self.tm.controller.position_mode()
self.check_state(2)

for i in range(5):
self.tm.controller.position.setpoint = i * 10000 * ticks
self.tm.controller.position.setpoint = i * 3000 * ticks
time.sleep(0.25)
self.assertAlmostEqual(
i * 10000 * ticks, self.tm.encoder.position_estimate, delta=1000 * ticks
i * 3000 * ticks, self.tm.encoder.position_estimate, delta=1000 * ticks
)


Expand Down
33 changes: 22 additions & 11 deletions studio/Python/tests/test_board.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,19 +367,30 @@ def test_p_flux_braking(self):
# Ensure we're idle
self.check_state(0)
self.try_calibrate()

self.tm.controller.current.max_Ibrake = 10
self.tm.controller.current.max_Ibrake = 0
self.tm.controller.velocity_mode()
self.tm.controller.velocity.setpoint = 200000
time.sleep(0.4)
self.tm.controller.velocity.setpoint = 0
I_brake_vals = []
for _ in range(50):
I_brake_vals.append(self.tm.Ibus)
time.sleep(0.005)
time.sleep(0.5)
for v_set in [-250000, 250000]:
self.tm.controller.velocity.setpoint = v_set
time.sleep(0.4)
self.tm.controller.velocity.setpoint = 0
I_brake_vals = []
for _ in range(200):
I_brake_vals.append(self.tm.Ibus)
time.sleep(0.001)
time.sleep(0.2)
self.assertLess(min(I_brake_vals), -0.12 * A)
self.tm.controller.current.max_Ibrake = 10
for v_set in [-250000, 250000]:
self.tm.controller.velocity.setpoint = v_set
time.sleep(0.4)
self.tm.controller.velocity.setpoint = 0
I_brake_vals = []
for _ in range(200):
I_brake_vals.append(self.tm.Ibus)
time.sleep(0.001)
time.sleep(0.2)
self.assertGreater(min(I_brake_vals), -0.12 * A)
self.tm.controller.current.max_Ibrake = 0
self.assertGreater(min(I_brake_vals), -1 * A)
self.tm.controller.idle()
time.sleep(0.4)

Expand Down
3 changes: 1 addition & 2 deletions studio/Python/tests/test_dfu.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@
from tinymovr import init_tee, destroy_tee
from tinymovr.config import (
get_bus_config,
create_device,
definitions
create_device
)

import unittest
Expand Down
12 changes: 10 additions & 2 deletions studio/Python/tinymovr/cli.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
"""Tinymovr Studio CLI

Usage:
tinymovr_cli [--bus=<bus>] [--chan=<chan>] [--bitrate=<bitrate>]
tinymovr_cli [--bus=<bus>] [--chan=<chan>] [--spec=<spec>] [--bitrate=<bitrate>]
tinymovr_cli -h | --help
tinymovr_cli --version

Options:
--bus=<bus> One or more interfaces to use, first available is used [default: canine,slcan_disco].
--chan=<chan> The bus device "channel".
--spec=<spec> A custom device spec to be added to the list of discoverable spec.
--bitrate=<bitrate> CAN bitrate [default: 1000000].
"""

import yaml
import can
import pkg_resources
import IPython
Expand All @@ -20,7 +22,7 @@
from tinymovr import init_tee, destroy_tee
from tinymovr.discovery import Discovery
from tinymovr.constants import app_name
from tinymovr.config import get_bus_config, configure_logging
from tinymovr.config import get_bus_config, configure_logging, add_spec

"""
Tinymovr CLI Module
Expand Down Expand Up @@ -49,6 +51,12 @@ def spawn():

logger = configure_logging()

spec_file = arguments["--spec"]
if spec_file:
with open(spec_file, 'r') as file:
spec_data = yaml.safe_load(file)
add_spec(spec_data, logger)

buses = arguments["--bus"].rsplit(sep=",")
channel = arguments["--chan"]
bitrate = int(arguments["--bitrate"])
Expand Down
3 changes: 1 addition & 2 deletions studio/Python/tinymovr/config/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
from tinymovr.config.config import (
get_bus_config,
configure_logging,
definitions,
create_device,
create_device_with_hash_msg,
ProtocolVersionError,
add_spec,
)
82 changes: 38 additions & 44 deletions studio/Python/tinymovr/config/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,29 +25,30 @@
from tinymovr.codec import DataType
from tinymovr.channel import CANChannel

definitions = {"hash_uint32": {}, "name": {}}

for yaml_file in Path(files("tinymovr").joinpath("specs/")).glob("*.yaml"):
with open(str(yaml_file)) as def_raw:
definition = yaml.safe_load(def_raw)
tmp_node = deserialize(definition)
definitions["hash_uint32"][tmp_node.hash_uint32] = definition
definitions["name"][definition["name"]] = definition


class ProtocolVersionError(Exception):
def __init__(self, dev_id, version_str, *args, **kwargs):
self.dev_id = dev_id
self.version_str = cleanup_incomplete_version(version_str)
msg = (
"Incompatible protocol versions (hash mismatch) for device {}. "
"Firmware is compatible with Studio version {}.\n\n"
"Either upgrade studio and firmware, or install a compatible Studio version like so:\n\n"
"pip3 uninstall tinymovr\npip3 install tinymovr=={}".format(
self.dev_id, self.version_str, self.version_str
)
)
super().__init__(msg, *args, **kwargs)
specs = {"hash_uint32": {}}


def init_specs_dict():
global specs
for yaml_file in Path(files("tinymovr").joinpath("specs/")).glob("*.yaml"):
with open(str(yaml_file)) as def_raw:
spec = yaml.safe_load(def_raw)
add_spec(spec)


def add_spec(spec, logger=None):
if logger is None:
logger = logging.getLogger("tinymovr")

tmp_node = deserialize(spec)
hash_value = tmp_node.hash_uint32
if hash_value in specs["hash_uint32"]:
logger.warning("Provided spec with hash {} already exists in hash/name dictionary".format(hash_value))
else:
specs["hash_uint32"][hash_value] = spec


init_specs_dict()


def get_bus_config(suggested_types=None):
Expand All @@ -70,24 +71,22 @@ def create_device(node_id):
"""
chan = CANChannel(node_id)

# Temporarily using a default definition to get the protocol_hash
# This assumes that `protocol_hash` is standard across different definitions
# Get the first definition as a temp
tmp_definition = list(definitions["hash_uint32"].values())[0]
node = deserialize(tmp_definition)
# Temporarily using a default spec to get the protocol_hash
# This assumes that `protocol_hash` is standard across different specs
# Get the first spec as a temp
tmp_spec = list(specs["hash_uint32"].values())[0]
node = deserialize(tmp_spec)
node._channel = chan

# Check for the correct definition using the remote hash
# Check for the correct spec using the remote hash
protocol_hash = node.protocol_hash
device_definition = definitions["hash_uint32"].get(protocol_hash)
device_spec = specs["hash_uint32"].get(protocol_hash)

if not device_definition:
raise ValueError(f"No device definition found for hash {protocol_hash}.")
if not device_spec:
raise ValueError(f"No device spec found for hash {protocol_hash}.")

node = deserialize(device_definition)
node = deserialize(device_spec)
node._channel = chan
if node.hash_uint32 != protocol_hash:
raise ProtocolVersionError(node_id, "")

return node

Expand All @@ -101,17 +100,12 @@ def create_device_with_hash_msg(heartbeat_msg):
chan = CANChannel(node_id)

hash, *_ = chan.serializer.deserialize(heartbeat_msg.data[:4], DataType.UINT32)
device_definition = definitions["hash_uint32"].get(hash)
device_spec = specs["hash_uint32"].get(hash)

if not device_definition:
raise ValueError(f"No device definition found for hash {hash}.")
if not device_spec:
raise ValueError(f"No device spec found for hash {hash}.")

node = deserialize(device_definition)
if node.hash_uint32 != hash:
version_str = "".join([chr(n) for n in heartbeat_msg.data[4:]])
if not version_str.strip():
version_str = "1.3.1"
raise ProtocolVersionError(node_id, version_str)
node = deserialize(device_spec)

node._channel = chan
return node
Expand Down
4 changes: 2 additions & 2 deletions studio/Python/tinymovr/discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from tinymovr.channel import ResponseError
from tinymovr.tee import get_tee
from tinymovr.constants import HEARTBEAT_BASE
from tinymovr.config import create_device_with_hash_msg, ProtocolVersionError
from tinymovr.config import create_device_with_hash_msg


class Discovery:
Expand Down Expand Up @@ -72,7 +72,7 @@ def _recv_cb(self, frame):
self._append_to_queue((node, node_id))
except ResponseError as e:
self.logger.error(e)
except ProtocolVersionError as e:
except ValueError as e:
self.logger.error(e)
self.incompatible_nodes.add(node_id)
self.pending_nodes.remove(node_id)
Expand Down
7 changes: 5 additions & 2 deletions studio/Python/tinymovr/gui/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@
display_file_open_dialog,
display_file_save_dialog,
magnitude_of,
hold_sema,
TimedGetter,
check_selected_items,
get_dynamic_attrs,
is_dark_mode
)
from tinymovr.gui.widgets import (
OurQTreeWidget,
NodeTreeWidgetItem,
AttrTreeWidgetItem,
FuncTreeWidgetItem,
OptionsTreeWidgetItem,
PlaceholderQTreeWidget,
IconComboBoxWidget,
ArgumentInputDialog
)
Expand Down
16 changes: 14 additions & 2 deletions studio/Python/tinymovr/gui/gui.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
"""Tinymovr Studio GUI

Usage:
tinymovr [--bus=<bus>] [--chan=<chan>] [--bitrate=<bitrate>] [--max-timeouts=<count>]
tinymovr [--bus=<bus>] [--chan=<chan>] [--spec=<spec>] [--bitrate=<bitrate>] [--max-timeouts=<count>]
tinymovr -h | --help
tinymovr --version

Options:
--bus=<bus> One or more interfaces to use, first available is used [default: canine,slcan_disco].
--chan=<chan> The bus device "channel".
--spec=<spec> A custom device spec to be added to the list of discoverable specs.
--bitrate=<bitrate> CAN bitrate [default: 1000000].
--max-timeouts=<count> Max timeouts before nodes are rescanned [default: 5].
"""

import sys
import yaml
import pkg_resources
from docopt import docopt
from PySide6.QtWidgets import QApplication
from tinymovr.gui import MainWindow, app_stylesheet, app_stylesheet_dark, is_dark_mode
from tinymovr.constants import app_name
from tinymovr.config import configure_logging, add_spec


"""
Expand All @@ -41,11 +44,20 @@
def spawn():
version = pkg_resources.require("tinymovr")[0].version
arguments = docopt(__doc__, version=app_name + " " + str(version))

logger = configure_logging()

spec_file = arguments["--spec"]
if spec_file:
with open(spec_file, 'r') as file:
spec_data = yaml.safe_load(file)
add_spec(spec_data, logger)

app = QApplication(sys.argv)
if is_dark_mode():
app.setStyleSheet(app_stylesheet_dark)
else:
app.setStyleSheet(app_stylesheet)
w = MainWindow(app, arguments)
w = MainWindow(app, arguments, logger)
w.show()
sys.exit(app.exec_())
Loading
Loading