Skip to content

Sensors 2021 Handover

Franz Miltz edited this page Aug 23, 2021 · 4 revisions

This document was created by Yeyao Liu (2020/21 Sensors PM) to capture the state of Sensors for the next year.

Overview

The sensors project works closely with the hardware we have on the pod. We are responsible for developing and maintaining drivers using one or more of the 3 (technically 5) communication protocols. On the pod we use I2C (similar to UART, which we technically also have), SPI (Serial Peripheral Interface), CAN (Controller Area Network) and GPIO (General Purpose Input Output, which is basically something that can be on or off (1 or 0)). To learn more about these, you can watch some YouTube videos about them or read up on them. Here are some suggested ones:

We have a vast array of sensors which are split into mini-projects which people can take on. Currently it consists of IMUs, Brakes, Battery Management System (BMS), Keyence sensor, Infrared (IR) sensor (new wheel encoders), lateral displacement sensor and “other small sensors”. Each of these can be assigned to one or more people depending on the current state of the project.

IMU

This is the Inertial Measurement Unit, we use it to get acceleration values. These values are then passed on to navigation where they do the maths (who likes maths) to figure out the speed, displacement etc.. The IMU uses the SPI protocol to communicate to the BBB but there is an aspect of I2C involved but not really (I’ll explain where the I2C is used later).

To begin you probably want to have a quick read of the datasheet linked below. In it you will see a register map. This part is mostly the part we are interested in and others are not as interesting. For us anyways. From the register map we can see that the registers are split into banks, this means that registers can have the same address in a different bank limits the number of addresses.

So, I'm going to assume you watched the videos above on SPI works and I will not explain it here. Now we can move onto coding, woo! Let's start with the configuration we do outside of the code. (all paths are relative to the home of hyped-202X(1) So for example I say /config it would be hyped-2021/config) So we have a config file in /configurations and inside it includes a file `sensors.txt. Within you will find the line “ChipSelect 47,22,27,86”. This indicates the GPIO pins that will be used for the chip select on each IMU. GPIO ping 47, 22 etc.. this can be changed and code does not need to be re-compiled.

Now we can dive into the actual code. The code is located at /src/sensors/and within you will find imu.hpp and imu.cpp. One is the header file so it will naturally understand it if you understand the cpp so I wont touch imu.hpp. To create the sensor we need 2 things, we need to know the GPIO pin it's connected to and if we want FIFO (First In First Out) enabled. The GPIO pin is simple as we can get it from the config file and FIFO is… Basically we get like a truck load of values more than non fifo and this is good, look it up - hard to explain.

During the initialization phase we reset the device first to make sure there is no leftover config on it. Then we proceed to apply the settings we like for the sensor by writing a byte to the register specified on the datasheet. Then we enable the FIFO, this shouldn’t affect anything if we choose not to use the FIFO. Then we can get the data by reading from the registers indicated in the datasheet or from the FIFO. The way the data is stored inside the registers/FIFO are indicated in the datasheet.

We also have imu_manager, this is called by the main “controller” and from within it creates the 4 instances of imu and it will constantly request data from the 4 imu’s in order and then update it to the navigation vector which they take it and do fancy maths to it. If we want to run the fake imu the IMU manager also handles it by calling the FakeImuFromFile providing the path to the fake data.

Inside fake_imu all its job is to read in the fake values from the text files and then feed it back when it's requested. This will simulate the real imu without actually needing to plug in an imu.

There is a demo_imu inside /run. This basically will create the imu_manager and then display the acceleration values to the console. We basically force the state machine to the accelerating state so it will constantly read in values.

What's left to do?

Well, there isn’t much. We need to test the IMU to make sure it works with the ICM-20948 and we can actually read decent looking values. Since the addition of the cruising state, we need to make sure that imu doesn’t break when we enter the cruising state and still function correctly. We tried to refactor fake_imu in the past but there was an issue (segfault) so we had to abandon it but the code still lives in the sns-fake_imu_. If you want to see if you can fix it then go ahead. So basically a lot of testing and possible refactor of the fake_imu. Good luck :D

(Side Note) There is a magnetometer on the sensor as well. We have a branch called sns-magnetometer and inside there is a magnetometer.cpp and hpp. They are a bodged together imu driver that activates the magnetometer as well as the imu originally intended for the EHW demo but then the demo was abandoned. The way this works is using the normal IMU driver for the IMU part and using the ICM20948 as a I2C master. This is because the magnetometer only communicates on I2C. By using a mix of online sources there is a bodged together version of the driver that works by reading both, and by running /run/demo_magnetometer.cpp it will output the values to the console. To test, you can move a magnet near the sensor and/or move the imu to test the acceleration.

https://devzone.nordicsemi.com/f/nordic-q-a/36615/invensense-icm-20948 was used to get the idea of how it would work by making itself the I2C master etc… https://github.com/kriswiner/MPU9250/issues/367 was the coding example for an older sensor but using the new register addresses etc… we can change it to work with the newer model of sensor.

BMS

The battery management system is used to fetch and monitor the battery data. The whole BMS code is made up of two parts. One is bms.cpp which just fetching data from the CAN bus and store it in memory. Another one is bms_manager.cpp which is used to check if battery data is in the safe range. For our pod, we got 2 high power battery packs and 3 low power battery packs. Each battery pack has their own BMS. To beware that our LP BMS is slightly different to the rest of the CAN devices. Due to the CAN bitrate issue, we have to use CAN-UART converter when communicating with LP BMS. So when you need to request data from LP BMS you have to write it in UART format then send it to the converter via CAN bus. It will translate from CAN message to UART message then send it to the LP BMS. Also, the LP BMS return message also will be sent to BBB in UART format via CAN bus.

BBB<--CAN-->CONVERTER<--UART-->BMS

The code on the sns-bms branch (2021 repo) is only just a demo for single HP BMS and single LP BMS. The whole BMS code is still WIP and I never got a chance to test it on the actual hardware

(Sadly) So what you need to do is

  1. Read and understand the current demo code and BMS datasheet
  2. Test the code we currently have or write a demo code by yourself
  3. Expand the code in order to communicate with 2 HP BMS and 3 LP BMS. (Beware you needs to assign different CAN ID to the BMS)
  4. Talk to others teams to find out what is the safety range value for batteries. Then write it into the bms_manager.cpp

(The state machine part for BMS is already sorted. so don't worry :D) Good luck :D

Brakes

This year the brakes use a pneumatic system to operate. There is a set of magnetic brakes and a set of mechanical brakes. The brakes are operated by turning a value which then allows the pressure through, activating the brakes. This makes our coding really simple. The brakes can only be in 2 states, On and Off, which means we can use the GPIO protocol. Each brake also has a physical button telling us that it is engaged or not which we can read from to verify the brakes are actually engaged or not. We have 4 of these buttons, 2 for each type of brake.

Nearly all of the brake’s code lives within src/embrakes, why is it called embrakes? Well, it’s too many files to dig through to change all the instances that look for embrakes and don't want to break anything, so if you want to change it, it can be done. (Editor's note: This was done in the hyped-2022 repo. cf. PR#19) Inside the directory we have stepper, main, interface and fake_stepper

Inside stepper, it is our “valve” if you would like to imagine it that way. So from here we will send commands to using GPIO to engage the brakes or disengage. This is also where to check the button each brake has and make sure that the brakes are at the state we want them to be.

Inside main is where we communicate with the rest of the software system. So we initialise each brake with their command pin and button pin. The command pin is where we tell the brakes to engage or disengage and the button pin we read from to check where the brakes are. This runs on its own thread, and it constantly checks the state we are currently in from STM. Based on the state we either tell the brake to engage and check that it has engaged or tell it to disengage or just check the position it is in.

Inside fake_stepper it basically sets the values to the ideal ones manually instead of reading from a sensor. Which would act like the real stepper

So earlier I said “nearly” all of the brake code is in src/embrakes but since we are using a pneumatic system we have to monitor the pressure, so we have a pressure sensor!! This lives in src/sensors/pressure.cpp and in the branch “sns-pressure”. This is very similar to the temperature code as it uses ADC. This basically uses the BBB to read the voltage given by the sensor and we read it from the BBB. Then from this voltage we use a formula to convert it into units we want, such as Bar.

What's left to do?

  1. We need to confirm the brake code itself will work with the new state “cruising”.
  2. Need to figure out how many actuators we need to control per brake.
  3. Add the pressure sensor checks to the brakes code.
  4. Verify the pressure sensor works.
  5. Test the whole thing.

Keyence Sensor

This is an optical sensor that reads “stripes” on the wall of the tunnel (spacex thing, not sure if it's still a thing but it’s there) and each stripe is a certain distance away so we can calculate the distance traveled based on how many stripes we passed. This is a very simple design (coding wise). We basically read the GPIO pin which tells us if the sensor detects a stripe or not. Then we update the number of stripes we passed by 1.

The code is in /src/sensors/gpio_counter.cpp and instances of these are created from /src/sensors/main.cpp. We have 2 keyence sensors, one on the left and one on the right side of the pod. The fake_gpo_counter works in a similar way but instead it reads in a timestamp and the number of stripes it has passed. So it compares the timestamp read in to the time since the pod has run and when it matches it updates the number of stripes it has passed. I feel that the code is pretty self explanatory.

What's left to do?

Umm… it should work but since we have a new state of cruising. Need to make sure that the real system and the fake system both still work as intended.

IR Sensor

This sensor is supposed to replace the wheel encoders. We couldn't find a wheel encoder to our spec and this was the alternative. Basically, this is similar to the keyence sensor above and it reads a reflective material and outputs a pulse. By doing some maths, we can convert the pulses in RPM and into distance/displacement/speed etc.. There wasn't alot of discussion about this and not a lot of information circulating around for it. Only information I have is messages and drawings from Albin.

The diagram on the right is how the wheel will be coloured (yellow and reflective material) which will raise the voltage and black sections will drop the voltage giving us 2 pulses.

Apart from this information we have very little on the sensor itself. I believe the TCND5000 (datasheet found in the electronics folder) will be used for this. This will be a fresh start as we have not started coding for this as the sensor was suggested very late into the year.

What is left to do?

Everything. Nothing has been done.

Good luck! :D

Lateral Displacement Sensor

This is a sensor which is introduced by propulsion. Basically they want us to monitor the distance between the I-Beam (track) and the LIMs (Linear Induction Motors). If the distance gets too close there could be issues. The very original idea was to create an active suspension system where we control some suspension modules and make sure the pod is always centered but this was scrapped as it was way out of the scope for this year. It could make a return? Idk. There wasn't much info on this apart from this message from Albin:

“We've been investigating it a bit and an idea we have as of right now (still early in concept design) is to have a force sensitive resistor mounted on the spring of the lateral suspension modules. So that'll be a changing voltage (analogue) signal corresponding to how much the FSR is pressed, i.e. the pod is displaced laterally We're just trying to figure out a mathematical relationship between spring compression force and overall lateral displacement so we can use that So yeah if we can get this to work it should be quite a simple implementation and would just be an analogue signal for you guys. Problem is however thát all the analogue pins on the BBB are already in use for pressure/temp measurements so we might need to free up some of those”

There is no code on this nor a lot of information on how this would work, so it's something new to work on.

What is left to do?

Everything. Nothing has been done for this.

Good luck! :D

Clone this wiki locally